@umituz/react-native-ai-generation-content 1.61.63 → 1.61.65
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/core/index.ts +1 -1
- package/src/domain/entities/index.ts +1 -1
- package/src/domain/interfaces/ai-provider.interface.ts +1 -1
- package/src/domain/interfaces/index.ts +1 -1
- package/src/domains/background/domain/entities/index.ts +1 -0
- package/src/domains/background/domain/interfaces/index.ts +1 -0
- package/src/{domain → domains/background/domain}/interfaces/provider-job-manager.interface.ts +1 -1
- package/src/domains/background/domain/types/background-generation.types.ts +28 -0
- package/src/domains/background/infrastructure/executors/backgroundJobExecutor.ts +105 -0
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller-factory.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.service.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.types.ts +2 -2
- package/src/{infrastructure → domains/background/infrastructure}/utils/polling-interval.util.ts +1 -1
- package/src/{infrastructure → domains/background/infrastructure}/utils/status-checker.util.ts +1 -1
- package/src/domains/background/presentation/hooks/use-background-generation.ts +97 -0
- package/src/domains/creations/presentation/components/PendingJobsSection.tsx +1 -1
- package/src/{features → domains}/image-to-video/domain/constants/index.ts +0 -5
- package/src/{features → domains}/image-to-video/domain/types/index.ts +0 -3
- package/src/{features → domains}/image-to-video/index.ts +0 -7
- package/src/{features → domains}/image-to-video/presentation/components/index.ts +0 -4
- package/src/domains/image-to-video/presentation/hooks/imageToVideoStrategy.ts +77 -0
- package/src/domains/image-to-video/presentation/hooks/useImageToVideoFeature.ts +102 -0
- package/src/domains/scenarios/presentation/containers/CategoryNavigationContainer.tsx +4 -80
- package/src/{features → domains}/text-to-image/infrastructure/services/text-to-image-executor.ts +2 -82
- package/src/domains/text-to-image/infrastructure/utils/imageResultExtractor.ts +58 -0
- package/src/domains/text-to-video/presentation/hooks/textToVideoStrategy.ts +75 -0
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoFeature.ts +120 -0
- package/src/exports/features.ts +15 -16
- package/src/presentation/components/PendingJobCard.tsx +1 -1
- package/src/features/image-to-video/domain/constants/music.constants.ts +0 -53
- package/src/features/image-to-video/domain/types/music.types.ts +0 -21
- package/src/features/image-to-video/presentation/components/MusicMoodSelector.tsx +0 -181
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +0 -186
- package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +0 -186
- package/src/presentation/hooks/use-background-generation.ts +0 -185
- /package/src/{domain → domains/background/domain}/entities/job.types.ts +0 -0
- /package/src/{infrastructure → domains/background/infrastructure}/utils/result-validator.util.ts +0 -0
- /package/src/{presentation → domains/background/presentation}/hooks/use-pending-jobs.ts +0 -0
- /package/src/{features → domains}/image-to-video/README.md +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/animation.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/duration.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/constants/form.constants.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/animation.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/duration.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/form.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/domain/types/image-to-video.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/services/image-to-video-executor.ts +0 -0
- /package/src/{features → domains}/image-to-video/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/AddMoreCard.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/AnimationStyleSelector.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/DurationSelector.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/EmptyGridState.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/GridImageItem.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.styles.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.tsx +0 -0
- /package/src/{features → domains}/image-to-video/presentation/components/ImageSelectionGrid.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/image-to-video-feature.types.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useFormState.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useGeneration.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/hooks/useImageToVideoForm.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/index.ts +0 -0
- /package/src/{features → domains}/image-to-video/presentation/screens/ImageToVideoWizardFlow.tsx +0 -0
- /package/src/{features → domains}/shared/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/components/AutoSkipPreview.tsx +0 -0
- /package/src/{features → domains}/shared/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/utils/index.ts +0 -0
- /package/src/{features → domains}/shared/presentation/utils/wizard-flow.utils.ts +0 -0
- /package/src/{features → domains}/text-to-image/README.md +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/options.constants.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/constants/styles.constants.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/form.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/domain/types/text-to-image.types.ts +0 -0
- /package/src/{features → domains}/text-to-image/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useFormState.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useGeneration.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/hooks/useTextToImageForm.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/index.ts +0 -0
- /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.tsx +0 -0
- /package/src/{features → domains}/text-to-image/presentation/screens/TextToImageWizardFlow.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/README.md +0 -0
- /package/src/{features → domains}/text-to-video/domain/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/callback.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/component.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/config.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/request.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/domain/types/state.types.ts +0 -0
- /package/src/{features → domains}/text-to-video/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/services/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/infrastructure/services/text-to-video-executor.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/FrameSelector.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/GenerationTabs.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/HeroSection.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/HintCarousel.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/OptionsPanel.tsx +0 -0
- /package/src/{features → domains}/text-to-video/presentation/components/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/hooks/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/hooks/useTextToVideoForm.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/index.ts +0 -0
- /package/src/{features → domains}/text-to-video/presentation/screens/TextToVideoWizardFlow.tsx +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.61.
|
|
3
|
+
"version": "1.61.65",
|
|
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",
|
package/src/core/index.ts
CHANGED
|
@@ -57,7 +57,7 @@ export type {
|
|
|
57
57
|
// Segregated provider sub-interfaces
|
|
58
58
|
export type { IAIProviderLifecycle } from "../domain/interfaces/provider-lifecycle.interface";
|
|
59
59
|
export type { IAIProviderCapabilities } from "../domain/interfaces/provider-capabilities.interface";
|
|
60
|
-
export type { IAIProviderJobManager } from "../domain/interfaces/provider-job-manager.interface";
|
|
60
|
+
export type { IAIProviderJobManager } from "../domains/background/domain/interfaces/provider-job-manager.interface";
|
|
61
61
|
export type { IAIProviderExecutor } from "../domain/interfaces/provider-executor.interface";
|
|
62
62
|
export type { IAIProviderImageFeatures } from "../domain/interfaces/provider-image-features.interface";
|
|
63
63
|
export type { IAIProviderVideoFeatures } from "../domain/interfaces/provider-video-features.interface";
|
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
export * from "./error.types";
|
|
7
7
|
export * from "./generation.types";
|
|
8
8
|
export * from "./polling.types";
|
|
9
|
-
export * from "
|
|
9
|
+
export * from "../../domains/background/domain/entities/job.types";
|
|
10
10
|
export * from "./processing-modes.types";
|
|
11
11
|
export * from "./flow-config.types";
|
|
@@ -155,7 +155,7 @@ export interface VideoFeatureInputData {
|
|
|
155
155
|
|
|
156
156
|
import type { IAIProviderLifecycle } from "./provider-lifecycle.interface";
|
|
157
157
|
import type { IAIProviderCapabilities } from "./provider-capabilities.interface";
|
|
158
|
-
import type { IAIProviderJobManager } from "
|
|
158
|
+
import type { IAIProviderJobManager } from "../../domains/background/domain/interfaces/provider-job-manager.interface";
|
|
159
159
|
import type { IAIProviderExecutor } from "./provider-executor.interface";
|
|
160
160
|
import type { IAIProviderImageFeatures } from "./provider-image-features.interface";
|
|
161
161
|
import type { IAIProviderVideoFeatures } from "./provider-video-features.interface";
|
|
@@ -9,7 +9,7 @@ export * from "./app-services.interface";
|
|
|
9
9
|
// Interface Segregation - Split provider interfaces
|
|
10
10
|
export type { IAIProviderLifecycle } from "./provider-lifecycle.interface";
|
|
11
11
|
export type { IAIProviderCapabilities } from "./provider-capabilities.interface";
|
|
12
|
-
export type { IAIProviderJobManager } from "
|
|
12
|
+
export type { IAIProviderJobManager } from "../../domains/background/domain/interfaces/provider-job-manager.interface";
|
|
13
13
|
export type { IAIProviderExecutor } from "./provider-executor.interface";
|
|
14
14
|
export type { IAIProviderImageFeatures } from "./provider-image-features.interface";
|
|
15
15
|
export type { IAIProviderVideoFeatures } from "./provider-video-features.interface";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./job.types";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./provider-job-manager.interface";
|
package/src/{domain → domains/background/domain}/interfaces/provider-job-manager.interface.ts
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Single Responsibility: Async job submission, status checking, and result retrieval
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { JobSubmission, JobStatus } from "
|
|
6
|
+
import type { JobSubmission, JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
|
|
7
7
|
|
|
8
8
|
export interface IAIProviderJobManager {
|
|
9
9
|
/**
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BackgroundJob,
|
|
3
|
+
BackgroundQueueConfig,
|
|
4
|
+
JobExecutorConfig,
|
|
5
|
+
} from "../entities/job.types";
|
|
6
|
+
import type { executeDirectGeneration } from "../../infrastructure/executors/backgroundJobExecutor";
|
|
7
|
+
|
|
8
|
+
export type { DirectExecutionResult } from "../../infrastructure/executors/backgroundJobExecutor";
|
|
9
|
+
|
|
10
|
+
export interface UseBackgroundGenerationOptions<TInput, TResult>
|
|
11
|
+
extends Partial<BackgroundQueueConfig> {
|
|
12
|
+
readonly executor: JobExecutorConfig<TInput, TResult>;
|
|
13
|
+
readonly onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
14
|
+
readonly onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
15
|
+
readonly onAllComplete?: () => void;
|
|
16
|
+
readonly onProgress?: (progress: number) => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UseBackgroundGenerationReturn<TInput, TResult> {
|
|
20
|
+
readonly startJob: (input: TInput, type: string) => Promise<string>;
|
|
21
|
+
readonly executeDirectly: (input: TInput) => ReturnType<typeof executeDirectGeneration<TInput, TResult>>;
|
|
22
|
+
readonly cancelJob: (id: string) => void;
|
|
23
|
+
readonly pendingJobs: BackgroundJob<TInput, TResult>[];
|
|
24
|
+
readonly activeJobCount: number;
|
|
25
|
+
readonly hasActiveJobs: boolean;
|
|
26
|
+
readonly isProcessing: boolean;
|
|
27
|
+
readonly progress: number;
|
|
28
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { BackgroundJob, JobExecutorConfig } from "../../domain/entities/job.types";
|
|
2
|
+
|
|
3
|
+
export interface DirectExecutionResult<TResult> {
|
|
4
|
+
readonly success: boolean;
|
|
5
|
+
readonly result?: TResult;
|
|
6
|
+
readonly error?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface DirectExecutionParams<TInput, TResult> {
|
|
10
|
+
input: TInput;
|
|
11
|
+
executor: JobExecutorConfig<TInput, TResult>;
|
|
12
|
+
onProgress?: (progress: number) => void;
|
|
13
|
+
setProgress: (progress: number) => void;
|
|
14
|
+
setIsProcessing: (isProcessing: boolean) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const executeDirectGeneration = async <TInput, TResult>(
|
|
18
|
+
params: DirectExecutionParams<TInput, TResult>,
|
|
19
|
+
): Promise<DirectExecutionResult<TResult>> => {
|
|
20
|
+
const { input, executor, onProgress, setProgress, setIsProcessing } = params;
|
|
21
|
+
|
|
22
|
+
setIsProcessing(true);
|
|
23
|
+
setProgress(0);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = await executor.execute(input, (p) => {
|
|
27
|
+
setProgress(p);
|
|
28
|
+
onProgress?.(p);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
setProgress(100);
|
|
32
|
+
return { success: true, result };
|
|
33
|
+
} catch (error) {
|
|
34
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
35
|
+
return { success: false, error: errorMsg };
|
|
36
|
+
} finally {
|
|
37
|
+
setIsProcessing(false);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
interface QueuedExecutionParams<TInput, TResult> {
|
|
42
|
+
jobId: string;
|
|
43
|
+
input: TInput;
|
|
44
|
+
executor: JobExecutorConfig<TInput, TResult>;
|
|
45
|
+
updateJob: (params: { id: string; updates: Partial<BackgroundJob<TInput, TResult>> }) => void;
|
|
46
|
+
removeJob: (id: string) => void;
|
|
47
|
+
getJob: (id: string) => BackgroundJob<TInput, TResult> | undefined;
|
|
48
|
+
activeJobsRef: React.MutableRefObject<Set<string>>;
|
|
49
|
+
onJobComplete?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
50
|
+
onJobError?: (job: BackgroundJob<TInput, TResult>) => void;
|
|
51
|
+
onAllComplete?: () => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const executeQueuedJob = async <TInput, TResult>(
|
|
55
|
+
params: QueuedExecutionParams<TInput, TResult>,
|
|
56
|
+
): Promise<void> => {
|
|
57
|
+
const {
|
|
58
|
+
jobId,
|
|
59
|
+
input,
|
|
60
|
+
executor,
|
|
61
|
+
updateJob,
|
|
62
|
+
removeJob,
|
|
63
|
+
getJob,
|
|
64
|
+
activeJobsRef,
|
|
65
|
+
onJobComplete,
|
|
66
|
+
onJobError,
|
|
67
|
+
onAllComplete,
|
|
68
|
+
} = params;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
updateJob({ id: jobId, updates: { status: "processing", progress: 10 } });
|
|
72
|
+
|
|
73
|
+
const result = await executor.execute(input, (p) => {
|
|
74
|
+
updateJob({ id: jobId, updates: { progress: p } });
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
updateJob({
|
|
78
|
+
id: jobId,
|
|
79
|
+
updates: { status: "completed", progress: 100, result, completedAt: new Date() },
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const completedJob = getJob(jobId);
|
|
83
|
+
if (completedJob) {
|
|
84
|
+
await executor.onComplete?.(completedJob);
|
|
85
|
+
onJobComplete?.(completedJob);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
removeJob(jobId);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
91
|
+
|
|
92
|
+
updateJob({ id: jobId, updates: { status: "failed", error: errorMsg, progress: 0 } });
|
|
93
|
+
|
|
94
|
+
const failedJob = getJob(jobId);
|
|
95
|
+
if (failedJob) {
|
|
96
|
+
await executor.onError?.(failedJob, error instanceof Error ? error : new Error(errorMsg));
|
|
97
|
+
onJobError?.(failedJob);
|
|
98
|
+
}
|
|
99
|
+
} finally {
|
|
100
|
+
activeJobsRef.current.delete(jobId);
|
|
101
|
+
if (activeJobsRef.current.size === 0) {
|
|
102
|
+
onAllComplete?.();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
package/src/{infrastructure → domains/background/infrastructure}/services/job-poller-factory.ts
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Creates pre-configured job poller instances
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { PollingConfig } from "
|
|
6
|
+
import type { PollingConfig } from "../../../../domain/entities/polling.types";
|
|
7
7
|
import type { PollJobOptions } from "./job-poller.types";
|
|
8
8
|
import { pollJob } from "./job-poller.service";
|
|
9
9
|
|
package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.service.ts
RENAMED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Reports only real status - no fake progress
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { DEFAULT_POLLING_CONFIG } from "
|
|
7
|
+
import { DEFAULT_POLLING_CONFIG } from "../../../../domain/entities/polling.types";
|
|
8
8
|
import { calculatePollingInterval } from "../utils/polling-interval.util";
|
|
9
9
|
import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
|
|
10
10
|
import { validateResult } from "../utils/result-validator.util";
|
package/src/{infrastructure → domains/background/infrastructure}/services/job-poller.types.ts
RENAMED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Job Poller Type Definitions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { IAIProvider, JobStatus } from "
|
|
6
|
-
import type { PollingConfig } from "
|
|
5
|
+
import type { IAIProvider, JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
|
|
6
|
+
import type { PollingConfig } from "../../../../domain/entities/polling.types";
|
|
7
7
|
|
|
8
8
|
export interface PollJobOptions {
|
|
9
9
|
provider: IAIProvider;
|
package/src/{infrastructure → domains/background/infrastructure}/utils/status-checker.util.ts
RENAMED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Checks job status responses for errors
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import type { JobStatus, AILogEntry } from "
|
|
6
|
+
import type { JobStatus, AILogEntry } from "../../../../domain/interfaces/ai-provider.interface";
|
|
7
7
|
|
|
8
8
|
export interface StatusCheckResult {
|
|
9
9
|
status: string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { useCallback, useRef, useState } from "react";
|
|
2
|
+
import { usePendingJobs } from "./use-pending-jobs";
|
|
3
|
+
import { executeDirectGeneration, executeQueuedJob } from "../../infrastructure/executors/backgroundJobExecutor";
|
|
4
|
+
import { DEFAULT_QUEUE_CONFIG } from "../../domain/entities/job.types";
|
|
5
|
+
import type {
|
|
6
|
+
UseBackgroundGenerationOptions,
|
|
7
|
+
UseBackgroundGenerationReturn,
|
|
8
|
+
} from "../../domain/types/background-generation.types";
|
|
9
|
+
|
|
10
|
+
export type { DirectExecutionResult, UseBackgroundGenerationOptions, UseBackgroundGenerationReturn } from "../../domain/types/background-generation.types";
|
|
11
|
+
|
|
12
|
+
export function useBackgroundGeneration<TInput = unknown, TResult = unknown>(
|
|
13
|
+
options: UseBackgroundGenerationOptions<TInput, TResult>,
|
|
14
|
+
): UseBackgroundGenerationReturn<TInput, TResult> {
|
|
15
|
+
const config = { ...DEFAULT_QUEUE_CONFIG, ...options };
|
|
16
|
+
const activeJobsRef = useRef<Set<string>>(new Set());
|
|
17
|
+
const jobInputsRef = useRef<Map<string, { input: TInput; type: string }>>(
|
|
18
|
+
new Map(),
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const [isProcessing, setIsProcessing] = useState(false);
|
|
22
|
+
const [progress, setProgress] = useState(0);
|
|
23
|
+
|
|
24
|
+
const { jobs, addJobAsync, updateJob, removeJob, getJob } = usePendingJobs<
|
|
25
|
+
TInput,
|
|
26
|
+
TResult
|
|
27
|
+
>({
|
|
28
|
+
queryKey: config.queryKey,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const { executor, onProgress, onJobComplete, onJobError, onAllComplete } = options;
|
|
32
|
+
|
|
33
|
+
const executeDirectly = useCallback(
|
|
34
|
+
(input: TInput) =>
|
|
35
|
+
executeDirectGeneration({ input, executor, onProgress, setProgress, setIsProcessing }),
|
|
36
|
+
[executor, onProgress],
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const executeJob = useCallback(
|
|
40
|
+
(jobId: string, input: TInput) =>
|
|
41
|
+
executeQueuedJob({
|
|
42
|
+
jobId,
|
|
43
|
+
input,
|
|
44
|
+
executor,
|
|
45
|
+
updateJob,
|
|
46
|
+
removeJob,
|
|
47
|
+
getJob,
|
|
48
|
+
activeJobsRef,
|
|
49
|
+
onJobComplete,
|
|
50
|
+
onJobError,
|
|
51
|
+
onAllComplete,
|
|
52
|
+
}),
|
|
53
|
+
[executor, onJobComplete, onJobError, onAllComplete, updateJob, removeJob, getJob],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const startJob = useCallback(
|
|
57
|
+
async (input: TInput, type: string): Promise<string> => {
|
|
58
|
+
const jobId = `job-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
59
|
+
|
|
60
|
+
jobInputsRef.current.set(jobId, { input, type });
|
|
61
|
+
|
|
62
|
+
await addJobAsync({
|
|
63
|
+
id: jobId,
|
|
64
|
+
input,
|
|
65
|
+
type,
|
|
66
|
+
status: "queued",
|
|
67
|
+
progress: 0,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
activeJobsRef.current.add(jobId);
|
|
71
|
+
void executeJob(jobId, input);
|
|
72
|
+
|
|
73
|
+
return jobId;
|
|
74
|
+
},
|
|
75
|
+
[addJobAsync, executeJob],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const cancelJob = useCallback(
|
|
79
|
+
(id: string) => {
|
|
80
|
+
activeJobsRef.current.delete(id);
|
|
81
|
+
jobInputsRef.current.delete(id);
|
|
82
|
+
removeJob(id);
|
|
83
|
+
},
|
|
84
|
+
[removeJob],
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
startJob,
|
|
89
|
+
executeDirectly,
|
|
90
|
+
cancelJob,
|
|
91
|
+
pendingJobs: jobs,
|
|
92
|
+
activeJobCount: activeJobsRef.current.size,
|
|
93
|
+
hasActiveJobs: activeJobsRef.current.size > 0,
|
|
94
|
+
isProcessing,
|
|
95
|
+
progress,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { View, StyleSheet } from "react-native";
|
|
8
8
|
import { AtomicText, useAppDesignTokens } from "@umituz/react-native-design-system";
|
|
9
|
-
import type { BackgroundJob } from "
|
|
9
|
+
import type { BackgroundJob } from "../../../background/domain/entities/job.types";
|
|
10
10
|
import { PendingJobCard } from "../../../../presentation/components/PendingJobCard";
|
|
11
11
|
|
|
12
12
|
export interface PendingJobsSectionProps {
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
// Animation Types
|
|
2
2
|
export type { AnimationStyle, AnimationStyleId } from "./animation.types";
|
|
3
3
|
|
|
4
|
-
// Music Types
|
|
5
|
-
export type { MusicMood, MusicMoodId } from "./music.types";
|
|
6
|
-
|
|
7
4
|
// Duration Types
|
|
8
5
|
export type { VideoDuration, DurationOption } from "./duration.types";
|
|
9
6
|
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
// Animation Types
|
|
11
11
|
export type { AnimationStyle, AnimationStyleId } from "./domain";
|
|
12
12
|
|
|
13
|
-
// Music Types
|
|
14
|
-
export type { MusicMood, MusicMoodId } from "./domain";
|
|
15
|
-
|
|
16
13
|
// Duration Types
|
|
17
14
|
export type { VideoDuration, DurationOption } from "./domain";
|
|
18
15
|
|
|
@@ -54,8 +51,6 @@ export type {
|
|
|
54
51
|
export {
|
|
55
52
|
DEFAULT_ANIMATION_STYLES as IMAGE_TO_VIDEO_ANIMATION_STYLES,
|
|
56
53
|
DEFAULT_ANIMATION_STYLE_ID as IMAGE_TO_VIDEO_DEFAULT_ANIMATION,
|
|
57
|
-
DEFAULT_MUSIC_MOODS as IMAGE_TO_VIDEO_MUSIC_MOODS,
|
|
58
|
-
DEFAULT_MUSIC_MOOD_ID as IMAGE_TO_VIDEO_DEFAULT_MUSIC,
|
|
59
54
|
DEFAULT_DURATION_OPTIONS as IMAGE_TO_VIDEO_DURATION_OPTIONS,
|
|
60
55
|
DEFAULT_VIDEO_DURATION as IMAGE_TO_VIDEO_DEFAULT_DURATION,
|
|
61
56
|
DEFAULT_FORM_VALUES as IMAGE_TO_VIDEO_FORM_DEFAULTS,
|
|
@@ -101,7 +96,6 @@ export type {
|
|
|
101
96
|
export {
|
|
102
97
|
ImageToVideoAnimationStyleSelector,
|
|
103
98
|
ImageToVideoDurationSelector,
|
|
104
|
-
ImageToVideoMusicMoodSelector,
|
|
105
99
|
ImageToVideoSelectionGrid,
|
|
106
100
|
ImageToVideoGenerateButton,
|
|
107
101
|
} from "./presentation";
|
|
@@ -109,7 +103,6 @@ export {
|
|
|
109
103
|
export type {
|
|
110
104
|
ImageToVideoAnimationStyleSelectorProps,
|
|
111
105
|
ImageToVideoDurationSelectorProps,
|
|
112
|
-
ImageToVideoMusicMoodSelectorProps,
|
|
113
106
|
ImageToVideoSelectionGridProps,
|
|
114
107
|
ImageToVideoSelectionGridTranslations,
|
|
115
108
|
ImageToVideoGenerateButtonProps,
|
|
@@ -10,10 +10,6 @@ export type { AnimationStyleSelectorProps as ImageToVideoAnimationStyleSelectorP
|
|
|
10
10
|
export { DurationSelector as ImageToVideoDurationSelector } from "./DurationSelector";
|
|
11
11
|
export type { DurationSelectorProps as ImageToVideoDurationSelectorProps } from "./DurationSelector";
|
|
12
12
|
|
|
13
|
-
// Music Mood Selector
|
|
14
|
-
export { MusicMoodSelector as ImageToVideoMusicMoodSelector } from "./MusicMoodSelector";
|
|
15
|
-
export type { MusicMoodSelectorProps as ImageToVideoMusicMoodSelectorProps } from "./MusicMoodSelector";
|
|
16
|
-
|
|
17
13
|
// Image Selection Grid
|
|
18
14
|
export { ImageSelectionGrid as ImageToVideoSelectionGrid } from "./ImageSelectionGrid";
|
|
19
15
|
export type {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { executeImageToVideo } from "../../infrastructure/services";
|
|
2
|
+
import type { GenerationStrategy } from "../../../../presentation/hooks/generation";
|
|
3
|
+
import type {
|
|
4
|
+
ImageToVideoConfig,
|
|
5
|
+
ImageToVideoCallbacks,
|
|
6
|
+
ImageToVideoResult,
|
|
7
|
+
ImageToVideoOptions,
|
|
8
|
+
ImageToVideoInputBuilder,
|
|
9
|
+
ImageToVideoResultExtractor,
|
|
10
|
+
} from "../../domain/types";
|
|
11
|
+
|
|
12
|
+
interface VideoGenerationInput {
|
|
13
|
+
imageUrl: string;
|
|
14
|
+
prompt: string;
|
|
15
|
+
options?: ImageToVideoOptions;
|
|
16
|
+
creationId: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface CreateStrategyParams {
|
|
20
|
+
config: ImageToVideoConfig;
|
|
21
|
+
callbacks: ImageToVideoCallbacks;
|
|
22
|
+
buildInput: ImageToVideoInputBuilder;
|
|
23
|
+
extractResult?: ImageToVideoResultExtractor;
|
|
24
|
+
userId: string;
|
|
25
|
+
currentPrompt: string;
|
|
26
|
+
creationIdRef: React.MutableRefObject<string>;
|
|
27
|
+
updateState: (videoUrl: string | null, thumbnailUrl: string | null) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const createImageToVideoStrategy = (
|
|
31
|
+
params: CreateStrategyParams,
|
|
32
|
+
): GenerationStrategy<VideoGenerationInput, ImageToVideoResult> => {
|
|
33
|
+
const { config, callbacks, buildInput, extractResult, userId, currentPrompt, creationIdRef, updateState } = params;
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
execute: async (input) => {
|
|
37
|
+
creationIdRef.current = input.creationId;
|
|
38
|
+
|
|
39
|
+
callbacks.onGenerationStart?.({
|
|
40
|
+
creationId: input.creationId,
|
|
41
|
+
type: "image-to-video",
|
|
42
|
+
imageUrl: input.imageUrl,
|
|
43
|
+
prompt: input.prompt,
|
|
44
|
+
metadata: input.options as Record<string, unknown> | undefined,
|
|
45
|
+
}).catch(() => {});
|
|
46
|
+
|
|
47
|
+
const result = await executeImageToVideo(
|
|
48
|
+
{ imageUrl: input.imageUrl, prompt: input.prompt, userId, options: input.options },
|
|
49
|
+
{ model: config.model, buildInput, extractResult },
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (!result.success || !result.videoUrl) {
|
|
53
|
+
throw new Error(result.error || "Generation failed");
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
updateState(result.videoUrl ?? null, result.thumbnailUrl ?? null);
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
success: true,
|
|
60
|
+
videoUrl: result.videoUrl,
|
|
61
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
getCreditCost: () => config.creditCost,
|
|
65
|
+
save: async (result) => {
|
|
66
|
+
if (result.success && result.videoUrl && creationIdRef.current) {
|
|
67
|
+
await callbacks.onCreationSave?.({
|
|
68
|
+
creationId: creationIdRef.current,
|
|
69
|
+
type: "image-to-video",
|
|
70
|
+
videoUrl: result.videoUrl,
|
|
71
|
+
thumbnailUrl: result.thumbnailUrl,
|
|
72
|
+
prompt: currentPrompt,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo, useRef } from "react";
|
|
2
|
+
import { useGenerationOrchestrator } from "../../../../presentation/hooks/generation";
|
|
3
|
+
import { createImageToVideoStrategy } from "./imageToVideoStrategy";
|
|
4
|
+
import type {
|
|
5
|
+
UseImageToVideoFeatureProps,
|
|
6
|
+
UseImageToVideoFeatureReturn,
|
|
7
|
+
INITIAL_STATE,
|
|
8
|
+
DEFAULT_ALERT_MESSAGES,
|
|
9
|
+
} from "./image-to-video-feature.types";
|
|
10
|
+
|
|
11
|
+
export type {
|
|
12
|
+
UseImageToVideoFeatureProps,
|
|
13
|
+
UseImageToVideoFeatureReturn,
|
|
14
|
+
} from "./image-to-video-feature.types";
|
|
15
|
+
|
|
16
|
+
export function useImageToVideoFeature(props: UseImageToVideoFeatureProps): UseImageToVideoFeatureReturn {
|
|
17
|
+
const { config, callbacks, userId } = props;
|
|
18
|
+
const [state, setState] = useState(INITIAL_STATE);
|
|
19
|
+
const creationIdRef = useRef("");
|
|
20
|
+
|
|
21
|
+
const updateState = useCallback((videoUrl: string | null, thumbnailUrl: string | null) => {
|
|
22
|
+
setState((prev) => ({ ...prev, videoUrl, thumbnailUrl }));
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
const strategy = useMemo(
|
|
26
|
+
() =>
|
|
27
|
+
createImageToVideoStrategy({
|
|
28
|
+
config,
|
|
29
|
+
callbacks,
|
|
30
|
+
buildInput: config.buildInput,
|
|
31
|
+
extractResult: config.extractResult,
|
|
32
|
+
userId,
|
|
33
|
+
currentPrompt: state.motionPrompt || "",
|
|
34
|
+
creationIdRef,
|
|
35
|
+
updateState,
|
|
36
|
+
}),
|
|
37
|
+
[config, callbacks, userId, state.motionPrompt, updateState],
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const orchestrator = useGenerationOrchestrator(strategy, {
|
|
41
|
+
userId,
|
|
42
|
+
alertMessages: DEFAULT_ALERT_MESSAGES,
|
|
43
|
+
onCreditsExhausted: () => callbacks.onShowPaywall?.(config.creditCost ?? 0),
|
|
44
|
+
onSuccess: (result) => {
|
|
45
|
+
config.onProcessingComplete?.();
|
|
46
|
+
callbacks.onGenerate?.(result);
|
|
47
|
+
},
|
|
48
|
+
onError: (err) => {
|
|
49
|
+
config.onProcessingError?.(err.message);
|
|
50
|
+
callbacks.onError?.(err.message);
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const setImageUri = useCallback((imageUri: string) => {
|
|
55
|
+
setState((prev) => ({ ...prev, imageUri, error: null }));
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
const setMotionPrompt = useCallback((motionPrompt: string) => {
|
|
59
|
+
setState((prev) => ({ ...prev, motionPrompt, error: null }));
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
const generate = useCallback(
|
|
63
|
+
async (params?: any) => {
|
|
64
|
+
const imageUri = params?.imageUri || state.imageUri;
|
|
65
|
+
if (!imageUri) {
|
|
66
|
+
const error = "Image is required";
|
|
67
|
+
setState((prev) => ({ ...prev, error }));
|
|
68
|
+
return { success: false, error };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
setState((prev) => ({ ...prev, isProcessing: true, error: null }));
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const result = await orchestrator.generate({
|
|
75
|
+
imageUrl: imageUri,
|
|
76
|
+
prompt: state.motionPrompt || "",
|
|
77
|
+
options: params,
|
|
78
|
+
creationId: `image-to-video-${Date.now()}`,
|
|
79
|
+
});
|
|
80
|
+
setState((prev) => ({ ...prev, isProcessing: false }));
|
|
81
|
+
return result;
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const message = error instanceof Error ? error.message : "Generation failed";
|
|
84
|
+
setState((prev) => ({ ...prev, isProcessing: false, error: message }));
|
|
85
|
+
return { success: false, error: message };
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
[state.imageUri, state.motionPrompt, orchestrator],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const reset = useCallback(() => setState(INITIAL_STATE), []);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
state,
|
|
95
|
+
setImageUri,
|
|
96
|
+
setMotionPrompt,
|
|
97
|
+
generate,
|
|
98
|
+
reset,
|
|
99
|
+
isReady: !orchestrator.isGenerating && !state.isProcessing,
|
|
100
|
+
canGenerate: !orchestrator.isGenerating && !state.isProcessing && !!state.imageUri,
|
|
101
|
+
};
|
|
102
|
+
}
|