@umituz/react-native-ai-generation-content 1.17.0 → 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 +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/CreationsHomeCard.tsx +1 -1
- 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 +261 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +8 -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/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/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/photo-restoration/domain/types/index.ts +2 -5
- package/src/features/photo-restoration/domain/types/photo-restore.types.ts +14 -0
- package/src/features/photo-restoration/index.ts +3 -8
- package/src/features/photo-restoration/infrastructure/services/index.ts +1 -6
- package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +64 -30
- package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +11 -6
- 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/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/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 +63 -0
- package/src/features/face-swap/domain/entities.ts +0 -48
- package/src/features/photo-restoration/domain/types/provider.types.ts +0 -23
- package/src/features/photo-restoration/infrastructure/services/photo-restore-provider-registry.ts +0 -77
- package/src/features/text-to-image/domain/entities.ts +0 -58
- package/src/features/text-to-video/domain/entities.ts +0 -52
- 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,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAdvancedFilter Hook
|
|
3
|
+
* Advanced filtering with category, status, and search support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useState, useMemo, useCallback } from "react";
|
|
7
|
+
import type { CreationFilter, CreationStats, FilterOption } from "../../domain/types";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_CREATION_FILTER,
|
|
10
|
+
MEDIA_FILTER_OPTIONS,
|
|
11
|
+
STATUS_FILTER_OPTIONS,
|
|
12
|
+
calculateCreationStats,
|
|
13
|
+
isTypeInCategory,
|
|
14
|
+
} from "../../domain/types";
|
|
15
|
+
import type { CreationCategory, CreationStatus, CreationTypeId } from "../../domain/types";
|
|
16
|
+
|
|
17
|
+
interface Creation {
|
|
18
|
+
id: string;
|
|
19
|
+
type?: string;
|
|
20
|
+
status?: string;
|
|
21
|
+
prompt?: string;
|
|
22
|
+
createdAt?: Date | number;
|
|
23
|
+
updatedAt?: Date | number;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface UseAdvancedFilterProps<T extends Creation> {
|
|
28
|
+
creations: T[] | undefined;
|
|
29
|
+
initialFilter?: Partial<CreationFilter>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface UseAdvancedFilterReturn<T extends Creation> {
|
|
33
|
+
// Filtered results
|
|
34
|
+
filtered: T[];
|
|
35
|
+
|
|
36
|
+
// Current filter state
|
|
37
|
+
filter: CreationFilter;
|
|
38
|
+
|
|
39
|
+
// Stats
|
|
40
|
+
stats: CreationStats;
|
|
41
|
+
|
|
42
|
+
// Filter state
|
|
43
|
+
activeMediaFilter: string;
|
|
44
|
+
activeStatusFilter: string;
|
|
45
|
+
hasActiveFilters: boolean;
|
|
46
|
+
|
|
47
|
+
// Filter options with counts
|
|
48
|
+
mediaFilterOptions: FilterOption[];
|
|
49
|
+
statusFilterOptions: FilterOption[];
|
|
50
|
+
|
|
51
|
+
// Actions
|
|
52
|
+
setMediaFilter: (filter: CreationCategory | CreationTypeId) => void;
|
|
53
|
+
setStatusFilter: (status: CreationStatus | "all") => void;
|
|
54
|
+
setSearchQuery: (query: string) => void;
|
|
55
|
+
updateFilter: (update: Partial<CreationFilter>) => void;
|
|
56
|
+
resetFilters: () => void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Advanced filtering hook for creations
|
|
61
|
+
* Supports category, status, search, and sorting
|
|
62
|
+
*/
|
|
63
|
+
export function useAdvancedFilter<T extends Creation>({
|
|
64
|
+
creations,
|
|
65
|
+
initialFilter,
|
|
66
|
+
}: UseAdvancedFilterProps<T>): UseAdvancedFilterReturn<T> {
|
|
67
|
+
const [filter, setFilter] = useState<CreationFilter>({
|
|
68
|
+
...DEFAULT_CREATION_FILTER,
|
|
69
|
+
...initialFilter,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Calculate stats from all creations
|
|
73
|
+
const stats = useMemo(() => {
|
|
74
|
+
if (!creations) {
|
|
75
|
+
return {
|
|
76
|
+
total: 0,
|
|
77
|
+
byCategory: { all: 0, image: 0, video: 0, voice: 0 },
|
|
78
|
+
byStatus: { pending: 0, queued: 0, processing: 0, completed: 0, failed: 0 },
|
|
79
|
+
byType: {},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return calculateCreationStats(creations);
|
|
83
|
+
}, [creations]);
|
|
84
|
+
|
|
85
|
+
// Filter creations
|
|
86
|
+
const filtered = useMemo(() => {
|
|
87
|
+
if (!creations) return [];
|
|
88
|
+
|
|
89
|
+
let result = [...creations];
|
|
90
|
+
|
|
91
|
+
// Filter by type/category
|
|
92
|
+
if (filter.type && filter.type !== "all") {
|
|
93
|
+
const filterType = filter.type;
|
|
94
|
+
|
|
95
|
+
// Check if it's a category
|
|
96
|
+
if (["image", "video", "voice"].includes(filterType)) {
|
|
97
|
+
const category = filterType as CreationCategory;
|
|
98
|
+
result = result.filter((c) =>
|
|
99
|
+
c.type && isTypeInCategory(c.type as CreationTypeId, category)
|
|
100
|
+
);
|
|
101
|
+
} else {
|
|
102
|
+
// It's a specific type
|
|
103
|
+
result = result.filter((c) => c.type === filterType);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Filter by status
|
|
108
|
+
if (filter.status && filter.status !== "all") {
|
|
109
|
+
result = result.filter((c) => c.status === filter.status);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Filter by search query
|
|
113
|
+
if (filter.searchQuery && filter.searchQuery.trim()) {
|
|
114
|
+
const query = filter.searchQuery.toLowerCase().trim();
|
|
115
|
+
result = result.filter((c) => {
|
|
116
|
+
const prompt = c.prompt?.toLowerCase() || "";
|
|
117
|
+
const type = c.type?.toLowerCase() || "";
|
|
118
|
+
return prompt.includes(query) || type.includes(query);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Filter by date range
|
|
123
|
+
if (filter.startDate) {
|
|
124
|
+
result = result.filter((c) => {
|
|
125
|
+
const createdAt = c.createdAt instanceof Date
|
|
126
|
+
? c.createdAt.getTime()
|
|
127
|
+
: (c.createdAt || 0);
|
|
128
|
+
return createdAt >= filter.startDate!;
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (filter.endDate) {
|
|
133
|
+
result = result.filter((c) => {
|
|
134
|
+
const createdAt = c.createdAt instanceof Date
|
|
135
|
+
? c.createdAt.getTime()
|
|
136
|
+
: (c.createdAt || 0);
|
|
137
|
+
return createdAt <= filter.endDate!;
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Sort
|
|
142
|
+
if (filter.sortField) {
|
|
143
|
+
result.sort((a, b) => {
|
|
144
|
+
let aVal: string | number | Date | undefined;
|
|
145
|
+
let bVal: string | number | Date | undefined;
|
|
146
|
+
|
|
147
|
+
switch (filter.sortField) {
|
|
148
|
+
case "createdAt":
|
|
149
|
+
aVal = a.createdAt;
|
|
150
|
+
bVal = b.createdAt;
|
|
151
|
+
break;
|
|
152
|
+
case "updatedAt":
|
|
153
|
+
aVal = a.updatedAt;
|
|
154
|
+
bVal = b.updatedAt;
|
|
155
|
+
break;
|
|
156
|
+
case "type":
|
|
157
|
+
aVal = a.type;
|
|
158
|
+
bVal = b.type;
|
|
159
|
+
break;
|
|
160
|
+
case "status":
|
|
161
|
+
aVal = a.status;
|
|
162
|
+
bVal = b.status;
|
|
163
|
+
break;
|
|
164
|
+
default:
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Convert dates to numbers for comparison
|
|
169
|
+
if (aVal instanceof Date) aVal = aVal.getTime();
|
|
170
|
+
if (bVal instanceof Date) bVal = bVal.getTime();
|
|
171
|
+
|
|
172
|
+
// Handle undefined values
|
|
173
|
+
if (aVal === undefined && bVal === undefined) return 0;
|
|
174
|
+
if (aVal === undefined) return 1;
|
|
175
|
+
if (bVal === undefined) return -1;
|
|
176
|
+
|
|
177
|
+
// Compare
|
|
178
|
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
|
179
|
+
return filter.sortOrder === "desc"
|
|
180
|
+
? bVal.localeCompare(aVal)
|
|
181
|
+
: aVal.localeCompare(bVal);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
185
|
+
return filter.sortOrder === "desc" ? bVal - aVal : aVal - bVal;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return 0;
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Apply limit
|
|
193
|
+
if (filter.limit && filter.limit > 0) {
|
|
194
|
+
result = result.slice(0, filter.limit);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return result;
|
|
198
|
+
}, [creations, filter]);
|
|
199
|
+
|
|
200
|
+
// Media filter options with counts
|
|
201
|
+
const mediaFilterOptions = useMemo<FilterOption[]>(() => {
|
|
202
|
+
return MEDIA_FILTER_OPTIONS.map((opt) => ({
|
|
203
|
+
...opt,
|
|
204
|
+
count: opt.id === "all"
|
|
205
|
+
? stats.total
|
|
206
|
+
: stats.byCategory[opt.id as CreationCategory] || 0,
|
|
207
|
+
}));
|
|
208
|
+
}, [stats]);
|
|
209
|
+
|
|
210
|
+
// Status filter options with counts
|
|
211
|
+
const statusFilterOptions = useMemo<FilterOption[]>(() => {
|
|
212
|
+
return STATUS_FILTER_OPTIONS.map((opt) => ({
|
|
213
|
+
...opt,
|
|
214
|
+
count: opt.id === "all"
|
|
215
|
+
? stats.total
|
|
216
|
+
: stats.byStatus[opt.id as CreationStatus] || 0,
|
|
217
|
+
}));
|
|
218
|
+
}, [stats]);
|
|
219
|
+
|
|
220
|
+
// Actions
|
|
221
|
+
const setMediaFilter = useCallback((type: CreationCategory | CreationTypeId) => {
|
|
222
|
+
setFilter((prev) => ({ ...prev, type }));
|
|
223
|
+
}, []);
|
|
224
|
+
|
|
225
|
+
const setStatusFilter = useCallback((status: CreationStatus | "all") => {
|
|
226
|
+
setFilter((prev) => ({ ...prev, status }));
|
|
227
|
+
}, []);
|
|
228
|
+
|
|
229
|
+
const setSearchQuery = useCallback((searchQuery: string) => {
|
|
230
|
+
setFilter((prev) => ({ ...prev, searchQuery }));
|
|
231
|
+
}, []);
|
|
232
|
+
|
|
233
|
+
const updateFilter = useCallback((update: Partial<CreationFilter>) => {
|
|
234
|
+
setFilter((prev) => ({ ...prev, ...update }));
|
|
235
|
+
}, []);
|
|
236
|
+
|
|
237
|
+
const resetFilters = useCallback(() => {
|
|
238
|
+
setFilter(DEFAULT_CREATION_FILTER);
|
|
239
|
+
}, []);
|
|
240
|
+
|
|
241
|
+
// Derived state
|
|
242
|
+
const hasActiveFilters = filter.type !== "all" || filter.status !== "all" || !!filter.searchQuery;
|
|
243
|
+
const activeMediaFilter = (filter.type as string) || "all";
|
|
244
|
+
const activeStatusFilter = (filter.status as string) || "all";
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
filtered,
|
|
248
|
+
filter,
|
|
249
|
+
stats,
|
|
250
|
+
activeMediaFilter,
|
|
251
|
+
activeStatusFilter,
|
|
252
|
+
hasActiveFilters,
|
|
253
|
+
mediaFilterOptions,
|
|
254
|
+
statusFilterOptions,
|
|
255
|
+
setMediaFilter,
|
|
256
|
+
setStatusFilter,
|
|
257
|
+
setSearchQuery,
|
|
258
|
+
updateFilter,
|
|
259
|
+
resetFilters,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
@@ -55,7 +55,7 @@ function CreationsGalleryScreenContent({
|
|
|
55
55
|
repository,
|
|
56
56
|
config,
|
|
57
57
|
t,
|
|
58
|
-
locale = "en-US",
|
|
58
|
+
locale: _locale = "en-US",
|
|
59
59
|
enableEditing = false,
|
|
60
60
|
onImageEdit,
|
|
61
61
|
onEmptyAction,
|
|
@@ -199,11 +199,13 @@ function CreationsGalleryScreenContent({
|
|
|
199
199
|
creations={filtered}
|
|
200
200
|
isLoading={isLoading}
|
|
201
201
|
onRefresh={() => void refetch()}
|
|
202
|
-
|
|
203
|
-
onShare={handleShare}
|
|
204
|
-
onDelete={handleDelete}
|
|
205
|
-
onFavorite={
|
|
206
|
-
|
|
202
|
+
onPress={(creation) => handleView(creation as Creation)}
|
|
203
|
+
onShare={async (creation) => handleShare(creation as Creation)}
|
|
204
|
+
onDelete={(creation) => handleDelete(creation as Creation)}
|
|
205
|
+
onFavorite={(creation) => {
|
|
206
|
+
const c = creation as Creation;
|
|
207
|
+
handleFavorite(c, !c.isFavorite);
|
|
208
|
+
}}
|
|
207
209
|
contentContainerStyle={{ paddingBottom: tokens.spacing.xl }}
|
|
208
210
|
ListEmptyComponent={renderEmptyComponent}
|
|
209
211
|
/>
|
|
@@ -17,7 +17,7 @@ export class PromptGenerationService implements IPromptGenerationService {
|
|
|
17
17
|
|
|
18
18
|
const generatedText = this.replaceTemplateVariables(template.template, variables);
|
|
19
19
|
resolve({ success: true, data: generatedText });
|
|
20
|
-
} catch
|
|
20
|
+
} catch {
|
|
21
21
|
resolve({
|
|
22
22
|
success: false,
|
|
23
23
|
error: 'GENERATION_FAILED',
|
|
@@ -62,7 +62,7 @@ export const useFaceSwap = (
|
|
|
62
62
|
};
|
|
63
63
|
|
|
64
64
|
setResult(generationResult);
|
|
65
|
-
} catch
|
|
65
|
+
} catch {
|
|
66
66
|
setError('An unexpected error occurred');
|
|
67
67
|
}
|
|
68
68
|
}, [faceSwapService, historyRepository, setError, setResult, clearError]);
|
|
@@ -70,7 +70,7 @@ export const useFaceSwap = (
|
|
|
70
70
|
const getAvailableStyles = useCallback(async (): Promise<string[]> => {
|
|
71
71
|
try {
|
|
72
72
|
return await faceSwapService.getAvailableStyles();
|
|
73
|
-
} catch
|
|
73
|
+
} catch {
|
|
74
74
|
setError('Failed to load available styles');
|
|
75
75
|
return [];
|
|
76
76
|
}
|
|
@@ -70,7 +70,7 @@ export const usePromptGeneration = (
|
|
|
70
70
|
setGeneratedPrompt(newPrompt);
|
|
71
71
|
|
|
72
72
|
void loadHistory(50);
|
|
73
|
-
} catch
|
|
73
|
+
} catch {
|
|
74
74
|
setError('An unexpected error occurred');
|
|
75
75
|
}
|
|
76
76
|
},
|
|
@@ -87,7 +87,7 @@ export const usePromptGeneration = (
|
|
|
87
87
|
} else {
|
|
88
88
|
setError(('message' in result && result.message) || 'Failed to load history');
|
|
89
89
|
}
|
|
90
|
-
} catch
|
|
90
|
+
} catch {
|
|
91
91
|
setError('Failed to load history');
|
|
92
92
|
}
|
|
93
93
|
},
|
|
@@ -99,7 +99,7 @@ export const usePromptGeneration = (
|
|
|
99
99
|
try {
|
|
100
100
|
await historyRepository.clear();
|
|
101
101
|
setHistory([]);
|
|
102
|
-
} catch
|
|
102
|
+
} catch {
|
|
103
103
|
setError('Failed to clear history');
|
|
104
104
|
}
|
|
105
105
|
}, [historyRepository, setHistory, setError, clearError]);
|
|
@@ -110,7 +110,7 @@ export const usePromptGeneration = (
|
|
|
110
110
|
try {
|
|
111
111
|
await historyRepository.save(prompt);
|
|
112
112
|
void loadHistory(50);
|
|
113
|
-
} catch
|
|
113
|
+
} catch {
|
|
114
114
|
setError('Failed to save to history');
|
|
115
115
|
}
|
|
116
116
|
},
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Hug Feature Types
|
|
3
|
+
* Request, Result, Config types for AI hug generation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface AIHugOptions {
|
|
7
|
+
intensity?: "gentle" | "warm" | "tight";
|
|
8
|
+
preserveFaces?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface AIHugRequest {
|
|
12
|
+
sourceImageUri: string;
|
|
13
|
+
targetImageUri: string;
|
|
14
|
+
sourceImageBase64?: string;
|
|
15
|
+
targetImageBase64?: string;
|
|
16
|
+
userId: string;
|
|
17
|
+
options?: AIHugOptions;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface AIHugResult {
|
|
21
|
+
success: boolean;
|
|
22
|
+
imageUrl?: string;
|
|
23
|
+
imageBase64?: string;
|
|
24
|
+
error?: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface AIHugFeatureState {
|
|
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 AIHugTranslations {
|
|
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 AIHugInputBuilder = (
|
|
53
|
+
sourceBase64: string,
|
|
54
|
+
targetBase64: string,
|
|
55
|
+
options?: AIHugOptions,
|
|
56
|
+
) => Record<string, unknown>;
|
|
57
|
+
|
|
58
|
+
export type AIHugResultExtractor = (result: unknown) => string | undefined;
|
|
59
|
+
|
|
60
|
+
export interface AIHugFeatureConfig {
|
|
61
|
+
providerId?: string;
|
|
62
|
+
creditCost?: number;
|
|
63
|
+
model: string;
|
|
64
|
+
buildInput: AIHugInputBuilder;
|
|
65
|
+
extractResult?: AIHugResultExtractor;
|
|
66
|
+
prepareImage: (imageUri: string) => Promise<string>;
|
|
67
|
+
onSourceImageSelect?: (uri: string) => void;
|
|
68
|
+
onTargetImageSelect?: (uri: string) => void;
|
|
69
|
+
onProcessingStart?: () => void;
|
|
70
|
+
onProcessingComplete?: (result: AIHugResult) => void;
|
|
71
|
+
onError?: (error: string) => void;
|
|
72
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Hug Feature
|
|
3
|
+
* Provider-agnostic AI hug generation feature
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Domain Types
|
|
7
|
+
export type {
|
|
8
|
+
AIHugOptions,
|
|
9
|
+
AIHugRequest,
|
|
10
|
+
AIHugResult,
|
|
11
|
+
AIHugFeatureState,
|
|
12
|
+
AIHugTranslations,
|
|
13
|
+
AIHugFeatureConfig,
|
|
14
|
+
AIHugInputBuilder,
|
|
15
|
+
AIHugResultExtractor,
|
|
16
|
+
} from "./domain";
|
|
17
|
+
|
|
18
|
+
// Infrastructure Services
|
|
19
|
+
export { executeAIHug, hasAIHugSupport } from "./infrastructure";
|
|
20
|
+
export type { ExecuteAIHugOptions } from "./infrastructure";
|
|
21
|
+
|
|
22
|
+
// Presentation Hooks
|
|
23
|
+
export { useAIHugFeature } from "./presentation";
|
|
24
|
+
export type {
|
|
25
|
+
UseAIHugFeatureProps,
|
|
26
|
+
UseAIHugFeatureReturn,
|
|
27
|
+
} from "./presentation";
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Hug Executor
|
|
3
|
+
* Provider-agnostic AI hug 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
|
+
AIHugRequest,
|
|
11
|
+
AIHugResult,
|
|
12
|
+
AIHugInputBuilder,
|
|
13
|
+
AIHugResultExtractor,
|
|
14
|
+
} from "../../domain/types";
|
|
15
|
+
|
|
16
|
+
declare const __DEV__: boolean;
|
|
17
|
+
|
|
18
|
+
export interface ExecuteAIHugOptions {
|
|
19
|
+
model: string;
|
|
20
|
+
buildInput: AIHugInputBuilder;
|
|
21
|
+
extractResult?: AIHugResultExtractor;
|
|
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 executeAIHug(
|
|
37
|
+
request: AIHugRequest,
|
|
38
|
+
options: ExecuteAIHugOptions,
|
|
39
|
+
): Promise<AIHugResult> {
|
|
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(`[AIHug] 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("[AIHug] Error:", message);
|
|
88
|
+
}
|
|
89
|
+
return { success: false, error: message };
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function hasAIHugSupport(): boolean {
|
|
94
|
+
const provider = providerRegistry.getActiveProvider();
|
|
95
|
+
return provider !== null && provider.isInitialized();
|
|
96
|
+
}
|