@umituz/react-native-ai-generation-content 1.17.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.
Files changed (110) 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/index.ts +23 -3
  21. package/src/domains/creations/presentation/hooks/index.ts +1 -0
  22. package/src/domains/creations/presentation/hooks/useAdvancedFilter.ts +262 -0
  23. package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +5 -6
  24. package/src/features/ai-hug/domain/index.ts +5 -0
  25. package/src/features/ai-hug/domain/types/ai-hug.types.ts +72 -0
  26. package/src/features/ai-hug/domain/types/index.ts +14 -0
  27. package/src/features/ai-hug/index.ts +27 -0
  28. package/src/features/ai-hug/infrastructure/index.ts +5 -0
  29. package/src/features/ai-hug/infrastructure/services/ai-hug-executor.ts +96 -0
  30. package/src/features/ai-hug/infrastructure/services/index.ts +6 -0
  31. package/src/features/ai-hug/presentation/hooks/index.ts +9 -0
  32. package/src/features/ai-hug/presentation/hooks/useAIHugFeature.ts +157 -0
  33. package/src/features/ai-hug/presentation/index.ts +5 -0
  34. package/src/features/ai-kiss/domain/index.ts +5 -0
  35. package/src/features/ai-kiss/domain/types/ai-kiss.types.ts +72 -0
  36. package/src/features/ai-kiss/domain/types/index.ts +14 -0
  37. package/src/features/ai-kiss/index.ts +27 -0
  38. package/src/features/ai-kiss/infrastructure/index.ts +5 -0
  39. package/src/features/ai-kiss/infrastructure/services/ai-kiss-executor.ts +96 -0
  40. package/src/features/ai-kiss/infrastructure/services/index.ts +6 -0
  41. package/src/features/ai-kiss/presentation/hooks/index.ts +9 -0
  42. package/src/features/ai-kiss/presentation/hooks/useAIKissFeature.ts +157 -0
  43. package/src/features/ai-kiss/presentation/index.ts +5 -0
  44. package/src/features/anime-selfie/domain/index.ts +5 -0
  45. package/src/features/anime-selfie/domain/types/anime-selfie.types.ts +72 -0
  46. package/src/features/anime-selfie/domain/types/index.ts +15 -0
  47. package/src/features/anime-selfie/index.ts +28 -0
  48. package/src/features/anime-selfie/infrastructure/index.ts +5 -0
  49. package/src/features/anime-selfie/infrastructure/services/anime-selfie-executor.ts +95 -0
  50. package/src/features/anime-selfie/infrastructure/services/index.ts +6 -0
  51. package/src/features/anime-selfie/presentation/hooks/index.ts +9 -0
  52. package/src/features/anime-selfie/presentation/hooks/useAnimeSelfieFeature.ts +138 -0
  53. package/src/features/anime-selfie/presentation/index.ts +5 -0
  54. package/src/features/background/domain/types/index.ts +15 -0
  55. package/src/features/background/domain/types/replace-background.types.ts +82 -0
  56. package/src/features/background/index.ts +31 -3
  57. package/src/features/background/infrastructure/index.ts +5 -0
  58. package/src/features/background/infrastructure/services/index.ts +6 -0
  59. package/src/features/background/infrastructure/services/replace-background-executor.ts +95 -0
  60. package/src/features/background/presentation/hooks/index.ts +6 -1
  61. package/src/features/background/presentation/hooks/useReplaceBackgroundFeature.ts +160 -0
  62. package/src/features/face-swap/domain/index.ts +5 -0
  63. package/src/features/face-swap/domain/types/face-swap.types.ts +72 -0
  64. package/src/features/face-swap/domain/types/index.ts +14 -0
  65. package/src/features/face-swap/index.ts +27 -1
  66. package/src/features/face-swap/infrastructure/index.ts +5 -0
  67. package/src/features/face-swap/infrastructure/services/face-swap-executor.ts +96 -0
  68. package/src/features/face-swap/infrastructure/services/index.ts +6 -0
  69. package/src/features/face-swap/presentation/hooks/index.ts +9 -0
  70. package/src/features/face-swap/presentation/hooks/useFaceSwapFeature.ts +157 -0
  71. package/src/features/face-swap/presentation/index.ts +5 -0
  72. package/src/features/photo-restoration/domain/types/index.ts +2 -5
  73. package/src/features/photo-restoration/domain/types/photo-restore.types.ts +14 -0
  74. package/src/features/photo-restoration/index.ts +3 -8
  75. package/src/features/photo-restoration/infrastructure/services/index.ts +1 -6
  76. package/src/features/photo-restoration/infrastructure/services/photo-restore-executor.ts +64 -30
  77. package/src/features/photo-restoration/presentation/hooks/usePhotoRestoreFeature.ts +11 -6
  78. package/src/features/remove-background/domain/index.ts +5 -0
  79. package/src/features/remove-background/domain/types/index.ts +14 -0
  80. package/src/features/remove-background/domain/types/remove-background.types.ts +69 -0
  81. package/src/features/remove-background/index.ts +27 -0
  82. package/src/features/remove-background/infrastructure/index.ts +5 -0
  83. package/src/features/remove-background/infrastructure/services/index.ts +6 -0
  84. package/src/features/remove-background/infrastructure/services/remove-background-executor.ts +95 -0
  85. package/src/features/remove-background/presentation/hooks/index.ts +9 -0
  86. package/src/features/remove-background/presentation/hooks/useRemoveBackgroundFeature.ts +137 -0
  87. package/src/features/remove-background/presentation/index.ts +5 -0
  88. package/src/features/remove-object/domain/index.ts +5 -0
  89. package/src/features/remove-object/domain/types/index.ts +14 -0
  90. package/src/features/remove-object/domain/types/remove-object.types.ts +77 -0
  91. package/src/features/remove-object/index.ts +27 -0
  92. package/src/features/remove-object/infrastructure/index.ts +5 -0
  93. package/src/features/remove-object/infrastructure/services/index.ts +6 -0
  94. package/src/features/remove-object/infrastructure/services/remove-object-executor.ts +99 -0
  95. package/src/features/remove-object/presentation/hooks/index.ts +9 -0
  96. package/src/features/remove-object/presentation/hooks/useRemoveObjectFeature.ts +168 -0
  97. package/src/features/remove-object/presentation/index.ts +5 -0
  98. package/src/features/upscaling/domain/types/index.ts +0 -1
  99. package/src/features/upscaling/domain/types/upscale.types.ts +14 -0
  100. package/src/features/upscaling/index.ts +3 -11
  101. package/src/features/upscaling/infrastructure/services/index.ts +1 -6
  102. package/src/features/upscaling/infrastructure/services/upscale-executor.ts +64 -30
  103. package/src/features/upscaling/presentation/hooks/useUpscaleFeature.ts +12 -7
  104. package/src/index.ts +39 -0
  105. package/src/types/jsx.d.ts +19 -0
  106. package/src/features/face-swap/domain/entities.ts +0 -48
  107. package/src/features/photo-restoration/domain/types/provider.types.ts +0 -23
  108. package/src/features/photo-restoration/infrastructure/services/photo-restore-provider-registry.ts +0 -77
  109. package/src/features/upscaling/domain/types/provider.types.ts +0 -23
  110. package/src/features/upscaling/infrastructure/services/upscale-provider-registry.ts +0 -77
