@umituz/react-native-ai-generation-content 1.36.2 → 1.37.1
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 +2 -2
- package/src/domains/creations/infrastructure/repositories/CreationsWriter.ts +124 -199
- package/src/domains/creations/presentation/components/GalleryResultPreview.tsx +88 -0
- package/src/domains/creations/presentation/hooks/useGalleryCallbacks.ts +127 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +37 -123
- package/src/domains/generation/wizard/presentation/components/GenericWizardFlow.tsx +5 -231
- package/src/domains/generation/wizard/presentation/components/WizardContinueButton.tsx +73 -0
- package/src/domains/generation/wizard/presentation/components/WizardFlowContent.tsx +181 -0
- package/src/domains/generation/wizard/presentation/components/WizardStepRenderer.tsx +18 -134
- package/src/domains/generation/wizard/presentation/components/step-renderers/renderPhotoUploadStep.tsx +52 -0
- package/src/domains/generation/wizard/presentation/components/step-renderers/renderSelectionStep.tsx +59 -0
- package/src/domains/generation/wizard/presentation/components/step-renderers/renderTextInputStep.tsx +62 -0
- package/src/domains/generation/wizard/presentation/hooks/useWizardFlowHandlers.ts +133 -0
- package/src/domains/generation/wizard/presentation/screens/GenericPhotoUploadScreen.tsx +15 -83
- package/src/domains/generation/wizard/presentation/screens/SelectionScreen.tsx +55 -134
- package/src/domains/result-preview/presentation/components/GenerationErrorScreen.tsx +19 -122
- package/src/domains/result-preview/presentation/hooks/useResultActions.ts +16 -131
- package/src/domains/scenarios/presentation/components/ScenarioContinueButton.tsx +76 -0
- package/src/domains/scenarios/presentation/hooks/useHierarchicalScenarios.ts +70 -0
- package/src/domains/scenarios/presentation/screens/HierarchicalScenarioListScreen.tsx +37 -170
- package/src/presentation/hooks/generation/moderation-handler.ts +77 -0
- package/src/presentation/hooks/generation/orchestrator.ts +33 -125
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Moderation Handler
|
|
3
|
+
* Handles content moderation logic for generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createGenerationError, parseError, getAlertMessage } from "./errors";
|
|
7
|
+
import type { GenerationError, ModerationCallbacks, AlertMessages } from "./types";
|
|
8
|
+
|
|
9
|
+
export interface ModerationHandlerParams<TInput, TResult> {
|
|
10
|
+
readonly input: TInput;
|
|
11
|
+
readonly moderation: ModerationCallbacks | undefined;
|
|
12
|
+
readonly alertMessages: AlertMessages;
|
|
13
|
+
readonly isMountedRef: React.MutableRefObject<boolean>;
|
|
14
|
+
readonly isGeneratingRef: React.MutableRefObject<boolean>;
|
|
15
|
+
readonly setState: (state: { status: string; isGenerating: boolean; result: TResult | null; error: GenerationError | null }) => void;
|
|
16
|
+
readonly resetState: () => void;
|
|
17
|
+
readonly executeGeneration: (input: TInput) => Promise<TResult>;
|
|
18
|
+
readonly showError: (title: string, message: string) => void;
|
|
19
|
+
readonly onError?: (error: GenerationError) => void;
|
|
20
|
+
readonly handleLifecycleComplete: (status: "success" | "error", result?: TResult, error?: GenerationError) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function handleModeration<TInput, TResult>(
|
|
24
|
+
params: ModerationHandlerParams<TInput, TResult>,
|
|
25
|
+
): Promise<TResult | undefined> {
|
|
26
|
+
const {
|
|
27
|
+
input,
|
|
28
|
+
moderation,
|
|
29
|
+
alertMessages,
|
|
30
|
+
isMountedRef,
|
|
31
|
+
isGeneratingRef,
|
|
32
|
+
setState,
|
|
33
|
+
resetState,
|
|
34
|
+
executeGeneration,
|
|
35
|
+
showError,
|
|
36
|
+
onError,
|
|
37
|
+
handleLifecycleComplete,
|
|
38
|
+
} = params;
|
|
39
|
+
|
|
40
|
+
if (!moderation) {
|
|
41
|
+
return executeGeneration(input);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setState({ status: "moderating", isGenerating: true, result: null, error: null });
|
|
45
|
+
const moderationResult = await moderation.checkContent(input);
|
|
46
|
+
|
|
47
|
+
if (!moderationResult.allowed && moderationResult.warnings.length > 0) {
|
|
48
|
+
if (moderation.onShowWarning) {
|
|
49
|
+
moderation.onShowWarning(
|
|
50
|
+
moderationResult.warnings,
|
|
51
|
+
() => {
|
|
52
|
+
isGeneratingRef.current = false;
|
|
53
|
+
if (isMountedRef.current) resetState();
|
|
54
|
+
},
|
|
55
|
+
async () => {
|
|
56
|
+
try {
|
|
57
|
+
await executeGeneration(input);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const error = parseError(err);
|
|
60
|
+
if (isMountedRef.current) {
|
|
61
|
+
setState({ status: "error", isGenerating: false, result: null, error });
|
|
62
|
+
}
|
|
63
|
+
showError("Error", getAlertMessage(error, alertMessages));
|
|
64
|
+
onError?.(error);
|
|
65
|
+
handleLifecycleComplete("error", undefined, error);
|
|
66
|
+
} finally {
|
|
67
|
+
isGeneratingRef.current = false;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
);
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
throw createGenerationError("policy", alertMessages.policyViolation);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return executeGeneration(input);
|
|
77
|
+
}
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generation Orchestrator
|
|
3
|
-
* Handles AI generation execution with
|
|
4
|
-
* - Network check
|
|
5
|
-
* - Content moderation (optional)
|
|
6
|
-
* - Credit deduction (after success)
|
|
7
|
-
* - Error handling
|
|
8
|
-
*
|
|
9
|
-
* NOTE: Credit CHECK is handled by useFeatureGate before generation starts.
|
|
10
|
-
* This orchestrator only DEDUCTS credits after successful generation.
|
|
11
|
-
*
|
|
12
|
-
* Progress is NOT tracked here - UI uses indeterminate progress bar with
|
|
13
|
-
* time-based phase detection (see useGenerationPhase hook).
|
|
3
|
+
* Handles AI generation execution with network check, moderation, credit deduction, and error handling
|
|
14
4
|
*/
|
|
15
5
|
|
|
16
6
|
import { useState, useCallback, useRef, useEffect } from "react";
|
|
17
7
|
import { useOfflineStore, useAlert } from "@umituz/react-native-design-system";
|
|
18
8
|
import { useDeductCredit } from "@umituz/react-native-subscription";
|
|
19
9
|
import { createGenerationError, getAlertMessage, parseError } from "./errors";
|
|
10
|
+
import { handleModeration } from "./moderation-handler";
|
|
20
11
|
import type {
|
|
21
12
|
GenerationStrategy,
|
|
22
13
|
GenerationConfig,
|
|
@@ -27,26 +18,13 @@ import type {
|
|
|
27
18
|
|
|
28
19
|
declare const __DEV__: boolean;
|
|
29
20
|
|
|
30
|
-
const INITIAL_STATE = {
|
|
31
|
-
status: "idle" as const,
|
|
32
|
-
isGenerating: false,
|
|
33
|
-
result: null,
|
|
34
|
-
error: null,
|
|
35
|
-
};
|
|
21
|
+
const INITIAL_STATE = { status: "idle" as const, isGenerating: false, result: null, error: null };
|
|
36
22
|
|
|
37
23
|
export const useGenerationOrchestrator = <TInput, TResult>(
|
|
38
24
|
strategy: GenerationStrategy<TInput, TResult>,
|
|
39
25
|
config: GenerationConfig,
|
|
40
26
|
): UseGenerationOrchestratorReturn<TInput, TResult> => {
|
|
41
|
-
const {
|
|
42
|
-
userId,
|
|
43
|
-
alertMessages,
|
|
44
|
-
onCreditsExhausted,
|
|
45
|
-
onSuccess,
|
|
46
|
-
onError,
|
|
47
|
-
moderation,
|
|
48
|
-
lifecycle,
|
|
49
|
-
} = config;
|
|
27
|
+
const { userId, alertMessages, onCreditsExhausted, onSuccess, onError, moderation, lifecycle } = config;
|
|
50
28
|
|
|
51
29
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
52
30
|
console.log("[Orchestrator] Hook initialized:", { userId });
|
|
@@ -62,20 +40,14 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
62
40
|
|
|
63
41
|
useEffect(() => {
|
|
64
42
|
isMountedRef.current = true;
|
|
65
|
-
return () => {
|
|
66
|
-
isMountedRef.current = false;
|
|
67
|
-
};
|
|
43
|
+
return () => { isMountedRef.current = false; };
|
|
68
44
|
}, []);
|
|
69
45
|
|
|
70
46
|
const handleLifecycleComplete = useCallback(
|
|
71
47
|
(status: "success" | "error", result?: TResult, error?: GenerationError) => {
|
|
72
48
|
if (!lifecycle?.onComplete) return;
|
|
73
49
|
const delay = lifecycle.completeDelay ?? 500;
|
|
74
|
-
setTimeout(() => {
|
|
75
|
-
if (isMountedRef.current) {
|
|
76
|
-
lifecycle.onComplete?.(status, result, error);
|
|
77
|
-
}
|
|
78
|
-
}, delay);
|
|
50
|
+
setTimeout(() => { if (isMountedRef.current) lifecycle.onComplete?.(status, result, error); }, delay);
|
|
79
51
|
},
|
|
80
52
|
[lifecycle],
|
|
81
53
|
);
|
|
@@ -83,10 +55,7 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
83
55
|
const executeGeneration = useCallback(
|
|
84
56
|
async (input: TInput) => {
|
|
85
57
|
setState((prev) => ({ ...prev, status: "generating" }));
|
|
86
|
-
|
|
87
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
88
|
-
console.log("[Orchestrator] Starting generation");
|
|
89
|
-
}
|
|
58
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[Orchestrator] Starting generation");
|
|
90
59
|
|
|
91
60
|
const result = await strategy.execute(input);
|
|
92
61
|
|
|
@@ -95,34 +64,19 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
95
64
|
try {
|
|
96
65
|
await strategy.save(result, userId);
|
|
97
66
|
} catch (saveErr) {
|
|
98
|
-
throw createGenerationError(
|
|
99
|
-
"save",
|
|
100
|
-
alertMessages.saveFailed,
|
|
101
|
-
saveErr instanceof Error ? saveErr : undefined,
|
|
102
|
-
);
|
|
67
|
+
throw createGenerationError("save", alertMessages.saveFailed, saveErr instanceof Error ? saveErr : undefined);
|
|
103
68
|
}
|
|
104
69
|
}
|
|
105
70
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
if (!creditDeducted) {
|
|
109
|
-
throw createGenerationError("credits", alertMessages.creditFailed);
|
|
110
|
-
}
|
|
71
|
+
const creditDeducted = await deductCredit(strategy.getCreditCost());
|
|
72
|
+
if (!creditDeducted) throw createGenerationError("credits", alertMessages.creditFailed);
|
|
111
73
|
|
|
112
|
-
if (isMountedRef.current) {
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
117
|
-
console.log("[Orchestrator] Generation SUCCESS");
|
|
118
|
-
}
|
|
74
|
+
if (isMountedRef.current) setState({ status: "success", isGenerating: false, result, error: null });
|
|
75
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[Orchestrator] Generation SUCCESS");
|
|
119
76
|
|
|
120
|
-
if (alertMessages.success)
|
|
121
|
-
showSuccess("Success", alertMessages.success);
|
|
122
|
-
}
|
|
77
|
+
if (alertMessages.success) showSuccess("Success", alertMessages.success);
|
|
123
78
|
onSuccess?.(result);
|
|
124
79
|
handleLifecycleComplete("success", result);
|
|
125
|
-
|
|
126
80
|
return result;
|
|
127
81
|
},
|
|
128
82
|
[strategy, userId, alertMessages, deductCredit, showSuccess, onSuccess, handleLifecycleComplete],
|
|
@@ -130,63 +84,32 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
130
84
|
|
|
131
85
|
const generate = useCallback(
|
|
132
86
|
async (input: TInput) => {
|
|
133
|
-
if (typeof __DEV__ !== "undefined" && __DEV__)
|
|
134
|
-
console.log("[Orchestrator] generate() called");
|
|
135
|
-
}
|
|
136
|
-
|
|
87
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[Orchestrator] generate() called");
|
|
137
88
|
if (isGeneratingRef.current) return;
|
|
138
89
|
|
|
139
90
|
isGeneratingRef.current = true;
|
|
140
91
|
setState({ ...INITIAL_STATE, status: "checking", isGenerating: true });
|
|
141
92
|
|
|
142
93
|
try {
|
|
143
|
-
if (!offlineStore.isOnline)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
},
|
|
159
|
-
async () => {
|
|
160
|
-
try {
|
|
161
|
-
await executeGeneration(input);
|
|
162
|
-
} catch (err) {
|
|
163
|
-
const error = parseError(err);
|
|
164
|
-
if (isMountedRef.current) {
|
|
165
|
-
setState({ status: "error", isGenerating: false, result: null, error });
|
|
166
|
-
}
|
|
167
|
-
showError("Error", getAlertMessage(error, alertMessages));
|
|
168
|
-
onError?.(error);
|
|
169
|
-
handleLifecycleComplete("error", undefined, error);
|
|
170
|
-
} finally {
|
|
171
|
-
isGeneratingRef.current = false;
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
);
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
throw createGenerationError("policy", alertMessages.policyViolation);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return await executeGeneration(input);
|
|
94
|
+
if (!offlineStore.isOnline) throw createGenerationError("network", alertMessages.networkError);
|
|
95
|
+
|
|
96
|
+
return await handleModeration({
|
|
97
|
+
input,
|
|
98
|
+
moderation,
|
|
99
|
+
alertMessages,
|
|
100
|
+
isMountedRef,
|
|
101
|
+
isGeneratingRef,
|
|
102
|
+
setState: (s) => setState(s as GenerationState<TResult>),
|
|
103
|
+
resetState: () => setState(INITIAL_STATE),
|
|
104
|
+
executeGeneration,
|
|
105
|
+
showError,
|
|
106
|
+
onError,
|
|
107
|
+
handleLifecycleComplete,
|
|
108
|
+
});
|
|
182
109
|
} catch (err) {
|
|
183
110
|
const error = parseError(err);
|
|
184
|
-
if (typeof __DEV__ !== "undefined" && __DEV__)
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
if (isMountedRef.current) {
|
|
188
|
-
setState({ status: "error", isGenerating: false, result: null, error });
|
|
189
|
-
}
|
|
111
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[Orchestrator] Error:", error);
|
|
112
|
+
if (isMountedRef.current) setState({ status: "error", isGenerating: false, result: null, error });
|
|
190
113
|
showError("Error", getAlertMessage(error, alertMessages));
|
|
191
114
|
onError?.(error);
|
|
192
115
|
handleLifecycleComplete("error", undefined, error);
|
|
@@ -195,15 +118,7 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
195
118
|
isGeneratingRef.current = false;
|
|
196
119
|
}
|
|
197
120
|
},
|
|
198
|
-
[
|
|
199
|
-
moderation,
|
|
200
|
-
alertMessages,
|
|
201
|
-
offlineStore.isOnline,
|
|
202
|
-
executeGeneration,
|
|
203
|
-
showError,
|
|
204
|
-
onError,
|
|
205
|
-
handleLifecycleComplete,
|
|
206
|
-
],
|
|
121
|
+
[moderation, alertMessages, offlineStore.isOnline, executeGeneration, showError, onError, handleLifecycleComplete],
|
|
207
122
|
);
|
|
208
123
|
|
|
209
124
|
const reset = useCallback(() => {
|
|
@@ -211,12 +126,5 @@ export const useGenerationOrchestrator = <TInput, TResult>(
|
|
|
211
126
|
isGeneratingRef.current = false;
|
|
212
127
|
}, []);
|
|
213
128
|
|
|
214
|
-
return {
|
|
215
|
-
generate,
|
|
216
|
-
reset,
|
|
217
|
-
status: state.status,
|
|
218
|
-
isGenerating: state.isGenerating,
|
|
219
|
-
result: state.result,
|
|
220
|
-
error: state.error,
|
|
221
|
-
};
|
|
129
|
+
return { generate, reset, status: state.status, isGenerating: state.isGenerating, result: state.result, error: state.error };
|
|
222
130
|
};
|