@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.
Files changed (156) hide show
  1. package/package.json +13 -14
  2. package/src/domains/creations/domain/entities/Creation.ts +33 -2
  3. package/src/domains/creations/domain/entities/index.ts +1 -1
  4. package/src/domains/creations/domain/types/creation-categories.ts +133 -0
  5. package/src/domains/creations/domain/types/creation-filter.ts +131 -0
  6. package/src/domains/creations/domain/types/creation-types.ts +63 -0
  7. package/src/domains/creations/domain/types/index.ts +44 -0
  8. package/src/domains/creations/domain/utils/creation-helpers.ts +134 -0
  9. package/src/domains/creations/domain/utils/index.ts +8 -0
  10. package/src/domains/creations/domain/utils/preview-helpers.ts +84 -0
  11. package/src/domains/creations/domain/utils/status-helpers.ts +90 -0
  12. package/src/domains/creations/index.ts +95 -21
  13. package/src/domains/creations/infrastructure/repositories/CreationsRepository.ts +14 -1
  14. package/src/domains/creations/presentation/components/CreationActions.tsx +120 -0
  15. package/src/domains/creations/presentation/components/CreationBadges.tsx +111 -0
  16. package/src/domains/creations/presentation/components/CreationCard.tsx +201 -102
  17. package/src/domains/creations/presentation/components/CreationPreview.tsx +117 -0
  18. package/src/domains/creations/presentation/components/CreationsFilterBar.tsx +254 -0
  19. package/src/domains/creations/presentation/components/CreationsGrid.tsx +121 -68
  20. package/src/domains/creations/presentation/components/CreationsHomeCard.tsx +1 -1
  21. package/src/domains/creations/presentation/components/index.ts +23 -3
  22. package/src/domains/creations/presentation/hooks/index.ts +1 -0
  23. package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +261 -0
  24. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +8 -6
  25. package/src/domains/face-detection/infrastructure/validators/faceValidator.ts +1 -1
  26. package/src/domains/prompts/infrastructure/services/PromptGenerationService.ts +1 -1
  27. package/src/domains/prompts/presentation/hooks/useFaceSwap.ts +2 -2
  28. package/src/domains/prompts/presentation/hooks/usePromptGeneration.ts +4 -4
  29. package/src/features/ai-hug/domain/index.ts +5 -0
  30. package/src/features/ai-hug/domain/types/ai-hug.types.ts +72 -0
  31. package/src/features/ai-hug/domain/types/index.ts +14 -0
  32. package/src/features/ai-hug/index.ts +27 -0
  33. package/src/features/ai-hug/infrastructure/index.ts +5 -0
  34. package/src/features/ai-hug/infrastructure/services/ai-hug-executor.ts +96 -0
  35. package/src/features/ai-hug/infrastructure/services/index.ts +6 -0
  36. package/src/features/ai-hug/presentation/hooks/index.ts +9 -0
  37. package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +157 -0
  38. package/src/features/ai-hug/presentation/index.ts +5 -0
  39. package/src/features/ai-kiss/domain/index.ts +5 -0
  40. package/src/features/ai-kiss/domain/types/ai-kiss.types.ts +72 -0
  41. package/src/features/ai-kiss/domain/types/index.ts +14 -0
  42. package/src/features/ai-kiss/index.ts +27 -0
  43. package/src/features/ai-kiss/infrastructure/index.ts +5 -0
  44. package/src/features/ai-kiss/infrastructure/services/ai-kiss-executor.ts +96 -0
  45. package/src/features/ai-kiss/infrastructure/services/index.ts +6 -0
  46. package/src/features/ai-kiss/presentation/hooks/index.ts +9 -0
  47. package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +157 -0
  48. package/src/features/ai-kiss/presentation/index.ts +5 -0
  49. package/src/features/anime-selfie/domain/index.ts +5 -0
  50. package/src/features/anime-selfie/domain/types/anime-selfie.types.ts +72 -0
  51. package/src/features/anime-selfie/domain/types/index.ts +15 -0
  52. package/src/features/anime-selfie/index.ts +28 -0
  53. package/src/features/anime-selfie/infrastructure/index.ts +5 -0
  54. package/src/features/anime-selfie/infrastructure/services/anime-selfie-executor.ts +95 -0
  55. package/src/features/anime-selfie/infrastructure/services/index.ts +6 -0
  56. package/src/features/anime-selfie/presentation/hooks/index.ts +9 -0
  57. package/src/features/anime-selfie/presentation/hooks/useAnimeSelfieFeature.ts +138 -0
  58. package/src/features/anime-selfie/presentation/index.ts +5 -0
  59. package/src/features/background/domain/types/index.ts +15 -0
  60. package/src/features/background/domain/types/replace-background.types.ts +82 -0
  61. package/src/features/background/index.ts +31 -3
  62. package/src/features/background/infrastructure/index.ts +5 -0
  63. package/src/features/background/infrastructure/services/index.ts +6 -0
  64. package/src/features/background/infrastructure/services/replace-background-executor.ts +95 -0
  65. package/src/features/background/presentation/hooks/index.ts +6 -1
  66. package/src/features/background/presentation/hooks/useReplaceBackgroundFeature.ts +160 -0
  67. package/src/features/face-swap/domain/index.ts +5 -0
  68. package/src/features/face-swap/domain/types/face-swap.types.ts +72 -0
  69. package/src/features/face-swap/domain/types/index.ts +14 -0
  70. package/src/features/face-swap/index.ts +27 -1
  71. package/src/features/face-swap/infrastructure/index.ts +5 -0
  72. package/src/features/face-swap/infrastructure/services/face-swap-executor.ts +96 -0
  73. package/src/features/face-swap/infrastructure/services/index.ts +6 -0
  74. package/src/features/face-swap/presentation/hooks/index.ts +9 -0
  75. package/src/features/face-swap/presentation/hooks/useFaceSwapFeature.ts +157 -0
  76. package/src/features/face-swap/presentation/index.ts +5 -0
  77. package/src/features/image-to-video/domain/index.ts +1 -0
  78. package/src/features/image-to-video/domain/types/image-to-video.types.ts +71 -0
  79. package/src/features/image-to-video/domain/types/index.ts +10 -0
  80. package/src/features/image-to-video/index.ts +27 -0
  81. package/src/features/image-to-video/infrastructure/index.ts +1 -0
  82. package/src/features/image-to-video/infrastructure/services/image-to-video-executor.ts +112 -0
  83. package/src/features/image-to-video/infrastructure/services/index.ts +5 -0
  84. package/src/features/image-to-video/presentation/hooks/index.ts +5 -0
  85. package/src/features/image-to-video/presentation/hooks/useImageToVideoFeature.ts +121 -0
  86. package/src/features/image-to-video/presentation/index.ts +1 -0
  87. package/src/features/photo-restoration/domain/types/index.ts +2 -5
  88. package/src/features/photo-restoration/domain/types/photo-restore.types.ts +14 -0
  89. package/src/features/photo-restoration/index.ts +3 -8
  90. package/src/features/photo-restoration/infrastructure/services/index.ts +1 -6
  91. package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +64 -30
  92. package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +11 -6
  93. package/src/features/remove-background/domain/index.ts +5 -0
  94. package/src/features/remove-background/domain/types/index.ts +14 -0
  95. package/src/features/remove-background/domain/types/remove-background.types.ts +69 -0
  96. package/src/features/remove-background/index.ts +27 -0
  97. package/src/features/remove-background/infrastructure/index.ts +5 -0
  98. package/src/features/remove-background/infrastructure/services/index.ts +6 -0
  99. package/src/features/remove-background/infrastructure/services/remove-background-executor.ts +95 -0
  100. package/src/features/remove-background/presentation/hooks/index.ts +9 -0
  101. package/src/features/remove-background/presentation/hooks/useRemoveBackgroundFeature.ts +137 -0
  102. package/src/features/remove-background/presentation/index.ts +5 -0
  103. package/src/features/remove-object/domain/index.ts +5 -0
  104. package/src/features/remove-object/domain/types/index.ts +14 -0
  105. package/src/features/remove-object/domain/types/remove-object.types.ts +77 -0
  106. package/src/features/remove-object/index.ts +27 -0
  107. package/src/features/remove-object/infrastructure/index.ts +5 -0
  108. package/src/features/remove-object/infrastructure/services/index.ts +6 -0
  109. package/src/features/remove-object/infrastructure/services/remove-object-executor.ts +99 -0
  110. package/src/features/remove-object/presentation/hooks/index.ts +9 -0
  111. package/src/features/remove-object/presentation/hooks/useRemoveObjectFeature.ts +168 -0
  112. package/src/features/remove-object/presentation/index.ts +5 -0
  113. package/src/features/text-to-image/domain/index.ts +1 -0
  114. package/src/features/text-to-image/domain/types/index.ts +10 -0
  115. package/src/features/text-to-image/domain/types/text-to-image.types.ts +66 -0
  116. package/src/features/text-to-image/index.ts +27 -1
  117. package/src/features/text-to-image/infrastructure/index.ts +1 -0
  118. package/src/features/text-to-image/infrastructure/services/index.ts +5 -0
  119. package/src/features/text-to-image/infrastructure/services/text-to-image-executor.ts +113 -0
  120. package/src/features/text-to-image/presentation/hooks/index.ts +5 -0
  121. package/src/features/text-to-image/presentation/hooks/useTextToImageFeature.ts +111 -0
  122. package/src/features/text-to-image/presentation/index.ts +1 -0
  123. package/src/features/text-to-video/domain/index.ts +1 -0
  124. package/src/features/text-to-video/domain/types/index.ts +10 -0
  125. package/src/features/text-to-video/domain/types/text-to-video.types.ts +65 -0
  126. package/src/features/text-to-video/index.ts +27 -1
  127. package/src/features/text-to-video/infrastructure/index.ts +1 -0
  128. package/src/features/text-to-video/infrastructure/services/index.ts +5 -0
  129. package/src/features/text-to-video/infrastructure/services/text-to-video-executor.ts +108 -0
  130. package/src/features/text-to-video/presentation/hooks/index.ts +5 -0
  131. package/src/features/text-to-video/presentation/hooks/useTextToVideoFeature.ts +111 -0
  132. package/src/features/text-to-video/presentation/index.ts +1 -0
  133. package/src/features/text-to-voice/domain/index.ts +1 -0
  134. package/src/features/text-to-voice/domain/types/index.ts +10 -0
  135. package/src/features/text-to-voice/domain/types/text-to-voice.types.ts +65 -0
  136. package/src/features/text-to-voice/index.ts +27 -0
  137. package/src/features/text-to-voice/infrastructure/index.ts +1 -0
  138. package/src/features/text-to-voice/infrastructure/services/index.ts +5 -0
  139. package/src/features/text-to-voice/infrastructure/services/text-to-voice-executor.ts +111 -0
  140. package/src/features/text-to-voice/presentation/hooks/index.ts +5 -0
  141. package/src/features/text-to-voice/presentation/hooks/useTextToVoiceFeature.ts +105 -0
  142. package/src/features/text-to-voice/presentation/index.ts +1 -0
  143. package/src/features/upscaling/domain/types/index.ts +0 -1
  144. package/src/features/upscaling/domain/types/upscale.types.ts +14 -0
  145. package/src/features/upscaling/index.ts +3 -11
  146. package/src/features/upscaling/infrastructure/services/index.ts +1 -6
  147. package/src/features/upscaling/infrastructure/services/upscale-executor.ts +64 -30
  148. package/src/features/upscaling/presentation/hooks/useUpscaleFeature.ts +12 -7
  149. package/src/index.ts +63 -0
  150. package/src/features/face-swap/domain/entities.ts +0 -48
  151. package/src/features/photo-restoration/domain/types/provider.types.ts +0 -23
  152. package/src/features/photo-restoration/infrastructure/services/photo-restore-provider-registry.ts +0 -77
  153. package/src/features/text-to-image/domain/entities.ts +0 -58
  154. package/src/features/text-to-video/domain/entities.ts +0 -52
  155. package/src/features/upscaling/domain/types/provider.types.ts +0 -23
  156. 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