@@ -0,0 +1,262 @@
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
+ getTypesForCategory,
14
+ isTypeInCategory,
15
+ } from "../../domain/types";
16
+ import type { CreationCategory, CreationStatus, CreationTypeId } from "../../domain/types";
17
+
18
+ interface Creation {
19
+ id: string;
20
+ type?: string;
21
+ status?: string;
22
+ prompt?: string;
23
+ createdAt?: Date | number;
24
+ updatedAt?: Date | number;
25
+ metadata?: Record<string, unknown>;
26
+ }
27
+
28
+ interface UseAdvancedFilterProps<T extends Creation> {
29
+ creations: T[] | undefined;
30
+ initialFilter?: Partial<CreationFilter>;
31
+ }
32
+
33
+ interface UseAdvancedFilterReturn<T extends Creation> {
34
+ // Filtered results
35
+ filtered: T[];
36
+
37
+ // Current filter state
38
+ filter: CreationFilter;
39
+
40
+ // Stats
41
+ stats: CreationStats;
42
+
43
+ // Filter state
44
+ activeMediaFilter: string;
45
+ activeStatusFilter: string;
46
+ hasActiveFilters: boolean;
47
+
48
+ // Filter options with counts
49
+ mediaFilterOptions: FilterOption[];
50
+ statusFilterOptions: FilterOption[];
51
+
52
+ // Actions
53
+ setMediaFilter: (filter: CreationCategory | CreationTypeId) => void;
54
+ setStatusFilter: (status: CreationStatus | "all") => void;
55
+ setSearchQuery: (query: string) => void;
56
+ updateFilter: (update: Partial<CreationFilter>) => void;
57
+ resetFilters: () => void;
58
+ }
59
+
60
+ /**
61
+ * Advanced filtering hook for creations
62
+ * Supports category, status, search, and sorting
63
+ */
64
+ export function useAdvancedFilter<T extends Creation>({
65
+ creations,
66
+ initialFilter,
67
+ }: UseAdvancedFilterProps<T>): UseAdvancedFilterReturn<T> {
68
+ const [filter, setFilter] = useState<CreationFilter>({
69
+ ...DEFAULT_CREATION_FILTER,
70
+ ...initialFilter,
71
+ });
72
+
73
+ // Calculate stats from all creations
74
+ const stats = useMemo(() => {
75
+ if (!creations) {
76
+ return {
77
+ total: 0,
78
+ byCategory: { all: 0, image: 0, video: 0, voice: 0 },
79
+ byStatus: { pending: 0, queued: 0, processing: 0, completed: 0, failed: 0 },
80
+ byType: {},
81
+ };
82
+ }
83
+ return calculateCreationStats(creations);
84
+ }, [creations]);
85
+
86
+ // Filter creations
87
+ const filtered = useMemo(() => {
88
+ if (!creations) return [];
89
+
90
+ let result = [...creations];
91
+
92
+ // Filter by type/category
93
+ if (filter.type && filter.type !== "all") {
94
+ const filterType = filter.type;
95
+
96
+ // Check if it's a category
97
+ if (["image", "video", "voice"].includes(filterType)) {
98
+ const category = filterType as CreationCategory;
99
+ result = result.filter((c) =>
100
+ c.type && isTypeInCategory(c.type as CreationTypeId, category)
101
+ );
102
+ } else {
103
+ // It's a specific type
104
+ result = result.filter((c) => c.type === filterType);
105
+ }
106
+ }
107
+
108
+ // Filter by status
109
+ if (filter.status && filter.status !== "all") {
110
+ result = result.filter((c) => c.status === filter.status);
111
+ }
112
+
113
+ // Filter by search query
114
+ if (filter.searchQuery && filter.searchQuery.trim()) {
115
+ const query = filter.searchQuery.toLowerCase().trim();
116
+ result = result.filter((c) => {
117
+ const prompt = c.prompt?.toLowerCase() || "";
118
+ const type = c.type?.toLowerCase() || "";
119
+ return prompt.includes(query) || type.includes(query);
120
+ });
121
+ }
122
+
123
+ // Filter by date range
124
+ if (filter.startDate) {
125
+ result = result.filter((c) => {
126
+ const createdAt = c.createdAt instanceof Date
127
+ ? c.createdAt.getTime()
128
+ : (c.createdAt || 0);
129
+ return createdAt >= filter.startDate!;
130
+ });
131
+ }
132
+
133
+ if (filter.endDate) {
134
+ result = result.filter((c) => {
135
+ const createdAt = c.createdAt instanceof Date
136
+ ? c.createdAt.getTime()
137
+ : (c.createdAt || 0);
138
+ return createdAt <= filter.endDate!;
139
+ });
140
+ }
141
+
142
+ // Sort
143
+ if (filter.sortField) {
144
+ result.sort((a, b) => {
145
+ let aVal: string | number | Date | undefined;
146
+ let bVal: string | number | Date | undefined;
147
+
148
+ switch (filter.sortField) {
149
+ case "createdAt":
150
+ aVal = a.createdAt;
151
+ bVal = b.createdAt;
152
+ break;
153
+ case "updatedAt":
154
+ aVal = a.updatedAt;
155
+ bVal = b.updatedAt;
156
+ break;
157
+ case "type":
158
+ aVal = a.type;
159
+ bVal = b.type;
160
+ break;
161
+ case "status":
162
+ aVal = a.status;
163
+ bVal = b.status;
164
+ break;
165
+ default:
166
+ return 0;
167
+ }
168
+
169
+ // Convert dates to numbers for comparison
170
+ if (aVal instanceof Date) aVal = aVal.getTime();
171
+ if (bVal instanceof Date) bVal = bVal.getTime();
172
+
173
+ // Handle undefined values
174
+ if (aVal === undefined && bVal === undefined) return 0;
175
+ if (aVal === undefined) return 1;
176
+ if (bVal === undefined) return -1;
177
+
178
+ // Compare
179
+ if (typeof aVal === "string" && typeof bVal === "string") {
180
+ return filter.sortOrder === "desc"
181
+ ? bVal.localeCompare(aVal)
182
+ : aVal.localeCompare(bVal);
183
+ }
184
+
185
+ if (typeof aVal === "number" && typeof bVal === "number") {
186
+ return filter.sortOrder === "desc" ? bVal - aVal : aVal - bVal;
187
+ }
188
+
189
+ return 0;
190
+ });
191
+ }
192
+
193
+ // Apply limit
194
+ if (filter.limit && filter.limit > 0) {
195
+ result = result.slice(0, filter.limit);
196
+ }
197
+
198
+ return result;
199
+ }, [creations, filter]);
200
+
201
+ // Media filter options with counts
202
+ const mediaFilterOptions = useMemo<FilterOption[]>(() => {
203
+ return MEDIA_FILTER_OPTIONS.map((opt) => ({
204
+ ...opt,
205
+ count: opt.id === "all"
206
+ ? stats.total
207
+ : stats.byCategory[opt.id as CreationCategory] || 0,
208
+ }));
209
+ }, [stats]);
210
+
211
+ // Status filter options with counts
212
+ const statusFilterOptions = useMemo<FilterOption[]>(() => {
213
+ return STATUS_FILTER_OPTIONS.map((opt) => ({
214
+ ...opt,
215
+ count: opt.id === "all"
216
+ ? stats.total
217
+ : stats.byStatus[opt.id as CreationStatus] || 0,
218
+ }));
219
+ }, [stats]);
220
+
221
+ // Actions
222
+ const setMediaFilter = useCallback((type: CreationCategory | CreationTypeId) => {
223
+ setFilter((prev) => ({ ...prev, type }));
224
+ }, []);
225
+
226
+ const setStatusFilter = useCallback((status: CreationStatus | "all") => {
227
+ setFilter((prev) => ({ ...prev, status }));
228
+ }, []);
229
+
230
+ const setSearchQuery = useCallback((searchQuery: string) => {
231
+ setFilter((prev) => ({ ...prev, searchQuery }));
232
+ }, []);
233
+
234
+ const updateFilter = useCallback((update: Partial<CreationFilter>) => {
235
+ setFilter((prev) => ({ ...prev, ...update }));
236
+ }, []);
237
+
238
+ const resetFilters = useCallback(() => {
239
+ setFilter(DEFAULT_CREATION_FILTER);
240
+ }, []);
241
+
242
+ // Derived state
243
+ const hasActiveFilters = filter.type !== "all" || filter.status !== "all" || !!filter.searchQuery;
244
+ const activeMediaFilter = (filter.type as string) || "all";
245
+ const activeStatusFilter = (filter.status as string) || "all";
246
+
247
+ return {
248
+ filtered,
249
+ filter,
250
+ stats,
251
+ activeMediaFilter,
252
+ activeStatusFilter,
253
+ hasActiveFilters,
254
+ mediaFilterOptions,
255
+ statusFilterOptions,
256
+ setMediaFilter,
257
+ setStatusFilter,
258
+ setSearchQuery,
259
+ updateFilter,
260
+ resetFilters,
261
+ };
262
+ }
@@ -196,14 +196,13 @@ function CreationsGalleryScreenContent({
196
196
  >
197
197
  {/* Main Content Grid - handles empty/loading via ListEmptyComponent */}
198
198
  <CreationsGrid
199
- creations={filtered}
199
+ creations={filtered as any}
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={handleView}
203
+ onShare={async (creation) => handleShare(creation as any)}
204
+ onDelete={(creation) => handleDelete(creation as any)}
205
+ onFavorite={(creation) => handleFavorite(creation as any, !(creation as any).isFavorite)}
207
206
  contentContainerStyle={{ paddingBottom: tokens.spacing.xl }}
208
207
  ListEmptyComponent={renderEmptyComponent}
209
208
  />
@@ -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";
@@ -0,0 +1,157 @@
1
+ /**
2
+ * useAIHugFeature Hook
3
+ * Manages AI hug feature state and actions
4
+ */
5
+
6
+ import { useState, useCallback } from "react";
7
+ import { executeAIHug } from "../../infrastructure/services";
8
+ import type {
9
+ AIHugFeatureState,
10
+ AIHugFeatureConfig,
11
+ AIHugResult,
12
+ } from "../../domain/types";
13
+
14
+ declare const __DEV__: boolean;
15
+
16
+ export interface UseAIHugFeatureProps {
17
+ config: AIHugFeatureConfig;
18
+ userId: string;
19
+ onSelectSourceImage: () => Promise<string | null>;
20
+ onSelectTargetImage: () => Promise<string | null>;
21
+ onSaveImage: (imageUrl: string) => Promise<void>;
22
+ }
23
+
24
+ export interface UseAIHugFeatureReturn extends AIHugFeatureState {
25
+ selectSourceImage: () => Promise<void>;
26
+ selectTargetImage: () => Promise<void>;
27
+ process: () => Promise<void>;
28
+ save: () => Promise<void>;
29
+ reset: () => void;
30
+ }
31
+
32
+ const initialState: AIHugFeatureState = {
33
+ sourceImageUri: null,
34
+ targetImageUri: null,
35
+ processedUrl: null,
36
+ isProcessing: false,
37
+ progress: 0,
38
+ error: null,
39
+ };
40
+
41
+ export function useAIHugFeature(
42
+ props: UseAIHugFeatureProps,
43
+ ): UseAIHugFeatureReturn {
44
+ const { config, userId, onSelectSourceImage, onSelectTargetImage, onSaveImage } = props;
45
+ const [state, setState] = useState<AIHugFeatureState>(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("[useAIHugFeature] Starting AI hug process");
92
+ }
93
+
94
+ const sourceImageBase64 = await config.prepareImage(state.sourceImageUri);
95
+ const targetImageBase64 = await config.prepareImage(state.targetImageUri);
96
+
97
+ const result: AIHugResult = await executeAIHug(
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,5 @@
1
+ /**
2
+ * AI Hug Presentation Index
3
+ */
4
+
5
+ export * from "./hooks";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * AI Kiss Domain Index
3
+ */
4
+
5
+ export * from "./types";