@umituz/react-native-ai-generation-content 1.61.62 → 1.61.64

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.
Files changed (121) hide show
  1. package/package.json +1 -1
  2. package/src/core/index.ts +1 -1
  3. package/src/domain/entities/index.ts +1 -1
  4. package/src/domain/interfaces/ai-provider.interface.ts +1 -1
  5. package/src/domain/interfaces/index.ts +1 -1
  6. package/src/domains/background/domain/entities/index.ts +1 -0
  7. package/src/domains/background/domain/interfaces/index.ts +1 -0
  8. package/src/{domain → domains/background/domain}/interfaces/provider-job-manager.interface.ts +1 -1
  9. package/src/domains/background/domain/types/background-generation.types.ts +28 -0
  10. package/src/domains/background/infrastructure/executors/backgroundJobExecutor.ts +105 -0
  11. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller-factory.ts +1 -1
  12. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.service.ts +1 -1
  13. package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.types.ts +2 -2
  14. package/src/{infrastructure → domains/background/infrastructure}/utils/polling-interval.util.ts +1 -1
  15. package/src/{infrastructure → domains/background/infrastructure}/utils/status-checker.util.ts +1 -1
  16. package/src/domains/background/presentation/hooks/use-background-generation.ts +97 -0
  17. package/src/domains/creations/presentation/components/PendingJobsSection.tsx +1 -1
  18. package/src/domains/generation/wizard/presentation/hooks/generationExecutor.ts +65 -0
  19. package/src/domains/generation/wizard/presentation/hooks/generationStateMachine.ts +35 -0
  20. package/src/domains/generation/wizard/presentation/hooks/typeGuards.ts +13 -0
  21. package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +34 -71
  22. package/src/domains/generation/wizard/presentation/hooks/useWizardFlowHandlers.ts +6 -84
  23. package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +19 -131
  24. package/src/domains/generation/wizard/presentation/hooks/videoQueuePoller.ts +59 -0
  25. package/src/domains/image-to-video/presentation/hooks/imageToVideoStrategy.ts +77 -0
  26. package/src/domains/image-to-video/presentation/hooks/useImageToVideoFeature.ts +102 -0
  27. package/src/domains/scenarios/presentation/containers/CategoryNavigationContainer.tsx +4 -80
  28. package/src/{features → domains}/text-to-image/infrastructure/services/text-to-image-executor.ts +2 -82
  29. package/src/domains/text-to-image/infrastructure/utils/imageResultExtractor.ts +58 -0
  30. package/src/domains/text-to-video/presentation/hooks/textToVideoStrategy.ts +75 -0
  31. package/src/domains/text-to-video/presentation/hooks/useTextToVideoFeature.ts +120 -0
  32. package/src/exports/features.ts +12 -12
  33. package/src/presentation/components/PendingJobCard.tsx +1 -1
  34. package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +0 -186
  35. package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +0 -186
  36. package/src/presentation/hooks/use-background-generation.ts +0 -185
  37. /package/src/{domain → domains/background/domain}/entities/job.types.ts +0 -0
  38. /package/src/{infrastructure → domains/background/infrastructure}/utils/result-validator.util.ts +0 -0
  39. /package/src/{presentation → domains/background/presentation}/hooks/use-pending-jobs.ts +0 -0
  40. /package/src/{features → domains}/image-to-video/README.md +0 -0
  41. /package/src/{features → domains}/image-to-video/domain/constants/animation.constants.ts +0 -0
  42. /package/src/{features → domains}/image-to-video/domain/constants/duration.constants.ts +0 -0
  43. /package/src/{features → domains}/image-to-video/domain/constants/form.constants.ts +0 -0
  44. /package/src/{features → domains}/image-to-video/domain/constants/index.ts +0 -0
  45. /package/src/{features → domains}/image-to-video/domain/constants/music.constants.ts +0 -0
  46. /package/src/{features → domains}/image-to-video/domain/index.ts +0 -0
  47. /package/src/{features → domains}/image-to-video/domain/types/animation.types.ts +0 -0
  48. /package/src/{features → domains}/image-to-video/domain/types/config.types.ts +0 -0
  49. /package/src/{features → domains}/image-to-video/domain/types/duration.types.ts +0 -0
  50. /package/src/{features → domains}/image-to-video/domain/types/form.types.ts +0 -0
  51. /package/src/{features → domains}/image-to-video/domain/types/image-to-video.types.ts +0 -0
  52. /package/src/{features → domains}/image-to-video/domain/types/index.ts +0 -0
  53. /package/src/{features → domains}/image-to-video/domain/types/music.types.ts +0 -0
  54. /package/src/{features → domains}/image-to-video/index.ts +0 -0
  55. /package/src/{features → domains}/image-to-video/infrastructure/index.ts +0 -0
  56. /package/src/{features → domains}/image-to-video/infrastructure/services/image-to-video-executor.ts +0 -0
  57. /package/src/{features → domains}/image-to-video/infrastructure/services/index.ts +0 -0
  58. /package/src/{features → domains}/image-to-video/presentation/components/AddMoreCard.tsx +0 -0
  59. /package/src/{features → domains}/image-to-video/presentation/components/AnimationStyleSelector.tsx +0 -0
  60. /package/src/{features → domains}/image-to-video/presentation/components/DurationSelector.tsx +0 -0
  61. /package/src/{features → domains}/image-to-video/presentation/components/EmptyGridState.tsx +0 -0
  62. /package/src/{features → domains}/image-to-video/presentation/components/GridImageItem.tsx +0 -0
  63. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +0 -0
  64. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.tsx +0 -0
  65. /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.types.ts +0 -0
  66. /package/src/{features → domains}/image-to-video/presentation/components/MusicMoodSelector.tsx +0 -0
  67. /package/src/{features → domains}/image-to-video/presentation/components/index.ts +0 -0
  68. /package/src/{features → domains}/image-to-video/presentation/hooks/image-to-video-feature.types.ts +0 -0
  69. /package/src/{features → domains}/image-to-video/presentation/hooks/index.ts +0 -0
  70. /package/src/{features → domains}/image-to-video/presentation/hooks/useFormState.ts +0 -0
  71. /package/src/{features → domains}/image-to-video/presentation/hooks/useGeneration.ts +0 -0
  72. /package/src/{features → domains}/image-to-video/presentation/hooks/useImageToVideoForm.ts +0 -0
  73. /package/src/{features → domains}/image-to-video/presentation/index.ts +0 -0
  74. /package/src/{features → domains}/image-to-video/presentation/screens/ImageToVideoWizardFlow.tsx +0 -0
  75. /package/src/{features → domains}/shared/index.ts +0 -0
  76. /package/src/{features → domains}/shared/presentation/components/AutoSkipPreview.tsx +0 -0
  77. /package/src/{features → domains}/shared/presentation/components/index.ts +0 -0
  78. /package/src/{features → domains}/shared/presentation/utils/index.ts +0 -0
  79. /package/src/{features → domains}/shared/presentation/utils/wizard-flow.utils.ts +0 -0
  80. /package/src/{features → domains}/text-to-image/README.md +0 -0
  81. /package/src/{features → domains}/text-to-image/domain/constants/index.ts +0 -0
  82. /package/src/{features → domains}/text-to-image/domain/constants/options.constants.ts +0 -0
  83. /package/src/{features → domains}/text-to-image/domain/constants/styles.constants.ts +0 -0
  84. /package/src/{features → domains}/text-to-image/domain/index.ts +0 -0
  85. /package/src/{features → domains}/text-to-image/domain/types/config.types.ts +0 -0
  86. /package/src/{features → domains}/text-to-image/domain/types/form.types.ts +0 -0
  87. /package/src/{features → domains}/text-to-image/domain/types/index.ts +0 -0
  88. /package/src/{features → domains}/text-to-image/domain/types/text-to-image.types.ts +0 -0
  89. /package/src/{features → domains}/text-to-image/index.ts +0 -0
  90. /package/src/{features → domains}/text-to-image/infrastructure/index.ts +0 -0
  91. /package/src/{features → domains}/text-to-image/infrastructure/services/index.ts +0 -0
  92. /package/src/{features → domains}/text-to-image/presentation/components/index.ts +0 -0
  93. /package/src/{features → domains}/text-to-image/presentation/hooks/index.ts +0 -0
  94. /package/src/{features → domains}/text-to-image/presentation/hooks/useFormState.ts +0 -0
  95. /package/src/{features → domains}/text-to-image/presentation/hooks/useGeneration.ts +0 -0
  96. /package/src/{features → domains}/text-to-image/presentation/hooks/useTextToImageForm.ts +0 -0
  97. /package/src/{features → domains}/text-to-image/presentation/index.ts +0 -0
  98. /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.tsx +0 -0
  99. /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.types.ts +0 -0
  100. /package/src/{features → domains}/text-to-video/README.md +0 -0
  101. /package/src/{features → domains}/text-to-video/domain/index.ts +0 -0
  102. /package/src/{features → domains}/text-to-video/domain/types/callback.types.ts +0 -0
  103. /package/src/{features → domains}/text-to-video/domain/types/component.types.ts +0 -0
  104. /package/src/{features → domains}/text-to-video/domain/types/config.types.ts +0 -0
  105. /package/src/{features → domains}/text-to-video/domain/types/index.ts +0 -0
  106. /package/src/{features → domains}/text-to-video/domain/types/request.types.ts +0 -0
  107. /package/src/{features → domains}/text-to-video/domain/types/state.types.ts +0 -0
  108. /package/src/{features → domains}/text-to-video/index.ts +0 -0
  109. /package/src/{features → domains}/text-to-video/infrastructure/index.ts +0 -0
  110. /package/src/{features → domains}/text-to-video/infrastructure/services/index.ts +0 -0
  111. /package/src/{features → domains}/text-to-video/infrastructure/services/text-to-video-executor.ts +0 -0
  112. /package/src/{features → domains}/text-to-video/presentation/components/FrameSelector.tsx +0 -0
  113. /package/src/{features → domains}/text-to-video/presentation/components/GenerationTabs.tsx +0 -0
  114. /package/src/{features → domains}/text-to-video/presentation/components/HeroSection.tsx +0 -0
  115. /package/src/{features → domains}/text-to-video/presentation/components/HintCarousel.tsx +0 -0
  116. /package/src/{features → domains}/text-to-video/presentation/components/OptionsPanel.tsx +0 -0
  117. /package/src/{features → domains}/text-to-video/presentation/components/index.ts +0 -0
  118. /package/src/{features → domains}/text-to-video/presentation/hooks/index.ts +0 -0
  119. /package/src/{features → domains}/text-to-video/presentation/hooks/useTextToVideoForm.ts +0 -0
  120. /package/src/{features → domains}/text-to-video/presentation/index.ts +0 -0
  121. /package/src/{features → domains}/text-to-video/presentation/screens/TextToVideoWizardFlow.tsx +0 -0
