@umituz/react-native-ai-generation-content 1.90.3 → 1.90.5
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/index.ts +3 -0
- package/src/domains/background/infrastructure/services/job-poller-utils.ts +0 -3
- package/src/domains/background/infrastructure/services/job-poller.service.ts +179 -0
- package/src/domains/content-moderation/index.ts +7 -13
- package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/text.moderator.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts +1 -1
- package/src/domains/content-moderation/infrastructure/services/pattern-matcher.service.ts +1 -2
- package/src/domains/creations/domain/types/creation-categories.helpers.ts +2 -2
- package/src/domains/creations/domain/types/creation-categories.ts +2 -3
- package/src/domains/creations/domain/utils/creation-display.util.ts +1 -1
- package/src/domains/creations/domain/utils/index.ts +46 -8
- package/src/domains/creations/domain/utils/status-helpers.ts +1 -1
- package/src/domains/creations/presentation/hooks/useCreations.ts +1 -1
- package/src/domains/creations/presentation/hooks/useProcessingJobsPoller.ts +39 -0
- package/src/domains/creations/presentation/screens/CreationsGalleryScreen.tsx +0 -1
- package/src/domains/face-detection/presentation/hooks/useFaceDetection.ts +1 -1
- package/src/domains/generation/infrastructure/appearance-analysis/index.ts +5 -0
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-preparation.ts +1 -1
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts +2 -2
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts +2 -2
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple.ts +1 -1
- package/src/domains/generation/infrastructure/couple-generation-builder/builder-scenario.ts +2 -3
- package/src/domains/generation/infrastructure/couple-generation-builder/types.ts +1 -1
- package/src/domains/generation/infrastructure/couple-generation-builder/utils.ts +2 -2
- package/src/domains/generation/infrastructure/flow/useFlowStore.ts +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-extraction.ts +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-strategy-factory.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation-submission.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/video-generation.types.ts +0 -1
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/index.ts +1 -0
- package/src/domains/generation/wizard/presentation/hooks/photo-upload/types.ts +1 -1
- package/src/domains/generation/wizard/presentation/hooks/use-video-queue-utils.ts +0 -1
- package/src/domains/generation/wizard/presentation/hooks/video-queue/index.ts +0 -5
- 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 +1 -2
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationPolling.ts +1 -2
- package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts +2 -2
- 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 +0 -1
- package/src/domains/text-to-video/domain/types/request.types.ts +0 -1
- package/src/domains/text-to-video/domain/types/state.types.ts +0 -20
- package/src/exports/features.ts +1 -1
- package/src/infrastructure/utils/couple-input-index.ts +1 -0
- package/src/infrastructure/utils/couple-input-photorealistic.ts +40 -0
- package/src/infrastructure/utils/couple-input-types.ts +1 -4
- package/src/infrastructure/utils/couple-input.util.ts +1 -1
- package/src/infrastructure/validation/base-validator.ts +3 -0
- package/src/shared-kernel/application/hooks/use-feature-state.ts +0 -1
- package/src/shared-kernel/infrastructure/validation/error-handler.utils.ts +1 -1
- package/src/shared-kernel/infrastructure/validation/index.ts +64 -22
- package/src/domains/content-moderation/infrastructure/services/index.ts +0 -8
- package/src/domains/creations/domain/constants/index.ts +0 -12
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-ai-generation-content",
|
|
3
|
-
"version": "1.90.
|
|
3
|
+
"version": "1.90.5",
|
|
4
4
|
"description": "Provider-agnostic AI generation orchestration for React Native with result preview components",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"@tanstack/react-query": "^5.66.7",
|
|
74
74
|
"@tanstack/react-query-persist-client": "^5.66.7",
|
|
75
75
|
"@types/react": "~19.1.10",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
77
|
-
"@typescript-eslint/parser": "^8.
|
|
76
|
+
"@typescript-eslint/eslint-plugin": "^8.57.1",
|
|
77
|
+
"@typescript-eslint/parser": "^8.57.1",
|
|
78
78
|
"@umituz/react-native-ai-fal-provider": "*",
|
|
79
79
|
"@umituz/react-native-design-system": "*",
|
|
80
80
|
"@umituz/react-native-firebase": "*",
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
export * from "./ai-provider.interface";
|
|
7
7
|
export * from "./app-services.interface";
|
|
8
|
+
export * from "./app-services-auth.interface";
|
|
9
|
+
export * from "./app-services-composite.interface";
|
|
10
|
+
export * from "./app-services-optional.interface";
|
|
8
11
|
|
|
9
12
|
// Video Model Configuration
|
|
10
13
|
export type { VideoModelConfig, ModelCapabilityOption } from "./video-model-config.types";
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
* Job Poller Service - Utility Functions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
|
|
6
|
-
import { validateResult } from "../utils/result-validator.util";
|
|
7
|
-
|
|
8
5
|
/**
|
|
9
6
|
* Wrap a promise with abort signal support
|
|
10
7
|
* Rejects if signal is aborted before promise resolves
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Job Poller Service
|
|
3
|
+
* Provider-agnostic job polling with exponential backoff
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { JobStatus } from "../../../../domain/interfaces/ai-provider.interface";
|
|
7
|
+
import type { PollingConfig } from "../../../../domain/entities/polling.types";
|
|
8
|
+
import type { PollJobOptions, PollJobResult } from "./job-poller.types";
|
|
9
|
+
import { withAbortSignal, validateRequestId, validateModel, logTransientError, logMaxConsecutiveErrors } from "./job-poller-utils";
|
|
10
|
+
import { checkStatusForErrors, isJobComplete } from "../utils/status-checker.util";
|
|
11
|
+
import { validateResult } from "../utils/result-validator.util";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default polling configuration
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_CONFIG: Partial<PollingConfig> = {
|
|
17
|
+
maxAttempts: 40,
|
|
18
|
+
initialIntervalMs: 1500,
|
|
19
|
+
maxIntervalMs: 5000,
|
|
20
|
+
backoffMultiplier: 1.3,
|
|
21
|
+
maxConsecutiveErrors: 5,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Poll a job until completion or timeout
|
|
26
|
+
*/
|
|
27
|
+
export async function pollJob<T = unknown>(
|
|
28
|
+
options: PollJobOptions
|
|
29
|
+
): Promise<PollJobResult<T>> {
|
|
30
|
+
const {
|
|
31
|
+
provider,
|
|
32
|
+
model,
|
|
33
|
+
requestId,
|
|
34
|
+
config = DEFAULT_CONFIG,
|
|
35
|
+
onProgress,
|
|
36
|
+
onStatusChange,
|
|
37
|
+
signal,
|
|
38
|
+
} = options;
|
|
39
|
+
|
|
40
|
+
// Validate inputs
|
|
41
|
+
const requestIdValidation = validateRequestId(requestId);
|
|
42
|
+
if (!requestIdValidation.valid) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: new Error(requestIdValidation.error!),
|
|
46
|
+
attempts: 0,
|
|
47
|
+
elapsedMs: 0,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const modelValidation = validateModel(model);
|
|
52
|
+
if (!modelValidation.valid) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
error: new Error(modelValidation.error!),
|
|
56
|
+
attempts: 0,
|
|
57
|
+
elapsedMs: 0,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const startTime = Date.now();
|
|
62
|
+
let currentInterval = config.initialIntervalMs || DEFAULT_CONFIG.initialIntervalMs!;
|
|
63
|
+
const maxInterval = config.maxIntervalMs || DEFAULT_CONFIG.maxIntervalMs!;
|
|
64
|
+
const maxAttempts = config.maxAttempts || DEFAULT_CONFIG.maxAttempts!;
|
|
65
|
+
const backoffMultiplier = config.backoffMultiplier || DEFAULT_CONFIG.backoffMultiplier!;
|
|
66
|
+
const maxConsecutiveErrors = config.maxConsecutiveErrors || DEFAULT_CONFIG.maxConsecutiveErrors!;
|
|
67
|
+
|
|
68
|
+
let consecutiveErrors = 0;
|
|
69
|
+
|
|
70
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
71
|
+
// Check for abort signal
|
|
72
|
+
if (signal?.aborted) {
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error: new Error("Operation aborted"),
|
|
76
|
+
attempts: attempt + 1,
|
|
77
|
+
elapsedMs: Date.now() - startTime,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Check job status
|
|
83
|
+
const statusResult = await withAbortSignal(
|
|
84
|
+
provider.checkStatus(requestId, model),
|
|
85
|
+
signal,
|
|
86
|
+
config.maxTotalTimeMs ? config.maxTotalTimeMs - (Date.now() - startTime) : undefined
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Notify status change
|
|
90
|
+
if (onStatusChange && typeof statusResult === 'object' && 'status' in statusResult) {
|
|
91
|
+
onStatusChange(statusResult as JobStatus);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check for errors in status
|
|
95
|
+
const statusError = checkStatusForErrors(statusResult as JobStatus | Record<string, unknown>);
|
|
96
|
+
if (statusError) {
|
|
97
|
+
return {
|
|
98
|
+
success: false,
|
|
99
|
+
error: statusError,
|
|
100
|
+
attempts: attempt + 1,
|
|
101
|
+
elapsedMs: Date.now() - startTime,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Reset consecutive errors on success
|
|
106
|
+
consecutiveErrors = 0;
|
|
107
|
+
|
|
108
|
+
// Check if job is complete
|
|
109
|
+
if (isJobComplete(statusResult as JobStatus | Record<string, unknown>)) {
|
|
110
|
+
// Validate result
|
|
111
|
+
const validationResult = validateResult(statusResult);
|
|
112
|
+
if (!validationResult.isValid) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: new Error(validationResult.errorMessage || "Result validation failed"),
|
|
116
|
+
attempts: attempt + 1,
|
|
117
|
+
elapsedMs: Date.now() - startTime,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Report progress
|
|
122
|
+
onProgress?.(100);
|
|
123
|
+
|
|
124
|
+
// Extract result data if available
|
|
125
|
+
let data: T | undefined = undefined;
|
|
126
|
+
if (typeof statusResult === 'object' && statusResult !== null && 'result' in statusResult) {
|
|
127
|
+
data = statusResult.result as T;
|
|
128
|
+
} else {
|
|
129
|
+
data = statusResult as T;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
success: true,
|
|
134
|
+
data,
|
|
135
|
+
attempts: attempt + 1,
|
|
136
|
+
elapsedMs: Date.now() - startTime,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Report progress based on attempt number
|
|
141
|
+
const progress = Math.min((attempt / maxAttempts) * 100, 90);
|
|
142
|
+
onProgress?.(progress);
|
|
143
|
+
|
|
144
|
+
} catch (error) {
|
|
145
|
+
consecutiveErrors++;
|
|
146
|
+
logTransientError(attempt, requestId, model, consecutiveErrors, error);
|
|
147
|
+
|
|
148
|
+
// Check if we've hit max consecutive errors
|
|
149
|
+
if (consecutiveErrors >= maxConsecutiveErrors) {
|
|
150
|
+
logMaxConsecutiveErrors(maxConsecutiveErrors, requestId, model);
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
154
|
+
attempts: attempt + 1,
|
|
155
|
+
elapsedMs: Date.now() - startTime,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Wait before next attempt with exponential backoff
|
|
161
|
+
await withAbortSignal(
|
|
162
|
+
new Promise(resolve => setTimeout(resolve, currentInterval)),
|
|
163
|
+
signal
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Increase interval for next attempt (exponential backoff)
|
|
167
|
+
currentInterval = Math.min(currentInterval * backoffMultiplier, maxInterval);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Max attempts reached
|
|
171
|
+
return {
|
|
172
|
+
success: false,
|
|
173
|
+
error: new Error(`Job did not complete after ${maxAttempts} attempts`),
|
|
174
|
+
attempts: maxAttempts,
|
|
175
|
+
elapsedMs: Date.now() - startTime,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export type { PollJobOptions, PollJobResult } from './job-poller.types';
|
|
@@ -38,19 +38,13 @@ export type {
|
|
|
38
38
|
// INFRASTRUCTURE LAYER - Services
|
|
39
39
|
// =============================================================================
|
|
40
40
|
|
|
41
|
-
export {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
BaseModerator,
|
|
49
|
-
} from "./infrastructure/services";
|
|
50
|
-
|
|
51
|
-
export type {
|
|
52
|
-
PatternMatch,
|
|
53
|
-
} from "./infrastructure/services";
|
|
41
|
+
export { contentModerationService } from "./infrastructure/services/content-moderation.service";
|
|
42
|
+
export { patternMatcherService, type PatternMatch } from "./infrastructure/services/pattern-matcher.service";
|
|
43
|
+
export { textModerator } from "./infrastructure/services/moderators/text.moderator";
|
|
44
|
+
export { imageModerator } from "./infrastructure/services/moderators/image.moderator";
|
|
45
|
+
export { videoModerator } from "./infrastructure/services/moderators/video.moderator";
|
|
46
|
+
export { voiceModerator } from "./infrastructure/services/moderators/voice.moderator";
|
|
47
|
+
export { BaseModerator } from "./infrastructure/services/moderators/base.moderator";
|
|
54
48
|
|
|
55
49
|
// =============================================================================
|
|
56
50
|
// INFRASTRUCTURE LAYER - Rules
|
package/src/domains/content-moderation/infrastructure/services/moderators/image.moderator.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { Violation } from "../../../domain/entities/moderation.types";
|
|
7
7
|
import { BaseModerator, type ModerationResult } from "./base.moderator";
|
|
8
8
|
import { DEFAULT_PROTOCOLS, DEFAULT_MAX_URI_LENGTH } from "../../constants/moderation.constants";
|
|
9
|
-
import { validateUrl, validateString, validateRequiredFields } from "
|
|
9
|
+
import { validateUrl, validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
|
|
10
10
|
|
|
11
11
|
class ImageModerator extends BaseModerator {
|
|
12
12
|
private allowedProtocols: readonly string[] = DEFAULT_PROTOCOLS;
|
|
@@ -10,7 +10,7 @@ import { BaseModerator, type ModerationResult } from "./base.moderator";
|
|
|
10
10
|
import { DEFAULT_MAX_TEXT_LENGTH } from "../../constants/moderation.constants";
|
|
11
11
|
import { containsMaliciousPatterns } from "../../utils/content-security.util";
|
|
12
12
|
import { containsPromptInjection } from "../../utils/prompt-injection.util";
|
|
13
|
-
import { validateString, validateRequiredFields } from "
|
|
13
|
+
import { validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class TextModerator extends BaseModerator {
|
package/src/domains/content-moderation/infrastructure/services/moderators/video.moderator.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { Violation } from "../../../domain/entities/moderation.types";
|
|
7
7
|
import { BaseModerator, type ModerationResult } from "./base.moderator";
|
|
8
8
|
import { VIDEO_PROTOCOLS, DEFAULT_MAX_URI_LENGTH } from "../../constants/moderation.constants";
|
|
9
|
-
import { validateUrl, validateString, validateRequiredFields } from "
|
|
9
|
+
import { validateUrl, validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
|
|
10
10
|
|
|
11
11
|
class VideoModerator extends BaseModerator {
|
|
12
12
|
private allowedProtocols: readonly string[] = VIDEO_PROTOCOLS;
|
package/src/domains/content-moderation/infrastructure/services/moderators/voice.moderator.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { patternMatcherService } from "../pattern-matcher.service";
|
|
|
8
8
|
import { rulesRegistry } from "../../rules/rules-registry";
|
|
9
9
|
import { BaseModerator, type ModerationResult } from "./base.moderator";
|
|
10
10
|
import { env } from "../../../../../infrastructure/config/env.config";
|
|
11
|
-
import { validateString, validateRequiredFields } from "
|
|
11
|
+
import { validateString, validateRequiredFields } from "../../../../../shared-kernel/infrastructure/validation";
|
|
12
12
|
|
|
13
13
|
class VoiceModerator extends BaseModerator {
|
|
14
14
|
private maxLength = env.moderationVoiceMaxLength;
|
|
@@ -113,8 +113,7 @@ class PatternMatcherService {
|
|
|
113
113
|
const regex = new RegExp(escaped, "gi");
|
|
114
114
|
return regex.test(content);
|
|
115
115
|
} catch {
|
|
116
|
-
|
|
117
|
-
return content.toLowerCase().includes(searchTerm.toLowerCase());
|
|
116
|
+
return false;
|
|
118
117
|
}
|
|
119
118
|
}
|
|
120
119
|
|
|
@@ -25,7 +25,7 @@ export function getTypesForCategory(
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* Get category for a creation type
|
|
28
|
+
* Get category for a creation type
|
|
29
29
|
*/
|
|
30
30
|
export function getCategoryForType(type: CreationTypeId): CreationCategory {
|
|
31
31
|
if (IMAGE_CREATION_TYPES.includes(type)) {
|
|
@@ -34,7 +34,7 @@ export function getCategoryForType(type: CreationTypeId): CreationCategory {
|
|
|
34
34
|
if (VIDEO_CREATION_TYPES.includes(type)) {
|
|
35
35
|
return "video";
|
|
36
36
|
}
|
|
37
|
-
return "image";
|
|
37
|
+
return "image";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
@@ -25,7 +25,7 @@ export function getCategoryForCreation(creation: {
|
|
|
25
25
|
};
|
|
26
26
|
uri?: string;
|
|
27
27
|
}): CreationCategory {
|
|
28
|
-
//
|
|
28
|
+
// Check output field names
|
|
29
29
|
if (creation.output?.videoUrl) {
|
|
30
30
|
return "video";
|
|
31
31
|
}
|
|
@@ -34,12 +34,11 @@ export function getCategoryForCreation(creation: {
|
|
|
34
34
|
return "image";
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
//
|
|
37
|
+
// Use type-based categorization
|
|
38
38
|
if (creation.type) {
|
|
39
39
|
return getCategoryForType(creation.type as import("./creation-types").CreationTypeId);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
// Final fallback
|
|
43
42
|
return "image";
|
|
44
43
|
}
|
|
45
44
|
|
|
@@ -1,12 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Creation Domain Utils
|
|
3
|
-
* Utility functions for creation
|
|
3
|
+
* Utility functions for creation display, formatting, and helpers
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export
|
|
6
|
+
// Display utilities
|
|
7
|
+
export {
|
|
8
|
+
truncateText,
|
|
9
|
+
} from './creation-display.util';
|
|
10
|
+
|
|
11
|
+
// Format utilities
|
|
12
|
+
export {
|
|
13
|
+
generateCreationId,
|
|
14
|
+
} from './creation-format.util';
|
|
15
|
+
|
|
16
|
+
// Search utilities
|
|
17
|
+
export {
|
|
18
|
+
filterBySearch,
|
|
19
|
+
} from './creation-search.util';
|
|
20
|
+
|
|
21
|
+
// Sort utilities
|
|
22
|
+
export {
|
|
23
|
+
sortCreations,
|
|
24
|
+
} from './creation-sort.util';
|
|
25
|
+
|
|
26
|
+
// Preview helpers
|
|
27
|
+
export {
|
|
28
|
+
getPreviewUrl,
|
|
29
|
+
getAllMediaUrls,
|
|
30
|
+
hasDownloadableContent,
|
|
31
|
+
hasVideoContent,
|
|
32
|
+
hasAudioContent,
|
|
33
|
+
getPrimaryMediaUrl,
|
|
34
|
+
} from './preview-helpers';
|
|
35
|
+
|
|
36
|
+
// Status helpers
|
|
37
|
+
export {
|
|
38
|
+
getStatusColorKey,
|
|
39
|
+
getStatusColor,
|
|
40
|
+
getStatusTextKey,
|
|
41
|
+
getStatusText,
|
|
42
|
+
isInProgress,
|
|
43
|
+
isCompleted,
|
|
44
|
+
isFailed,
|
|
45
|
+
} from './status-helpers';
|
|
46
|
+
|
|
47
|
+
// Types
|
|
48
|
+
export type { StatusColorKey } from './status-helpers';
|
|
49
|
+
export type { IconName } from './creation-display.util';
|
|
50
|
+
export type { CreationOutput } from './preview-helpers';
|
|
@@ -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__) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useProcessingJobsPoller Hook
|
|
3
|
+
* Polls queue status for "processing" creations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { useEffect } from 'react';
|
|
7
|
+
|
|
8
|
+
export interface UseProcessingJobsPollerConfig {
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
interval?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UseProcessingJobsPollerReturn {
|
|
14
|
+
isPolling: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Hook to poll processing jobs
|
|
19
|
+
* TODO: Implement actual polling logic
|
|
20
|
+
*/
|
|
21
|
+
export function useProcessingJobsPoller(
|
|
22
|
+
config: UseProcessingJobsPollerConfig = {}
|
|
23
|
+
): UseProcessingJobsPollerReturn {
|
|
24
|
+
const { enabled = false, interval = 5000 } = config;
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (!enabled) return;
|
|
28
|
+
|
|
29
|
+
const timer = setInterval(() => {
|
|
30
|
+
// Polling logic here
|
|
31
|
+
}, interval);
|
|
32
|
+
|
|
33
|
+
return () => clearInterval(timer);
|
|
34
|
+
}, [enabled, interval]);
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
isPolling: enabled,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -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")} />
|
|
@@ -12,7 +12,7 @@ import type {
|
|
|
12
12
|
import { analyzeImageForFace, type AIAnalyzerFunction } from "../../infrastructure/analyzers/faceAnalyzer";
|
|
13
13
|
import { isValidFace } from "../../infrastructure/validators/faceValidator";
|
|
14
14
|
import { useFeatureState } from "../../../../shared-kernel/application/hooks";
|
|
15
|
-
import { handleError
|
|
15
|
+
import { handleError } from "../../../../shared-kernel/infrastructure/validation";
|
|
16
16
|
|
|
17
17
|
interface UseFaceDetectionProps {
|
|
18
18
|
aiAnalyzer: AIAnalyzerFunction;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Handles photo URI extraction and appearance analysis
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getAppearanceContext } from "
|
|
7
|
+
import { getAppearanceContext } from "../../appearance-analysis";
|
|
8
8
|
import { logBuilderStep } from "./utils";
|
|
9
9
|
import type { CoupleGenerationInputParams } from "./types";
|
|
10
10
|
|
package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-prompt.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import {
|
|
8
8
|
prependContext,
|
|
9
9
|
refinePromptForCouple,
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
createPhotorealisticPrompt,
|
|
11
|
+
} from "../../../../infrastructure/utils/couple-input.util";
|
|
12
12
|
import { logBuilderStep } from "./utils";
|
|
13
13
|
import type { CoupleGenerationInputParams } from "./types";
|
|
14
14
|
|
package/src/domains/generation/infrastructure/couple-generation-builder/builder-couple-resolution.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import {
|
|
8
8
|
resolveCoupleInput,
|
|
9
|
-
} from "
|
|
10
|
-
import { logBuilderStep, logBuilderEnd
|
|
9
|
+
} from "../../../../infrastructure/utils/couple-input.util";
|
|
10
|
+
import { logBuilderStep, logBuilderEnd } from "./utils";
|
|
11
11
|
import type {
|
|
12
12
|
CoupleGenerationInputParams,
|
|
13
13
|
CoupleGenerationInput,
|
|
@@ -44,7 +44,7 @@ export async function buildCoupleGenerationInput(
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
// Phase 1: Prepare photo URIs and analyze appearance
|
|
47
|
-
const {
|
|
47
|
+
const { appearanceContext } = await prepareCoupleGeneration(params, prefix);
|
|
48
48
|
|
|
49
49
|
// Phase 2: Process and refine prompt
|
|
50
50
|
const { prompt } = processCouplePrompt(params, appearanceContext, prefix);
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
resolveCoupleInput,
|
|
9
9
|
refinePromptForCouple,
|
|
10
10
|
prependContext,
|
|
11
|
-
} from "
|
|
12
|
-
import { getAppearanceContext } from "
|
|
11
|
+
} from "../../../../infrastructure/utils/couple-input.util";
|
|
12
|
+
import { getAppearanceContext } from "../../appearance-analysis";
|
|
13
13
|
import type {
|
|
14
14
|
ScenarioGenerationInputParams,
|
|
15
15
|
CoupleGenerationInput,
|
|
@@ -25,7 +25,6 @@ import { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils";
|
|
|
25
25
|
export async function buildScenarioGenerationInput(
|
|
26
26
|
params: ScenarioGenerationInputParams,
|
|
27
27
|
): Promise<CoupleGenerationInput> {
|
|
28
|
-
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
29
28
|
|
|
30
29
|
const {
|
|
31
30
|
partner1PhotoUri,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Bu utility'yi tüm çift görüntü oluşturma işlemleri kullanır.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { GenerationTargetLike } from "
|
|
8
|
+
import type { GenerationTargetLike } from "../../../../infrastructure/utils/couple-input.util";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Couple generation input parameters
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* Logging and helper functions for the couple generation builder
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils";
|
|
8
|
-
export type { BuilderStartParams, BuilderStepParams } from "./utils";
|
|
7
|
+
export { logBuilderStart, logBuilderStep, logBuilderEnd } from "./utils/index";
|
|
8
|
+
export type { BuilderStartParams, BuilderStepParams } from "./utils/types";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { createStore } from "@umituz/react-native-design-system/storage";
|
|
6
6
|
|
|
7
|
-
import type {
|
|
7
|
+
import type { FlowActions } from "../../../../domain/entities/flow-config.types";
|
|
8
8
|
import type { FlowStoreState, FlowStoreConfig } from "./use-flow-store.types";
|
|
9
9
|
import { createInitialState } from "./flow-store-initial-state";
|
|
10
10
|
import { createFlowActions } from "./flow-store-actions";
|
|
@@ -55,7 +55,7 @@ export async function extractImageData(
|
|
|
55
55
|
console.log("[ImageStrategy] Base64 photos count:", photos.length);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
// Extract prompt
|
|
58
|
+
// Extract prompt
|
|
59
59
|
let prompt = extractPrompt(wizardData, scenario.aiPrompt);
|
|
60
60
|
|
|
61
61
|
if (DEV) {
|
package/src/domains/generation/wizard/infrastructure/strategies/image-input-prompt-builder.ts
CHANGED
|
@@ -22,7 +22,6 @@ export async function buildImagePrompt(
|
|
|
22
22
|
context: PromptBuildContext,
|
|
23
23
|
): Promise<string> {
|
|
24
24
|
const { photos, photoUris, prompt, wizardData } = context;
|
|
25
|
-
const DEV = typeof __DEV__ !== "undefined" && __DEV__;
|
|
26
25
|
|
|
27
26
|
// Apply style enhancements for photo-based generation
|
|
28
27
|
if (photos.length === 0) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Image Generation Strategy - Strategy Factory
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
|
|
6
5
|
import type { WizardStrategy } from "./wizard-strategy.types";
|
|
7
6
|
import type { CreateImageStrategyOptions } from "./image-generation.types";
|
|
8
7
|
import { executeImageGeneration } from "./image-generation.executor";
|
package/src/domains/generation/wizard/infrastructure/strategies/video-generation-executor-index.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Video Generation Executor
|
|
3
3
|
* Handles the actual video generation execution.
|
|
4
4
|
* Model-agnostic: uses VideoModelConfig.buildInput() for model-specific parameters.
|
|
5
|
-
* Fallback: generic input builder when no modelConfig is provided.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
export { executeVideoGeneration } from "./video-generation-executor";
|
package/src/domains/generation/wizard/infrastructure/strategies/video-generation.executor.ts
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Video Generation Executor
|
|
3
3
|
* Handles the actual video generation execution.
|
|
4
4
|
* Model-agnostic: uses VideoModelConfig.buildInput() for model-specific parameters.
|
|
5
|
-
* Fallback: generic input builder when no modelConfig is provided.
|
|
6
5
|
*/
|
|
7
6
|
|
|
8
7
|
export { executeVideoGeneration, submitVideoGenerationToQueue, buildGenericInput } from "./video-generation-executor-index";
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import type { WizardScenarioData } from "../../presentation/hooks/useWizardGeneration";
|
|
7
|
-
import type { ScenarioInputType } from "../../../../scenarios/domain/Scenario";
|
|
8
7
|
import type { VideoModelConfig } from "../../../../../domain/interfaces/video-model-config.types";
|
|
9
8
|
|
|
10
9
|
export interface WizardVideoInput {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Uses design system's useMedia hook for media picking with built-in validation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { UploadedImage } from "./types";
|
|
7
8
|
import { useState } from "react";
|
|
8
9
|
import type { UsePhotoUploadStateProps, UsePhotoUploadStateReturn } from "./types";
|
|
9
10
|
import { usePhotoUploadStateLogic } from "./usePhotoUploadStateLogic";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Generic Photo Upload State Hook - Type Definitions
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import type { UploadedImage } from "
|
|
5
|
+
import type { UploadedImage } from "../../../../../../../presentation/hooks/generation/useAIGenerateState";
|
|
6
6
|
|
|
7
7
|
export interface PhotoUploadConfig {
|
|
8
8
|
readonly maxFileSizeMB?: number;
|
|
@@ -3,15 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { useEffect } from "react";
|
|
6
|
-
import type { GenerationUrls } from "../generation-result.utils";
|
|
7
6
|
import type {
|
|
8
7
|
UseVideoQueueGenerationProps,
|
|
9
8
|
UseVideoQueueGenerationReturn,
|
|
10
9
|
} from "../use-video-queue-generation.types";
|
|
11
|
-
import {
|
|
12
|
-
createClearPolling,
|
|
13
|
-
createResetRefs,
|
|
14
|
-
} from "./use-video-queue-utils";
|
|
15
10
|
import { useVideoQueueGenerationRefs, useVideoQueueGenerationState } from "./useVideoQueueGenerationRefs";
|
|
16
11
|
import { useCompletionHandler, useErrorHandler } from "./useVideoQueueGenerationCallbacks";
|
|
17
12
|
import { usePollStatus, useCallbackRefs } from "./useVideoQueueGenerationPolling";
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Video Queue Utilities
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface VideoQueueUtils {
|
|
6
|
+
isQueueFull: () => boolean;
|
|
7
|
+
getQueueSize: () => number;
|
|
8
|
+
clearQueue: () => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createVideoQueueUtils(): VideoQueueUtils {
|
|
12
|
+
return {
|
|
13
|
+
isQueueFull: () => false,
|
|
14
|
+
getQueueSize: () => 0,
|
|
15
|
+
clearQueue: () => {},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
import type { VideoQueueRefs } from "./useVideoQueueGenerationRefs";
|
|
20
|
+
import type { VideoQueueState } from "./useVideoQueueGenerationRefs";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a clear polling function
|
|
24
|
+
*/
|
|
25
|
+
export function createClearPolling(refs: VideoQueueRefs): () => void {
|
|
26
|
+
const { pollingRef } = refs;
|
|
27
|
+
return () => {
|
|
28
|
+
if (pollingRef.current) {
|
|
29
|
+
clearInterval(pollingRef.current);
|
|
30
|
+
pollingRef.current = null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a reset refs function
|
|
37
|
+
*/
|
|
38
|
+
export function createResetRefs(
|
|
39
|
+
refs: VideoQueueRefs,
|
|
40
|
+
state: VideoQueueState
|
|
41
|
+
): () => void {
|
|
42
|
+
const {
|
|
43
|
+
creationIdRef,
|
|
44
|
+
requestIdRef,
|
|
45
|
+
modelRef,
|
|
46
|
+
isGeneratingRef,
|
|
47
|
+
isPollingRef,
|
|
48
|
+
consecutiveErrorsRef,
|
|
49
|
+
pollStartTimeRef,
|
|
50
|
+
} = refs;
|
|
51
|
+
const { setIsGenerating } = state;
|
|
52
|
+
|
|
53
|
+
return () => {
|
|
54
|
+
creationIdRef.current = null;
|
|
55
|
+
requestIdRef.current = null;
|
|
56
|
+
modelRef.current = null;
|
|
57
|
+
isGeneratingRef.current = false;
|
|
58
|
+
isPollingRef.current = false;
|
|
59
|
+
consecutiveErrorsRef.current = 0;
|
|
60
|
+
pollStartTimeRef.current = null;
|
|
61
|
+
setIsGenerating(false);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Log completion event
|
|
67
|
+
*/
|
|
68
|
+
export function logCompletion(
|
|
69
|
+
creationId: string | null,
|
|
70
|
+
userId: string | undefined,
|
|
71
|
+
urls: { videoUrl?: string; imageUrl?: string },
|
|
72
|
+
hasCallback: boolean
|
|
73
|
+
): void {
|
|
74
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
75
|
+
console.log("[VideoQueue] ✅ Generation completed", {
|
|
76
|
+
creationId,
|
|
77
|
+
userId,
|
|
78
|
+
hasVideoUrl: !!urls.videoUrl,
|
|
79
|
+
hasImageUrl: !!urls.imageUrl,
|
|
80
|
+
hasCallback,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log error event
|
|
87
|
+
*/
|
|
88
|
+
export function logError(message: string, data?: Record<string, unknown>): void {
|
|
89
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
90
|
+
console.error("[VideoQueue] ❌ Error:", message, data);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Validate completion data
|
|
96
|
+
*/
|
|
97
|
+
export function validateCompletionData(
|
|
98
|
+
creationId: string | null,
|
|
99
|
+
userId: string | undefined,
|
|
100
|
+
uri: string
|
|
101
|
+
): boolean {
|
|
102
|
+
return !!(creationId && userId && uri);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract input metadata for generation
|
|
107
|
+
*/
|
|
108
|
+
export function extractInputMetadata(params: {
|
|
109
|
+
readonly model: string;
|
|
110
|
+
readonly prompt: string;
|
|
111
|
+
readonly imageUrls?: string[];
|
|
112
|
+
}): {
|
|
113
|
+
readonly model: string;
|
|
114
|
+
readonly prompt: string;
|
|
115
|
+
readonly imageUrls: string[];
|
|
116
|
+
} {
|
|
117
|
+
return {
|
|
118
|
+
model: params.model,
|
|
119
|
+
prompt: params.prompt,
|
|
120
|
+
imageUrls: params.imageUrls || [],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
@@ -24,8 +24,7 @@ export function useCompletionHandler(
|
|
|
24
24
|
clearPolling: () => void,
|
|
25
25
|
resetRefs: () => void,
|
|
26
26
|
) {
|
|
27
|
-
const { userId, persistence,
|
|
28
|
-
const { setIsGenerating } = state;
|
|
27
|
+
const { userId, persistence, creditCost, deductCredits, onSuccess, onError } = props;
|
|
29
28
|
|
|
30
29
|
return useCallback(
|
|
31
30
|
async (urls: GenerationUrls) => {
|
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
import { useCallback, useEffect } from "react";
|
|
6
6
|
import { pollQueueStatus } from "../videoQueuePoller";
|
|
7
7
|
import {
|
|
8
|
-
DEFAULT_POLL_INTERVAL_MS,
|
|
9
8
|
DEFAULT_MAX_POLL_TIME_MS,
|
|
10
|
-
} from "
|
|
9
|
+
} from "../../../../../../infrastructure/constants/polling.constants";
|
|
11
10
|
import type { VideoQueueRefs } from "./useVideoQueueGenerationRefs";
|
|
12
11
|
|
|
13
12
|
/**
|
package/src/domains/generation/wizard/presentation/hooks/video-queue/useVideoQueueGenerationStart.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { useCallback } from "react";
|
|
6
6
|
import {
|
|
7
7
|
DEFAULT_POLL_INTERVAL_MS,
|
|
8
|
-
} from "
|
|
8
|
+
} from "../../../../../../infrastructure/constants/polling.constants";
|
|
9
9
|
import { extractInputMetadata } from "./use-video-queue-utils";
|
|
10
10
|
import type {
|
|
11
11
|
UseVideoQueueGenerationProps,
|
|
@@ -19,7 +19,7 @@ export function useStartGeneration(
|
|
|
19
19
|
props: UseVideoQueueGenerationProps,
|
|
20
20
|
refs: VideoQueueRefs,
|
|
21
21
|
state: VideoQueueState,
|
|
22
|
-
|
|
22
|
+
_clearPolling: () => void,
|
|
23
23
|
): (input: unknown, prompt: string) => Promise<void> {
|
|
24
24
|
const { userId, scenario, persistence, strategy, creditCost, onError } = props;
|
|
25
25
|
const { setIsGenerating } = state;
|
|
@@ -8,18 +8,17 @@ export {
|
|
|
8
8
|
export interface PromptSuggestion {
|
|
9
9
|
readonly id: string;
|
|
10
10
|
readonly translationKey: string;
|
|
11
|
-
readonly fallbackText: string;
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
/** Default text-to-image example prompts */
|
|
15
14
|
export const DEFAULT_TEXT_TO_IMAGE_PROMPTS: readonly PromptSuggestion[] = [
|
|
16
|
-
{ id: "1", translationKey: "prompts.text2image.fantasy"
|
|
17
|
-
{ id: "2", translationKey: "prompts.text2image.portrait"
|
|
18
|
-
{ id: "3", translationKey: "prompts.text2image.landscape"
|
|
15
|
+
{ id: "1", translationKey: "prompts.text2image.fantasy" },
|
|
16
|
+
{ id: "2", translationKey: "prompts.text2image.portrait" },
|
|
17
|
+
{ id: "3", translationKey: "prompts.text2image.landscape" },
|
|
19
18
|
];
|
|
20
19
|
|
|
21
20
|
/** Default text-to-voice example prompts */
|
|
22
21
|
export const DEFAULT_TEXT_TO_VOICE_PROMPTS: readonly PromptSuggestion[] = [
|
|
23
|
-
{ id: "1", translationKey: "prompts.text2voice.greeting"
|
|
24
|
-
{ id: "2", translationKey: "prompts.text2voice.story"
|
|
22
|
+
{ id: "1", translationKey: "prompts.text2voice.greeting" },
|
|
23
|
+
{ id: "2", translationKey: "prompts.text2voice.story" },
|
|
25
24
|
];
|
|
@@ -29,17 +29,6 @@ export interface TextToVideoFormState {
|
|
|
29
29
|
professionalMode: boolean;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/**
|
|
33
|
-
* Text-to-video generation state
|
|
34
|
-
* Legacy state for backward compatibility
|
|
35
|
-
*/
|
|
36
|
-
export interface TextToVideoGenerationState {
|
|
37
|
-
isGenerating: boolean;
|
|
38
|
-
progress: number;
|
|
39
|
-
contentWarnings: string[];
|
|
40
|
-
error: string | null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
32
|
/**
|
|
44
33
|
* Frame data structure
|
|
45
34
|
*/
|
|
@@ -62,12 +51,3 @@ export const INITIAL_FORM_STATE: TextToVideoFormState = {
|
|
|
62
51
|
professionalMode: false,
|
|
63
52
|
};
|
|
64
53
|
|
|
65
|
-
/**
|
|
66
|
-
* Initial generation state
|
|
67
|
-
*/
|
|
68
|
-
export const INITIAL_GENERATION_STATE: TextToVideoGenerationState = {
|
|
69
|
-
isGenerating: false,
|
|
70
|
-
progress: 0,
|
|
71
|
-
contentWarnings: [],
|
|
72
|
-
error: null,
|
|
73
|
-
};
|
package/src/exports/features.ts
CHANGED
|
@@ -47,7 +47,7 @@ export type {
|
|
|
47
47
|
UseTextToVideoFormProps, UseTextToVideoFormReturn, ExecuteTextToVideoOptions,
|
|
48
48
|
} from "../domains/text-to-video";
|
|
49
49
|
export {
|
|
50
|
-
INITIAL_FORM_STATE,
|
|
50
|
+
INITIAL_FORM_STATE,
|
|
51
51
|
executeTextToVideo, hasTextToVideoSupport,
|
|
52
52
|
useTextToVideoFeature, useTextToVideoForm,
|
|
53
53
|
GenerationTabs, FrameSelector, OptionsPanel, HeroSection, HintCarousel,
|
|
@@ -5,4 +5,5 @@
|
|
|
5
5
|
export { resolveCoupleInput } from "./couple-input-resolver";
|
|
6
6
|
export { prependContext } from "./couple-input-context";
|
|
7
7
|
export { refinePromptForCouple } from "./couple-input-refiner";
|
|
8
|
+
export { createPhotorealisticPrompt } from "./couple-input-photorealistic";
|
|
8
9
|
export type { GenerationTargetLike } from "./couple-input-types";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Couple Input Utilities - Photorealistic Prompt Enhancement
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface PhotorealisticPromptOptions {
|
|
6
|
+
readonly isCouple?: boolean;
|
|
7
|
+
readonly customInstructions?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Create a photorealistic prompt from refined input
|
|
12
|
+
* Adds photorealistic enhancements to the base prompt
|
|
13
|
+
*/
|
|
14
|
+
export function createPhotorealisticPrompt(
|
|
15
|
+
refinedPrompt: string,
|
|
16
|
+
options: PhotorealisticPromptOptions = {}
|
|
17
|
+
): string {
|
|
18
|
+
const { isCouple = false, customInstructions } = options;
|
|
19
|
+
|
|
20
|
+
// Photorealistic quality keywords
|
|
21
|
+
const photorealisticPrefix = "high quality, photorealistic, detailed, 8k, professional photography";
|
|
22
|
+
|
|
23
|
+
// Build the final prompt
|
|
24
|
+
let finalPrompt = refinedPrompt;
|
|
25
|
+
|
|
26
|
+
// Add custom instructions if provided
|
|
27
|
+
if (customInstructions) {
|
|
28
|
+
finalPrompt = `${customInstructions}. ${finalPrompt}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Add photorealistic prefix
|
|
32
|
+
finalPrompt = `${photorealisticPrefix}, ${finalPrompt}`;
|
|
33
|
+
|
|
34
|
+
// Add couple-specific enhancements
|
|
35
|
+
if (isCouple) {
|
|
36
|
+
finalPrompt = `${finalPrompt}, romantic couple, natural lighting, candid moment`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return finalPrompt;
|
|
40
|
+
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Couple Input Utilities
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export { resolveCoupleInput, prependContext, refinePromptForCouple } from "./couple-input-index";
|
|
5
|
+
export { resolveCoupleInput, prependContext, refinePromptForCouple, createPhotorealisticPrompt } from "./couple-input-index";
|
|
6
6
|
export type { GenerationTargetLike } from "./couple-input-index";
|
|
7
7
|
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
|
|
6
6
|
import type { ValidationResult, StringValidationOptions, NumericValidationOptions } from "./base-validator.types";
|
|
7
7
|
|
|
8
|
+
// Re-export types for convenience
|
|
9
|
+
export type { ValidationResult, StringValidationOptions, NumericValidationOptions };
|
|
10
|
+
|
|
8
11
|
/**
|
|
9
12
|
* Validates a string input against provided rules
|
|
10
13
|
*/
|
|
@@ -1,28 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
3
|
-
* Exports all validation and error handling utilities
|
|
2
|
+
* Shared Validation Utilities
|
|
4
3
|
*/
|
|
5
4
|
|
|
5
|
+
// Export types from base-validator.types
|
|
6
6
|
export type {
|
|
7
7
|
ValidationResult,
|
|
8
8
|
StringValidationOptions,
|
|
9
|
-
|
|
10
|
-
} from
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
9
|
+
NumericValidationOptions,
|
|
10
|
+
} from "../../../infrastructure/validation/base-validator.types";
|
|
11
|
+
|
|
12
|
+
// Export functions from advanced-validator
|
|
13
|
+
export { combineValidationResults } from "../../../infrastructure/validation/advanced-validator";
|
|
14
|
+
|
|
15
|
+
// Export error handling utilities
|
|
16
|
+
export { handleError } from "./error-handler";
|
|
17
|
+
export { ErrorType } from "./error-handler.types";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Validate a string is not empty
|
|
21
|
+
*/
|
|
22
|
+
export function validateString(value: string): ValidationResult {
|
|
23
|
+
if (typeof value !== 'string') {
|
|
24
|
+
return { isValid: false, errors: ['Value must be a string'] };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (value.trim().length === 0) {
|
|
28
|
+
return { isValid: false, errors: ['String cannot be empty'] };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { isValid: true, errors: [] };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Validate URL format
|
|
36
|
+
*/
|
|
37
|
+
export function validateUrl(url: string): ValidationResult {
|
|
38
|
+
if (typeof url !== 'string') {
|
|
39
|
+
return { isValid: false, errors: ['URL must be a string'] };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
new URL(url);
|
|
44
|
+
return { isValid: true, errors: [] };
|
|
45
|
+
} catch {
|
|
46
|
+
return { isValid: false, errors: ['Invalid URL format'] };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Validate required fields in an object
|
|
52
|
+
*/
|
|
53
|
+
export function validateRequiredFields<T extends Record<string, unknown>>(
|
|
54
|
+
obj: T,
|
|
55
|
+
requiredFields: (keyof T)[]
|
|
56
|
+
): { isValid: boolean; missingFields: string[] } {
|
|
57
|
+
const missingFields: string[] = [];
|
|
58
|
+
|
|
59
|
+
for (const field of requiredFields) {
|
|
60
|
+
const value = obj[field];
|
|
61
|
+
if (value === undefined || value === null || value === '') {
|
|
62
|
+
missingFields.push(String(field));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
isValid: missingFields.length === 0,
|
|
68
|
+
missingFields,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creation Domain Constants - Modular Exports
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// Status constants
|
|
6
|
-
export * from "./creation-status.constants";
|
|
7
|
-
|
|
8
|
-
// Field name constants
|
|
9
|
-
export * from "./creation-fields.constants";
|
|
10
|
-
|
|
11
|
-
// Validation rule constants
|
|
12
|
-
export * from "./creation-validation.constants";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./services";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./types";
|