- onView={handleView}
203
- onShare={handleShare}
204
- onDelete={handleDelete}
205
- onFavorite={handleFavorite}
206
- locale={locale}
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
  />
@@ -32,7 +32,7 @@ export const parseDetectionResponse = (
32
32
  confidence: Number(parsed.confidence) || 0,
33
33
  message: String(parsed.reason || ""),
34
34
  };
35
- } catch (error) {
35
+ } catch {
36
36
  return createFailedResult("Failed to parse response");
37
37
  }
38
38
  };
@@ -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 (error) {
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 (error) {
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 (error) {
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 (error) {
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 (error) {
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 (error) {
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 (error) {
113
+ } catch {
114
114
  setError('Failed to save to history');
115
115
  }
116
116
  },
@@ -0,0 +1,5 @@
1
+ /**
2
+ * AI Hug Domain Index
3
+ */
4
+
5
+ export * from "./types";
@@ -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,14 @@
1
+ /**
2
+ * AI Hug Domain Types Index
3
+ */
4
+
5
+ export type {
6
+ AIHugOptions,
7
+ AIHugRequest,
8
+ AIHugResult,
9
+ AIHugFeatureState,
10
+ AIHugTranslations,
11
+ AIHugInputBuilder,
12
+ AIHugResultExtractor,
13
+ AIHugFeatureConfig,
14
+ } from "./ai-hug.types";
@@ -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,5 @@
1
+ /**
2
+ * AI Hug Infrastructure Index
3
+ */
4
+
5
+ export * from "./services";
@@ -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
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * AI Hug Infrastructure Services Index
3
+ */
4
+
5
+ export { executeAIHug, hasAIHugSupport } from "./ai-hug-executor";
6
+ export type { ExecuteAIHugOptions } from "./ai-hug-executor";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * AI Hug Presentation Hooks Index
3
+ */
4
+
5
+ export { useAIHugFeature } from "./useAIHugFeature";
6
+ export type {
7
+ UseAIHugFeatureProps,
8
+ UseAIHugFeatureReturn,
9
+ } from "./useAIHugFeature";