@@ -1,186 +0,0 @@
1
- /**
2
- * Image-to-Video Feature Hook
3
- * Uses centralized useGenerationOrchestrator for consistent auth, credits, and error handling
4
- */
5
-
6
- import { useState, useCallback, useMemo, useRef } from "react";
7
- import {
8
- useGenerationOrchestrator,
9
- type GenerationStrategy,
10
- } from "../../../../presentation/hooks/generation";
11
- import { executeImageToVideo } from "../../infrastructure/services";
12
- import type { ImageToVideoResult } from "../../domain/types";
13
- import {
14
- INITIAL_STATE,
15
- DEFAULT_ALERT_MESSAGES,
16
- generateCreationId,
17
- type UseImageToVideoFeatureProps,
18
- type UseImageToVideoFeatureReturn,
19
- type VideoGenerationInput,
20
- } from "./image-to-video-feature.types";
21
-
22
- declare const __DEV__: boolean;
23
-
24
- export type {
25
- UseImageToVideoFeatureProps,
26
- UseImageToVideoFeatureReturn,
27
- } from "./image-to-video-feature.types";
28
-
29
- export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseImageToVideoFeatureReturn {
30
- const { config, callbacks, userId } = props;
31
- const [state, setState] = useState(INITIAL_STATE);
32
- const currentCreationIdRef = useRef("");
33
-
34
- const strategy: GenerationStrategy<VideoGenerationInput, ImageToVideoResult> = useMemo(
35
- () => ({
36
- execute: async (input) => {
37
- if (typeof __DEV__ !== "undefined" && __DEV__) {
38
- console.log("[ImageToVideo] Executing generation, creationId:", input.creationId);
39
- }
40
-
41
- currentCreationIdRef.current = input.creationId;
42
- config.onProcessingStart?.();
43
-
44
- callbacks?.onGenerationStart?.({
45
- creationId: input.creationId,
46
- type: "image-to-video",
47
- imageUri: input.imageUri,
48
- metadata: input.options as Record<string, unknown> | undefined,
49
- }).catch((err) => {
50
- if (typeof __DEV__ !== "undefined" && __DEV__) {
51
- console.warn("[ImageToVideo] onGenerationStart failed:", err);
52
- }
53
- });
54
-
55
- const result = await executeImageToVideo(
56
- {
57
- imageUri: input.imageUri,
58
- imageBase64: input.imageBase64,
59
- userId,
60
- motionPrompt: input.motionPrompt || undefined,
61
- options: input.options,
62
- },
63
- {
64
- model: config.model,
65
- buildInput: config.buildInput,
66
- extractResult: config.extractResult,
67
- },
68
- );
69
-
70
- if (!result.success || !result.videoUrl) {
71
- throw new Error(result.error || "Generation failed");
72
- }
73
-
74
- const videoResult: ImageToVideoResult = {
75
- success: true,
76
- videoUrl: result.videoUrl,
77
- thumbnailUrl: result.thumbnailUrl,
78
- };
79
-
80
- setState((prev) => ({
81
- ...prev,
82
- videoUrl: videoResult.videoUrl ?? null,
83
- thumbnailUrl: videoResult.thumbnailUrl ?? null,
84
- }));
85
-
86
- return videoResult;
87
- },
88
- getCreditCost: () => config.creditCost ?? 0,
89
- save: async (result) => {
90
- if (result.success && result.videoUrl && state.imageUri && currentCreationIdRef.current) {
91
- await callbacks?.onCreationSave?.({
92
- creationId: currentCreationIdRef.current,
93
- type: "image-to-video",
94
- videoUrl: result.videoUrl,
95
- thumbnailUrl: result.thumbnailUrl,
96
- imageUri: state.imageUri,
97
- });
98
- }
99
- },
100
- }),
101
- [config, callbacks, userId, state.imageUri, currentCreationIdRef],
102
- );
103
-
104
- const orchestrator = useGenerationOrchestrator(strategy, {
105
- userId,
106
- alertMessages: DEFAULT_ALERT_MESSAGES,
107
- onCreditsExhausted: () => callbacks?.onShowPaywall?.(config.creditCost ?? 0),
108
- onSuccess: (result) => {
109
- const videoResult = result as ImageToVideoResult;
110
- callbacks?.onGenerate?.(videoResult);
111
- config.onProcessingComplete?.(videoResult);
112
- },
113
- onError: (err) => {
114
- callbacks?.onError?.(err.message);
115
- config.onError?.(err.message);
116
- },
117
- });
118
-
119
- const setImageUri = useCallback(
120
- (uri: string) => {
121
- setState((prev) => ({ ...prev, imageUri: uri, error: null }));
122
- config.onImageSelect?.(uri);
123
- },
124
- [config],
125
- );
126
-
127
- const setMotionPrompt = useCallback((prompt: string) => {
128
- setState((prev) => ({ ...prev, motionPrompt: prompt }));
129
- }, []);
130
-
131
- const generate = useCallback(
132
- async (params?: Parameters<UseImageToVideoFeatureReturn["generate"]>[0]): Promise<ImageToVideoResult> => {
133
- const { imageUri: paramImageUri, motionPrompt: paramMotionPrompt, ...options } = params || {};
134
- const effectiveImageUri = paramImageUri || state.imageUri;
135
- const effectiveMotionPrompt = paramMotionPrompt ?? state.motionPrompt;
136
-
137
- if (typeof __DEV__ !== "undefined" && __DEV__) {
138
- console.log("[ImageToVideoFeature] generate called, hasImage:", !!effectiveImageUri);
139
- }
140
-
141
- if (!effectiveImageUri) {
142
- const error = "Image is required";
143
- setState((prev) => ({ ...prev, error }));
144
- callbacks?.onError?.(error);
145
- return { success: false, error };
146
- }
147
-
148
- if (paramImageUri) {
149
- setState((prev) => ({ ...prev, imageUri: paramImageUri }));
150
- }
151
-
152
- setState((prev) => ({ ...prev, isProcessing: true, error: null, progress: 0 }));
153
-
154
- try {
155
- const imageBase64 = await config.prepareImage(effectiveImageUri);
156
-
157
- const input: VideoGenerationInput = {
158
- imageUri: effectiveImageUri,
159
- imageBase64,
160
- motionPrompt: effectiveMotionPrompt,
161
- options,
162
- creationId: generateCreationId("image-to-video"),
163
- };
164
-
165
- const genResult = await orchestrator.generate(input);
166
- const videoResult = genResult as ImageToVideoResult | undefined;
167
- setState((prev) => ({ ...prev, isProcessing: false }));
168
- return { success: true, videoUrl: videoResult?.videoUrl || undefined };
169
- } catch (error) {
170
- const message = error instanceof Error ? error.message : "Generation failed";
171
- setState((prev) => ({ ...prev, isProcessing: false, error: message }));
172
- return { success: false, error: message };
173
- }
174
- },
175
- [state.imageUri, state.motionPrompt, config, callbacks, orchestrator],
176
- );
177
-
178
- const reset = useCallback(() => {
179
- setState(INITIAL_STATE);
180
- }, []);
181
-
182
- const isReady = useMemo(() => state.imageUri !== null && !state.isProcessing, [state.imageUri, state.isProcessing]);
183
- const canGenerate = useMemo(() => isReady && !state.error, [isReady, state.error]);
184
-
185
- return { state, setImageUri, setMotionPrompt, generate, reset, isReady, canGenerate };
186
- }
@@ -1,186 +0,0 @@
1
- /**
2
- * useTextToVideoFeature Hook
3
- * Simplified hook for text-to-video generation
4
- */
5
-
6
- import { useState, useCallback, useMemo, useRef } from "react";
7
- import {
8
- useGenerationOrchestrator,
9
- type GenerationStrategy,
10
- } from "../../../../presentation/hooks/generation";
11
- import { DEFAULT_ALERT_MESSAGES } from "../../../../presentation/constants/alert-messages";
12
- import { generateCreationId } from "../../../../infrastructure/utils/id-generator.util";
13
- import { executeTextToVideo } from "../../infrastructure/services";
14
- import type {
15
- TextToVideoFeatureState,
16
- TextToVideoConfig,
17
- TextToVideoCallbacks,
18
- TextToVideoResult,
19
- TextToVideoOptions,
20
- TextToVideoInputBuilder,
21
- TextToVideoResultExtractor,
22
- } from "../../domain/types";
23
-
24
- declare const __DEV__: boolean;
25
-
26
- export interface UseTextToVideoFeatureProps {
27
- config: TextToVideoConfig;
28
- callbacks: TextToVideoCallbacks;
29
- userId: string;
30
- buildInput: TextToVideoInputBuilder;
31
- extractResult?: TextToVideoResultExtractor;
32
- }
33
-
34
- export interface TextToVideoGenerateParams extends TextToVideoOptions {
35
- prompt?: string;
36
- }
37
-
38
- export interface UseTextToVideoFeatureReturn {
39
- state: TextToVideoFeatureState;
40
- setPrompt: (prompt: string) => void;
41
- generate: (params?: TextToVideoGenerateParams) => Promise<TextToVideoResult>;
42
- reset: () => void;
43
- isReady: boolean;
44
- canGenerate: boolean;
45
- }
46
-
47
- const INITIAL_STATE: TextToVideoFeatureState = {
48
- prompt: "",
49
- videoUrl: null,
50
- thumbnailUrl: null,
51
- isProcessing: false,
52
- progress: 0,
53
- error: null,
54
- };
55
-
56
- interface VideoGenerationInput {
57
- prompt: string;
58
- options?: TextToVideoOptions;
59
- creationId: string;
60
- }
61
-
62
- export function useTextToVideoFeature(props: UseTextToVideoFeatureProps): UseTextToVideoFeatureReturn {
63
- const { config, callbacks, userId, buildInput, extractResult } = props;
64
- const [state, setState] = useState<TextToVideoFeatureState>(INITIAL_STATE);
65
-
66
- const currentCreationIdRef = useRef("");
67
-
68
- const strategy: GenerationStrategy<VideoGenerationInput, TextToVideoResult> = useMemo(
69
- () => ({
70
- execute: async (input) => {
71
- if (typeof __DEV__ !== "undefined" && __DEV__) {
72
- console.log("[TextToVideo] Executing generation:", input.prompt.slice(0, 100));
73
- }
74
-
75
- currentCreationIdRef.current = input.creationId;
76
-
77
- callbacks.onGenerationStart?.({
78
- creationId: input.creationId,
79
- type: "text-to-video",
80
- prompt: input.prompt,
81
- metadata: input.options as Record<string, unknown> | undefined,
82
- }).catch((err) => {
83
- if (typeof __DEV__ !== "undefined" && __DEV__) {
84
- console.warn("[TextToVideo] onGenerationStart failed:", err);
85
- }
86
- });
87
-
88
- const result = await executeTextToVideo(
89
- { prompt: input.prompt, userId, options: input.options },
90
- {
91
- model: config.model,
92
- buildInput,
93
- extractResult,
94
- },
95
- );
96
-
97
- if (!result.success || !result.videoUrl) {
98
- throw new Error(result.error || "Generation failed");
99
- }
100
-
101
- const videoResult: TextToVideoResult = {
102
- success: true,
103
- videoUrl: result.videoUrl,
104
- thumbnailUrl: result.thumbnailUrl,
105
- };
106
-
107
- setState((prev) => ({
108
- ...prev,
109
- videoUrl: videoResult.videoUrl ?? null,
110
- thumbnailUrl: videoResult.thumbnailUrl ?? null,
111
- }));
112
-
113
- return videoResult;
114
- },
115
- getCreditCost: () => config.creditCost,
116
- save: async (result) => {
117
- if (result.success && result.videoUrl && currentCreationIdRef.current) {
118
- await callbacks.onCreationSave?.({
119
- creationId: currentCreationIdRef.current,
120
- type: "text-to-video",
121
- videoUrl: result.videoUrl,
122
- thumbnailUrl: result.thumbnailUrl,
123
- prompt: state.prompt,
124
- });
125
- }
126
- },
127
- }),
128
- [config, callbacks, buildInput, extractResult, userId, state.prompt, currentCreationIdRef],
129
- );
130
-
131
- const orchestrator = useGenerationOrchestrator(strategy, {
132
- userId,
133
- alertMessages: DEFAULT_ALERT_MESSAGES,
134
- onCreditsExhausted: () => callbacks.onShowPaywall?.(config.creditCost),
135
- onSuccess: (result) => {
136
- const videoResult = result as TextToVideoResult;
137
- callbacks.onGenerate?.(videoResult);
138
- },
139
- onError: (err) => {
140
- callbacks.onError?.(err.message);
141
- },
142
- });
143
-
144
- const setPrompt = useCallback((prompt: string) => {
145
- setState((prev) => ({ ...prev, prompt, error: null }));
146
- }, []);
147
-
148
- const generate = useCallback(
149
- async (params?: TextToVideoGenerateParams): Promise<TextToVideoResult> => {
150
- const prompt = params?.prompt || state.prompt;
151
- if (!prompt.trim()) {
152
- const error = "Prompt is required";
153
- setState((prev) => ({ ...prev, error }));
154
- return { success: false, error };
155
- }
156
-
157
- setState((prev) => ({ ...prev, isProcessing: true, error: null, progress: 0 }));
158
-
159
- try {
160
- const input: VideoGenerationInput = {
161
- prompt: prompt.trim(),
162
- options: params,
163
- creationId: generateCreationId("text-to-video"),
164
- };
165
- const result = await orchestrator.generate(input);
166
- const videoResult = result as TextToVideoResult | undefined;
167
- setState((prev) => ({ ...prev, isProcessing: false }));
168
- return { success: true, videoUrl: videoResult?.videoUrl || undefined };
169
- } catch (error) {
170
- const message = error instanceof Error ? error.message : "Generation failed";
171
- setState((prev) => ({ ...prev, isProcessing: false, error: message }));
172
- return { success: false, error: message };
173
- }
174
- },
175
- [state.prompt, orchestrator],
176
- );
177
-
178
- const reset = useCallback(() => {
179
- setState(INITIAL_STATE);
180
- }, []);
181
-
182
- const isReady = !orchestrator.isGenerating && !state.isProcessing;
183
- const canGenerate = isReady && state.prompt.trim().length > 0;
184
-
185
- return { state, setPrompt, generate, reset, isReady, canGenerate };
186
- }
@@ -1,185 +0,0 @@
1
- /**
2
- * useBackgroundGeneration Hook
3
- * Executes AI generation tasks with optional queue management
4
- * - mode: 'direct' - Execute immediately, no queue UI (for images)
5
- * - mode: 'queued' - Use pending jobs queue with UI (for videos)
6
- */
7
-
8
- import { useCallback, useRef, useState } from "react";
9
- import { usePendingJobs } from "./use-pending-jobs";
10
- import type {
11
- BackgroundJob,
12
- JobExecutorConfig,
13
- BackgroundQueueConfig,
14
- } from "../../domain/entities/job.types";
15
- import { DEFAULT_QUEUE_CONFIG } from "../../domain/entities/job.types";
16
-
17
- export interface UseBackgroundGenerationOptions<TInput, TResult>
18
- extends Partial<BackgroundQueueConfig> {
19
- readonly executor: JobExecutorConfig<TInput, TResult>;
20
- readonly onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
21
- readonly onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
22
- readonly onAllComplete?: () => void;
23
- readonly onProgress?: (progress: number) => void;
24
- }
25
-
26
- export interface DirectExecutionResult<TResult> {
27
- readonly success: boolean;
28
- readonly result?: TResult;
29
- readonly error?: string;
30
- }
31
-
32
- export interface UseBackgroundGenerationReturn<TInput, TResult> {
33
- readonly startJob: (input: TInput, type: string) => Promise<string>;
34
- readonly executeDirectly: (
35
- input: TInput,
36
- ) => Promise<DirectExecutionResult<TResult>>;
37
- readonly cancelJob: (id: string) => void;
38
- readonly pendingJobs: BackgroundJob<TInput, TResult>[];
39
- readonly activeJobCount: number;
40
- readonly hasActiveJobs: boolean;
41
- readonly isProcessing: boolean;
42
- readonly progress: number;
43
- }
44
-
45
- export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
46
- options: UseBackgroundGenerationOptions<TInput, TResult>,
47
- ): UseBackgroundGenerationReturn<TInput, TResult> {
48
- const config = { ...DEFAULT_QUEUE_CONFIG, ...options };
49
- const activeJobsRef = useRef<Set<string>>(new Set());
50
- const jobInputsRef = useRef<Map<string, { input: TInput; type: string }>>(
51
- new Map(),
52
- );
53
-
54
- const [isProcessing, setIsProcessing] = useState(false);
55
- const [progress, setProgress] = useState(0);
56
-
57
- const { jobs, addJobAsync, updateJob, removeJob, getJob } = usePendingJobs<
58
- TInput,
59
- TResult
60
- >({
61
- queryKey: config.queryKey,
62
- });
63
-
64
- const { executor, onProgress, onJobComplete, onJobError, onAllComplete } = options;
65
-
66
- const executeDirectly = useCallback(
67
- async (input: TInput): Promise<DirectExecutionResult<TResult>> => {
68
- setIsProcessing(true);
69
- setProgress(0);
70
-
71
- try {
72
- const result = await executor.execute(input, (p) => {
73
- setProgress(p);
74
- onProgress?.(p);
75
- });
76
-
77
- setProgress(100);
78
- return { success: true, result };
79
- } catch (error) {
80
- const errorMsg = error instanceof Error ? error.message : String(error);
81
- return { success: false, error: errorMsg };
82
- } finally {
83
- setIsProcessing(false);
84
- }
85
- },
86
- [executor, onProgress],
87
- );
88
-
89
- const executeJob = useCallback(
90
- async (jobId: string, input: TInput) => {
91
- try {
92
- updateJob({
93
- id: jobId,
94
- updates: { status: "processing", progress: 10 },
95
- });
96
-
97
- const result = await executor.execute(input, (p) => {
98
- updateJob({ id: jobId, updates: { progress: p } });
99
- });
100
-
101
- updateJob({
102
- id: jobId,
103
- updates: {
104
- status: "completed",
105
- progress: 100,
106
- result,
107
- completedAt: new Date(),
108
- },
109
- });
110
-
111
- const completedJob = getJob(jobId);
112
- if (completedJob) {
113
- await executor.onComplete?.(completedJob);
114
- onJobComplete?.(completedJob);
115
- }
116
-
117
- removeJob(jobId);
118
- } catch (error) {
119
- const errorMsg = error instanceof Error ? error.message : String(error);
120
-
121
- updateJob({
122
- id: jobId,
123
- updates: { status: "failed", error: errorMsg, progress: 0 },
124
- });
125
-
126
- const failedJob = getJob(jobId);
127
- if (failedJob) {
128
- await executor.onError?.(
129
- failedJob,
130
- error instanceof Error ? error : new Error(errorMsg),
131
- );
132
- onJobError?.(failedJob);
133
- }
134
- } finally {
135
- activeJobsRef.current.delete(jobId);
136
- if (activeJobsRef.current.size === 0) {
137
- onAllComplete?.();
138
- }
139
- }
140
- },
141
- [executor, onJobComplete, onJobError, onAllComplete, updateJob, removeJob, getJob],
142
- );
143
-
144
- const startJob = useCallback(
145
- async (input: TInput, type: string): Promise<string> => {
146
- const jobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
147
-
148
- jobInputsRef.current.set(jobId, { input, type });
149
-
150
- await addJobAsync({
151
- id: jobId,
152
- input,
153
- type,
154
- status: "queued",
155
- progress: 0,
156
- });
157
-
158
- activeJobsRef.current.add(jobId);
159
- void executeJob(jobId, input);
160
-
161
- return jobId;
162
- },
163
- [addJobAsync, executeJob],
164
- );
165
-
166
- const cancelJob = useCallback(
167
- (id: string) => {
168
- activeJobsRef.current.delete(id);
169
- jobInputsRef.current.delete(id);
170
- removeJob(id);
171
- },
172
- [removeJob],
173
- );
174
-
175
- return {
176
- startJob,
177
- executeDirectly,
178
- cancelJob,
179
- pendingJobs: jobs,
180
- activeJobCount: activeJobsRef.current.size,
181
- hasActiveJobs: activeJobsRef.current.size > 0,
182
- isProcessing,
183
- progress,
184
- };
185
- }
File without changes