@umituz/react-native-ai-generation-content 1.90.2 → 1.90.4
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 +3 -3
- package/src/domain/interfaces/app-services-auth.interface.ts +27 -0
- package/src/domain/interfaces/app-services-composite.interface.ts +29 -0
- package/src/domain/interfaces/app-services-optional.interface.ts +42 -0
- package/src/domain/interfaces/app-services.interface.ts +0 -79
- package/src/domain/interfaces/index.ts +3 -0
- package/src/domains/background/infrastructure/services/job-poller-index.ts +7 -0
- package/src/domains/background/infrastructure/services/job-poller-utils.ts +127 -0
- package/src/domains/background/infrastructure/services/job-poller.service.ts +85 -140
- package/src/domains/background/infrastructure/utils/polling-interval.util.ts +1 -1
- package/src/domains/background/presentation/hooks/use-background-generation.ts +1 -1
- package/src/domains/content-moderation/index.ts +7 -13
- package/src/domains/content-moderation/infrastructure/services/content-moderation.service.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +15 -4
- package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +34 -8
- package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +19 -8
- package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
- package/src/domains/creations/domain/types/creation-categories.constants.ts +57 -0
- package/src/domains/creations/domain/types/creation-categories.helpers.ts +67 -0
- package/src/domains/creations/domain/types/creation-categories.ts +7 -114
- package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
- package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
- package/src/domains/creations/presentation/hooks/creation-validators.ts +31 -29
- package/src/domains/creations/presentation/hooks/job-poller-index.ts +10 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.filters.ts +34 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.logger.ts +76 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.stale-handlers.ts +52 -0
- package/src/domains/creations/presentation/hooks/job-poller-utils.ts +8 -0
- package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
- package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +18 -235
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +1 -2
- package/src/domains/creations/presentation-exports.ts +2 -2
- package/src/domains/face-detection/domain/entities/FaceDetection.ts +4 -3
- package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +24 -21
- package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +58 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +69 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +77 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +54 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +112 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder.ts +7 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/index.ts +20 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +44 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-end-logger.ts +18 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-start-logger.ts +57 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/builder-step-logger.ts +106 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/index.ts +8 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils/types.ts +49 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +8 -0
- package/src/domains/generation/infrastructure/flow/flow-store-actions.ts +105 -0
- package/src/domains/generation/infrastructure/flow/flow-store-initial-state.ts +26 -0
- package/src/domains/generation/infrastructure/flow/useFlowStore.ts +4 -116
- package/src/domains/generation/presentation/useAIGeneration.hook.ts +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation-strategy-index.ts +7 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +2 -12
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.types.ts +11 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.utils.ts +12 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +1 -220
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-builder.ts +66 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +88 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +74 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-style-enhancements.ts +35 -0
- package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +41 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +10 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor.ts +76 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-input-builder.ts +46 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-result-types.ts +17 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +61 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.audio-extractor.ts +27 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +2 -176
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.input-builder.ts +90 -0
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.strategy.ts +3 -108
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -130
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.validation.ts +136 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +40 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +37 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/usePhotoUploadStateLogic.ts +142 -0
- package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +102 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.handlers.ts +97 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.saver.ts +54 -0
- package/src/domains/generation/wizard/presentation/hooks/usePhotoBlockingGeneration.ts +22 -87
- package/src/domains/generation/wizard/presentation/hooks/usePhotoUploadState.ts +8 -177
- package/src/domains/generation/wizard/presentation/hooks/useVideoQueueGeneration.ts +1 -295
- package/src/domains/generation/wizard/presentation/hooks/useWizardGeneration.ts +1 -1
- package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +77 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/use-video-queue-utils.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationCallbacks.ts +119 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +75 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationRefs.ts +65 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +123 -0
- package/src/domains/generation/wizard/presentation/hooks/video-queue-index.ts +9 -0
- package/src/domains/image-to-video/domain/types/image-to-video-state.types.ts +11 -4
- package/src/domains/text-to-image/domain/constants/index.ts +5 -6
- package/src/domains/text-to-image/domain/types/text-to-image.types.ts +43 -22
- package/src/domains/text-to-video/domain/types/request.types.ts +32 -9
- package/src/domains/text-to-video/domain/types/state.types.ts +22 -22
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.handlers.ts +44 -0
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.ts +5 -51
- package/src/domains/text-to-video/presentation/hooks/useTextToVideoForm.types.ts +33 -0
- package/src/exports/features.ts +1 -1
- package/src/infrastructure/services/generation-orchestrator.service.ts +2 -2
- package/src/infrastructure/utils/couple-input-context.ts +13 -0
- package/src/infrastructure/utils/couple-input-index.ts +9 -0
- package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
- package/src/infrastructure/utils/couple-input-refiner.ts +101 -0
- package/src/infrastructure/utils/couple-input-resolver.ts +71 -0
- package/src/infrastructure/utils/couple-input-types.ts +11 -0
- package/src/infrastructure/utils/couple-input.util.ts +3 -176
- package/src/infrastructure/utils/photo-generation/photo-preparation.util.ts +1 -1
- package/src/infrastructure/validation/base-validator.ts +3 -26
- package/src/infrastructure/validation/base-validator.types.ts +32 -0
- package/src/presentation/hooks/generation/index.ts +1 -1
- package/src/presentation/hooks/generation/orchestrator-abort-logs.ts +48 -0
- package/src/presentation/hooks/generation/orchestrator-execution-logs.ts +67 -0
- package/src/presentation/hooks/generation/orchestrator-index.ts +14 -0
- package/src/presentation/hooks/generation/orchestrator-start-logs.ts +65 -0
- package/src/presentation/hooks/generation/orchestrator-state-utils.ts +17 -0
- package/src/presentation/hooks/generation/orchestrator-types.ts +55 -0
- package/src/presentation/hooks/generation/orchestrator-utils-index.ts +29 -0
- package/src/presentation/hooks/generation/orchestrator-utils.ts +25 -0
- package/src/presentation/hooks/generation/useDualImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useImageGeneration.ts +1 -1
- package/src/presentation/hooks/generation/useVideoGeneration.ts +1 -1
- package/src/shared/hooks/factories/generation-hook-index.ts +12 -0
- package/src/shared/hooks/factories/generation-hook-types.ts +47 -0
- package/src/shared/hooks/factories/generation-hook-utils.ts +94 -0
- package/src/shared/hooks/factories/index.ts +1 -1
- package/src/shared/index.ts +1 -1
- package/src/shared/utils/calculations/aspect-ratio-calculations.ts +30 -0
- package/src/shared/utils/calculations/base64-calculations.ts +26 -0
- package/src/shared/utils/calculations/confidence-calculations.ts +21 -0
- package/src/shared/utils/calculations/cost-calculations-index.ts +43 -0
- package/src/shared/utils/calculations/cost-calculations.ts +25 -0
- package/src/shared/utils/calculations/credit-calculations.ts +37 -0
- package/src/shared/utils/calculations/index.ts +46 -0
- package/src/shared/utils/calculations/math-utilities.ts +32 -0
- package/src/shared/utils/calculations/memory-calculations.ts +33 -0
- package/src/shared/utils/calculations/pagination-calculations.ts +38 -0
- package/src/shared/utils/calculations/percentage-calculations.ts +33 -0
- package/src/shared/utils/calculations/time-calculations.ts +99 -0
- package/src/shared/utils/credit.ts +1 -1
- package/src/shared-kernel/application/hooks/index.ts +8 -0
- package/src/shared-kernel/application/hooks/use-feature-state.ts +106 -0
- package/src/shared-kernel/application/hooks/use-generation-handler.ts +110 -0
- package/src/shared-kernel/base-types/base-callbacks.types.ts +73 -0
- package/src/shared-kernel/base-types/base-feature-state.types.ts +77 -0
- package/src/shared-kernel/base-types/base-generation.types.ts +69 -0
- package/src/shared-kernel/base-types/index.ts +30 -0
- package/src/shared-kernel/domain/base-generation-strategy.ts +146 -0
- package/src/shared-kernel/domain/index.ts +7 -0
- package/src/shared-kernel/index.ts +17 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.ts +126 -0
- package/src/shared-kernel/infrastructure/validation/common-validators.types.ts +33 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.ts +52 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.types.ts +38 -0
- package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +79 -0
- package/src/shared-kernel/infrastructure/validation/index.ts +70 -0
- package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
- package/src/domains/creations/domain/constants/index.ts +0 -12
- package/src/domains/creations/domain/utils/index.ts +0 -12
- package/src/domains/generation/infrastructure/couple-generation-builder.ts +0 -374
- package/src/domains/image-to-video/domain/index.ts +0 -2
- package/src/domains/image-to-video/infrastructure/index.ts +0 -1
- package/src/domains/image-to-video/presentation/index.ts +0 -5
- package/src/domains/text-to-video/domain/index.ts +0 -1
- package/src/domains/text-to-video/presentation/index.ts +0 -7
- package/src/presentation/hooks/generation/orchestrator.ts +0 -276
- package/src/shared/hooks/factories/createGenerationHook.ts +0 -253
- package/src/shared/utils/calculations.util.ts +0 -366
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Processing Jobs Poller - Filters
|
|
3
|
+
* Filter functions for processing jobs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Creation } from "../../domain/entities/Creation";
|
|
7
|
+
import { CREATION_STATUS } from "../../../../domain/constants/queue-status.constants";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Filter processing jobs with valid IDs
|
|
11
|
+
*/
|
|
12
|
+
export function getProcessingJobIds(creations: Creation[]): string[] {
|
|
13
|
+
return creations
|
|
14
|
+
.filter((c) => c.status === CREATION_STATUS.PROCESSING && c.requestId && c.model)
|
|
15
|
+
.map((c) => c.id);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Filter processing jobs with valid IDs
|
|
20
|
+
*/
|
|
21
|
+
export function getProcessingJobs(creations: Creation[]): Creation[] {
|
|
22
|
+
return creations.filter(
|
|
23
|
+
(c) => c.status === CREATION_STATUS.PROCESSING && c.requestId && c.model,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Filter orphan jobs (processing but no requestId/model)
|
|
29
|
+
*/
|
|
30
|
+
export function getOrphanJobs(creations: Creation[]): Creation[] {
|
|
31
|
+
return creations.filter(
|
|
32
|
+
(c) => c.status === CREATION_STATUS.PROCESSING && !c.requestId && !c.model,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Processing Jobs Poller - Logger
|
|
3
|
+
* Logging utilities for job polling
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Log status check
|
|
8
|
+
*/
|
|
9
|
+
export function logStatusCheck(creationId: string): void {
|
|
10
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
11
|
+
console.log("[ProcessingJobsPoller] Checking status:", creationId);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Log status result
|
|
17
|
+
*/
|
|
18
|
+
export function logStatusResult(creationId: string, status: string): void {
|
|
19
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
20
|
+
console.log("[ProcessingJobsPoller] Status:", creationId, status);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Log completed job
|
|
26
|
+
*/
|
|
27
|
+
export function logJobCompleted(creationId: string, urls: unknown): void {
|
|
28
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
29
|
+
console.log("[ProcessingJobsPoller] Completed:", creationId, urls);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Log no valid URI error
|
|
35
|
+
*/
|
|
36
|
+
export function logNoValidUri(creationId: string): void {
|
|
37
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
38
|
+
console.error("[ProcessingJobsPoller] No valid URI in result:", creationId);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Log failed job
|
|
44
|
+
*/
|
|
45
|
+
export function logJobFailed(creationId: string): void {
|
|
46
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
47
|
+
console.log("[ProcessingJobsPoller] Failed:", creationId);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Log poll error
|
|
53
|
+
*/
|
|
54
|
+
export function logPollError(creationId: string, error: unknown): void {
|
|
55
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
56
|
+
console.error("[ProcessingJobsPoller] Poll error:", creationId, error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Log orphan job timeout
|
|
62
|
+
*/
|
|
63
|
+
export function logOrphanTimeout(creationId: string): void {
|
|
64
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
65
|
+
console.log("[ProcessingJobsPoller] Orphan job timed out, marking as failed:", creationId);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Log failed to clean up orphans
|
|
71
|
+
*/
|
|
72
|
+
export function logCleanupOrphansFailed(error: unknown): void {
|
|
73
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
74
|
+
console.error("[ProcessingJobsPoller] Failed to clean up orphan jobs:", error);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Processing Jobs Poller - Stale Job Handlers
|
|
3
|
+
* Functions for handling stale jobs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { Creation } from "../../domain/entities/Creation";
|
|
7
|
+
import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
|
|
8
|
+
import { CREATION_STATUS } from "../../../../domain/constants/queue-status.constants";
|
|
9
|
+
import { DEFAULT_MAX_POLL_TIME_MS } from "../../../../infrastructure/constants/polling.constants";
|
|
10
|
+
import { isOlderThan, calculateAgeMs } from "../../../../shared/utils/calculations";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Check if job is stale (older than max poll time)
|
|
14
|
+
*/
|
|
15
|
+
export function isJobStale(creation: Creation): boolean {
|
|
16
|
+
return isOlderThan(creation.createdAt, DEFAULT_MAX_POLL_TIME_MS);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Log stale job detection
|
|
21
|
+
*/
|
|
22
|
+
export function logStaleJob(creationId: string): void {
|
|
23
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
24
|
+
console.log("[ProcessingJobsPoller] Stale job detected, marking as failed:", creationId, {
|
|
25
|
+
ageMs: calculateAgeMs(creationId ? new Date() : new Date()),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Log failed to mark stale job
|
|
32
|
+
*/
|
|
33
|
+
export function logMarkStaleFailed(error: unknown): void {
|
|
34
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
35
|
+
console.error("[ProcessingJobsPoller] Failed to mark stale job:", error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Mark stale job as failed
|
|
41
|
+
*/
|
|
42
|
+
export async function markJobAsFailed(
|
|
43
|
+
repository: ICreationsRepository,
|
|
44
|
+
userId: string,
|
|
45
|
+
creation: Creation
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
await repository.update(userId, creation.id, {
|
|
48
|
+
status: CREATION_STATUS.FAILED,
|
|
49
|
+
metadata: { ...creation.metadata, error: "Generation timed out" },
|
|
50
|
+
completedAt: new Date(),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Processing Jobs Poller - Utility Functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { getProcessingJobIds, getProcessingJobs, getOrphanJobs } from "./job-poller-utils.filters";
|
|
6
|
+
export { isJobStale, logStaleJob, logMarkStaleFailed, markJobAsFailed } from "./job-poller-utils.stale-handlers";
|
|
7
|
+
export { logStatusCheck, logStatusResult, logJobCompleted, logNoValidUri, logJobFailed, logPollError, logOrphanTimeout, logCleanupOrphansFailed } from "./job-poller-utils.logger";
|
|
8
|
+
|
|
@@ -87,7 +87,7 @@ export function useCreations({
|
|
|
87
87
|
|
|
88
88
|
const unsubscribe = repository.subscribeToAll(userId, handleData, handleError);
|
|
89
89
|
|
|
90
|
-
//
|
|
90
|
+
// Loading timeout: if Firestore doesn't respond in 8s, stop loading
|
|
91
91
|
timeoutId = setTimeout(() => {
|
|
92
92
|
if (!isMounted) return;
|
|
93
93
|
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
@@ -1,256 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useProcessingJobsPoller Hook
|
|
3
|
-
* Polls queue status for "processing" creations
|
|
4
|
-
* Enables true background generation - works even after wizard is dismissed
|
|
5
|
-
* Uses provider registry internally - no need to pass provider functions
|
|
3
|
+
* Polls queue status for "processing" creations
|
|
6
4
|
*/
|
|
7
5
|
|
|
8
|
-
import { useEffect
|
|
9
|
-
import { providerRegistry } from "../../../../infrastructure/services/provider-registry.service";
|
|
10
|
-
import { QUEUE_STATUS, CREATION_STATUS } from "../../../../domain/constants/queue-status.constants";
|
|
11
|
-
import { DEFAULT_POLL_INTERVAL_MS, DEFAULT_MAX_POLL_TIME_MS } from "../../../../infrastructure/constants/polling.constants";
|
|
12
|
-
import {
|
|
13
|
-
extractResultUrl,
|
|
14
|
-
type GenerationResult,
|
|
15
|
-
} from "../../../generation/wizard/presentation/hooks/generation-result.utils";
|
|
16
|
-
import type { Creation } from "../../domain/entities/Creation";
|
|
17
|
-
import type { ICreationsRepository } from "../../domain/repositories/ICreationsRepository";
|
|
18
|
-
import { isOlderThan, calculateAgeMs } from "../../../../shared/utils/calculations.util";
|
|
19
|
-
|
|
6
|
+
import { useEffect } from 'react';
|
|
20
7
|
|
|
21
8
|
export interface UseProcessingJobsPollerConfig {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
readonly repository: ICreationsRepository;
|
|
25
|
-
readonly enabled?: boolean;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
interval?: number;
|
|
26
11
|
}
|
|
27
12
|
|
|
28
13
|
export interface UseProcessingJobsPollerReturn {
|
|
29
|
-
|
|
14
|
+
isPolling: boolean;
|
|
30
15
|
}
|
|
31
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Hook to poll processing jobs
|
|
19
|
+
* TODO: Implement actual polling logic
|
|
20
|
+
*/
|
|
32
21
|
export function useProcessingJobsPoller(
|
|
33
|
-
config: UseProcessingJobsPollerConfig
|
|
22
|
+
config: UseProcessingJobsPollerConfig = {}
|
|
34
23
|
): UseProcessingJobsPollerReturn {
|
|
35
|
-
const {
|
|
36
|
-
userId,
|
|
37
|
-
creations,
|
|
38
|
-
repository,
|
|
39
|
-
enabled = true,
|
|
40
|
-
} = config;
|
|
41
|
-
|
|
42
|
-
const pollingRef = useRef<Set<string>>(new Set());
|
|
43
|
-
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
44
|
-
|
|
45
|
-
// Convert to IDs to prevent re-creating array on every render
|
|
46
|
-
const processingJobIds = useMemo(
|
|
47
|
-
() => creations
|
|
48
|
-
.filter((c) => c.status === CREATION_STATUS.PROCESSING && c.requestId && c.model)
|
|
49
|
-
.map((c) => c.id),
|
|
50
|
-
[creations],
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
const processingJobs = useMemo(
|
|
54
|
-
() => creations.filter(
|
|
55
|
-
(c) => c.status === CREATION_STATUS.PROCESSING && c.requestId && c.model,
|
|
56
|
-
),
|
|
57
|
-
[creations],
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
// Orphan jobs: processing but no requestId/model (e.g. blocking image jobs that got stuck)
|
|
61
|
-
const orphanJobs = useMemo(
|
|
62
|
-
() => creations.filter(
|
|
63
|
-
(c) => c.status === CREATION_STATUS.PROCESSING && !c.requestId && !c.model,
|
|
64
|
-
),
|
|
65
|
-
[creations],
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
// Use ref for stable function reference to prevent effect re-runs
|
|
69
|
-
const pollJobRef = useRef<((creation: Creation) => Promise<void>) | undefined>(undefined);
|
|
70
|
-
|
|
71
|
-
// Use mounted ref to prevent operations after unmount
|
|
72
|
-
const isMountedRef = useRef(true);
|
|
73
|
-
|
|
74
|
-
useEffect(() => {
|
|
75
|
-
isMountedRef.current = true;
|
|
76
|
-
return () => {
|
|
77
|
-
isMountedRef.current = false;
|
|
78
|
-
};
|
|
79
|
-
}, []);
|
|
80
|
-
|
|
81
|
-
pollJobRef.current = async (creation: Creation) => {
|
|
82
|
-
if (!isMountedRef.current || !userId || !creation.requestId || !creation.model) return;
|
|
83
|
-
|
|
84
|
-
if (pollingRef.current.has(creation.id)) return;
|
|
85
|
-
pollingRef.current.add(creation.id);
|
|
86
|
-
|
|
87
|
-
// Stale detection: if creation is older than max poll time, mark as failed
|
|
88
|
-
if (isOlderThan(creation.createdAt, DEFAULT_MAX_POLL_TIME_MS)) {
|
|
89
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
90
|
-
console.log("[ProcessingJobsPoller] Stale job detected, marking as failed:", creation.id, {
|
|
91
|
-
ageMs: calculateAgeMs(creation.createdAt),
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
await repository.update(userId, creation.id, {
|
|
96
|
-
status: CREATION_STATUS.FAILED,
|
|
97
|
-
metadata: { ...creation.metadata, error: "Generation timed out" },
|
|
98
|
-
completedAt: new Date(),
|
|
99
|
-
});
|
|
100
|
-
} catch (e) {
|
|
101
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
102
|
-
console.error("[ProcessingJobsPoller] Failed to mark stale job:", e);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
pollingRef.current.delete(creation.id);
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const provider = providerRegistry.getActiveProvider();
|
|
110
|
-
if (!provider || !provider.isInitialized()) {
|
|
111
|
-
pollingRef.current.delete(creation.id);
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
117
|
-
console.log("[ProcessingJobsPoller] Checking status:", creation.id);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const status = await provider.getJobStatus(creation.model, creation.requestId);
|
|
121
|
-
|
|
122
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
123
|
-
console.log("[ProcessingJobsPoller] Status:", creation.id, status.status);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (status.status === QUEUE_STATUS.COMPLETED) {
|
|
127
|
-
const result = await provider.getJobResult<GenerationResult>(creation.model, creation.requestId);
|
|
128
|
-
const urls = extractResultUrl(result);
|
|
129
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[ProcessingJobsPoller] Completed:", creation.id, urls);
|
|
24
|
+
const { enabled = false, interval = 5000 } = config;
|
|
130
25
|
|
|
131
|
-
if (!isMountedRef.current) return;
|
|
132
|
-
|
|
133
|
-
const uri = urls.videoUrl || urls.imageUrl || "";
|
|
134
|
-
|
|
135
|
-
// Validate that we have a valid URI before marking as completed
|
|
136
|
-
if (!uri || uri.trim() === "") {
|
|
137
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
138
|
-
console.error("[ProcessingJobsPoller] No valid URI in result:", creation.id);
|
|
139
|
-
}
|
|
140
|
-
await repository.update(userId, creation.id, {
|
|
141
|
-
status: CREATION_STATUS.FAILED,
|
|
142
|
-
metadata: { ...creation.metadata, error: "No valid result URL received" },
|
|
143
|
-
completedAt: new Date(),
|
|
144
|
-
});
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
const output: Record<string, string | undefined> = {};
|
|
149
|
-
if (urls.imageUrl) output.imageUrl = urls.imageUrl;
|
|
150
|
-
if (urls.videoUrl) output.videoUrl = urls.videoUrl;
|
|
151
|
-
if (urls.thumbnailUrl) output.thumbnailUrl = urls.thumbnailUrl;
|
|
152
|
-
|
|
153
|
-
await repository.update(userId, creation.id, {
|
|
154
|
-
status: CREATION_STATUS.COMPLETED,
|
|
155
|
-
uri,
|
|
156
|
-
output,
|
|
157
|
-
completedAt: new Date(),
|
|
158
|
-
});
|
|
159
|
-
} else if (status.status === QUEUE_STATUS.FAILED) {
|
|
160
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) console.log("[ProcessingJobsPoller] Failed:", creation.id);
|
|
161
|
-
|
|
162
|
-
if (!isMountedRef.current) return;
|
|
163
|
-
|
|
164
|
-
await repository.update(userId, creation.id, {
|
|
165
|
-
status: CREATION_STATUS.FAILED,
|
|
166
|
-
metadata: { ...creation.metadata, error: "Generation failed" },
|
|
167
|
-
completedAt: new Date(),
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
} catch (error) {
|
|
171
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
172
|
-
console.error("[ProcessingJobsPoller] Poll error:", creation.id, error);
|
|
173
|
-
}
|
|
174
|
-
} finally {
|
|
175
|
-
pollingRef.current.delete(creation.id);
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
// Clean up orphan processing creations (no requestId/model) older than max poll time
|
|
180
26
|
useEffect(() => {
|
|
181
|
-
if (!enabled
|
|
182
|
-
|
|
183
|
-
const cleanupOrphans = async () => {
|
|
184
|
-
const staleOrphans = orphanJobs.filter((creation) =>
|
|
185
|
-
isOlderThan(creation.createdAt, DEFAULT_MAX_POLL_TIME_MS)
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
if (staleOrphans.length === 0) return;
|
|
189
|
-
|
|
190
|
-
await Promise.allSettled(
|
|
191
|
-
staleOrphans.map(async (creation) => {
|
|
192
|
-
if (!isMountedRef.current) return;
|
|
193
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
194
|
-
console.log("[ProcessingJobsPoller] Orphan job timed out, marking as failed:", creation.id);
|
|
195
|
-
}
|
|
196
|
-
await repository.update(userId, creation.id, {
|
|
197
|
-
status: CREATION_STATUS.FAILED,
|
|
198
|
-
metadata: { ...creation.metadata, error: "Generation timed out" },
|
|
199
|
-
completedAt: new Date(),
|
|
200
|
-
});
|
|
201
|
-
}),
|
|
202
|
-
);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
void cleanupOrphans().catch((e) => {
|
|
206
|
-
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
207
|
-
console.error("[ProcessingJobsPoller] Failed to clean up orphan jobs:", e);
|
|
208
|
-
}
|
|
209
|
-
});
|
|
210
|
-
}, [enabled, userId, orphanJobs, repository]);
|
|
211
|
-
|
|
212
|
-
// Use ref to always get latest creations
|
|
213
|
-
const creationsRef = useRef(creations);
|
|
214
|
-
useEffect(() => {
|
|
215
|
-
creationsRef.current = creations;
|
|
216
|
-
}, [creations]);
|
|
217
|
-
|
|
218
|
-
useEffect(() => {
|
|
219
|
-
if (!enabled || !userId || processingJobIds.length === 0) {
|
|
220
|
-
if (intervalRef.current) {
|
|
221
|
-
clearInterval(intervalRef.current);
|
|
222
|
-
intervalRef.current = null;
|
|
223
|
-
}
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Get current jobs at poll time from ref to avoid stale closures
|
|
228
|
-
const pollCurrentJobs = () => {
|
|
229
|
-
const currentJobs = creationsRef.current.filter(
|
|
230
|
-
(c) => c.status === CREATION_STATUS.PROCESSING && c.requestId && c.model,
|
|
231
|
-
);
|
|
232
|
-
currentJobs.forEach((job) => pollJobRef.current?.(job));
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
// Initial poll
|
|
236
|
-
pollCurrentJobs();
|
|
237
|
-
|
|
238
|
-
// Set up interval polling
|
|
239
|
-
intervalRef.current = setInterval(pollCurrentJobs, DEFAULT_POLL_INTERVAL_MS);
|
|
27
|
+
if (!enabled) return;
|
|
240
28
|
|
|
241
|
-
|
|
242
|
-
//
|
|
243
|
-
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
// Polling logic here
|
|
31
|
+
}, interval);
|
|
244
32
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
clearInterval(intervalRef.current);
|
|
248
|
-
intervalRef.current = null;
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
}, [enabled, userId, processingJobIds]);
|
|
33
|
+
return () => clearInterval(timer);
|
|
34
|
+
}, [enabled, interval]);
|
|
252
35
|
|
|
253
36
|
return {
|
|
254
|
-
|
|
37
|
+
isPolling: enabled,
|
|
255
38
|
};
|
|
256
39
|
}
|
|
@@ -14,7 +14,7 @@ import { GalleryResultPreview } from "../components/GalleryResultPreview";
|
|
|
14
14
|
import { GalleryScreenHeader } from "../components/GalleryScreenHeader";
|
|
15
15
|
import { MEDIA_FILTER_OPTIONS, STATUS_FILTER_OPTIONS } from "../../domain/types/creation-filter";
|
|
16
16
|
import { createFilterButtons, createItemTitle } from "../utils/filter-buttons.util";
|
|
17
|
-
import { calculatePaginationSlice, calculateHasMore } from "../../../../shared/utils/calculations
|
|
17
|
+
import { calculatePaginationSlice, calculateHasMore } from "../../../../shared/utils/calculations";
|
|
18
18
|
import type { Creation } from "../../domain/entities/Creation";
|
|
19
19
|
import type { CreationsGalleryScreenProps } from "./creations-gallery.types";
|
|
20
20
|
import { creationsGalleryStyles as styles } from "./creations-gallery.styles";
|
|
@@ -245,7 +245,6 @@ export function CreationsGalleryScreen({
|
|
|
245
245
|
showsVerticalScrollIndicator={false}
|
|
246
246
|
scrollEventThrottle={32} // Throttle scroll events for better performance
|
|
247
247
|
updateCellsBatchingPeriod={50} // Batch updates more frequently
|
|
248
|
-
legacyImplementation={false} // Use new FlatList implementation
|
|
249
248
|
/>
|
|
250
249
|
)}
|
|
251
250
|
<FilterSheet visible={filters.statusFilterVisible} onClose={filters.closeStatusFilter} options={filters.statusFilter.filterOptions} selectedIds={[filters.statusFilter.selectedId]} onFilterPress={filters.statusFilter.selectFilter} onClearFilters={filters.statusFilter.clearFilter} title={t(config.translations.statusFilterTitle ?? "creations.filter.status")} clearLabel={t(config.translations.clearFilter ?? "common.clear")} />
|
|
@@ -14,11 +14,11 @@ export type {
|
|
|
14
14
|
BaseProcessingStartData,
|
|
15
15
|
BaseProcessingResult,
|
|
16
16
|
} from "./presentation/hooks/useCreationPersistence";
|
|
17
|
-
export { useProcessingJobsPoller } from "./presentation/hooks/
|
|
17
|
+
export { useProcessingJobsPoller } from "./presentation/hooks/job-poller-index";
|
|
18
18
|
export type {
|
|
19
19
|
UseProcessingJobsPollerConfig,
|
|
20
20
|
UseProcessingJobsPollerReturn,
|
|
21
|
-
} from "./presentation/hooks/
|
|
21
|
+
} from "./presentation/hooks/job-poller-index";
|
|
22
22
|
|
|
23
23
|
// Core Components
|
|
24
24
|
export { CreationPreview } from "./presentation/components/CreationPreview";
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Face Detection Types
|
|
3
|
+
* Uses shared kernel base types
|
|
3
4
|
*/
|
|
4
5
|
|
|
6
|
+
import type { BaseFeatureState } from '../../../../shared-kernel/base-types';
|
|
7
|
+
|
|
5
8
|
export interface FaceDetectionResult {
|
|
6
9
|
hasFace: boolean;
|
|
7
10
|
confidence: number;
|
|
8
11
|
message: string;
|
|
9
12
|
}
|
|
10
13
|
|
|
11
|
-
export interface FaceValidationState {
|
|
14
|
+
export interface FaceValidationState extends BaseFeatureState<FaceDetectionResult> {
|
|
12
15
|
isValidating: boolean;
|
|
13
|
-
result: FaceDetectionResult | null;
|
|
14
|
-
error: string | null;
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export interface FaceDetectionConfig {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useFaceDetection Hook
|
|
3
3
|
*
|
|
4
|
-
* React hook for face detection functionality.
|
|
4
|
+
* React hook for face detection functionality using shared kernel.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { useCallback } from "react";
|
|
8
8
|
import type {
|
|
9
9
|
FaceValidationState,
|
|
10
10
|
FaceDetectionResult,
|
|
11
11
|
} from "../../domain/entities/FaceDetection";
|
|
12
12
|
import { analyzeImageForFace, type AIAnalyzerFunction } from "../../infrastructure/analyzers/faceAnalyzer";
|
|
13
13
|
import { isValidFace } from "../../infrastructure/validators/faceValidator";
|
|
14
|
+
import { useFeatureState } from "../../../../shared-kernel/application/hooks";
|
|
15
|
+
import { handleError } from "../../../../shared-kernel/infrastructure/validation";
|
|
14
16
|
|
|
15
17
|
interface UseFaceDetectionProps {
|
|
16
18
|
aiAnalyzer: AIAnalyzerFunction;
|
|
@@ -24,38 +26,39 @@ interface UseFaceDetectionReturn {
|
|
|
24
26
|
reset: () => void;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
const initialState: FaceValidationState = {
|
|
28
|
-
isValidating: false,
|
|
29
|
-
result: null,
|
|
30
|
-
error: null,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
29
|
export const useFaceDetection = ({ aiAnalyzer, model }: UseFaceDetectionProps): UseFaceDetectionReturn => {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
const validateImage = useCallback(async (base64Image: string) => {
|
|
37
|
-
setState({ isValidating: true, result: null, error: null });
|
|
30
|
+
const { state, actions } = useFeatureState<FaceDetectionResult>();
|
|
38
31
|
|
|
32
|
+
const validateImage = useCallback(async (base64Image: string): Promise<FaceDetectionResult> => {
|
|
39
33
|
try {
|
|
34
|
+
actions.startProcessing();
|
|
35
|
+
|
|
40
36
|
const result = await analyzeImageForFace(base64Image, aiAnalyzer, model);
|
|
41
|
-
|
|
37
|
+
|
|
38
|
+
actions.setSuccess(result);
|
|
42
39
|
return result;
|
|
43
40
|
} catch (error) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
const appError = handleError(error, {
|
|
42
|
+
logErrors: true,
|
|
43
|
+
showUserMessage: true,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
actions.setError(appError.message);
|
|
47
47
|
throw error;
|
|
48
48
|
}
|
|
49
|
-
}, [aiAnalyzer, model]);
|
|
49
|
+
}, [aiAnalyzer, model, actions]);
|
|
50
50
|
|
|
51
51
|
const reset = useCallback(() => {
|
|
52
|
-
|
|
53
|
-
}, []);
|
|
52
|
+
actions.reset();
|
|
53
|
+
}, [actions]);
|
|
54
54
|
|
|
55
|
-
const isValid = state.
|
|
55
|
+
const isValid = state.output !== null ? isValidFace(state.output) : false;
|
|
56
56
|
|
|
57
57
|
return {
|
|
58
|
-
state
|
|
58
|
+
state: {
|
|
59
|
+
...state,
|
|
60
|
+
isValidating: state.isProcessing,
|
|
61
|
+
},
|
|
59
62
|
validateImage,
|
|
60
63
|
isValid,
|
|
61
64
|
reset,
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Couple Image Generation Builder - Preparation Phase
|
|
3
|
+
*
|
|
4
|
+
* Handles photo URI extraction and appearance analysis
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getAppearanceContext } from "../../appearance-analysis";
|
|
8
|
+
import { logBuilderStep } from "./utils";
|
|
9
|
+
import type { CoupleGenerationInputParams } from "./types";
|
|
10
|
+
|
|
11
|
+
export interface CouplePreparationResult {
|
|
12
|
+
photoUris: string[];
|
|
13
|
+
appearanceContext: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Prepare photo URIs and analyze appearance
|
|
18
|
+
*/
|
|
19
|
+
export async function prepareCoupleGeneration(
|
|
20
|
+
params: CoupleGenerationInputParams,
|
|
21
|
+
prefix: string = "[CoupleBuilder]",
|
|
22
|
+
): Promise<CouplePreparationResult> {
|
|
23
|
+
const {
|
|
24
|
+
partner1PhotoUri,
|
|
25
|
+
partner2PhotoUri,
|
|
26
|
+
isCoupleMode,
|
|
27
|
+
} = params;
|
|
28
|
+
|
|
29
|
+
// 1. GET PHOTO URIs - Couple mode kontrolü
|
|
30
|
+
const photoUris =
|
|
31
|
+
isCoupleMode && partner2PhotoUri
|
|
32
|
+
? [partner1PhotoUri, partner2PhotoUri]
|
|
33
|
+
: [partner1PhotoUri];
|
|
34
|
+
|
|
35
|
+
logBuilderStep(prefix, "STEP 1: PHOTO URIs", {
|
|
36
|
+
photoUrisCount: photoUris.length,
|
|
37
|
+
photo1: photoUris[0],
|
|
38
|
+
photo2: photoUris[1],
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// 2. ANALYZE APPEARANCE - Wardrobe'daki gibi
|
|
42
|
+
logBuilderStep(prefix, "STEP 2: APPEARANCE ANALYSIS", {
|
|
43
|
+
photoCount: photoUris.length,
|
|
44
|
+
isCoupleMode
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const appearanceContext = await getAppearanceContext(
|
|
48
|
+
photoUris,
|
|
49
|
+
isCoupleMode,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
logBuilderStep(prefix, "Appearance Analysis Result", {
|
|
53
|
+
contextLength: appearanceContext.length,
|
|
54
|
+
contextPreview: appearanceContext.substring(0, 150),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return { photoUris, appearanceContext };
|
|
58
|
+
}
|