@umituz/react-native-ai-generation-content 1.17.307 → 1.17.308
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 +1 -1
- package/src/features/couple-future/presentation/hooks/useCoupleFutureGeneration.ts +14 -7
- package/src/presentation/hooks/index.ts +7 -0
- package/src/presentation/hooks/photo-generation.types.ts +13 -2
- package/src/presentation/hooks/useGenerationCredits.ts +77 -0
- package/src/presentation/hooks/usePhotoGeneration.ts +45 -30
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.308",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCoupleFutureGeneration Hook
|
|
3
|
+
* Couple future generation with centralized credit management
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { useCallback } from "react";
|
|
2
|
-
import { useDeductCredit } from "@umituz/react-native-subscription";
|
|
3
7
|
import { usePhotoGeneration } from "../../../../presentation/hooks/usePhotoGeneration";
|
|
4
8
|
import { executeCoupleFuture } from "../../infrastructure/executor";
|
|
5
9
|
import type { CoupleFutureInput } from "../../domain/types";
|
|
@@ -20,6 +24,7 @@ export interface UseCoupleFutureGenerationConfig<
|
|
|
20
24
|
input: TInput,
|
|
21
25
|
) => Promise<TResult> | TResult;
|
|
22
26
|
buildCreation?: (result: TResult, input: TInput) => Creation | null;
|
|
27
|
+
onCreditsExhausted?: () => void;
|
|
23
28
|
onSuccess?: (result: TResult) => void;
|
|
24
29
|
onError?: (error: string) => void;
|
|
25
30
|
alertMessages: {
|
|
@@ -41,19 +46,25 @@ export const useCoupleFutureGeneration = <
|
|
|
41
46
|
userId,
|
|
42
47
|
processResult,
|
|
43
48
|
buildCreation,
|
|
49
|
+
onCreditsExhausted,
|
|
44
50
|
onSuccess,
|
|
45
51
|
onError,
|
|
46
52
|
alertMessages,
|
|
47
53
|
} = config;
|
|
48
54
|
|
|
49
|
-
const { checkCredits, deductCredit } = useDeductCredit({ userId });
|
|
50
55
|
const repository = useCallback(
|
|
51
56
|
() => createCreationsRepository("creations"),
|
|
52
57
|
[],
|
|
53
58
|
);
|
|
54
59
|
|
|
55
60
|
const generationConfig: PhotoGenerationConfig<TInput, TResult, void> = {
|
|
56
|
-
|
|
61
|
+
userId,
|
|
62
|
+
creditCost: 1,
|
|
63
|
+
onCreditsExhausted,
|
|
64
|
+
generate: async (
|
|
65
|
+
input: TInput,
|
|
66
|
+
onProgress?: (progress: number) => void,
|
|
67
|
+
) => {
|
|
57
68
|
const result = await executeCoupleFuture(
|
|
58
69
|
{
|
|
59
70
|
partnerABase64: input.partnerABase64,
|
|
@@ -69,7 +80,6 @@ export const useCoupleFutureGeneration = <
|
|
|
69
80
|
|
|
70
81
|
return processResult(result.imageUrl, input);
|
|
71
82
|
},
|
|
72
|
-
|
|
73
83
|
save: async (result: TResult, input: TInput) => {
|
|
74
84
|
if (!userId || !buildCreation) {
|
|
75
85
|
return;
|
|
@@ -79,9 +89,6 @@ export const useCoupleFutureGeneration = <
|
|
|
79
89
|
await repository().create(userId, creation);
|
|
80
90
|
}
|
|
81
91
|
},
|
|
82
|
-
|
|
83
|
-
checkCredits: () => checkCredits(1),
|
|
84
|
-
deductCredits: () => deductCredit(1).then(() => {}),
|
|
85
92
|
onSuccess,
|
|
86
93
|
onError: (error: PhotoGenerationError) => {
|
|
87
94
|
onError?.(error.message);
|
|
@@ -29,6 +29,13 @@ export type {
|
|
|
29
29
|
UsePhotoGenerationReturn,
|
|
30
30
|
} from "./usePhotoGeneration";
|
|
31
31
|
|
|
32
|
+
export { useGenerationCredits, CreditError } from "./useGenerationCredits";
|
|
33
|
+
export type {
|
|
34
|
+
UseGenerationCreditsParams,
|
|
35
|
+
UseGenerationCreditsReturn,
|
|
36
|
+
GenerationCreditsError,
|
|
37
|
+
} from "./useGenerationCredits";
|
|
38
|
+
|
|
32
39
|
export type {
|
|
33
40
|
PhotoGenerationInput,
|
|
34
41
|
PhotoGenerationResult,
|
|
@@ -29,14 +29,25 @@ export interface AlertMessages {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
export interface PhotoGenerationConfig<TInput, TResult, TSaveInput> {
|
|
32
|
+
/** User ID for credit operations - required for credit check/deduct */
|
|
33
|
+
userId: string | undefined;
|
|
34
|
+
/** Credit cost per generation (default: 1) */
|
|
35
|
+
creditCost?: number;
|
|
36
|
+
/** Generation function */
|
|
32
37
|
generate: (input: TInput, onProgress?: (progress: number) => void) => Promise<TResult>;
|
|
38
|
+
/** Save result function */
|
|
33
39
|
save?: (result: TResult, input: TInput) => Promise<TSaveInput>;
|
|
40
|
+
/** Build metadata for tracking */
|
|
34
41
|
buildMetadata?: (input: TInput) => Record<string, unknown>;
|
|
35
|
-
|
|
36
|
-
|
|
42
|
+
/** Called when credits are exhausted */
|
|
43
|
+
onCreditsExhausted?: () => void;
|
|
44
|
+
/** Success callback */
|
|
37
45
|
onSuccess?: (result: TResult) => void;
|
|
46
|
+
/** Error callback */
|
|
38
47
|
onError?: (error: PhotoGenerationError) => void;
|
|
48
|
+
/** Save complete callback */
|
|
39
49
|
onSaveComplete?: (saveResult: TSaveInput) => void;
|
|
50
|
+
/** Alert messages for errors */
|
|
40
51
|
alertMessages: AlertMessages;
|
|
41
52
|
}
|
|
42
53
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useGenerationCredits Hook
|
|
3
|
+
* Centralized credit management for all AI generation features
|
|
4
|
+
* Provides server-side credit validation before generation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useCallback } from "react";
|
|
8
|
+
import { useDeductCredit } from "@umituz/react-native-subscription";
|
|
9
|
+
|
|
10
|
+
export interface UseGenerationCreditsParams {
|
|
11
|
+
userId: string | undefined;
|
|
12
|
+
onCreditsExhausted?: () => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface GenerationCreditsError {
|
|
16
|
+
type: "no_credits" | "deduct_failed";
|
|
17
|
+
message: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseGenerationCreditsReturn {
|
|
21
|
+
/** Server-side credit check */
|
|
22
|
+
checkCredits: (cost?: number) => Promise<boolean>;
|
|
23
|
+
/** Deduct credits after successful generation */
|
|
24
|
+
deductCredits: (cost?: number) => Promise<boolean>;
|
|
25
|
+
/** Whether credit operation is in progress */
|
|
26
|
+
isProcessing: boolean;
|
|
27
|
+
/** Execute generation with automatic credit check and deduct */
|
|
28
|
+
withCredits: <T>(
|
|
29
|
+
generate: () => Promise<T>,
|
|
30
|
+
cost?: number,
|
|
31
|
+
) => Promise<T>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const useGenerationCredits = ({
|
|
35
|
+
userId,
|
|
36
|
+
onCreditsExhausted,
|
|
37
|
+
}: UseGenerationCreditsParams): UseGenerationCreditsReturn => {
|
|
38
|
+
const { checkCredits, deductCredit, isDeducting } = useDeductCredit({
|
|
39
|
+
userId,
|
|
40
|
+
onCreditsExhausted,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const withCredits = useCallback(
|
|
44
|
+
async <T>(generate: () => Promise<T>, cost: number = 1): Promise<T> => {
|
|
45
|
+
const hasCredits = await checkCredits(cost);
|
|
46
|
+
if (!hasCredits) {
|
|
47
|
+
throw new CreditError("no_credits", "Insufficient credits");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const result = await generate();
|
|
51
|
+
|
|
52
|
+
await deductCredit(cost);
|
|
53
|
+
|
|
54
|
+
return result;
|
|
55
|
+
},
|
|
56
|
+
[checkCredits, deductCredit],
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
checkCredits,
|
|
61
|
+
deductCredits: deductCredit,
|
|
62
|
+
isProcessing: isDeducting,
|
|
63
|
+
withCredits,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
class CreditError extends Error {
|
|
68
|
+
constructor(
|
|
69
|
+
public type: GenerationCreditsError["type"],
|
|
70
|
+
message: string,
|
|
71
|
+
) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "CreditError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { CreditError };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* usePhotoGeneration Hook
|
|
3
3
|
* Generic hook for photo-based AI generation workflows
|
|
4
|
+
* Uses centralized credit management
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
7
|
import { useState, useCallback, useRef } from "react";
|
|
7
8
|
import { useOfflineStore, useAlert } from "@umituz/react-native-design-system";
|
|
9
|
+
import { useGenerationCredits, CreditError } from "./useGenerationCredits";
|
|
8
10
|
import type {
|
|
9
11
|
PhotoGenerationConfig,
|
|
10
12
|
PhotoGenerationState,
|
|
@@ -12,7 +14,8 @@ import type {
|
|
|
12
14
|
PhotoGenerationStatus,
|
|
13
15
|
} from "./photo-generation.types";
|
|
14
16
|
|
|
15
|
-
export interface UsePhotoGenerationReturn<TInput, TResult>
|
|
17
|
+
export interface UsePhotoGenerationReturn<TInput, TResult>
|
|
18
|
+
extends PhotoGenerationState<TResult> {
|
|
16
19
|
generate: (input: TInput) => Promise<void>;
|
|
17
20
|
reset: () => void;
|
|
18
21
|
status: PhotoGenerationStatus;
|
|
@@ -22,10 +25,11 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
22
25
|
config: PhotoGenerationConfig<TInput, TResult, TSaveInput>,
|
|
23
26
|
): UsePhotoGenerationReturn<TInput, TResult> => {
|
|
24
27
|
const {
|
|
28
|
+
userId,
|
|
29
|
+
creditCost = 1,
|
|
25
30
|
generate: generateFn,
|
|
26
31
|
save: saveFn,
|
|
27
|
-
|
|
28
|
-
deductCredits,
|
|
32
|
+
onCreditsExhausted,
|
|
29
33
|
onSuccess,
|
|
30
34
|
onError,
|
|
31
35
|
onSaveComplete,
|
|
@@ -44,6 +48,11 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
44
48
|
const offlineStore = useOfflineStore();
|
|
45
49
|
const { showError } = useAlert();
|
|
46
50
|
|
|
51
|
+
const { checkCredits, deductCredits } = useGenerationCredits({
|
|
52
|
+
userId,
|
|
53
|
+
onCreditsExhausted,
|
|
54
|
+
});
|
|
55
|
+
|
|
47
56
|
const createError = useCallback(
|
|
48
57
|
(
|
|
49
58
|
type: PhotoGenerationError["type"],
|
|
@@ -68,31 +77,24 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
68
77
|
setStatus("validating");
|
|
69
78
|
|
|
70
79
|
try {
|
|
71
|
-
// Check network connectivity
|
|
72
80
|
if (!offlineStore.isOnline) {
|
|
73
81
|
throw createError("network_error", "No internet connection");
|
|
74
82
|
}
|
|
75
83
|
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
if (!hasCredits) {
|
|
80
|
-
throw createError("credit_failed", "Insufficient credits");
|
|
81
|
-
}
|
|
84
|
+
const hasCredits = await checkCredits(creditCost);
|
|
85
|
+
if (!hasCredits) {
|
|
86
|
+
throw createError("credit_failed", "Insufficient credits");
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
setStatus("generating");
|
|
85
90
|
setState((prev) => ({ ...prev, progress: 20 }));
|
|
86
91
|
|
|
87
|
-
// Generate without timeout - let AI provider handle its own timeout
|
|
88
|
-
// Pass progress callback to allow provider to report real progress
|
|
89
92
|
const result = await generateFn(input, (newProgress) => {
|
|
90
93
|
setState((prev) => ({ ...prev, progress: newProgress }));
|
|
91
94
|
});
|
|
92
95
|
|
|
93
96
|
setState((prev) => ({ ...prev, progress: 60 }));
|
|
94
97
|
|
|
95
|
-
// Save result
|
|
96
98
|
if (saveFn) {
|
|
97
99
|
setStatus("saving");
|
|
98
100
|
try {
|
|
@@ -109,14 +111,7 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
109
111
|
|
|
110
112
|
setState((prev) => ({ ...prev, progress: 80 }));
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
if (deductCredits) {
|
|
114
|
-
try {
|
|
115
|
-
await deductCredits();
|
|
116
|
-
} catch {
|
|
117
|
-
// Silently fail credit deduction as generation succeeded
|
|
118
|
-
}
|
|
119
|
-
}
|
|
114
|
+
await deductCredits(creditCost);
|
|
120
115
|
|
|
121
116
|
setState({
|
|
122
117
|
isGenerating: false,
|
|
@@ -129,13 +124,28 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
129
124
|
} catch (err: unknown) {
|
|
130
125
|
let generationError: PhotoGenerationError;
|
|
131
126
|
|
|
132
|
-
if (err
|
|
127
|
+
if (err instanceof CreditError) {
|
|
128
|
+
generationError = createError("credit_failed", err.message);
|
|
129
|
+
} else if (
|
|
130
|
+
err &&
|
|
131
|
+
typeof err === "object" &&
|
|
132
|
+
"type" in err &&
|
|
133
|
+
"message" in err
|
|
134
|
+
) {
|
|
133
135
|
generationError = err as PhotoGenerationError;
|
|
134
136
|
} else if (err instanceof Error) {
|
|
135
137
|
if (err.name === "ContentPolicyViolationError") {
|
|
136
|
-
generationError = createError(
|
|
138
|
+
generationError = createError(
|
|
139
|
+
"policy_violation",
|
|
140
|
+
"Content policy violation",
|
|
141
|
+
err,
|
|
142
|
+
);
|
|
137
143
|
} else {
|
|
138
|
-
generationError = createError(
|
|
144
|
+
generationError = createError(
|
|
145
|
+
"unknown",
|
|
146
|
+
err.message || "Generation failed",
|
|
147
|
+
err,
|
|
148
|
+
);
|
|
139
149
|
}
|
|
140
150
|
} else {
|
|
141
151
|
generationError = createError("unknown", "Generation failed");
|
|
@@ -150,11 +160,15 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
150
160
|
setStatus("error");
|
|
151
161
|
|
|
152
162
|
const errorMessage =
|
|
153
|
-
generationError.type === "network_error"
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
163
|
+
generationError.type === "network_error"
|
|
164
|
+
? alertMessages.networkError
|
|
165
|
+
: generationError.type === "policy_violation"
|
|
166
|
+
? alertMessages.policyViolation
|
|
167
|
+
: generationError.type === "save_failed"
|
|
168
|
+
? alertMessages.saveFailed
|
|
169
|
+
: generationError.type === "credit_failed"
|
|
170
|
+
? alertMessages.creditFailed
|
|
171
|
+
: alertMessages.unknown;
|
|
158
172
|
|
|
159
173
|
void showError("Error", errorMessage);
|
|
160
174
|
onError?.(generationError);
|
|
@@ -167,13 +181,14 @@ export const usePhotoGeneration = <TInput, TResult, TSaveInput = unknown>(
|
|
|
167
181
|
saveFn,
|
|
168
182
|
checkCredits,
|
|
169
183
|
deductCredits,
|
|
184
|
+
creditCost,
|
|
170
185
|
onSuccess,
|
|
171
186
|
onError,
|
|
172
187
|
onSaveComplete,
|
|
173
188
|
createError,
|
|
174
189
|
offlineStore,
|
|
175
190
|
alertMessages,
|
|
176
|
-
showError
|
|
191
|
+
showError,
|
|
177
192
|
],
|
|
178
193
|
);
|
|
179
194
|
|