@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
|
@@ -1 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Face Swap Feature
|
|
3
|
+
* Provider-agnostic face swap generation feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Domain Types
|
|
7
|
+
export type {
|
|
8
|
+
FaceSwapOptions,
|
|
9
|
+
FaceSwapRequest,
|
|
10
|
+
FaceSwapResult,
|
|
11
|
+
FaceSwapFeatureState,
|
|
12
|
+
FaceSwapTranslations,
|
|
13
|
+
FaceSwapFeatureConfig,
|
|
14
|
+
FaceSwapInputBuilder,
|
|
15
|
+
FaceSwapResultExtractor,
|
|
16
|
+
} from "./domain";
|
|
17
|
+
|
|
18
|
+
// Infrastructure Services
|
|
19
|
+
export { executeFaceSwap, hasFaceSwapSupport } from "./infrastructure";
|
|
20
|
+
export type { ExecuteFaceSwapOptions } from "./infrastructure";
|
|
21
|
+
|
|
22
|
+
// Presentation Hooks
|
|
23
|
+
export { useFaceSwapFeature } from "./presentation";
|
|
24
|
+
export type {
|
|
25
|
+
UseFaceSwapFeatureProps,
|
|
26
|
+
UseFaceSwapFeatureReturn,
|
|
27
|
+
} from "./presentation";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Face Swap Executor
|
|
3
|
+
* Provider-agnostic face swap 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
|
+
FaceSwapRequest,
|
|
11
|
+
FaceSwapResult,
|
|
12
|
+
FaceSwapInputBuilder,
|
|
13
|
+
FaceSwapResultExtractor,
|
|
14
|
+
} from "../../domain/types";
|
|
15
|
+
|
|
16
|
+
declare const __DEV__: boolean;
|
|
17
|
+
|
|
18
|
+
export interface ExecuteFaceSwapOptions {
|
|
19
|
+
model: string;
|
|
20
|
+
buildInput: FaceSwapInputBuilder;
|
|
21
|
+
extractResult?: FaceSwapResultExtractor;
|
|
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 executeFaceSwap(
|
|
37
|
+
request: FaceSwapRequest,
|
|
38
|
+
options: ExecuteFaceSwapOptions,
|
|
39
|
+
): Promise<FaceSwapResult> {
|
|
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.sourceImageBase64 || !request.targetImageBase64) {
|
|
51
|
+
return { success: false, error: "Both source and target image base64 are required" };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const { model, buildInput, extractResult, onProgress } = options;
|
|
55
|
+
|
|
56
|
+
if (__DEV__) {
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.log(`[FaceSwap] Provider: ${provider.providerId}, Model: ${model}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
onProgress?.(10);
|
|
63
|
+
|
|
64
|
+
const sourceBase64 = cleanBase64(request.sourceImageBase64);
|
|
65
|
+
const targetBase64 = cleanBase64(request.targetImageBase64);
|
|
66
|
+
onProgress?.(30);
|
|
67
|
+
|
|
68
|
+
const input = buildInput(sourceBase64, targetBase64, request.options);
|
|
69
|
+
onProgress?.(40);
|
|
70
|
+
|
|
71
|
+
const result = await provider.run(model, input);
|
|
72
|
+
onProgress?.(90);
|
|
73
|
+
|
|
74
|
+
const extractor = extractResult || defaultExtractResult;
|
|
75
|
+
const imageUrl = extractor(result);
|
|
76
|
+
onProgress?.(100);
|
|
77
|
+
|
|
78
|
+
if (!imageUrl) {
|
|
79
|
+
return { success: false, error: "No image in response" };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return { success: true, imageUrl };
|
|
83
|
+
} catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
85
|
+
if (__DEV__) {
|
|
86
|
+
// eslint-disable-next-line no-console
|
|
87
|
+
console.error("[FaceSwap] Error:", message);
|
|
88
|
+
}
|
|
89
|
+
return { success: false, error: message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function hasFaceSwapSupport(): boolean {
|
|
94
|
+
const provider = providerRegistry.getActiveProvider();
|
|
95
|
+
return provider !== null && provider.isInitialized();
|
|
96
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useFaceSwapFeature Hook
|
|
3
|
+
* Manages face swap feature state and actions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useCallback } from "react";
|
|
7
|
+
import { executeFaceSwap } from "../../infrastructure/services";
|
|
8
|
+
import type {
|
|
9
|
+
FaceSwapFeatureState,
|
|
10
|
+
FaceSwapFeatureConfig,
|
|
11
|
+
FaceSwapResult,
|
|
12
|
+
} from "../../domain/types";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export interface UseFaceSwapFeatureProps {
|
|
17
|
+
config: FaceSwapFeatureConfig;
|
|
18
|
+
userId: string;
|
|
19
|
+
onSelectSourceImage: () => Promise<string | null>;
|
|
20
|
+
onSelectTargetImage: () => Promise<string | null>;
|
|
21
|
+
onSaveImage: (imageUrl: string) => Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UseFaceSwapFeatureReturn extends FaceSwapFeatureState {
|
|
25
|
+
selectSourceImage: () => Promise<void>;
|
|
26
|
+
selectTargetImage: () => Promise<void>;
|
|
27
|
+
process: () => Promise<void>;
|
|
28
|
+
save: () => Promise<void>;
|
|
29
|
+
reset: () => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const initialState: FaceSwapFeatureState = {
|
|
33
|
+
sourceImageUri: null,
|
|
34
|
+
targetImageUri: null,
|
|
35
|
+
processedUrl: null,
|
|
36
|
+
isProcessing: false,
|
|
37
|
+
progress: 0,
|
|
38
|
+
error: null,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function useFaceSwapFeature(
|
|
42
|
+
props: UseFaceSwapFeatureProps,
|
|
43
|
+
): UseFaceSwapFeatureReturn {
|
|
44
|
+
const { config, userId, onSelectSourceImage, onSelectTargetImage, onSaveImage } = props;
|
|
45
|
+
const [state, setState] = useState<FaceSwapFeatureState>(initialState);
|
|
46
|
+
|
|
47
|
+
const selectSourceImage = useCallback(async () => {
|
|
48
|
+
try {
|
|
49
|
+
const uri = await onSelectSourceImage();
|
|
50
|
+
if (uri) {
|
|
51
|
+
setState((prev) => ({ ...prev, sourceImageUri: uri, error: null }));
|
|
52
|
+
config.onSourceImageSelect?.(uri);
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
57
|
+
}
|
|
58
|
+
}, [onSelectSourceImage, config]);
|
|
59
|
+
|
|
60
|
+
const selectTargetImage = useCallback(async () => {
|
|
61
|
+
try {
|
|
62
|
+
const uri = await onSelectTargetImage();
|
|
63
|
+
if (uri) {
|
|
64
|
+
setState((prev) => ({ ...prev, targetImageUri: uri, error: null }));
|
|
65
|
+
config.onTargetImageSelect?.(uri);
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
69
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
70
|
+
}
|
|
71
|
+
}, [onSelectTargetImage, config]);
|
|
72
|
+
|
|
73
|
+
const handleProgress = useCallback((progress: number) => {
|
|
74
|
+
setState((prev) => ({ ...prev, progress }));
|
|
75
|
+
}, []);
|
|
76
|
+
|
|
77
|
+
const process = useCallback(async () => {
|
|
78
|
+
if (!state.sourceImageUri || !state.targetImageUri) 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("[useFaceSwapFeature] Starting face swap process");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const sourceImageBase64 = await config.prepareImage(state.sourceImageUri);
|
|
95
|
+
const targetImageBase64 = await config.prepareImage(state.targetImageUri);
|
|
96
|
+
|
|
97
|
+
const result: FaceSwapResult = await executeFaceSwap(
|
|
98
|
+
{
|
|
99
|
+
sourceImageUri: state.sourceImageUri,
|
|
100
|
+
targetImageUri: state.targetImageUri,
|
|
101
|
+
sourceImageBase64,
|
|
102
|
+
targetImageBase64,
|
|
103
|
+
userId,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
model: config.model,
|
|
107
|
+
buildInput: config.buildInput,
|
|
108
|
+
extractResult: config.extractResult,
|
|
109
|
+
onProgress: handleProgress,
|
|
110
|
+
},
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (result.success && result.imageUrl) {
|
|
114
|
+
const url = result.imageUrl;
|
|
115
|
+
setState((prev) => ({
|
|
116
|
+
...prev,
|
|
117
|
+
isProcessing: false,
|
|
118
|
+
processedUrl: url,
|
|
119
|
+
progress: 100,
|
|
120
|
+
}));
|
|
121
|
+
config.onProcessingComplete?.(result);
|
|
122
|
+
} else {
|
|
123
|
+
const errorMessage = result.error || "Processing failed";
|
|
124
|
+
setState((prev) => ({
|
|
125
|
+
...prev,
|
|
126
|
+
isProcessing: false,
|
|
127
|
+
error: errorMessage,
|
|
128
|
+
progress: 0,
|
|
129
|
+
}));
|
|
130
|
+
config.onError?.(errorMessage);
|
|
131
|
+
}
|
|
132
|
+
}, [state.sourceImageUri, state.targetImageUri, userId, config, handleProgress]);
|
|
133
|
+
|
|
134
|
+
const save = useCallback(async () => {
|
|
135
|
+
if (!state.processedUrl) return;
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await onSaveImage(state.processedUrl);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
141
|
+
setState((prev) => ({ ...prev, error: message }));
|
|
142
|
+
}
|
|
143
|
+
}, [state.processedUrl, onSaveImage]);
|
|
144
|
+
|
|
145
|
+
const reset = useCallback(() => {
|
|
146
|
+
setState(initialState);
|
|
147
|
+
}, []);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
...state,
|
|
151
|
+
selectSourceImage,
|
|
152
|
+
selectTargetImage,
|
|
153
|
+
process,
|
|
154
|
+
save,
|
|
155
|
+
reset,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restore Feature Types
|
|
3
|
+
* Request, Result, Config types for photo restoration
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface PhotoRestoreOptions {
|
|
7
|
+
fixScratches?: boolean;
|
|
8
|
+
enhanceFaces?: boolean;
|
|
9
|
+
colorize?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PhotoRestoreRequest {
|
|
13
|
+
imageUri: string;
|
|
14
|
+
imageBase64?: string;
|
|
15
|
+
userId: string;
|
|
16
|
+
options?: PhotoRestoreOptions;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface PhotoRestoreResult {
|
|
20
|
+
success: boolean;
|
|
21
|
+
imageUrl?: string;
|
|
22
|
+
imageBase64?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
requestId?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface PhotoRestoreFeatureState {
|
|
28
|
+
imageUri: string | null;
|
|
29
|
+
processedUrl: string | null;
|
|
30
|
+
isProcessing: boolean;
|
|
31
|
+
progress: number;
|
|
32
|
+
error: string | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface PhotoRestoreTranslations {
|
|
36
|
+
uploadTitle: string;
|
|
37
|
+
uploadSubtitle: string;
|
|
38
|
+
uploadChange: string;
|
|
39
|
+
uploadAnalyzing: string;
|
|
40
|
+
description: string;
|
|
41
|
+
processingText: string;
|
|
42
|
+
processButtonText: string;
|
|
43
|
+
successText: string;
|
|
44
|
+
saveButtonText: string;
|
|
45
|
+
tryAnotherText: string;
|
|
46
|
+
beforeLabel?: string;
|
|
47
|
+
afterLabel?: string;
|
|
48
|
+
compareHint?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type PhotoRestoreInputBuilder = (
|
|
52
|
+
base64: string,
|
|
53
|
+
options?: PhotoRestoreOptions,
|
|
54
|
+
) => Record<string, unknown>;
|
|
55
|
+
|
|
56
|
+
export type PhotoRestoreResultExtractor = (
|
|
57
|
+
result: unknown,
|
|
58
|
+
) => string | undefined;
|
|
59
|
+
|
|
60
|
+
export interface PhotoRestoreFeatureConfig {
|
|
61
|
+
providerId?: string;
|
|
62
|
+
creditCost?: number;
|
|
63
|
+
model: string;
|
|
64
|
+
buildInput: PhotoRestoreInputBuilder;
|
|
65
|
+
extractResult?: PhotoRestoreResultExtractor;
|
|
66
|
+
prepareImage: (imageUri: string) => Promise<string>;
|
|
67
|
+
onImageSelect?: (uri: string) => void;
|
|
68
|
+
onProcessingStart?: () => void;
|
|
69
|
+
onProcessingComplete?: (result: PhotoRestoreResult) => void;
|
|
70
|
+
onError?: (error: string) => void;
|
|
71
|
+
}
|
|
@@ -1 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restoration Feature
|
|
3
|
+
* Provider-agnostic photo restoration feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Domain Types
|
|
7
|
+
export type {
|
|
8
|
+
PhotoRestoreOptions,
|
|
9
|
+
PhotoRestoreRequest,
|
|
10
|
+
PhotoRestoreResult,
|
|
11
|
+
PhotoRestoreFeatureState,
|
|
12
|
+
PhotoRestoreTranslations,
|
|
13
|
+
PhotoRestoreFeatureConfig,
|
|
14
|
+
PhotoRestoreInputBuilder,
|
|
15
|
+
PhotoRestoreResultExtractor,
|
|
16
|
+
} from "./domain";
|
|
17
|
+
|
|
18
|
+
// Infrastructure Services
|
|
19
|
+
export { executePhotoRestore, hasPhotoRestoreSupport } from "./infrastructure";
|
|
20
|
+
export type { ExecutePhotoRestoreOptions } from "./infrastructure";
|
|
21
|
+
|
|
22
|
+
// Presentation Hooks
|
|
23
|
+
export { usePhotoRestoreFeature } from "./presentation";
|
|
24
|
+
export type {
|
|
25
|
+
UsePhotoRestoreFeatureProps,
|
|
26
|
+
UsePhotoRestoreFeatureReturn,
|
|
27
|
+
} from "./presentation";
|
|
28
|
+
|
|
29
|
+
// Presentation Components
|
|
30
|
+
export { PhotoRestoreFeature, PhotoRestoreResultView } from "./presentation";
|
|
31
|
+
export type {
|
|
32
|
+
PhotoRestoreFeatureProps,
|
|
33
|
+
PhotoRestoreResultViewProps,
|
|
34
|
+
} from "./presentation";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./services";
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Photo Restore Executor
|
|
3
|
+
* Provider-agnostic photo restore execution using active AI provider
|
|
4
|
+
* Model and input format are provided via options from app level
|
|
5
|
+
*
|
|
6
|
+
* Note: imageBase64 must be provided in the request. Image URI to base64
|
|
7
|
+
* conversion should be handled at the app level before calling this executor.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { providerRegistry } from "../../../../infrastructure/services";
|
|
11
|
+
import { cleanBase64 } from "../../../../infrastructure/utils";
|
|
12
|
+
import type {
|
|
13
|
+
PhotoRestoreRequest,
|
|
14
|
+
PhotoRestoreResult,
|
|
15
|
+
PhotoRestoreInputBuilder,
|
|
16
|
+
PhotoRestoreResultExtractor,
|
|
17
|
+
} from "../../domain/types";
|
|
18
|
+
|
|
19
|
+
declare const __DEV__: boolean;
|
|
20
|
+
|
|
21
|
+
export interface ExecutePhotoRestoreOptions {
|
|
22
|
+
model: string;
|
|
23
|
+
buildInput: PhotoRestoreInputBuilder;
|
|
24
|
+
extractResult?: PhotoRestoreResultExtractor;
|
|
25
|
+
onProgress?: (progress: number) => void;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function defaultExtractResult(result: unknown): string | undefined {
|
|
29
|
+
if (typeof result !== "object" || result === null) return undefined;
|
|
30
|
+
|
|
31
|
+
const r = result as Record<string, unknown>;
|
|
32
|
+
|
|
33
|
+
if (typeof r.image === "string") return r.image;
|
|
34
|
+
if (Array.isArray(r.images) && r.images[0]?.url) return r.images[0].url;
|
|
35
|
+
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function executePhotoRestore(
|
|
40
|
+
request: PhotoRestoreRequest,
|
|
41
|
+
options: ExecutePhotoRestoreOptions,
|
|
42
|
+
): Promise<PhotoRestoreResult> {
|
|
43
|
+
const provider = providerRegistry.getActiveProvider();
|
|
44
|
+
|
|
45
|
+
if (!provider) {
|
|
46
|
+
return { success: false, error: "No AI provider configured" };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!provider.isInitialized()) {
|
|
50
|
+
return { success: false, error: "AI provider not initialized" };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!request.imageBase64) {
|
|
54
|
+
return { success: false, error: "Image base64 is required" };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { model, buildInput, extractResult, onProgress } = options;
|
|
58
|
+
|
|
59
|
+
if (__DEV__) {
|
|
60
|
+
// eslint-disable-next-line no-console
|
|
61
|
+
console.log(`[PhotoRestore] Provider: ${provider.providerId}, Model: ${model}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
onProgress?.(10);
|
|
66
|
+
|
|
67
|
+
const base64 = cleanBase64(request.imageBase64);
|
|
68
|
+
onProgress?.(30);
|
|
69
|
+
|
|
70
|
+
const input = buildInput(base64, request.options);
|
|
71
|
+
onProgress?.(40);
|
|
72
|
+
|
|
73
|
+
const result = await provider.run(model, input);
|
|
74
|
+
onProgress?.(90);
|
|
75
|
+
|
|
76
|
+
const extractor = extractResult || defaultExtractResult;
|
|
77
|
+
const imageUrl = extractor(result);
|
|
78
|
+
onProgress?.(100);
|
|
79
|
+
|
|
80
|
+
if (!imageUrl) {
|
|
81
|
+
return { success: false, error: "No image in response" };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { success: true, imageUrl };
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
87
|
+
if (__DEV__) {
|
|
88
|
+
// eslint-disable-next-line no-console
|
|
89
|
+
console.error("[PhotoRestore] Error:", message);
|
|
90
|
+
}
|
|
91
|
+
return { success: false, error: message };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function hasPhotoRestoreSupport(): boolean {
|
|
96
|
+
const provider = providerRegistry.getActiveProvider();
|
|
97
|
+
return provider !== null && provider.isInitialized();
|
|
98
|
+
}
|