@umituz/react-native-ai-generation-content 1.16.0 → 1.17.1
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 +13 -14
- package/src/domains/creations/domain/entities/Creation.ts +33 -2
- package/src/domains/creations/domain/entities/index.ts +1 -1
- package/src/domains/creations/domain/types/creation-categories.ts +133 -0
- package/src/domains/creations/domain/types/creation-filter.ts +131 -0
- package/src/domains/creations/domain/types/creation-types.ts +63 -0
- package/src/domains/creations/domain/types/index.ts +44 -0
- package/src/domains/creations/domain/utils/creation-helpers.ts +134 -0
- package/src/domains/creations/domain/utils/index.ts +8 -0
- package/src/domains/creations/domain/utils/preview-helpers.ts +84 -0
- package/src/domains/creations/domain/utils/status-helpers.ts +90 -0
- package/src/domains/creations/index.ts +95 -21
- package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +14 -1
- package/src/domains/creations/presentation/components/CreationActions.tsx +120 -0
- package/src/domains/creations/presentation/components/CreationBadges.tsx +111 -0
- package/src/domains/creations/presentation/components/CreationCard.tsx +201 -102
- package/src/domains/creations/presentation/components/CreationPreview.tsx +117 -0
- package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +254 -0
- package/src/domains/creations/presentation/components/CreationsGrid.tsx +121 -68
- package/src/domains/creations/presentation/components/index.ts +23 -3
- package/src/domains/creations/presentation/hooks/index.ts +1 -0
- package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +262 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +5 -6
- package/src/features/ai-hug/domain/index.ts +5 -0
- package/src/features/ai-hug/domain/types/ai-hug.types.ts +72 -0
- package/src/features/ai-hug/domain/types/index.ts +14 -0
- package/src/features/ai-hug/index.ts +27 -0
- package/src/features/ai-hug/infrastructure/index.ts +5 -0
- package/src/features/ai-hug/infrastructure/services/ai-hug-executor.ts +96 -0
- package/src/features/ai-hug/infrastructure/services/index.ts +6 -0
- package/src/features/ai-hug/presentation/hooks/index.ts +9 -0
- package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +157 -0
- package/src/features/ai-hug/presentation/index.ts +5 -0
- package/src/features/ai-kiss/domain/index.ts +5 -0
- package/src/features/ai-kiss/domain/types/ai-kiss.types.ts +72 -0
- package/src/features/ai-kiss/domain/types/index.ts +14 -0
- package/src/features/ai-kiss/index.ts +27 -0
- package/src/features/ai-kiss/infrastructure/index.ts +5 -0
- package/src/features/ai-kiss/infrastructure/services/ai-kiss-executor.ts +96 -0
- package/src/features/ai-kiss/infrastructure/services/index.ts +6 -0
- package/src/features/ai-kiss/presentation/hooks/index.ts +9 -0
- package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +157 -0
- package/src/features/ai-kiss/presentation/index.ts +5 -0
- package/src/features/anime-selfie/domain/index.ts +5 -0
- package/src/features/anime-selfie/domain/types/anime-selfie.types.ts +72 -0
- package/src/features/anime-selfie/domain/types/index.ts +15 -0
- package/src/features/anime-selfie/index.ts +28 -0
- package/src/features/anime-selfie/infrastructure/index.ts +5 -0
- package/src/features/anime-selfie/infrastructure/services/anime-selfie-executor.ts +95 -0
- package/src/features/anime-selfie/infrastructure/services/index.ts +6 -0
- package/src/features/anime-selfie/presentation/hooks/index.ts +9 -0
- package/src/features/anime-selfie/presentation/hooks/useAnimeSelfieFeature.ts +138 -0
- package/src/features/anime-selfie/presentation/index.ts +5 -0
- package/src/features/background/domain/types/index.ts +15 -0
- package/src/features/background/domain/types/replace-background.types.ts +82 -0
- package/src/features/background/index.ts +31 -3
- package/src/features/background/infrastructure/index.ts +5 -0
- package/src/features/background/infrastructure/services/index.ts +6 -0
- package/src/features/background/infrastructure/services/replace-background-executor.ts +95 -0
- package/src/features/background/presentation/hooks/index.ts +6 -1
- package/src/features/background/presentation/hooks/useReplaceBackgroundFeature.ts +160 -0
- package/src/features/face-swap/domain/index.ts +5 -0
- package/src/features/face-swap/domain/types/face-swap.types.ts +72 -0
- package/src/features/face-swap/domain/types/index.ts +14 -0
- package/src/features/face-swap/index.ts +27 -1
- package/src/features/face-swap/infrastructure/index.ts +5 -0
- package/src/features/face-swap/infrastructure/services/face-swap-executor.ts +96 -0
- package/src/features/face-swap/infrastructure/services/index.ts +6 -0
- package/src/features/face-swap/presentation/hooks/index.ts +9 -0
- package/src/features/face-swap/presentation/hooks/useFaceSwapFeature.ts +157 -0
- package/src/features/face-swap/presentation/index.ts +5 -0
- package/src/features/photo-restoration/domain/index.ts +1 -0
- package/src/features/photo-restoration/domain/types/index.ts +10 -0
- package/src/features/photo-restoration/domain/types/photo-restore.types.ts +71 -0
- package/src/features/photo-restoration/index.ts +34 -1
- package/src/features/photo-restoration/infrastructure/index.ts +1 -0
- package/src/features/photo-restoration/infrastructure/services/index.ts +2 -0
- package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +98 -0
- package/src/features/photo-restoration/presentation/components/PhotoRestoreFeature.tsx +175 -0
- package/src/features/photo-restoration/presentation/components/PhotoRestoreResultView.tsx +98 -0
- package/src/features/photo-restoration/presentation/components/index.ts +4 -0
- package/src/features/photo-restoration/presentation/hooks/index.ts +5 -0
- package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +137 -0
- package/src/features/photo-restoration/presentation/index.ts +2 -0
- package/src/features/remove-background/domain/index.ts +5 -0
- package/src/features/remove-background/domain/types/index.ts +14 -0
- package/src/features/remove-background/domain/types/remove-background.types.ts +69 -0
- package/src/features/remove-background/index.ts +27 -0
- package/src/features/remove-background/infrastructure/index.ts +5 -0
- package/src/features/remove-background/infrastructure/services/index.ts +6 -0
- package/src/features/remove-background/infrastructure/services/remove-background-executor.ts +95 -0
- package/src/features/remove-background/presentation/hooks/index.ts +9 -0
- package/src/features/remove-background/presentation/hooks/useRemoveBackgroundFeature.ts +137 -0
- package/src/features/remove-background/presentation/index.ts +5 -0
- package/src/features/remove-object/domain/index.ts +5 -0
- package/src/features/remove-object/domain/types/index.ts +14 -0
- package/src/features/remove-object/domain/types/remove-object.types.ts +77 -0
- package/src/features/remove-object/index.ts +27 -0
- package/src/features/remove-object/infrastructure/index.ts +5 -0
- package/src/features/remove-object/infrastructure/services/index.ts +6 -0
- package/src/features/remove-object/infrastructure/services/remove-object-executor.ts +99 -0
- package/src/features/remove-object/presentation/hooks/index.ts +9 -0
- package/src/features/remove-object/presentation/hooks/useRemoveObjectFeature.ts +168 -0
- package/src/features/remove-object/presentation/index.ts +5 -0
- package/src/features/upscaling/domain/types/index.ts +0 -1
- package/src/features/upscaling/domain/types/upscale.types.ts +14 -0
- package/src/features/upscaling/index.ts +3 -11
- package/src/features/upscaling/infrastructure/services/index.ts +1 -6
- package/src/features/upscaling/infrastructure/services/upscale-executor.ts +64 -30
- package/src/features/upscaling/presentation/hooks/useUpscaleFeature.ts +12 -7
- package/src/index.ts +45 -0
- package/src/types/jsx.d.ts +19 -0
- package/src/features/face-swap/domain/entities.ts +0 -48
- package/src/features/photo-restoration/domain/entities.ts +0 -48
- package/src/features/upscaling/domain/types/provider.types.ts +0 -23
- package/src/features/upscaling/infrastructure/services/upscale-provider-registry.ts +0 -77
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAnimeSelfieFeature Hook
|
|
3
|
+
* Manages anime selfie feature state and actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useCallback } from "react";
|
|
7
|
+
import { executeAnimeSelfie } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
AnimeSelfieFeatureState,
|
|
10
|
+
AnimeSelfieFeatureConfig,
|
|
11
|
+
AnimeSelfieResult,
|
|
12
|
+
} from "../../domain/types";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export interface UseAnimeSelfieFeatureProps {
|
|
17
|
+
config: AnimeSelfieFeatureConfig;
|
|
18
|
+
userId: string;
|
|
19
|
+
onSelectImage: () => Promise<string | null>;
|
|
20
|
+
onSaveImage: (imageUrl: string) => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface UseAnimeSelfieFeatureReturn extends AnimeSelfieFeatureState {
|
|
24
|
+
selectImage: () => Promise<void>;
|
|
25
|
+
process: () => Promise<void>;
|
|
26
|
+
save: () => Promise<void>;
|
|
27
|
+
reset: () => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const initialState: AnimeSelfieFeatureState = {
|
|
31
|
+
imageUri: null,
|
|
32
|
+
processedUrl: null,
|
|
33
|
+
isProcessing: false,
|
|
34
|
+
progress: 0,
|
|
35
|
+
error: null,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function useAnimeSelfieFeature(
|
|
39
|
+
props: UseAnimeSelfieFeatureProps,
|
|
40
|
+
): UseAnimeSelfieFeatureReturn {
|
|
41
|
+
const { config, userId, onSelectImage, onSaveImage } = props;
|
|
42
|
+
const [state, setState] = useState<AnimeSelfieFeatureState>(initialState);
|
|
43
|
+
|
|
44
|
+
const selectImage = useCallback(async () => {
|
|
45
|
+
try {
|
|
46
|
+
const uri = await onSelectImage();
|
|
47
|
+
if (uri) {
|
|
48
|
+
setState((prev) => ({ ...prev, imageUri: uri, error: null }));
|
|
49
|
+
config.onImageSelect?.(uri);
|
|
50
|
+
}
|
|
51
|
+
} catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
53
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
54
|
+
}
|
|
55
|
+
}, [onSelectImage, config]);
|
|
56
|
+
|
|
57
|
+
const handleProgress = useCallback((progress: number) => {
|
|
58
|
+
setState((prev) => ({ ...prev, progress }));
|
|
59
|
+
}, []);
|
|
60
|
+
|
|
61
|
+
const process = useCallback(async () => {
|
|
62
|
+
if (!state.imageUri) return;
|
|
63
|
+
|
|
64
|
+
setState((prev) => ({
|
|
65
|
+
...prev,
|
|
66
|
+
isProcessing: true,
|
|
67
|
+
progress: 0,
|
|
68
|
+
error: null,
|
|
69
|
+
}));
|
|
70
|
+
|
|
71
|
+
config.onProcessingStart?.();
|
|
72
|
+
|
|
73
|
+
if (__DEV__) {
|
|
74
|
+
// eslint-disable-next-line no-console
|
|
75
|
+
console.log("[useAnimeSelfieFeature] Starting anime selfie process");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const imageBase64 = await config.prepareImage(state.imageUri);
|
|
79
|
+
|
|
80
|
+
const result: AnimeSelfieResult = await executeAnimeSelfie(
|
|
81
|
+
{
|
|
82
|
+
imageUri: state.imageUri,
|
|
83
|
+
imageBase64,
|
|
84
|
+
userId,
|
|
85
|
+
options: { style: config.defaultStyle },
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
model: config.model,
|
|
89
|
+
buildInput: config.buildInput,
|
|
90
|
+
extractResult: config.extractResult,
|
|
91
|
+
onProgress: handleProgress,
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
if (result.success && result.imageUrl) {
|
|
96
|
+
const url = result.imageUrl;
|
|
97
|
+
setState((prev) => ({
|
|
98
|
+
...prev,
|
|
99
|
+
isProcessing: false,
|
|
100
|
+
processedUrl: url,
|
|
101
|
+
progress: 100,
|
|
102
|
+
}));
|
|
103
|
+
config.onProcessingComplete?.(result);
|
|
104
|
+
} else {
|
|
105
|
+
const errorMessage = result.error || "Processing failed";
|
|
106
|
+
setState((prev) => ({
|
|
107
|
+
...prev,
|
|
108
|
+
isProcessing: false,
|
|
109
|
+
error: errorMessage,
|
|
110
|
+
progress: 0,
|
|
111
|
+
}));
|
|
112
|
+
config.onError?.(errorMessage);
|
|
113
|
+
}
|
|
114
|
+
}, [state.imageUri, userId, config, handleProgress]);
|
|
115
|
+
|
|
116
|
+
const save = useCallback(async () => {
|
|
117
|
+
if (!state.processedUrl) return;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
await onSaveImage(state.processedUrl);
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
124
|
+
}
|
|
125
|
+
}, [state.processedUrl, onSaveImage]);
|
|
126
|
+
|
|
127
|
+
const reset = useCallback(() => {
|
|
128
|
+
setState(initialState);
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
...state,
|
|
133
|
+
selectImage,
|
|
134
|
+
process,
|
|
135
|
+
save,
|
|
136
|
+
reset,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background Domain Types Index
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
ReplaceBackgroundMode,
|
|
7
|
+
ReplaceBackgroundOptions,
|
|
8
|
+
ReplaceBackgroundRequest,
|
|
9
|
+
ReplaceBackgroundResult,
|
|
10
|
+
ReplaceBackgroundFeatureState,
|
|
11
|
+
ReplaceBackgroundTranslations,
|
|
12
|
+
ReplaceBackgroundInputBuilder,
|
|
13
|
+
ReplaceBackgroundResultExtractor,
|
|
14
|
+
ReplaceBackgroundFeatureConfig,
|
|
15
|
+
} from "./replace-background.types";
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace Background Feature Types
|
|
3
|
+
* Request, Result, Config types for background replacement
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type ReplaceBackgroundMode =
|
|
7
|
+
| "replace"
|
|
8
|
+
| "blur"
|
|
9
|
+
| "creative-scene"
|
|
10
|
+
| "solid-color";
|
|
11
|
+
|
|
12
|
+
export interface ReplaceBackgroundOptions {
|
|
13
|
+
mode?: ReplaceBackgroundMode;
|
|
14
|
+
prompt?: string;
|
|
15
|
+
backgroundColor?: string;
|
|
16
|
+
blurIntensity?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ReplaceBackgroundRequest {
|
|
20
|
+
imageUri: string;
|
|
21
|
+
imageBase64?: string;
|
|
22
|
+
userId: string;
|
|
23
|
+
prompt?: string;
|
|
24
|
+
options?: ReplaceBackgroundOptions;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ReplaceBackgroundResult {
|
|
28
|
+
success: boolean;
|
|
29
|
+
imageUrl?: string;
|
|
30
|
+
imageBase64?: string;
|
|
31
|
+
error?: string;
|
|
32
|
+
requestId?: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface ReplaceBackgroundFeatureState {
|
|
36
|
+
imageUri: string | null;
|
|
37
|
+
prompt: string;
|
|
38
|
+
processedUrl: string | null;
|
|
39
|
+
isProcessing: boolean;
|
|
40
|
+
progress: number;
|
|
41
|
+
error: string | null;
|
|
42
|
+
mode: ReplaceBackgroundMode;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface ReplaceBackgroundTranslations {
|
|
46
|
+
uploadTitle: string;
|
|
47
|
+
uploadSubtitle: string;
|
|
48
|
+
uploadChange: string;
|
|
49
|
+
uploadAnalyzing: string;
|
|
50
|
+
promptPlaceholder: string;
|
|
51
|
+
description: string;
|
|
52
|
+
processingText: string;
|
|
53
|
+
processButtonText: string;
|
|
54
|
+
successText: string;
|
|
55
|
+
saveButtonText: string;
|
|
56
|
+
tryAnotherText: string;
|
|
57
|
+
beforeLabel?: string;
|
|
58
|
+
afterLabel?: string;
|
|
59
|
+
compareHint?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type ReplaceBackgroundInputBuilder = (
|
|
63
|
+
base64: string,
|
|
64
|
+
prompt?: string,
|
|
65
|
+
options?: ReplaceBackgroundOptions,
|
|
66
|
+
) => Record<string, unknown>;
|
|
67
|
+
|
|
68
|
+
export type ReplaceBackgroundResultExtractor = (result: unknown) => string | undefined;
|
|
69
|
+
|
|
70
|
+
export interface ReplaceBackgroundFeatureConfig {
|
|
71
|
+
providerId?: string;
|
|
72
|
+
creditCost?: number;
|
|
73
|
+
defaultMode?: ReplaceBackgroundMode;
|
|
74
|
+
model: string;
|
|
75
|
+
buildInput: ReplaceBackgroundInputBuilder;
|
|
76
|
+
extractResult?: ReplaceBackgroundResultExtractor;
|
|
77
|
+
prepareImage: (imageUri: string) => Promise<string>;
|
|
78
|
+
onImageSelect?: (uri: string) => void;
|
|
79
|
+
onProcessingStart?: () => void;
|
|
80
|
+
onProcessingComplete?: (result: ReplaceBackgroundResult) => void;
|
|
81
|
+
onError?: (error: string) => void;
|
|
82
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* import {
|
|
7
7
|
* BackgroundFeature,
|
|
8
8
|
* useBackgroundFeature,
|
|
9
|
+
* useReplaceBackgroundFeature,
|
|
9
10
|
* ImagePicker,
|
|
10
11
|
* ComparisonSlider,
|
|
11
12
|
* ModeSelector,
|
|
@@ -13,7 +14,7 @@
|
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
16
|
// =============================================================================
|
|
16
|
-
// DOMAIN LAYER - Types & Interfaces
|
|
17
|
+
// DOMAIN LAYER - Types & Interfaces (Legacy)
|
|
17
18
|
// =============================================================================
|
|
18
19
|
|
|
19
20
|
export type {
|
|
@@ -38,12 +39,35 @@ export type {
|
|
|
38
39
|
UseBackgroundFeatureConfig,
|
|
39
40
|
} from "./domain/entities";
|
|
40
41
|
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// DOMAIN LAYER - New Provider-Agnostic Types
|
|
44
|
+
// =============================================================================
|
|
45
|
+
|
|
46
|
+
export type {
|
|
47
|
+
ReplaceBackgroundMode,
|
|
48
|
+
ReplaceBackgroundOptions,
|
|
49
|
+
ReplaceBackgroundRequest,
|
|
50
|
+
ReplaceBackgroundResult,
|
|
51
|
+
ReplaceBackgroundFeatureState,
|
|
52
|
+
ReplaceBackgroundTranslations,
|
|
53
|
+
ReplaceBackgroundFeatureConfig,
|
|
54
|
+
ReplaceBackgroundInputBuilder,
|
|
55
|
+
ReplaceBackgroundResultExtractor,
|
|
56
|
+
} from "./domain/types";
|
|
57
|
+
|
|
41
58
|
// =============================================================================
|
|
42
59
|
// INFRASTRUCTURE LAYER - Constants
|
|
43
60
|
// =============================================================================
|
|
44
61
|
|
|
45
62
|
export { DEFAULT_SAMPLE_PROMPTS } from "./infrastructure/constants";
|
|
46
63
|
|
|
64
|
+
// =============================================================================
|
|
65
|
+
// INFRASTRUCTURE LAYER - Services
|
|
66
|
+
// =============================================================================
|
|
67
|
+
|
|
68
|
+
export { executeReplaceBackground, hasReplaceBackgroundSupport } from "./infrastructure";
|
|
69
|
+
export type { ExecuteReplaceBackgroundOptions } from "./infrastructure";
|
|
70
|
+
|
|
47
71
|
// =============================================================================
|
|
48
72
|
// PRESENTATION LAYER - Components
|
|
49
73
|
// =============================================================================
|
|
@@ -67,6 +91,10 @@ export type { BackgroundFeatureProps } from "./presentation/components";
|
|
|
67
91
|
// PRESENTATION LAYER - Hooks
|
|
68
92
|
// =============================================================================
|
|
69
93
|
|
|
70
|
-
export { useBackgroundFeature } from "./presentation/hooks";
|
|
94
|
+
export { useBackgroundFeature, useReplaceBackgroundFeature } from "./presentation/hooks";
|
|
71
95
|
|
|
72
|
-
export type {
|
|
96
|
+
export type {
|
|
97
|
+
UseBackgroundFeatureReturn,
|
|
98
|
+
UseReplaceBackgroundFeatureProps,
|
|
99
|
+
UseReplaceBackgroundFeatureReturn,
|
|
100
|
+
} from "./presentation/hooks";
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace Background Executor
|
|
3
|
+
* Provider-agnostic background replacement execution using active AI provider
|
|
4
|
+
* Model and input format are provided via options from app level
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { providerRegistry } from "../../../../infrastructure/services";
|
|
8
|
+
import { cleanBase64 } from "../../../../infrastructure/utils";
|
|
9
|
+
import type {
|
|
10
|
+
ReplaceBackgroundRequest,
|
|
11
|
+
ReplaceBackgroundResult,
|
|
12
|
+
ReplaceBackgroundInputBuilder,
|
|
13
|
+
ReplaceBackgroundResultExtractor,
|
|
14
|
+
} from "../../domain/types";
|
|
15
|
+
|
|
16
|
+
declare const __DEV__: boolean;
|
|
17
|
+
|
|
18
|
+
export interface ExecuteReplaceBackgroundOptions {
|
|
19
|
+
model: string;
|
|
20
|
+
buildInput: ReplaceBackgroundInputBuilder;
|
|
21
|
+
extractResult?: ReplaceBackgroundResultExtractor;
|
|
22
|
+
onProgress?: (progress: number) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function defaultExtractResult(result: unknown): 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") return r.image;
|
|
31
|
+
if (Array.isArray(r.images) && r.images[0]?.url) return r.images[0].url;
|
|
32
|
+
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function executeReplaceBackground(
|
|
37
|
+
request: ReplaceBackgroundRequest,
|
|
38
|
+
options: ExecuteReplaceBackgroundOptions,
|
|
39
|
+
): Promise<ReplaceBackgroundResult> {
|
|
40
|
+
const provider = providerRegistry.getActiveProvider();
|
|
41
|
+
|
|
42
|
+
if (!provider) {
|
|
43
|
+
return { success: false, error: "No AI provider configured" };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!provider.isInitialized()) {
|
|
47
|
+
return { success: false, error: "AI provider not initialized" };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (!request.imageBase64) {
|
|
51
|
+
return { success: false, error: "Image base64 is required" };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { model, buildInput, extractResult, onProgress } = options;
|
|
55
|
+
|
|
56
|
+
if (__DEV__) {
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.log(`[ReplaceBackground] Provider: ${provider.providerId}, Model: ${model}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
onProgress?.(10);
|
|
63
|
+
|
|
64
|
+
const base64 = cleanBase64(request.imageBase64);
|
|
65
|
+
onProgress?.(30);
|
|
66
|
+
|
|
67
|
+
const input = buildInput(base64, request.prompt, request.options);
|
|
68
|
+
onProgress?.(40);
|
|
69
|
+
|
|
70
|
+
const result = await provider.run(model, input);
|
|
71
|
+
onProgress?.(90);
|
|
72
|
+
|
|
73
|
+
const extractor = extractResult || defaultExtractResult;
|
|
74
|
+
const imageUrl = extractor(result);
|
|
75
|
+
onProgress?.(100);
|
|
76
|
+
|
|
77
|
+
if (!imageUrl) {
|
|
78
|
+
return { success: false, error: "No image in response" };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { success: true, imageUrl };
|
|
82
|
+
} catch (error) {
|
|
83
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
84
|
+
if (__DEV__) {
|
|
85
|
+
// eslint-disable-next-line no-console
|
|
86
|
+
console.error("[ReplaceBackground] Error:", message);
|
|
87
|
+
}
|
|
88
|
+
return { success: false, error: message };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function hasReplaceBackgroundSupport(): boolean {
|
|
93
|
+
const provider = providerRegistry.getActiveProvider();
|
|
94
|
+
return provider !== null && provider.isInitialized();
|
|
95
|
+
}
|
|
@@ -3,5 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export { useBackgroundFeature } from "./useBackgroundFeature";
|
|
6
|
-
|
|
7
6
|
export type { UseBackgroundFeatureReturn } from "./useBackgroundFeature";
|
|
7
|
+
|
|
8
|
+
export { useReplaceBackgroundFeature } from "./useReplaceBackgroundFeature";
|
|
9
|
+
export type {
|
|
10
|
+
UseReplaceBackgroundFeatureProps,
|
|
11
|
+
UseReplaceBackgroundFeatureReturn,
|
|
12
|
+
} from "./useReplaceBackgroundFeature";
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useReplaceBackgroundFeature Hook
|
|
3
|
+
* Manages replace background feature state and actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useCallback } from "react";
|
|
7
|
+
import { executeReplaceBackground } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
ReplaceBackgroundFeatureState,
|
|
10
|
+
ReplaceBackgroundFeatureConfig,
|
|
11
|
+
ReplaceBackgroundResult,
|
|
12
|
+
ReplaceBackgroundMode,
|
|
13
|
+
} from "../../domain/types";
|
|
14
|
+
|
|
15
|
+
declare const __DEV__: boolean;
|
|
16
|
+
|
|
17
|
+
export interface UseReplaceBackgroundFeatureProps {
|
|
18
|
+
config: ReplaceBackgroundFeatureConfig;
|
|
19
|
+
userId: string;
|
|
20
|
+
onSelectImage: () => Promise<string | null>;
|
|
21
|
+
onSaveImage: (imageUrl: string) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UseReplaceBackgroundFeatureReturn extends ReplaceBackgroundFeatureState {
|
|
25
|
+
selectImage: () => Promise<void>;
|
|
26
|
+
setPrompt: (prompt: string) => void;
|
|
27
|
+
setMode: (mode: ReplaceBackgroundMode) => void;
|
|
28
|
+
process: () => Promise<void>;
|
|
29
|
+
save: () => Promise<void>;
|
|
30
|
+
reset: () => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const initialState: ReplaceBackgroundFeatureState = {
|
|
34
|
+
imageUri: null,
|
|
35
|
+
prompt: "",
|
|
36
|
+
processedUrl: null,
|
|
37
|
+
isProcessing: false,
|
|
38
|
+
progress: 0,
|
|
39
|
+
error: null,
|
|
40
|
+
mode: "replace",
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export function useReplaceBackgroundFeature(
|
|
44
|
+
props: UseReplaceBackgroundFeatureProps,
|
|
45
|
+
): UseReplaceBackgroundFeatureReturn {
|
|
46
|
+
const { config, userId, onSelectImage, onSaveImage } = props;
|
|
47
|
+
const [state, setState] = useState<ReplaceBackgroundFeatureState>({
|
|
48
|
+
...initialState,
|
|
49
|
+
mode: config.defaultMode || "replace",
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const selectImage = useCallback(async () => {
|
|
53
|
+
try {
|
|
54
|
+
const uri = await onSelectImage();
|
|
55
|
+
if (uri) {
|
|
56
|
+
setState((prev) => ({ ...prev, imageUri: uri, error: null }));
|
|
57
|
+
config.onImageSelect?.(uri);
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
61
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
62
|
+
}
|
|
63
|
+
}, [onSelectImage, config]);
|
|
64
|
+
|
|
65
|
+
const setPrompt = useCallback((prompt: string) => {
|
|
66
|
+
setState((prev) => ({ ...prev, prompt }));
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
const setMode = useCallback((mode: ReplaceBackgroundMode) => {
|
|
70
|
+
setState((prev) => ({ ...prev, mode }));
|
|
71
|
+
}, []);
|
|
72
|
+
|
|
73
|
+
const handleProgress = useCallback((progress: number) => {
|
|
74
|
+
setState((prev) => ({ ...prev, progress }));
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
const process = useCallback(async () => {
|
|
78
|
+
if (!state.imageUri) return;
|
|
79
|
+
|
|
80
|
+
setState((prev) => ({
|
|
81
|
+
...prev,
|
|
82
|
+
isProcessing: true,
|
|
83
|
+
progress: 0,
|
|
84
|
+
error: null,
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
config.onProcessingStart?.();
|
|
88
|
+
|
|
89
|
+
if (__DEV__) {
|
|
90
|
+
// eslint-disable-next-line no-console
|
|
91
|
+
console.log("[useReplaceBackgroundFeature] Starting background replacement process");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const imageBase64 = await config.prepareImage(state.imageUri);
|
|
95
|
+
|
|
96
|
+
const result: ReplaceBackgroundResult = await executeReplaceBackground(
|
|
97
|
+
{
|
|
98
|
+
imageUri: state.imageUri,
|
|
99
|
+
imageBase64,
|
|
100
|
+
userId,
|
|
101
|
+
prompt: state.prompt || undefined,
|
|
102
|
+
options: { mode: state.mode },
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
model: config.model,
|
|
106
|
+
buildInput: config.buildInput,
|
|
107
|
+
extractResult: config.extractResult,
|
|
108
|
+
onProgress: handleProgress,
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
if (result.success && result.imageUrl) {
|
|
113
|
+
const url = result.imageUrl;
|
|
114
|
+
setState((prev) => ({
|
|
115
|
+
...prev,
|
|
116
|
+
isProcessing: false,
|
|
117
|
+
processedUrl: url,
|
|
118
|
+
progress: 100,
|
|
119
|
+
}));
|
|
120
|
+
config.onProcessingComplete?.(result);
|
|
121
|
+
} else {
|
|
122
|
+
const errorMessage = result.error || "Processing failed";
|
|
123
|
+
setState((prev) => ({
|
|
124
|
+
...prev,
|
|
125
|
+
isProcessing: false,
|
|
126
|
+
error: errorMessage,
|
|
127
|
+
progress: 0,
|
|
128
|
+
}));
|
|
129
|
+
config.onError?.(errorMessage);
|
|
130
|
+
}
|
|
131
|
+
}, [state.imageUri, state.prompt, state.mode, userId, config, handleProgress]);
|
|
132
|
+
|
|
133
|
+
const save = useCallback(async () => {
|
|
134
|
+
if (!state.processedUrl) return;
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
await onSaveImage(state.processedUrl);
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
140
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
141
|
+
}
|
|
142
|
+
}, [state.processedUrl, onSaveImage]);
|
|
143
|
+
|
|
144
|
+
const reset = useCallback(() => {
|
|
145
|
+
setState({
|
|
146
|
+
...initialState,
|
|
147
|
+
mode: config.defaultMode || "replace",
|
|
148
|
+
});
|
|
149
|
+
}, [config.defaultMode]);
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
...state,
|
|
153
|
+
selectImage,
|
|
154
|
+
setPrompt,
|
|
155
|
+
setMode,
|
|
156
|
+
process,
|
|
157
|
+
save,
|
|
158
|
+
reset,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Face Swap Feature Types
|
|
3
|
+
* Request, Result, Config types for face swap generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface FaceSwapOptions {
|
|
7
|
+
enhanceFace?: boolean;
|
|
8
|
+
preserveSkinTone?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface FaceSwapRequest {
|
|
12
|
+
sourceImageUri: string;
|
|
13
|
+
targetImageUri: string;
|
|
14
|
+
sourceImageBase64?: string;
|
|
15
|
+
targetImageBase64?: string;
|
|
16
|
+
userId: string;
|
|
17
|
+
options?: FaceSwapOptions;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface FaceSwapResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
imageUrl?: string;
|
|
23
|
+
imageBase64?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FaceSwapFeatureState {
|
|
29
|
+
sourceImageUri: string | null;
|
|
30
|
+
targetImageUri: string | null;
|
|
31
|
+
processedUrl: string | null;
|
|
32
|
+
isProcessing: boolean;
|
|
33
|
+
progress: number;
|
|
34
|
+
error: string | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface FaceSwapTranslations {
|
|
38
|
+
sourceUploadTitle: string;
|
|
39
|
+
sourceUploadSubtitle: string;
|
|
40
|
+
targetUploadTitle: string;
|
|
41
|
+
targetUploadSubtitle: string;
|
|
42
|
+
uploadChange: string;
|
|
43
|
+
uploadAnalyzing: string;
|
|
44
|
+
description: string;
|
|
45
|
+
processingText: string;
|
|
46
|
+
processButtonText: string;
|
|
47
|
+
successText: string;
|
|
48
|
+
saveButtonText: string;
|
|
49
|
+
tryAnotherText: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type FaceSwapInputBuilder = (
|
|
53
|
+
sourceBase64: string,
|
|
54
|
+
targetBase64: string,
|
|
55
|
+
options?: FaceSwapOptions,
|
|
56
|
+
) => Record<string, unknown>;
|
|
57
|
+
|
|
58
|
+
export type FaceSwapResultExtractor = (result: unknown) => string | undefined;
|
|
59
|
+
|
|
60
|
+
export interface FaceSwapFeatureConfig {
|
|
61
|
+
providerId?: string;
|
|
62
|
+
creditCost?: number;
|
|
63
|
+
model: string;
|
|
64
|
+
buildInput: FaceSwapInputBuilder;
|
|
65
|
+
extractResult?: FaceSwapResultExtractor;
|
|
66
|
+
prepareImage: (imageUri: string) => Promise<string>;
|
|
67
|
+
onSourceImageSelect?: (uri: string) => void;
|
|
68
|
+
onTargetImageSelect?: (uri: string) => void;
|
|
69
|
+
onProcessingStart?: () => void;
|
|
70
|
+
onProcessingComplete?: (result: FaceSwapResult) => void;
|
|
71
|
+
onError?: (error: string) => void;
|
|
72
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Face Swap Domain Types Index
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
FaceSwapOptions,
|
|
7
|
+
FaceSwapRequest,
|
|
8
|
+
FaceSwapResult,
|
|
9
|
+
FaceSwapFeatureState,
|
|
10
|
+
FaceSwapTranslations,
|
|
11
|
+
FaceSwapInputBuilder,
|
|
12
|
+
FaceSwapResultExtractor,
|
|
13
|
+
FaceSwapFeatureConfig,
|
|
14
|
+
} from "./face-swap.types";
|