@umituz/react-native-ai-generation-content 1.17.91 → 1.17.93
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 -1
- package/src/features/text-to-image/index.ts +0 -4
- package/src/features/text-to-image/presentation/hooks/index.ts +1 -9
- package/src/index.ts +6 -0
- package/src/presentation/components/AIGenerationForm.tsx +4 -1
- package/src/presentation/components/buttons/GenerateButton.tsx +3 -0
- package/src/presentation/hooks/generation-callbacks.types.ts +42 -0
- package/src/presentation/hooks/index.ts +9 -0
- package/src/presentation/hooks/useGenerationCallbacksBuilder.ts +121 -0
- package/src/features/text-to-image/presentation/hooks/useTextToImageCallbacksBuilder.ts +0 -200
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.93",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"@umituz/react-native-firebase": "*",
|
|
43
43
|
"@umituz/react-native-image": "*",
|
|
44
44
|
"@umituz/react-native-offline": "*",
|
|
45
|
+
"@umituz/react-native-tanstack": "*",
|
|
45
46
|
"@umituz/react-native-timezone": "*",
|
|
46
47
|
"@umituz/react-native-uuid": "*"
|
|
47
48
|
},
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
"@umituz/react-native-localization": "latest",
|
|
74
75
|
"@umituz/react-native-offline": "*",
|
|
75
76
|
"@umituz/react-native-storage": "latest",
|
|
77
|
+
"@umituz/react-native-tanstack": "latest",
|
|
76
78
|
"@umituz/react-native-timezone": "latest",
|
|
77
79
|
"@umituz/react-native-uuid": "*",
|
|
78
80
|
"eslint": "^9.0.0",
|
|
@@ -69,7 +69,6 @@ export {
|
|
|
69
69
|
useFormState,
|
|
70
70
|
useGeneration,
|
|
71
71
|
useTextToImageForm,
|
|
72
|
-
useTextToImageCallbacksBuilder,
|
|
73
72
|
} from "./presentation";
|
|
74
73
|
export type {
|
|
75
74
|
UseFormStateOptions,
|
|
@@ -79,9 +78,6 @@ export type {
|
|
|
79
78
|
UseGenerationReturn,
|
|
80
79
|
UseTextToImageFormOptions,
|
|
81
80
|
UseTextToImageFormReturn,
|
|
82
|
-
TextToImageCallbacksBuilderConfig,
|
|
83
|
-
UseTextToImageCallbacksBuilderOptions,
|
|
84
|
-
UseTextToImageCallbacksBuilderReturn,
|
|
85
81
|
} from "./presentation";
|
|
86
82
|
|
|
87
83
|
// Provider-based Feature Hook
|
|
@@ -22,17 +22,9 @@ export type {
|
|
|
22
22
|
UseTextToImageFormReturn,
|
|
23
23
|
} from "./useTextToImageForm";
|
|
24
24
|
|
|
25
|
-
// Provider-based Feature Hook
|
|
25
|
+
// Provider-based Feature Hook
|
|
26
26
|
export { useTextToImageFeature } from "./useTextToImageFeature";
|
|
27
27
|
export type {
|
|
28
28
|
UseTextToImageFeatureProps,
|
|
29
29
|
UseTextToImageFeatureReturn,
|
|
30
30
|
} from "./useTextToImageFeature";
|
|
31
|
-
|
|
32
|
-
// Callbacks Builder Hook
|
|
33
|
-
export { useTextToImageCallbacksBuilder } from "./useTextToImageCallbacksBuilder";
|
|
34
|
-
export type {
|
|
35
|
-
TextToImageCallbacksBuilderConfig,
|
|
36
|
-
UseTextToImageCallbacksBuilderOptions,
|
|
37
|
-
UseTextToImageCallbacksBuilderReturn,
|
|
38
|
-
} from "./useTextToImageCallbacksBuilder";
|
package/src/index.ts
CHANGED
|
@@ -252,6 +252,7 @@ export {
|
|
|
252
252
|
useBackgroundGeneration,
|
|
253
253
|
usePhotoGeneration,
|
|
254
254
|
useGenerationFlow,
|
|
255
|
+
useGenerationCallbacksBuilder,
|
|
255
256
|
} from "./presentation/hooks";
|
|
256
257
|
|
|
257
258
|
export type {
|
|
@@ -271,6 +272,11 @@ export type {
|
|
|
271
272
|
PhotoGenerationStatus,
|
|
272
273
|
UseGenerationFlowOptions,
|
|
273
274
|
UseGenerationFlowReturn,
|
|
275
|
+
CreditType,
|
|
276
|
+
GenerationExecutionResult,
|
|
277
|
+
GenerationCallbacksConfig,
|
|
278
|
+
GenerationCallbacks,
|
|
279
|
+
UseGenerationCallbacksBuilderOptions,
|
|
274
280
|
} from "./presentation/hooks";
|
|
275
281
|
|
|
276
282
|
// =============================================================================
|
|
@@ -44,13 +44,16 @@ export const AIGenerationForm: React.FC<AIGenerationFormProps> = ({
|
|
|
44
44
|
translations,
|
|
45
45
|
children,
|
|
46
46
|
}) => {
|
|
47
|
+
// Log immediately on every render
|
|
48
|
+
if (__DEV__) console.log("[AIGenerationForm] RENDERING NOW - hideGenerateButton:", hideGenerateButton);
|
|
49
|
+
|
|
47
50
|
const tokens = useAppDesignTokens();
|
|
48
51
|
const isAdvancedVisible = showAdvanced !== undefined ? showAdvanced : true;
|
|
49
52
|
const buttonIsDisabled = onPromptChange ? !prompt?.trim() : false;
|
|
50
53
|
|
|
51
54
|
useEffect(() => {
|
|
52
55
|
if (__DEV__) {
|
|
53
|
-
console.log("[AIGenerationForm]
|
|
56
|
+
console.log("[AIGenerationForm] MOUNTED/UPDATED - prompt:", prompt, "isGenerating:", isGenerating, "buttonIsDisabled:", buttonIsDisabled, "hideGenerateButton:", hideGenerateButton);
|
|
54
57
|
}
|
|
55
58
|
}, [prompt, isGenerating, buttonIsDisabled, hideGenerateButton]);
|
|
56
59
|
|
|
@@ -42,6 +42,9 @@ export const GenerateButton: React.FC<GenerateButtonProps> = ({
|
|
|
42
42
|
onAccessoryRightPress,
|
|
43
43
|
style,
|
|
44
44
|
}) => {
|
|
45
|
+
// Log immediately on every render
|
|
46
|
+
if (__DEV__) console.log("[GenerateButton] RENDERING NOW");
|
|
47
|
+
|
|
45
48
|
const tokens = useAppDesignTokens();
|
|
46
49
|
const disabled = isDisabled || isProcessing;
|
|
47
50
|
const displayText = isProcessing && processingText ? processingText : text;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generation Callbacks Types
|
|
3
|
+
* Type definitions for unified generation flow
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type CreditType = "image" | "text" | "video" | "audio";
|
|
7
|
+
|
|
8
|
+
export interface GenerationExecutionResult<T = unknown> {
|
|
9
|
+
success: boolean;
|
|
10
|
+
data?: T;
|
|
11
|
+
error?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface GenerationCallbacksConfig<TRequest, TResult> {
|
|
15
|
+
userId: string | null;
|
|
16
|
+
isAuthenticated: boolean;
|
|
17
|
+
creditBalance: number;
|
|
18
|
+
creditCost: number;
|
|
19
|
+
creditType: CreditType;
|
|
20
|
+
executor: (request: TRequest) => Promise<GenerationExecutionResult<TResult>>;
|
|
21
|
+
deductCredit: (type: CreditType) => Promise<void>;
|
|
22
|
+
openPaywall: () => void;
|
|
23
|
+
showAuthModal?: () => void;
|
|
24
|
+
saveCreation?: (result: TResult) => Promise<void>;
|
|
25
|
+
onNavigateAfterSuccess?: () => void;
|
|
26
|
+
invalidateQueryKeys?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface GenerationCallbacks<TRequest, TResult> {
|
|
30
|
+
canAfford: (cost?: number) => boolean;
|
|
31
|
+
isAuthenticated: () => boolean;
|
|
32
|
+
calculateCost: (multiplier?: number) => number;
|
|
33
|
+
execute: (request: TRequest) => Promise<GenerationExecutionResult<TResult>>;
|
|
34
|
+
onAuthRequired: () => void;
|
|
35
|
+
onCreditsRequired: () => void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface UseGenerationCallbacksBuilderOptions<TRequest, TResult> {
|
|
39
|
+
config: GenerationCallbacksConfig<TRequest, TResult>;
|
|
40
|
+
onSuccess?: (result: TResult) => void;
|
|
41
|
+
onError?: (error: string) => void;
|
|
42
|
+
}
|
|
@@ -43,3 +43,12 @@ export type {
|
|
|
43
43
|
UseGenerationFlowOptions,
|
|
44
44
|
UseGenerationFlowReturn,
|
|
45
45
|
} from "./useGenerationFlow";
|
|
46
|
+
|
|
47
|
+
export { useGenerationCallbacksBuilder } from "./useGenerationCallbacksBuilder";
|
|
48
|
+
export type {
|
|
49
|
+
CreditType,
|
|
50
|
+
GenerationExecutionResult,
|
|
51
|
+
GenerationCallbacksConfig,
|
|
52
|
+
GenerationCallbacks,
|
|
53
|
+
UseGenerationCallbacksBuilderOptions,
|
|
54
|
+
} from "./generation-callbacks.types";
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic Generation Callbacks Builder
|
|
3
|
+
* Unified hook for ALL generation types (image, video, audio, text)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useCallback, useMemo, useRef } from "react";
|
|
7
|
+
import { useQueryClient } from "@umituz/react-native-tanstack";
|
|
8
|
+
import type {
|
|
9
|
+
GenerationExecutionResult,
|
|
10
|
+
GenerationCallbacks,
|
|
11
|
+
UseGenerationCallbacksBuilderOptions,
|
|
12
|
+
} from "./generation-callbacks.types";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export function useGenerationCallbacksBuilder<TRequest, TResult>(
|
|
17
|
+
options: UseGenerationCallbacksBuilderOptions<TRequest, TResult>,
|
|
18
|
+
): { callbacks: GenerationCallbacks<TRequest, TResult> } {
|
|
19
|
+
const { config, onSuccess, onError } = options;
|
|
20
|
+
const queryClient = useQueryClient();
|
|
21
|
+
const isExecutingRef = useRef(false);
|
|
22
|
+
|
|
23
|
+
const canAfford = useCallback(
|
|
24
|
+
(cost?: number): boolean => {
|
|
25
|
+
const actualCost = cost ?? config.creditCost;
|
|
26
|
+
return config.creditBalance >= actualCost;
|
|
27
|
+
},
|
|
28
|
+
[config.creditBalance, config.creditCost],
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const isAuthenticated = useCallback(
|
|
32
|
+
(): boolean => config.isAuthenticated,
|
|
33
|
+
[config.isAuthenticated],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const calculateCost = useCallback(
|
|
37
|
+
(multiplier = 1): number => config.creditCost * multiplier,
|
|
38
|
+
[config.creditCost],
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const onAuthRequired = useCallback(() => {
|
|
42
|
+
config.showAuthModal ? config.showAuthModal() : config.openPaywall();
|
|
43
|
+
}, [config]);
|
|
44
|
+
|
|
45
|
+
const onCreditsRequired = useCallback(() => {
|
|
46
|
+
config.openPaywall();
|
|
47
|
+
}, [config]);
|
|
48
|
+
|
|
49
|
+
const execute = useCallback(
|
|
50
|
+
async (request: TRequest): Promise<GenerationExecutionResult<TResult>> => {
|
|
51
|
+
if (isExecutingRef.current) {
|
|
52
|
+
return { success: false, error: "Generation already in progress" };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!config.isAuthenticated || !config.userId) {
|
|
56
|
+
onAuthRequired();
|
|
57
|
+
return { success: false, error: "Authentication required" };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!canAfford()) {
|
|
61
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
62
|
+
console.log("[Generation] Insufficient credits", {
|
|
63
|
+
balance: config.creditBalance,
|
|
64
|
+
cost: config.creditCost,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
onCreditsRequired();
|
|
68
|
+
return { success: false, error: "Insufficient credits" };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
isExecutingRef.current = true;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const result = await config.executor(request);
|
|
75
|
+
|
|
76
|
+
if (!result.success || !result.data) {
|
|
77
|
+
return { success: false, error: result.error || "Generation failed" };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await config.deductCredit(config.creditType);
|
|
81
|
+
|
|
82
|
+
if (config.saveCreation) {
|
|
83
|
+
try {
|
|
84
|
+
await config.saveCreation(result.data);
|
|
85
|
+
} catch {
|
|
86
|
+
// Silent fail for save
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const keys = config.invalidateQueryKeys ?? ["creations"];
|
|
91
|
+
keys.forEach((key) => queryClient.invalidateQueries({ queryKey: [key] }));
|
|
92
|
+
|
|
93
|
+
onSuccess?.(result.data);
|
|
94
|
+
config.onNavigateAfterSuccess?.();
|
|
95
|
+
|
|
96
|
+
return { success: true, data: result.data };
|
|
97
|
+
} catch (error) {
|
|
98
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
99
|
+
onError?.(message);
|
|
100
|
+
return { success: false, error: message };
|
|
101
|
+
} finally {
|
|
102
|
+
isExecutingRef.current = false;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
[config, canAfford, onAuthRequired, onCreditsRequired, queryClient, onSuccess, onError],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
const callbacks = useMemo<GenerationCallbacks<TRequest, TResult>>(
|
|
109
|
+
() => ({
|
|
110
|
+
canAfford,
|
|
111
|
+
isAuthenticated,
|
|
112
|
+
calculateCost,
|
|
113
|
+
execute,
|
|
114
|
+
onAuthRequired,
|
|
115
|
+
onCreditsRequired,
|
|
116
|
+
}),
|
|
117
|
+
[canAfford, isAuthenticated, calculateCost, execute, onAuthRequired, onCreditsRequired],
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return { callbacks };
|
|
121
|
+
}
|
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Text-to-Image Callbacks Builder Hook
|
|
3
|
-
* Creates callbacks with integrated credit, auth, and creations systems
|
|
4
|
-
* Main app only provides config, package handles everything
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useCallback, useMemo, useRef } from "react";
|
|
8
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
9
|
-
import type {
|
|
10
|
-
TextToImageCallbacks,
|
|
11
|
-
TextToImageGenerationRequest,
|
|
12
|
-
TextToImageGenerationResult,
|
|
13
|
-
NumImages,
|
|
14
|
-
TextToImageInputBuilder,
|
|
15
|
-
} from "../../domain/types";
|
|
16
|
-
import { executeTextToImage } from "../../infrastructure";
|
|
17
|
-
|
|
18
|
-
export interface TextToImageCallbacksBuilderConfig {
|
|
19
|
-
userId: string | null;
|
|
20
|
-
isAuthenticated: boolean;
|
|
21
|
-
isPremium: boolean;
|
|
22
|
-
imageCredits: number;
|
|
23
|
-
creditCostPerImage: number;
|
|
24
|
-
model: string;
|
|
25
|
-
buildInput: TextToImageInputBuilder;
|
|
26
|
-
deductCredit: (type: "image" | "text") => Promise<void>;
|
|
27
|
-
openPaywall: () => void;
|
|
28
|
-
onNavigateToCreations?: () => void;
|
|
29
|
-
saveCreation?: (imageUrl: string, prompt: string) => Promise<void>;
|
|
30
|
-
invalidateCreationsQuery?: () => void;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface UseTextToImageCallbacksBuilderOptions {
|
|
34
|
-
config: TextToImageCallbacksBuilderConfig;
|
|
35
|
-
onSuccess?: (imageUrls: string[]) => void;
|
|
36
|
-
onError?: (error: string) => void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface UseTextToImageCallbacksBuilderReturn {
|
|
40
|
-
callbacks: TextToImageCallbacks;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
declare const __DEV__: boolean;
|
|
44
|
-
|
|
45
|
-
export function useTextToImageCallbacksBuilder(
|
|
46
|
-
options: UseTextToImageCallbacksBuilderOptions,
|
|
47
|
-
): UseTextToImageCallbacksBuilderReturn {
|
|
48
|
-
const { config, onSuccess, onError } = options;
|
|
49
|
-
const queryClient = useQueryClient();
|
|
50
|
-
const isGeneratingRef = useRef(false);
|
|
51
|
-
|
|
52
|
-
const executeGeneration = useCallback(
|
|
53
|
-
async (
|
|
54
|
-
request: TextToImageGenerationRequest,
|
|
55
|
-
): Promise<TextToImageGenerationResult> => {
|
|
56
|
-
if (!config.userId) {
|
|
57
|
-
return { success: false, error: "User ID not found" };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (isGeneratingRef.current) {
|
|
61
|
-
return { success: false, error: "Generation already in progress" };
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
isGeneratingRef.current = true;
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
const result = await executeTextToImage(
|
|
68
|
-
{
|
|
69
|
-
prompt: request.prompt,
|
|
70
|
-
userId: config.userId,
|
|
71
|
-
negativePrompt: request.negativePrompt,
|
|
72
|
-
options: {
|
|
73
|
-
aspectRatio: request.aspectRatio,
|
|
74
|
-
size: request.size,
|
|
75
|
-
numImages: request.numImages,
|
|
76
|
-
guidanceScale: request.guidanceScale,
|
|
77
|
-
},
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
model: request.model || config.model,
|
|
81
|
-
buildInput: config.buildInput,
|
|
82
|
-
},
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
if (!result.success) {
|
|
86
|
-
return { success: false, error: result.error || "Generation failed" };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const imageUrls =
|
|
90
|
-
result.imageUrls || (result.imageUrl ? [result.imageUrl] : []);
|
|
91
|
-
|
|
92
|
-
if (imageUrls.length === 0) {
|
|
93
|
-
return { success: false, error: "No images generated" };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
await config.deductCredit("image");
|
|
97
|
-
|
|
98
|
-
return { success: true, imageUrls };
|
|
99
|
-
} catch (error) {
|
|
100
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
-
return { success: false, error: message };
|
|
102
|
-
} finally {
|
|
103
|
-
isGeneratingRef.current = false;
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
[config],
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const calculateCost = useCallback(
|
|
110
|
-
(numImages: NumImages, _model?: string | null): number => {
|
|
111
|
-
return config.creditCostPerImage * numImages;
|
|
112
|
-
},
|
|
113
|
-
[config.creditCostPerImage],
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
const checkCanAfford = useCallback(
|
|
117
|
-
(cost: number): boolean => {
|
|
118
|
-
if (config.isPremium) return true;
|
|
119
|
-
return config.imageCredits >= cost;
|
|
120
|
-
},
|
|
121
|
-
[config.isPremium, config.imageCredits],
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const checkIsAuthenticated = useCallback(
|
|
125
|
-
(): boolean => config.isAuthenticated,
|
|
126
|
-
[config.isAuthenticated],
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
const handleAuthRequired = useCallback(() => {
|
|
130
|
-
config.openPaywall();
|
|
131
|
-
}, [config]);
|
|
132
|
-
|
|
133
|
-
const handleCreditsRequired = useCallback(
|
|
134
|
-
(_cost: number) => config.openPaywall(),
|
|
135
|
-
[config],
|
|
136
|
-
);
|
|
137
|
-
|
|
138
|
-
const handleSuccess = useCallback(
|
|
139
|
-
async (imageUrls: string[]) => {
|
|
140
|
-
if (!config.userId || imageUrls.length === 0) return;
|
|
141
|
-
|
|
142
|
-
try {
|
|
143
|
-
if (config.saveCreation) {
|
|
144
|
-
for (const imageUrl of imageUrls) {
|
|
145
|
-
await config.saveCreation(imageUrl, "");
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (config.invalidateCreationsQuery) {
|
|
150
|
-
config.invalidateCreationsQuery();
|
|
151
|
-
} else {
|
|
152
|
-
queryClient.invalidateQueries({ queryKey: ["creations"] });
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
onSuccess?.(imageUrls);
|
|
156
|
-
config.onNavigateToCreations?.();
|
|
157
|
-
} catch (error) {
|
|
158
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
159
|
-
console.error("[TextToImage] Failed to save creation:", error);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
[config, queryClient, onSuccess],
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
const handleError = useCallback(
|
|
167
|
-
(error: string) => {
|
|
168
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
169
|
-
console.error("[TextToImage] Generation error:", error);
|
|
170
|
-
}
|
|
171
|
-
onError?.(error);
|
|
172
|
-
},
|
|
173
|
-
[onError],
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
const callbacks = useMemo<TextToImageCallbacks>(
|
|
177
|
-
() => ({
|
|
178
|
-
executeGeneration,
|
|
179
|
-
calculateCost,
|
|
180
|
-
canAfford: checkCanAfford,
|
|
181
|
-
isAuthenticated: checkIsAuthenticated,
|
|
182
|
-
onAuthRequired: handleAuthRequired,
|
|
183
|
-
onCreditsRequired: handleCreditsRequired,
|
|
184
|
-
onSuccess: handleSuccess,
|
|
185
|
-
onError: handleError,
|
|
186
|
-
}),
|
|
187
|
-
[
|
|
188
|
-
executeGeneration,
|
|
189
|
-
calculateCost,
|
|
190
|
-
checkCanAfford,
|
|
191
|
-
checkIsAuthenticated,
|
|
192
|
-
handleAuthRequired,
|
|
193
|
-
handleCreditsRequired,
|
|
194
|
-
handleSuccess,
|
|
195
|
-
handleError,
|
|
196
|
-
],
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
return { callbacks };
|
|
200
|
-
}
|