@umituz/react-native-ai-generation-content 1.17.1 → 1.17.2
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/domains/creations/presentation/components/CreationsHomeCard.tsx +1 -1
- package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +0 -1
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +9 -6
- package/src/domains/face-detection/infrastructure/validators/faceValidator.ts +1 -1
- package/src/domains/prompts/infrastructure/services/PromptGenerationService.ts +1 -1
- package/src/domains/prompts/presentation/hooks/useFaceSwap.ts +2 -2
- package/src/domains/prompts/presentation/hooks/usePromptGeneration.ts +4 -4
- package/src/features/image-to-video/domain/index.ts +1 -0
- package/src/features/image-to-video/domain/types/image-to-video.types.ts +71 -0
- package/src/features/image-to-video/domain/types/index.ts +10 -0
- package/src/features/image-to-video/index.ts +27 -0
- package/src/features/image-to-video/infrastructure/index.ts +1 -0
- package/src/features/image-to-video/infrastructure/services/image-to-video-executor.ts +112 -0
- package/src/features/image-to-video/infrastructure/services/index.ts +5 -0
- package/src/features/image-to-video/presentation/hooks/index.ts +5 -0
- package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +121 -0
- package/src/features/image-to-video/presentation/index.ts +1 -0
- package/src/features/text-to-image/domain/index.ts +1 -0
- package/src/features/text-to-image/domain/types/index.ts +10 -0
- package/src/features/text-to-image/domain/types/text-to-image.types.ts +66 -0
- package/src/features/text-to-image/index.ts +27 -1
- package/src/features/text-to-image/infrastructure/index.ts +1 -0
- package/src/features/text-to-image/infrastructure/services/index.ts +5 -0
- package/src/features/text-to-image/infrastructure/services/text-to-image-executor.ts +113 -0
- package/src/features/text-to-image/presentation/hooks/index.ts +5 -0
- package/src/features/text-to-image/presentation/hooks/useTextToImageFeature.ts +111 -0
- package/src/features/text-to-image/presentation/index.ts +1 -0
- package/src/features/text-to-video/domain/index.ts +1 -0
- package/src/features/text-to-video/domain/types/index.ts +10 -0
- package/src/features/text-to-video/domain/types/text-to-video.types.ts +65 -0
- package/src/features/text-to-video/index.ts +27 -1
- package/src/features/text-to-video/infrastructure/index.ts +1 -0
- package/src/features/text-to-video/infrastructure/services/index.ts +5 -0
- package/src/features/text-to-video/infrastructure/services/text-to-video-executor.ts +108 -0
- package/src/features/text-to-video/presentation/hooks/index.ts +5 -0
- package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +111 -0
- package/src/features/text-to-video/presentation/index.ts +1 -0
- package/src/features/text-to-voice/domain/index.ts +1 -0
- package/src/features/text-to-voice/domain/types/index.ts +10 -0
- package/src/features/text-to-voice/domain/types/text-to-voice.types.ts +65 -0
- package/src/features/text-to-voice/index.ts +27 -0
- package/src/features/text-to-voice/infrastructure/index.ts +1 -0
- package/src/features/text-to-voice/infrastructure/services/index.ts +5 -0
- package/src/features/text-to-voice/infrastructure/services/text-to-voice-executor.ts +111 -0
- package/src/features/text-to-voice/presentation/hooks/index.ts +5 -0
- package/src/features/text-to-voice/presentation/hooks/useTextToVoiceFeature.ts +105 -0
- package/src/features/text-to-voice/presentation/index.ts +1 -0
- package/src/index.ts +24 -0
- package/src/features/text-to-image/domain/entities.ts +0 -58
- package/src/features/text-to-video/domain/entities.ts +0 -52
- package/src/types/jsx.d.ts +0 -19
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Image Executor
|
|
3
|
+
* Provider-agnostic text-to-image execution using active AI provider
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { providerRegistry } from "../../../../infrastructure/services";
|
|
7
|
+
import type {
|
|
8
|
+
TextToImageRequest,
|
|
9
|
+
TextToImageResult,
|
|
10
|
+
TextToImageInputBuilder,
|
|
11
|
+
TextToImageResultExtractor,
|
|
12
|
+
} from "../../domain/types";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export interface ExecuteTextToImageOptions {
|
|
17
|
+
model: string;
|
|
18
|
+
buildInput: TextToImageInputBuilder;
|
|
19
|
+
extractResult?: TextToImageResultExtractor;
|
|
20
|
+
onProgress?: (progress: number) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function defaultExtractResult(
|
|
24
|
+
result: unknown,
|
|
25
|
+
): { imageUrl?: string; imageUrls?: string[] } | undefined {
|
|
26
|
+
if (typeof result !== "object" || result === null) return undefined;
|
|
27
|
+
|
|
28
|
+
const r = result as Record<string, unknown>;
|
|
29
|
+
|
|
30
|
+
if (typeof r.image === "string") {
|
|
31
|
+
return { imageUrl: r.image };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (Array.isArray(r.images)) {
|
|
35
|
+
const urls = r.images
|
|
36
|
+
.map((img) => {
|
|
37
|
+
if (typeof img === "string") return img;
|
|
38
|
+
if (img && typeof img === "object" && "url" in img) {
|
|
39
|
+
return (img as { url: string }).url;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
})
|
|
43
|
+
.filter((url): url is string => url !== null);
|
|
44
|
+
|
|
45
|
+
if (urls.length > 0) {
|
|
46
|
+
return { imageUrl: urls[0], imageUrls: urls };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function executeTextToImage(
|
|
54
|
+
request: TextToImageRequest,
|
|
55
|
+
options: ExecuteTextToImageOptions,
|
|
56
|
+
): Promise<TextToImageResult> {
|
|
57
|
+
const provider = providerRegistry.getActiveProvider();
|
|
58
|
+
|
|
59
|
+
if (!provider) {
|
|
60
|
+
return { success: false, error: "No AI provider configured" };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!provider.isInitialized()) {
|
|
64
|
+
return { success: false, error: "AI provider not initialized" };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!request.prompt) {
|
|
68
|
+
return { success: false, error: "Prompt is required" };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const { model, buildInput, extractResult, onProgress } = options;
|
|
72
|
+
|
|
73
|
+
if (__DEV__) {
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.log(`[TextToImage] Provider: ${provider.providerId}, Model: ${model}`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
onProgress?.(10);
|
|
80
|
+
|
|
81
|
+
const input = buildInput(request.prompt, request.options);
|
|
82
|
+
onProgress?.(20);
|
|
83
|
+
|
|
84
|
+
const result = await provider.run(model, input);
|
|
85
|
+
onProgress?.(90);
|
|
86
|
+
|
|
87
|
+
const extractor = extractResult || defaultExtractResult;
|
|
88
|
+
const extracted = extractor(result);
|
|
89
|
+
onProgress?.(100);
|
|
90
|
+
|
|
91
|
+
if (!extracted?.imageUrl) {
|
|
92
|
+
return { success: false, error: "No image in response" };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
imageUrl: extracted.imageUrl,
|
|
98
|
+
imageUrls: extracted.imageUrls,
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
+
if (__DEV__) {
|
|
103
|
+
// eslint-disable-next-line no-console
|
|
104
|
+
console.error("[TextToImage] Error:", message);
|
|
105
|
+
}
|
|
106
|
+
return { success: false, error: message };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function hasTextToImageSupport(): boolean {
|
|
111
|
+
const provider = providerRegistry.getActiveProvider();
|
|
112
|
+
return provider !== null && provider.isInitialized();
|
|
113
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Image Feature Hook
|
|
3
|
+
* Provider-agnostic hook for text-to-image generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useCallback } from "react";
|
|
7
|
+
import { executeTextToImage } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
TextToImageFeatureState,
|
|
10
|
+
TextToImageFeatureConfig,
|
|
11
|
+
TextToImageResult,
|
|
12
|
+
TextToImageOptions,
|
|
13
|
+
} from "../../domain/types";
|
|
14
|
+
|
|
15
|
+
export interface UseTextToImageFeatureProps {
|
|
16
|
+
config: TextToImageFeatureConfig;
|
|
17
|
+
userId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseTextToImageFeatureReturn {
|
|
21
|
+
state: TextToImageFeatureState;
|
|
22
|
+
setPrompt: (prompt: string) => void;
|
|
23
|
+
generate: (options?: TextToImageOptions) => Promise<TextToImageResult>;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
isReady: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const initialState: TextToImageFeatureState = {
|
|
29
|
+
prompt: "",
|
|
30
|
+
imageUrl: null,
|
|
31
|
+
imageUrls: [],
|
|
32
|
+
isProcessing: false,
|
|
33
|
+
progress: 0,
|
|
34
|
+
error: null,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function useTextToImageFeature(
|
|
38
|
+
props: UseTextToImageFeatureProps,
|
|
39
|
+
): UseTextToImageFeatureReturn {
|
|
40
|
+
const { config, userId } = props;
|
|
41
|
+
const [state, setState] = useState<TextToImageFeatureState>(initialState);
|
|
42
|
+
|
|
43
|
+
const setPrompt = useCallback(
|
|
44
|
+
(prompt: string) => {
|
|
45
|
+
setState((prev) => ({ ...prev, prompt, error: null }));
|
|
46
|
+
config.onPromptChange?.(prompt);
|
|
47
|
+
},
|
|
48
|
+
[config],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const generate = useCallback(
|
|
52
|
+
async (options?: TextToImageOptions): Promise<TextToImageResult> => {
|
|
53
|
+
if (!state.prompt) {
|
|
54
|
+
const error = "Prompt is required";
|
|
55
|
+
setState((prev) => ({ ...prev, error }));
|
|
56
|
+
return { success: false, error };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setState((prev) => ({
|
|
60
|
+
...prev,
|
|
61
|
+
isProcessing: true,
|
|
62
|
+
progress: 0,
|
|
63
|
+
error: null,
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
config.onProcessingStart?.();
|
|
67
|
+
|
|
68
|
+
const result = await executeTextToImage(
|
|
69
|
+
{ prompt: state.prompt, userId, options },
|
|
70
|
+
{
|
|
71
|
+
model: config.model,
|
|
72
|
+
buildInput: config.buildInput,
|
|
73
|
+
extractResult: config.extractResult,
|
|
74
|
+
onProgress: (progress) => {
|
|
75
|
+
setState((prev) => ({ ...prev, progress }));
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (result.success && result.imageUrl) {
|
|
81
|
+
setState((prev) => ({
|
|
82
|
+
...prev,
|
|
83
|
+
imageUrl: result.imageUrl ?? null,
|
|
84
|
+
imageUrls: result.imageUrls ?? [],
|
|
85
|
+
isProcessing: false,
|
|
86
|
+
progress: 100,
|
|
87
|
+
}));
|
|
88
|
+
} else {
|
|
89
|
+
const error = result.error || "Generation failed";
|
|
90
|
+
setState((prev) => ({
|
|
91
|
+
...prev,
|
|
92
|
+
isProcessing: false,
|
|
93
|
+
error,
|
|
94
|
+
}));
|
|
95
|
+
config.onError?.(error);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
config.onProcessingComplete?.(result);
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
[state.prompt, userId, config],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const reset = useCallback(() => {
|
|
105
|
+
setState(initialState);
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
const isReady = state.prompt.length > 0 && !state.isProcessing;
|
|
109
|
+
|
|
110
|
+
return { state, setPrompt, generate, reset, isReady };
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./hooks";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Video Feature Types
|
|
3
|
+
* Request, Result, Config types for text-to-video generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface TextToVideoOptions {
|
|
7
|
+
duration?: number;
|
|
8
|
+
fps?: number;
|
|
9
|
+
guidanceScale?: number;
|
|
10
|
+
aspectRatio?: "16:9" | "9:16" | "1:1";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface TextToVideoRequest {
|
|
14
|
+
prompt: string;
|
|
15
|
+
userId: string;
|
|
16
|
+
negativePrompt?: string;
|
|
17
|
+
options?: TextToVideoOptions;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TextToVideoResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
videoUrl?: string;
|
|
23
|
+
thumbnailUrl?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TextToVideoFeatureState {
|
|
29
|
+
prompt: string;
|
|
30
|
+
videoUrl: string | null;
|
|
31
|
+
thumbnailUrl: string | null;
|
|
32
|
+
isProcessing: boolean;
|
|
33
|
+
progress: number;
|
|
34
|
+
error: string | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface TextToVideoTranslations {
|
|
38
|
+
promptPlaceholder: string;
|
|
39
|
+
generateButtonText: string;
|
|
40
|
+
processingText: string;
|
|
41
|
+
successText: string;
|
|
42
|
+
saveButtonText: string;
|
|
43
|
+
tryAnotherText: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type TextToVideoInputBuilder = (
|
|
47
|
+
prompt: string,
|
|
48
|
+
options?: TextToVideoOptions,
|
|
49
|
+
) => Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
export type TextToVideoResultExtractor = (
|
|
52
|
+
result: unknown,
|
|
53
|
+
) => { videoUrl?: string; thumbnailUrl?: string } | undefined;
|
|
54
|
+
|
|
55
|
+
export interface TextToVideoFeatureConfig {
|
|
56
|
+
providerId?: string;
|
|
57
|
+
creditCost?: number;
|
|
58
|
+
model: string;
|
|
59
|
+
buildInput: TextToVideoInputBuilder;
|
|
60
|
+
extractResult?: TextToVideoResultExtractor;
|
|
61
|
+
onPromptChange?: (prompt: string) => void;
|
|
62
|
+
onProcessingStart?: () => void;
|
|
63
|
+
onProcessingComplete?: (result: TextToVideoResult) => void;
|
|
64
|
+
onError?: (error: string) => void;
|
|
65
|
+
}
|
|
@@ -1 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Video Feature
|
|
3
|
+
* Provider-agnostic text-to-video generation feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Domain Types
|
|
7
|
+
export type {
|
|
8
|
+
TextToVideoOptions,
|
|
9
|
+
TextToVideoRequest,
|
|
10
|
+
TextToVideoResult,
|
|
11
|
+
TextToVideoFeatureState,
|
|
12
|
+
TextToVideoTranslations,
|
|
13
|
+
TextToVideoInputBuilder,
|
|
14
|
+
TextToVideoResultExtractor,
|
|
15
|
+
TextToVideoFeatureConfig,
|
|
16
|
+
} from "./domain";
|
|
17
|
+
|
|
18
|
+
// Infrastructure Services
|
|
19
|
+
export { executeTextToVideo, hasTextToVideoSupport } from "./infrastructure";
|
|
20
|
+
export type { ExecuteTextToVideoOptions } from "./infrastructure";
|
|
21
|
+
|
|
22
|
+
// Presentation Hooks
|
|
23
|
+
export { useTextToVideoFeature } from "./presentation";
|
|
24
|
+
export type {
|
|
25
|
+
UseTextToVideoFeatureProps,
|
|
26
|
+
UseTextToVideoFeatureReturn,
|
|
27
|
+
} from "./presentation";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./services";
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Video Executor
|
|
3
|
+
* Provider-agnostic text-to-video execution using active AI provider
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { providerRegistry } from "../../../../infrastructure/services";
|
|
7
|
+
import type {
|
|
8
|
+
TextToVideoRequest,
|
|
9
|
+
TextToVideoResult,
|
|
10
|
+
TextToVideoInputBuilder,
|
|
11
|
+
TextToVideoResultExtractor,
|
|
12
|
+
} from "../../domain/types";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export interface ExecuteTextToVideoOptions {
|
|
17
|
+
model: string;
|
|
18
|
+
buildInput: TextToVideoInputBuilder;
|
|
19
|
+
extractResult?: TextToVideoResultExtractor;
|
|
20
|
+
onProgress?: (progress: number) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function defaultExtractResult(
|
|
24
|
+
result: unknown,
|
|
25
|
+
): { videoUrl?: string; thumbnailUrl?: string } | undefined {
|
|
26
|
+
if (typeof result !== "object" || result === null) return undefined;
|
|
27
|
+
|
|
28
|
+
const r = result as Record<string, unknown>;
|
|
29
|
+
|
|
30
|
+
if (typeof r.video === "string") {
|
|
31
|
+
return { videoUrl: r.video };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (r.video && typeof r.video === "object") {
|
|
35
|
+
const video = r.video as Record<string, unknown>;
|
|
36
|
+
if (typeof video.url === "string") {
|
|
37
|
+
return {
|
|
38
|
+
videoUrl: video.url,
|
|
39
|
+
thumbnailUrl:
|
|
40
|
+
typeof r.thumbnail === "string" ? r.thumbnail : undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function executeTextToVideo(
|
|
49
|
+
request: TextToVideoRequest,
|
|
50
|
+
options: ExecuteTextToVideoOptions,
|
|
51
|
+
): Promise<TextToVideoResult> {
|
|
52
|
+
const provider = providerRegistry.getActiveProvider();
|
|
53
|
+
|
|
54
|
+
if (!provider) {
|
|
55
|
+
return { success: false, error: "No AI provider configured" };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (!provider.isInitialized()) {
|
|
59
|
+
return { success: false, error: "AI provider not initialized" };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!request.prompt) {
|
|
63
|
+
return { success: false, error: "Prompt is required" };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { model, buildInput, extractResult, onProgress } = options;
|
|
67
|
+
|
|
68
|
+
if (__DEV__) {
|
|
69
|
+
// eslint-disable-next-line no-console
|
|
70
|
+
console.log(`[TextToVideo] Provider: ${provider.providerId}, Model: ${model}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
onProgress?.(10);
|
|
75
|
+
|
|
76
|
+
const input = buildInput(request.prompt, request.options);
|
|
77
|
+
onProgress?.(20);
|
|
78
|
+
|
|
79
|
+
const result = await provider.run(model, input);
|
|
80
|
+
onProgress?.(90);
|
|
81
|
+
|
|
82
|
+
const extractor = extractResult || defaultExtractResult;
|
|
83
|
+
const extracted = extractor(result);
|
|
84
|
+
onProgress?.(100);
|
|
85
|
+
|
|
86
|
+
if (!extracted?.videoUrl) {
|
|
87
|
+
return { success: false, error: "No video in response" };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
videoUrl: extracted.videoUrl,
|
|
93
|
+
thumbnailUrl: extracted.thumbnailUrl,
|
|
94
|
+
};
|
|
95
|
+
} catch (error) {
|
|
96
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
97
|
+
if (__DEV__) {
|
|
98
|
+
// eslint-disable-next-line no-console
|
|
99
|
+
console.error("[TextToVideo] Error:", message);
|
|
100
|
+
}
|
|
101
|
+
return { success: false, error: message };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function hasTextToVideoSupport(): boolean {
|
|
106
|
+
const provider = providerRegistry.getActiveProvider();
|
|
107
|
+
return provider !== null && provider.isInitialized();
|
|
108
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Video Feature Hook
|
|
3
|
+
* Provider-agnostic hook for text-to-video generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useCallback } from "react";
|
|
7
|
+
import { executeTextToVideo } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
TextToVideoFeatureState,
|
|
10
|
+
TextToVideoFeatureConfig,
|
|
11
|
+
TextToVideoResult,
|
|
12
|
+
TextToVideoOptions,
|
|
13
|
+
} from "../../domain/types";
|
|
14
|
+
|
|
15
|
+
export interface UseTextToVideoFeatureProps {
|
|
16
|
+
config: TextToVideoFeatureConfig;
|
|
17
|
+
userId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface UseTextToVideoFeatureReturn {
|
|
21
|
+
state: TextToVideoFeatureState;
|
|
22
|
+
setPrompt: (prompt: string) => void;
|
|
23
|
+
generate: (options?: TextToVideoOptions) => Promise<TextToVideoResult>;
|
|
24
|
+
reset: () => void;
|
|
25
|
+
isReady: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const initialState: TextToVideoFeatureState = {
|
|
29
|
+
prompt: "",
|
|
30
|
+
videoUrl: null,
|
|
31
|
+
thumbnailUrl: null,
|
|
32
|
+
isProcessing: false,
|
|
33
|
+
progress: 0,
|
|
34
|
+
error: null,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function useTextToVideoFeature(
|
|
38
|
+
props: UseTextToVideoFeatureProps,
|
|
39
|
+
): UseTextToVideoFeatureReturn {
|
|
40
|
+
const { config, userId } = props;
|
|
41
|
+
const [state, setState] = useState<TextToVideoFeatureState>(initialState);
|
|
42
|
+
|
|
43
|
+
const setPrompt = useCallback(
|
|
44
|
+
(prompt: string) => {
|
|
45
|
+
setState((prev) => ({ ...prev, prompt, error: null }));
|
|
46
|
+
config.onPromptChange?.(prompt);
|
|
47
|
+
},
|
|
48
|
+
[config],
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const generate = useCallback(
|
|
52
|
+
async (options?: TextToVideoOptions): Promise<TextToVideoResult> => {
|
|
53
|
+
if (!state.prompt) {
|
|
54
|
+
const error = "Prompt is required";
|
|
55
|
+
setState((prev) => ({ ...prev, error }));
|
|
56
|
+
return { success: false, error };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setState((prev) => ({
|
|
60
|
+
...prev,
|
|
61
|
+
isProcessing: true,
|
|
62
|
+
progress: 0,
|
|
63
|
+
error: null,
|
|
64
|
+
}));
|
|
65
|
+
|
|
66
|
+
config.onProcessingStart?.();
|
|
67
|
+
|
|
68
|
+
const result = await executeTextToVideo(
|
|
69
|
+
{ prompt: state.prompt, userId, options },
|
|
70
|
+
{
|
|
71
|
+
model: config.model,
|
|
72
|
+
buildInput: config.buildInput,
|
|
73
|
+
extractResult: config.extractResult,
|
|
74
|
+
onProgress: (progress) => {
|
|
75
|
+
setState((prev) => ({ ...prev, progress }));
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
if (result.success && result.videoUrl) {
|
|
81
|
+
setState((prev) => ({
|
|
82
|
+
...prev,
|
|
83
|
+
videoUrl: result.videoUrl ?? null,
|
|
84
|
+
thumbnailUrl: result.thumbnailUrl ?? null,
|
|
85
|
+
isProcessing: false,
|
|
86
|
+
progress: 100,
|
|
87
|
+
}));
|
|
88
|
+
} else {
|
|
89
|
+
const error = result.error || "Generation failed";
|
|
90
|
+
setState((prev) => ({
|
|
91
|
+
...prev,
|
|
92
|
+
isProcessing: false,
|
|
93
|
+
error,
|
|
94
|
+
}));
|
|
95
|
+
config.onError?.(error);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
config.onProcessingComplete?.(result);
|
|
99
|
+
return result;
|
|
100
|
+
},
|
|
101
|
+
[state.prompt, userId, config],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const reset = useCallback(() => {
|
|
105
|
+
setState(initialState);
|
|
106
|
+
}, []);
|
|
107
|
+
|
|
108
|
+
const isReady = state.prompt.length > 0 && !state.isProcessing;
|
|
109
|
+
|
|
110
|
+
return { state, setPrompt, generate, reset, isReady };
|
|
111
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./hooks";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types";
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Voice Feature Types
|
|
3
|
+
* Request, Result, Config types for text-to-voice generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface TextToVoiceOptions {
|
|
7
|
+
voice?: string;
|
|
8
|
+
speed?: number;
|
|
9
|
+
pitch?: number;
|
|
10
|
+
stability?: number;
|
|
11
|
+
similarityBoost?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface TextToVoiceRequest {
|
|
15
|
+
text: string;
|
|
16
|
+
userId: string;
|
|
17
|
+
options?: TextToVoiceOptions;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface TextToVoiceResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
audioUrl?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
requestId?: string;
|
|
25
|
+
duration?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface TextToVoiceFeatureState {
|
|
29
|
+
text: string;
|
|
30
|
+
audioUrl: string | null;
|
|
31
|
+
isProcessing: boolean;
|
|
32
|
+
progress: number;
|
|
33
|
+
error: string | null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TextToVoiceTranslations {
|
|
37
|
+
textPlaceholder: string;
|
|
38
|
+
generateButtonText: string;
|
|
39
|
+
processingText: string;
|
|
40
|
+
successText: string;
|
|
41
|
+
playButtonText: string;
|
|
42
|
+
saveButtonText: string;
|
|
43
|
+
tryAnotherText: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type TextToVoiceInputBuilder = (
|
|
47
|
+
text: string,
|
|
48
|
+
options?: TextToVoiceOptions,
|
|
49
|
+
) => Record<string, unknown>;
|
|
50
|
+
|
|
51
|
+
export type TextToVoiceResultExtractor = (
|
|
52
|
+
result: unknown,
|
|
53
|
+
) => { audioUrl?: string; duration?: number } | undefined;
|
|
54
|
+
|
|
55
|
+
export interface TextToVoiceFeatureConfig {
|
|
56
|
+
providerId?: string;
|
|
57
|
+
creditCost?: number;
|
|
58
|
+
model: string;
|
|
59
|
+
buildInput: TextToVoiceInputBuilder;
|
|
60
|
+
extractResult?: TextToVoiceResultExtractor;
|
|
61
|
+
onTextChange?: (text: string) => void;
|
|
62
|
+
onProcessingStart?: () => void;
|
|
63
|
+
onProcessingComplete?: (result: TextToVoiceResult) => void;
|
|
64
|
+
onError?: (error: string) => void;
|
|
65
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-Voice Feature
|
|
3
|
+
* Provider-agnostic text-to-voice generation feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Domain Types
|
|
7
|
+
export type {
|
|
8
|
+
TextToVoiceOptions,
|
|
9
|
+
TextToVoiceRequest,
|
|
10
|
+
TextToVoiceResult,
|
|
11
|
+
TextToVoiceFeatureState,
|
|
12
|
+
TextToVoiceTranslations,
|
|
13
|
+
TextToVoiceInputBuilder,
|
|
14
|
+
TextToVoiceResultExtractor,
|
|
15
|
+
TextToVoiceFeatureConfig,
|
|
16
|
+
} from "./domain";
|
|
17
|
+
|
|
18
|
+
// Infrastructure Services
|
|
19
|
+
export { executeTextToVoice, hasTextToVoiceSupport } from "./infrastructure";
|
|
20
|
+
export type { ExecuteTextToVoiceOptions } from "./infrastructure";
|
|
21
|
+
|
|
22
|
+
// Presentation Hooks
|
|
23
|
+
export { useTextToVoiceFeature } from "./presentation";
|
|
24
|
+
export type {
|
|
25
|
+
UseTextToVoiceFeatureProps,
|
|
26
|
+
UseTextToVoiceFeatureReturn,
|
|
27
|
+
} from "./presentation";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./services";
|