@umituz/react-native-ai-generation-content 1.12.25 → 1.12.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/domains/creations/application/services/CreationsService.ts +73 -0
- package/src/domains/creations/domain/entities/Creation.ts +60 -0
- package/src/domains/creations/domain/entities/index.ts +6 -0
- package/src/domains/creations/domain/repositories/ICreationsRepository.ts +23 -0
- package/src/domains/creations/domain/repositories/index.ts +5 -0
- package/src/domains/creations/domain/services/ICreationsStorageService.ts +13 -0
- package/src/domains/creations/domain/value-objects/CreationsConfig.ts +75 -0
- package/src/domains/creations/domain/value-objects/index.ts +12 -0
- package/src/domains/creations/index.ts +84 -0
- package/src/domains/creations/infrastructure/adapters/createRepository.ts +54 -0
- package/src/domains/creations/infrastructure/adapters/index.ts +5 -0
- package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +241 -0
- package/src/domains/creations/infrastructure/repositories/index.ts +8 -0
- package/src/domains/creations/infrastructure/services/CreationsStorageService.ts +49 -0
- package/src/domains/creations/presentation/components/CreationCard.tsx +136 -0
- package/src/domains/creations/presentation/components/CreationDetail/DetailActions.tsx +76 -0
- package/src/domains/creations/presentation/components/CreationDetail/DetailHeader.tsx +81 -0
- package/src/domains/creations/presentation/components/CreationDetail/DetailImage.tsx +41 -0
- package/src/domains/creations/presentation/components/CreationDetail/DetailStory.tsx +67 -0
- package/src/domains/creations/presentation/components/CreationDetail/index.ts +4 -0
- package/src/domains/creations/presentation/components/CreationImageViewer.tsx +43 -0
- package/src/domains/creations/presentation/components/CreationThumbnail.tsx +63 -0
- package/src/domains/creations/presentation/components/CreationsGrid.tsx +75 -0
- package/src/domains/creations/presentation/components/CreationsHomeCard.tsx +176 -0
- package/src/domains/creations/presentation/components/EmptyState.tsx +82 -0
- package/src/domains/creations/presentation/components/FilterBottomSheet.tsx +160 -0
- package/src/domains/creations/presentation/components/FilterChips.tsx +105 -0
- package/src/domains/creations/presentation/components/GalleryEmptyStates.tsx +87 -0
- package/src/domains/creations/presentation/components/GalleryHeader.tsx +106 -0
- package/src/domains/creations/presentation/components/index.ts +20 -0
- package/src/domains/creations/presentation/hooks/index.ts +7 -0
- package/src/domains/creations/presentation/hooks/useCreations.ts +38 -0
- package/src/domains/creations/presentation/hooks/useCreationsFilter.ts +77 -0
- package/src/domains/creations/presentation/hooks/useDeleteCreation.ts +51 -0
- package/src/domains/creations/presentation/screens/CreationDetailScreen.tsx +78 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +194 -0
- package/src/domains/creations/presentation/screens/index.ts +5 -0
- package/src/domains/creations/presentation/utils/filterUtils.ts +52 -0
- package/src/domains/creations/types.d.ts +42 -0
- package/src/domains/prompts/infrastructure/services/AIServiceProcessor.ts +142 -0
- package/src/domains/prompts/presentation/hooks/useAIServices.ts +15 -132
- package/src/features/background/presentation/components/ComparisonSlider.tsx +2 -2
- package/src/features/background/presentation/components/ErrorDisplay.tsx +2 -2
- package/src/features/background/presentation/components/GenerateButton.tsx +0 -2
- package/src/features/background/presentation/components/ImagePicker.tsx +2 -2
- package/src/features/background/presentation/components/ResultDisplay.tsx +2 -2
- package/src/index.ts +6 -0
- package/src/infrastructure/services/generation-orchestrator.service.ts +25 -162
- package/src/infrastructure/services/job-poller.ts +103 -0
- package/src/infrastructure/services/progress-manager.ts +58 -0
- package/src/infrastructure/services/provider-validator.ts +52 -0
- package/src/presentation/components/GenerationProgressContent.tsx +4 -4
- package/src/presentation/components/PendingJobCard.tsx +2 -2
- package/src/presentation/components/PendingJobCardActions.tsx +2 -2
- package/src/presentation/components/result/GenerationResultContent.tsx +2 -3
- package/src/presentation/hooks/usePhotoGeneration.ts +7 -5
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Poller
|
|
3
|
+
* Handles polling logic for job status
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IAIProvider, JobStatus } from "../../domain/interfaces";
|
|
7
|
+
import { DEFAULT_POLLING_CONFIG, type PollingConfig, type GenerationProgress } from "../../domain/entities";
|
|
8
|
+
import { isTransientError } from "../utils/error-classifier.util";
|
|
9
|
+
import { createPollingDelay } from "../utils/polling-interval.util";
|
|
10
|
+
|
|
11
|
+
declare const __DEV__: boolean;
|
|
12
|
+
|
|
13
|
+
export interface PollerConfig {
|
|
14
|
+
polling?: Partial<PollingConfig>;
|
|
15
|
+
onStatusUpdate?: (requestId: string, status: string) => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class JobPoller {
|
|
19
|
+
private config: PollerConfig = {};
|
|
20
|
+
|
|
21
|
+
configure(config: PollerConfig): void {
|
|
22
|
+
this.config = { ...this.config, ...config };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async pollForResult<T>(
|
|
26
|
+
provider: IAIProvider,
|
|
27
|
+
model: string,
|
|
28
|
+
requestId: string,
|
|
29
|
+
onProgress?: (progress: GenerationProgress) => void,
|
|
30
|
+
onStatusUpdate?: (status: JobStatus, attempt: number, config: PollingConfig) => void,
|
|
31
|
+
): Promise<T> {
|
|
32
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.log("[JobPoller] pollForResult() started", {
|
|
35
|
+
provider: provider.providerId,
|
|
36
|
+
model,
|
|
37
|
+
requestId,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const config = {
|
|
42
|
+
...DEFAULT_POLLING_CONFIG,
|
|
43
|
+
...this.config.polling,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
let consecutiveErrors = 0;
|
|
47
|
+
|
|
48
|
+
for (let attempt = 0; attempt < config.maxAttempts; attempt++) {
|
|
49
|
+
await createPollingDelay(attempt, config);
|
|
50
|
+
|
|
51
|
+
if (typeof __DEV__ !== "undefined" && __DEV__ && attempt % 5 === 0) {
|
|
52
|
+
// eslint-disable-next-line no-console
|
|
53
|
+
console.log("[JobPoller] pollForResult() attempt", {
|
|
54
|
+
attempt,
|
|
55
|
+
maxAttempts: config.maxAttempts,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const status = await provider.getJobStatus(model, requestId);
|
|
61
|
+
|
|
62
|
+
consecutiveErrors = 0;
|
|
63
|
+
|
|
64
|
+
onStatusUpdate?.(status, attempt, config);
|
|
65
|
+
|
|
66
|
+
if (status.status === "COMPLETED") {
|
|
67
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
68
|
+
// eslint-disable-next-line no-console
|
|
69
|
+
console.log("[JobPoller] pollForResult() job COMPLETED", {
|
|
70
|
+
requestId,
|
|
71
|
+
attempt,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return provider.getJobResult<T>(model, requestId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (status.status === "FAILED") {
|
|
78
|
+
throw new Error("Job failed on provider");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await this.config.onStatusUpdate?.(requestId, status.status);
|
|
82
|
+
} catch (error) {
|
|
83
|
+
if (isTransientError(error)) {
|
|
84
|
+
consecutiveErrors++;
|
|
85
|
+
|
|
86
|
+
if (consecutiveErrors >= config.maxConsecutiveErrors) {
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Polling timeout after ${config.maxAttempts} attempts`,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const jobPoller = new JobPoller();
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progress Manager
|
|
3
|
+
* Handles progress tracking and updates during generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { GenerationProgress, PollingConfig } from "../../domain/entities";
|
|
7
|
+
import type { JobStatus } from "../../domain/interfaces";
|
|
8
|
+
import { createProgressTracker } from "../utils/progress-calculator.util";
|
|
9
|
+
|
|
10
|
+
export class ProgressManager {
|
|
11
|
+
private progressTracker = createProgressTracker();
|
|
12
|
+
|
|
13
|
+
updateProgress(
|
|
14
|
+
stage: GenerationProgress["stage"],
|
|
15
|
+
subProgress: number,
|
|
16
|
+
onProgress?: (progress: GenerationProgress) => void,
|
|
17
|
+
): void {
|
|
18
|
+
const progress = this.progressTracker.setStatus(stage);
|
|
19
|
+
onProgress?.({
|
|
20
|
+
stage,
|
|
21
|
+
progress: progress + subProgress,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
updateProgressFromStatus(
|
|
26
|
+
status: JobStatus,
|
|
27
|
+
attempt: number,
|
|
28
|
+
config: PollingConfig,
|
|
29
|
+
onProgress?: (progress: GenerationProgress) => void,
|
|
30
|
+
): void {
|
|
31
|
+
const baseProgress = 25;
|
|
32
|
+
const maxProgress = 85;
|
|
33
|
+
const range = maxProgress - baseProgress;
|
|
34
|
+
|
|
35
|
+
let progress: number;
|
|
36
|
+
|
|
37
|
+
if (status.status === "IN_QUEUE") {
|
|
38
|
+
progress = baseProgress + range * 0.2;
|
|
39
|
+
} else if (status.status === "IN_PROGRESS") {
|
|
40
|
+
const ratio = Math.min(attempt / (config.maxAttempts * 0.7), 1);
|
|
41
|
+
progress = baseProgress + range * (0.2 + 0.6 * ratio);
|
|
42
|
+
} else {
|
|
43
|
+
progress = baseProgress;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
onProgress?.({
|
|
47
|
+
stage: "generating",
|
|
48
|
+
progress: Math.round(progress),
|
|
49
|
+
eta: status.eta,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
reset(): void {
|
|
54
|
+
this.progressTracker = createProgressTracker();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export const progressManager = new ProgressManager();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider Validator
|
|
3
|
+
* Validates provider availability and initialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { IAIProvider } from "../../domain/interfaces";
|
|
7
|
+
import { providerRegistry } from "./provider-registry.service";
|
|
8
|
+
|
|
9
|
+
declare const __DEV__: boolean;
|
|
10
|
+
|
|
11
|
+
export class ProviderValidator {
|
|
12
|
+
getProvider(): IAIProvider {
|
|
13
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
14
|
+
// eslint-disable-next-line no-console
|
|
15
|
+
console.log("[ProviderValidator] getProvider() called");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const provider = providerRegistry.getActiveProvider();
|
|
19
|
+
|
|
20
|
+
if (!provider) {
|
|
21
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.error("[ProviderValidator] No active provider found!");
|
|
24
|
+
}
|
|
25
|
+
throw new Error(
|
|
26
|
+
"No active AI provider. Register and set a provider first.",
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!provider.isInitialized()) {
|
|
31
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
32
|
+
// eslint-disable-next-line no-console
|
|
33
|
+
console.error("[ProviderValidator] Provider not initialized:", provider.providerId);
|
|
34
|
+
}
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Provider ${provider.providerId} is not initialized.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.log("[ProviderValidator] getProvider() returning:", {
|
|
43
|
+
providerId: provider.providerId,
|
|
44
|
+
isInitialized: provider.isInitialized(),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return provider;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const providerValidator = new ProviderValidator();
|
|
@@ -45,11 +45,11 @@ export const GenerationProgressContent: React.FC<
|
|
|
45
45
|
return (
|
|
46
46
|
<View style={[styles.modal, { backgroundColor: activeBgColor }]}>
|
|
47
47
|
{title && (
|
|
48
|
-
<AtomicText
|
|
48
|
+
<AtomicText style={[styles.title, { color: activeTextColor }]}>{title}</AtomicText>
|
|
49
49
|
)}
|
|
50
50
|
|
|
51
51
|
{message && (
|
|
52
|
-
<AtomicText
|
|
52
|
+
<AtomicText style={[styles.message, { color: activeTextColor }]}>
|
|
53
53
|
{message}
|
|
54
54
|
</AtomicText>
|
|
55
55
|
)}
|
|
@@ -62,7 +62,7 @@ export const GenerationProgressContent: React.FC<
|
|
|
62
62
|
/>
|
|
63
63
|
|
|
64
64
|
{hint && (
|
|
65
|
-
<AtomicText
|
|
65
|
+
<AtomicText style={[styles.hint, { color: activeTextColor }]}>{hint}</AtomicText>
|
|
66
66
|
)}
|
|
67
67
|
|
|
68
68
|
{onDismiss && (
|
|
@@ -73,7 +73,7 @@ export const GenerationProgressContent: React.FC<
|
|
|
73
73
|
]}
|
|
74
74
|
onPress={onDismiss}
|
|
75
75
|
>
|
|
76
|
-
<AtomicText
|
|
76
|
+
<AtomicText style={styles.dismissText}>{dismissLabel || "OK"}</AtomicText>
|
|
77
77
|
</TouchableOpacity>
|
|
78
78
|
)}
|
|
79
79
|
</View>
|
|
@@ -106,8 +106,8 @@ export function PendingJobCard<TInput = unknown, TResult = unknown>({
|
|
|
106
106
|
)}
|
|
107
107
|
<View style={styles.content}>
|
|
108
108
|
<View>
|
|
109
|
-
{typeLabel && <AtomicText
|
|
110
|
-
<AtomicText
|
|
109
|
+
{typeLabel && <AtomicText style={styles.typeText}>{typeLabel}</AtomicText>}
|
|
110
|
+
<AtomicText style={styles.statusText}>
|
|
111
111
|
{statusText}
|
|
112
112
|
</AtomicText>
|
|
113
113
|
{!isFailed && <PendingJobProgressBar progress={job.progress} />}
|
|
@@ -57,7 +57,7 @@ export const PendingJobCardActions: React.FC<PendingJobCardActionsProps> = ({
|
|
|
57
57
|
style={styles.actionButton}
|
|
58
58
|
onPress={() => onRetry(id)}
|
|
59
59
|
>
|
|
60
|
-
<AtomicText
|
|
60
|
+
<AtomicText style={styles.text}>↻</AtomicText>
|
|
61
61
|
</TouchableOpacity>
|
|
62
62
|
)}
|
|
63
63
|
{onCancel && (
|
|
@@ -65,7 +65,7 @@ export const PendingJobCardActions: React.FC<PendingJobCardActionsProps> = ({
|
|
|
65
65
|
style={styles.actionButton}
|
|
66
66
|
onPress={() => onCancel(id)}
|
|
67
67
|
>
|
|
68
|
-
<AtomicText
|
|
68
|
+
<AtomicText style={styles.errorText}>✕</AtomicText>
|
|
69
69
|
</TouchableOpacity>
|
|
70
70
|
)}
|
|
71
71
|
</View>
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { useMemo } from "react";
|
|
8
8
|
import { ScrollView, StyleSheet, Dimensions, type ViewStyle, type StyleProp } from "react-native";
|
|
9
|
-
import { Animated } from "@umituz/react-native-design-system";
|
|
10
|
-
import { useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
+
import { Animated, useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
11
10
|
import { ResultHeader } from "./ResultHeader";
|
|
12
11
|
import { ResultImageCard } from "./ResultImageCard";
|
|
13
12
|
import { ResultStoryCard } from "./ResultStoryCard";
|
|
@@ -55,7 +54,7 @@ export const GenerationResultContent: React.FC<GenerationResultContentProps> = (
|
|
|
55
54
|
container: {
|
|
56
55
|
width: width - 40,
|
|
57
56
|
maxHeight: "90%",
|
|
58
|
-
backgroundColor: tokens.colors.
|
|
57
|
+
backgroundColor: tokens.colors.background,
|
|
59
58
|
borderRadius: 28,
|
|
60
59
|
overflow: "hidden",
|
|
61
60
|
},
|
|
@@ -149,12 +149,12 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
149
149
|
|
|
150
150
|
const errorMessage =
|
|
151
151
|
generationError.type === "network_error" ? alertMessages.networkError :
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
generationError.type === "policy_violation" ? alertMessages.policyViolation :
|
|
153
|
+
generationError.type === "save_failed" ? alertMessages.saveFailed :
|
|
154
|
+
generationError.type === "credit_failed" ? alertMessages.creditFailed :
|
|
155
|
+
alertMessages.unknown;
|
|
156
156
|
|
|
157
|
-
showError("Error", errorMessage);
|
|
157
|
+
void showError("Error", errorMessage);
|
|
158
158
|
onError?.(generationError);
|
|
159
159
|
} finally {
|
|
160
160
|
isGeneratingRef.current = false;
|
|
@@ -170,6 +170,8 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
170
170
|
onSaveComplete,
|
|
171
171
|
createError,
|
|
172
172
|
offlineStore,
|
|
173
|
+
alertMessages,
|
|
174
|
+
showError
|
|
173
175
|
],
|
|
174
176
|
);
|
|
175
177
|
|