@umituz/react-native-ai-generation-content 1.17.112 → 1.17.114
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/domain/interfaces/ai-provider.interface.ts +50 -2
- package/src/domains/creations/infrastructure/repositories/CreationsWriter.ts +18 -1
- package/src/domains/creations/presentation/components/CreationVideoPreview.tsx +1 -1
- package/src/features/image-to-video/infrastructure/services/image-to-video-executor.ts +2 -2
- package/src/features/text-to-image/infrastructure/services/text-to-image-executor.ts +2 -2
- package/src/features/text-to-video/infrastructure/services/text-to-video-executor.ts +37 -6
- package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +69 -44
- package/src/index.ts +2 -0
package/package.json
CHANGED
|
@@ -16,6 +16,40 @@ export interface AIProviderConfig {
|
|
|
16
16
|
textToImageModel?: string;
|
|
17
17
|
/** Image editing model ID */
|
|
18
18
|
imageEditModel?: string;
|
|
19
|
+
/** Video generation model ID */
|
|
20
|
+
videoGenerationModel?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Provider-level progress info for run/subscribe operations
|
|
25
|
+
*/
|
|
26
|
+
export interface ProviderProgressInfo {
|
|
27
|
+
/** Progress percentage (0-100) */
|
|
28
|
+
progress: number;
|
|
29
|
+
/** Current job status */
|
|
30
|
+
status?: AIJobStatusType;
|
|
31
|
+
/** Human-readable message */
|
|
32
|
+
message?: string;
|
|
33
|
+
/** Estimated time remaining in ms */
|
|
34
|
+
estimatedTimeRemaining?: number;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Provider capabilities and metadata
|
|
39
|
+
*/
|
|
40
|
+
export interface ProviderCapabilities {
|
|
41
|
+
/** Supported image features */
|
|
42
|
+
imageFeatures: readonly ImageFeatureType[];
|
|
43
|
+
/** Supported video features */
|
|
44
|
+
videoFeatures: readonly VideoFeatureType[];
|
|
45
|
+
/** Supports text-to-image generation */
|
|
46
|
+
textToImage: boolean;
|
|
47
|
+
/** Supports text-to-video generation */
|
|
48
|
+
textToVideo: boolean;
|
|
49
|
+
/** Supports image-to-video generation */
|
|
50
|
+
imageToVideo: boolean;
|
|
51
|
+
/** Supports text-to-voice generation */
|
|
52
|
+
textToVoice: boolean;
|
|
19
53
|
}
|
|
20
54
|
|
|
21
55
|
export interface JobSubmission {
|
|
@@ -46,12 +80,12 @@ export interface AILogEntry {
|
|
|
46
80
|
export interface SubscribeOptions<T = unknown> {
|
|
47
81
|
timeoutMs?: number;
|
|
48
82
|
onQueueUpdate?: (status: JobStatus) => void;
|
|
49
|
-
onProgress?: (progress:
|
|
83
|
+
onProgress?: (progress: ProviderProgressInfo) => void;
|
|
50
84
|
onResult?: (result: T) => void;
|
|
51
85
|
}
|
|
52
86
|
|
|
53
87
|
export interface RunOptions {
|
|
54
|
-
onProgress?: (progress:
|
|
88
|
+
onProgress?: (progress: ProviderProgressInfo) => void;
|
|
55
89
|
}
|
|
56
90
|
|
|
57
91
|
/**
|
|
@@ -105,6 +139,16 @@ export interface IAIProvider {
|
|
|
105
139
|
initialize(config: AIProviderConfig): void;
|
|
106
140
|
isInitialized(): boolean;
|
|
107
141
|
|
|
142
|
+
/**
|
|
143
|
+
* Get provider capabilities
|
|
144
|
+
*/
|
|
145
|
+
getCapabilities(): ProviderCapabilities;
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if a specific feature is supported
|
|
149
|
+
*/
|
|
150
|
+
isFeatureSupported(feature: ImageFeatureType | VideoFeatureType): boolean;
|
|
151
|
+
|
|
108
152
|
submitJob(
|
|
109
153
|
model: string,
|
|
110
154
|
input: Record<string, unknown>,
|
|
@@ -130,11 +174,13 @@ export interface IAIProvider {
|
|
|
130
174
|
|
|
131
175
|
/**
|
|
132
176
|
* Get model ID for an image feature
|
|
177
|
+
* @throws Error if feature is not supported
|
|
133
178
|
*/
|
|
134
179
|
getImageFeatureModel(feature: ImageFeatureType): string;
|
|
135
180
|
|
|
136
181
|
/**
|
|
137
182
|
* Build provider-specific input for an image feature
|
|
183
|
+
* @throws Error if feature is not supported
|
|
138
184
|
*/
|
|
139
185
|
buildImageFeatureInput(
|
|
140
186
|
feature: ImageFeatureType,
|
|
@@ -143,11 +189,13 @@ export interface IAIProvider {
|
|
|
143
189
|
|
|
144
190
|
/**
|
|
145
191
|
* Get model ID for a video feature
|
|
192
|
+
* @throws Error if feature is not supported
|
|
146
193
|
*/
|
|
147
194
|
getVideoFeatureModel(feature: VideoFeatureType): string;
|
|
148
195
|
|
|
149
196
|
/**
|
|
150
197
|
* Build provider-specific input for a video feature
|
|
198
|
+
* @throws Error if feature is not supported
|
|
151
199
|
*/
|
|
152
200
|
buildVideoFeatureInput(
|
|
153
201
|
feature: VideoFeatureType,
|
|
@@ -12,6 +12,11 @@ export class CreationsWriter {
|
|
|
12
12
|
constructor(private readonly pathResolver: FirestorePathResolver) { }
|
|
13
13
|
|
|
14
14
|
async create(userId: string, creation: Creation): Promise<void> {
|
|
15
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
16
|
+
// eslint-disable-next-line no-console
|
|
17
|
+
console.log("[CreationsWriter] create() start", { userId, creationId: creation.id });
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
const docRef = this.pathResolver.getDocRef(userId, creation.id);
|
|
16
21
|
if (!docRef) throw new Error("Firestore not initialized");
|
|
17
22
|
|
|
@@ -27,7 +32,19 @@ export class CreationsWriter {
|
|
|
27
32
|
output: creation.output,
|
|
28
33
|
};
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
try {
|
|
36
|
+
await setDoc(docRef, data);
|
|
37
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
38
|
+
// eslint-disable-next-line no-console
|
|
39
|
+
console.log("[CreationsWriter] create() success", { creationId: creation.id });
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.error("[CreationsWriter] create() error", error);
|
|
45
|
+
}
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
async update(
|
|
@@ -66,7 +66,7 @@ export async function executeImageToVideo(
|
|
|
66
66
|
|
|
67
67
|
const { model, buildInput, extractResult, onProgress } = options;
|
|
68
68
|
|
|
69
|
-
if (__DEV__) {
|
|
69
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
70
70
|
// eslint-disable-next-line no-console
|
|
71
71
|
console.log(`[ImageToVideo] Provider: ${provider.providerId}, Model: ${model}`);
|
|
72
72
|
}
|
|
@@ -98,7 +98,7 @@ export async function executeImageToVideo(
|
|
|
98
98
|
};
|
|
99
99
|
} catch (error) {
|
|
100
100
|
const message = error instanceof Error ? error.message : String(error);
|
|
101
|
-
if (__DEV__) {
|
|
101
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
102
102
|
// eslint-disable-next-line no-console
|
|
103
103
|
console.error("[ImageToVideo] Error:", message);
|
|
104
104
|
}
|
|
@@ -84,7 +84,7 @@ export async function executeTextToImage(
|
|
|
84
84
|
|
|
85
85
|
const { model, buildInput, extractResult, onProgress } = options;
|
|
86
86
|
|
|
87
|
-
if (__DEV__) {
|
|
87
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
88
88
|
// eslint-disable-next-line no-console
|
|
89
89
|
console.log(`[TextToImage] Provider: ${provider.providerId}, Model: ${model}`);
|
|
90
90
|
}
|
|
@@ -113,7 +113,7 @@ export async function executeTextToImage(
|
|
|
113
113
|
};
|
|
114
114
|
} catch (error) {
|
|
115
115
|
const message = error instanceof Error ? error.message : String(error);
|
|
116
|
-
if (__DEV__) {
|
|
116
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
117
117
|
// eslint-disable-next-line no-console
|
|
118
118
|
console.error("[TextToImage] Error:", message);
|
|
119
119
|
}
|
|
@@ -49,13 +49,26 @@ export async function executeTextToVideo(
|
|
|
49
49
|
request: TextToVideoRequest,
|
|
50
50
|
options: ExecuteTextToVideoOptions,
|
|
51
51
|
): Promise<TextToVideoResult> {
|
|
52
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
53
|
+
// eslint-disable-next-line no-console
|
|
54
|
+
console.log("[TextToVideoExecutor] executeTextToVideo() called");
|
|
55
|
+
}
|
|
56
|
+
|
|
52
57
|
const provider = providerRegistry.getActiveProvider();
|
|
53
58
|
|
|
54
59
|
if (!provider) {
|
|
60
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.error("[TextToVideoExecutor] No AI provider configured");
|
|
63
|
+
}
|
|
55
64
|
return { success: false, error: "No AI provider configured" };
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
if (!provider.isInitialized()) {
|
|
68
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
69
|
+
// eslint-disable-next-line no-console
|
|
70
|
+
console.error("[TextToVideoExecutor] AI provider not initialized");
|
|
71
|
+
}
|
|
59
72
|
return { success: false, error: "AI provider not initialized" };
|
|
60
73
|
}
|
|
61
74
|
|
|
@@ -65,27 +78,45 @@ export async function executeTextToVideo(
|
|
|
65
78
|
|
|
66
79
|
const { model, buildInput, extractResult, onProgress } = options;
|
|
67
80
|
|
|
68
|
-
if (__DEV__) {
|
|
81
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
69
82
|
// eslint-disable-next-line no-console
|
|
70
|
-
console.log(`[
|
|
83
|
+
console.log(`[TextToVideoExecutor] Provider: ${provider.providerId}, Model: ${model}`);
|
|
71
84
|
}
|
|
72
85
|
|
|
73
86
|
try {
|
|
74
87
|
onProgress?.(5);
|
|
88
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
89
|
+
// eslint-disable-next-line no-console
|
|
90
|
+
console.log("[TextToVideoExecutor] Starting provider.run()...");
|
|
91
|
+
}
|
|
75
92
|
|
|
76
93
|
const input = buildInput(request.prompt, request.options);
|
|
77
94
|
|
|
78
95
|
const result = await provider.run(model, input, {
|
|
79
|
-
onProgress: (
|
|
80
|
-
|
|
96
|
+
onProgress: (progressInfo) => {
|
|
97
|
+
const progressValue = progressInfo.progress;
|
|
98
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
99
|
+
// eslint-disable-next-line no-console
|
|
100
|
+
console.log("[TextToVideoExecutor] Progress:", progressValue);
|
|
101
|
+
}
|
|
102
|
+
onProgress?.(progressValue);
|
|
81
103
|
},
|
|
82
104
|
});
|
|
83
105
|
|
|
106
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
108
|
+
console.log("[TextToVideoExecutor] provider.run() completed", result);
|
|
109
|
+
}
|
|
110
|
+
|
|
84
111
|
const extractor = extractResult || defaultExtractResult;
|
|
85
112
|
const extracted = extractor(result);
|
|
86
113
|
onProgress?.(100);
|
|
87
114
|
|
|
88
115
|
if (!extracted?.videoUrl) {
|
|
116
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
117
|
+
// eslint-disable-next-line no-console
|
|
118
|
+
console.error("[TextToVideoExecutor] No video URL in response");
|
|
119
|
+
}
|
|
89
120
|
return { success: false, error: "No video in response" };
|
|
90
121
|
}
|
|
91
122
|
|
|
@@ -96,9 +127,9 @@ export async function executeTextToVideo(
|
|
|
96
127
|
};
|
|
97
128
|
} catch (error) {
|
|
98
129
|
const message = error instanceof Error ? error.message : String(error);
|
|
99
|
-
if (__DEV__) {
|
|
130
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
100
131
|
// eslint-disable-next-line no-console
|
|
101
|
-
console.error("[
|
|
132
|
+
console.error("[TextToVideoExecutor] Error:", message);
|
|
102
133
|
}
|
|
103
134
|
return { success: false, error: message };
|
|
104
135
|
}
|
|
@@ -139,67 +139,92 @@ export function useTextToVideoFeature(
|
|
|
139
139
|
console.log("[TextToVideoFeature] Starting generation with prompt:", prompt, "creationId:", creationId);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
// Create "processing" creation at start
|
|
142
|
+
// Create "processing" creation at start (fire-and-forget to not block generation)
|
|
143
143
|
if (callbacks.onGenerationStart) {
|
|
144
|
-
|
|
144
|
+
callbacks.onGenerationStart({
|
|
145
145
|
creationId,
|
|
146
146
|
type: "text-to-video",
|
|
147
147
|
prompt,
|
|
148
148
|
metadata: options as Record<string, unknown> | undefined,
|
|
149
|
+
}).catch((err) => {
|
|
150
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
151
|
+
// eslint-disable-next-line no-console
|
|
152
|
+
console.warn("[TextToVideoFeature] onGenerationStart failed:", err);
|
|
153
|
+
}
|
|
149
154
|
});
|
|
150
155
|
}
|
|
151
156
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
buildInput,
|
|
157
|
-
extractResult,
|
|
158
|
-
onProgress: (progress) => {
|
|
159
|
-
setState((prev) => ({ ...prev, progress }));
|
|
160
|
-
callbacks.onProgress?.(progress);
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
);
|
|
164
|
-
|
|
165
|
-
if (result.success && result.videoUrl) {
|
|
166
|
-
setState((prev) => ({
|
|
167
|
-
...prev,
|
|
168
|
-
videoUrl: result.videoUrl ?? null,
|
|
169
|
-
thumbnailUrl: result.thumbnailUrl ?? null,
|
|
170
|
-
isProcessing: false,
|
|
171
|
-
progress: 100,
|
|
172
|
-
}));
|
|
157
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
158
|
+
// eslint-disable-next-line no-console
|
|
159
|
+
console.log("[TextToVideoFeature] Starting executeTextToVideo...");
|
|
160
|
+
}
|
|
173
161
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
162
|
+
try {
|
|
163
|
+
const result = await executeTextToVideo(
|
|
164
|
+
{ prompt, userId, options },
|
|
165
|
+
{
|
|
166
|
+
model: config.model,
|
|
167
|
+
buildInput,
|
|
168
|
+
extractResult,
|
|
169
|
+
onProgress: (progress) => {
|
|
170
|
+
setState((prev) => ({ ...prev, progress }));
|
|
171
|
+
callbacks.onProgress?.(progress);
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (result.success && result.videoUrl) {
|
|
177
|
+
setState((prev) => ({
|
|
178
|
+
...prev,
|
|
179
|
+
videoUrl: result.videoUrl ?? null,
|
|
180
|
+
thumbnailUrl: result.thumbnailUrl ?? null,
|
|
181
|
+
isProcessing: false,
|
|
182
|
+
progress: 100,
|
|
183
|
+
}));
|
|
184
|
+
|
|
185
|
+
// Deduct credits after successful generation
|
|
186
|
+
if (callbacks.onCreditDeduct) {
|
|
187
|
+
await callbacks.onCreditDeduct(config.creditCost);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Update creation to completed after successful generation
|
|
191
|
+
if (callbacks.onCreationSave) {
|
|
192
|
+
await callbacks.onCreationSave({
|
|
193
|
+
creationId,
|
|
194
|
+
type: "text-to-video",
|
|
195
|
+
videoUrl: result.videoUrl,
|
|
196
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
197
|
+
prompt,
|
|
198
|
+
metadata: options as Record<string, unknown> | undefined,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
callbacks.onGenerate?.(result);
|
|
203
|
+
} else {
|
|
204
|
+
const error = result.error || "Generation failed";
|
|
205
|
+
setState((prev) => ({
|
|
206
|
+
...prev,
|
|
207
|
+
isProcessing: false,
|
|
208
|
+
error,
|
|
209
|
+
}));
|
|
210
|
+
callbacks.onError?.(error);
|
|
177
211
|
}
|
|
178
212
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
thumbnailUrl: result.thumbnailUrl,
|
|
186
|
-
prompt,
|
|
187
|
-
metadata: options as Record<string, unknown> | undefined,
|
|
188
|
-
});
|
|
213
|
+
return result;
|
|
214
|
+
} catch (err) {
|
|
215
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
216
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
217
|
+
// eslint-disable-next-line no-console
|
|
218
|
+
console.error("[TextToVideoFeature] Generation error:", errorMessage);
|
|
189
219
|
}
|
|
190
|
-
|
|
191
|
-
callbacks.onGenerate?.(result);
|
|
192
|
-
} else {
|
|
193
|
-
const error = result.error || "Generation failed";
|
|
194
220
|
setState((prev) => ({
|
|
195
221
|
...prev,
|
|
196
222
|
isProcessing: false,
|
|
197
|
-
error,
|
|
223
|
+
error: errorMessage,
|
|
198
224
|
}));
|
|
199
|
-
callbacks.onError?.(
|
|
225
|
+
callbacks.onError?.(errorMessage);
|
|
226
|
+
return { success: false, error: errorMessage };
|
|
200
227
|
}
|
|
201
|
-
|
|
202
|
-
return result;
|
|
203
228
|
},
|
|
204
229
|
[userId, config.model, buildInput, extractResult, callbacks],
|
|
205
230
|
);
|