@umituz/react-native-ai-generation-content 1.83.85 → 1.83.87
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 +1 -1
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.executor.ts +12 -27
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.strategy.ts +1 -4
- package/src/domains/generation/wizard/infrastructure/strategies/image-generation.types.ts +1 -7
- package/src/domains/generation/wizard/presentation/hooks/wizard-generation.types.ts +1 -3
- package/src/domains/prompts/domain/base/constants.ts +0 -6
- package/src/domains/prompts/domain/base/creators.ts +0 -32
- package/src/domains/prompts/index.ts +4 -62
- package/src/domains/scenarios/domain/Scenario.ts +0 -8
- package/src/domains/scenarios/index.ts +0 -1
- package/src/domains/generation/wizard/infrastructure/strategies/shared/unified-prompt-builder.ts +0 -76
- package/src/domains/prompts/domain/entities/AIPromptTemplate.ts +0 -48
- package/src/domains/prompts/domain/entities/GeneratedPrompt.ts +0 -31
- package/src/domains/prompts/domain/entities/MultiPersonPromptStructure.ts +0 -67
- package/src/domains/prompts/domain/entities/image-prompt-segments.ts +0 -95
- package/src/domains/prompts/domain/entities/types.ts +0 -27
- package/src/domains/prompts/domain/entities/value-objects.ts +0 -33
- package/src/domains/prompts/domain/repositories/IAIPromptServices.ts +0 -21
- package/src/domains/prompts/domain/repositories/IPromptHistoryRepository.ts +0 -10
- package/src/domains/prompts/domain/repositories/ITemplateRepository.ts +0 -11
- package/src/domains/prompts/infrastructure/builders/face-preservation-builder.ts +0 -116
- package/src/domains/prompts/infrastructure/builders/interaction-style-builder.ts +0 -146
- package/src/domains/prompts/infrastructure/repositories/PromptHistoryRepository.ts +0 -45
- package/src/domains/prompts/infrastructure/repositories/TemplateRepository.ts +0 -77
- package/src/domains/prompts/infrastructure/services/ImagePromptBuilder.ts +0 -104
- package/src/domains/prompts/infrastructure/services/PromptGenerationService.ts +0 -59
- package/src/domains/prompts/infrastructure/services/image-prompt-builder.types.ts +0 -17
- package/src/domains/prompts/infrastructure/utils/prompt-creators.util.ts +0 -41
- package/src/domains/prompts/presentation/hooks/useAsyncState.ts +0 -56
- package/src/domains/prompts/presentation/hooks/usePromptGeneration.ts +0 -143
- package/src/domains/prompts/presentation/hooks/useTemplateRepository.ts +0 -113
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import type { AIPromptVariableType } from './types';
|
|
2
|
-
|
|
3
|
-
export interface AIPromptVariable {
|
|
4
|
-
name: string;
|
|
5
|
-
type: AIPromptVariableType;
|
|
6
|
-
description: string;
|
|
7
|
-
required: boolean;
|
|
8
|
-
defaultValue?: string | number | boolean;
|
|
9
|
-
options?: string[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface AIPromptSafety {
|
|
13
|
-
contentFilter: boolean;
|
|
14
|
-
adultContentFilter: boolean;
|
|
15
|
-
violenceFilter: boolean;
|
|
16
|
-
hateSpeechFilter: boolean;
|
|
17
|
-
copyrightFilter: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface AIPromptVersion {
|
|
21
|
-
major: number;
|
|
22
|
-
minor: number;
|
|
23
|
-
patch: number;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const createPromptVersion = (version: string): AIPromptVersion => {
|
|
27
|
-
const [major, minor, patch] = version.split('.').map(Number);
|
|
28
|
-
return { major: major || 1, minor: minor || 0, patch: patch || 0 };
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export const formatVersion = (version: AIPromptVersion): string => {
|
|
32
|
-
return `${version.major}.${version.minor}.${version.patch}`;
|
|
33
|
-
};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AIPromptTemplate } from '../entities/AIPromptTemplate';
|
|
2
|
-
import type { AIPromptResult } from '../entities/types';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Prompt Generation Service Interface
|
|
6
|
-
* Core service for generating prompts from templates
|
|
7
|
-
*/
|
|
8
|
-
export interface IPromptGenerationService {
|
|
9
|
-
generateFromTemplate(
|
|
10
|
-
template: AIPromptTemplate,
|
|
11
|
-
variables: Record<string, unknown>
|
|
12
|
-
): Promise<AIPromptResult<string>>;
|
|
13
|
-
validateVariables(
|
|
14
|
-
template: AIPromptTemplate,
|
|
15
|
-
variables: Record<string, unknown>
|
|
16
|
-
): AIPromptResult<void>;
|
|
17
|
-
replaceTemplateVariables(
|
|
18
|
-
template: string,
|
|
19
|
-
variables: Record<string, unknown>
|
|
20
|
-
): string;
|
|
21
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { GeneratedPrompt } from '../entities/GeneratedPrompt';
|
|
2
|
-
import type { AIPromptResult } from '../entities/types';
|
|
3
|
-
|
|
4
|
-
export interface IPromptHistoryRepository {
|
|
5
|
-
save(prompt: GeneratedPrompt): Promise<AIPromptResult<void>>;
|
|
6
|
-
findRecent(limit?: number): Promise<AIPromptResult<GeneratedPrompt[]>>;
|
|
7
|
-
findByTemplateId(templateId: string, limit?: number): Promise<AIPromptResult<GeneratedPrompt[]>>;
|
|
8
|
-
delete(id: string): Promise<AIPromptResult<void>>;
|
|
9
|
-
clear(): Promise<AIPromptResult<void>>;
|
|
10
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { AIPromptTemplate } from '../entities/AIPromptTemplate';
|
|
2
|
-
import type { AIPromptResult, AIPromptCategory } from '../entities/types';
|
|
3
|
-
|
|
4
|
-
export interface ITemplateRepository {
|
|
5
|
-
findById(id: string): Promise<AIPromptResult<AIPromptTemplate | null>>;
|
|
6
|
-
findByCategory(category: AIPromptCategory): Promise<AIPromptResult<AIPromptTemplate[]>>;
|
|
7
|
-
findAll(): Promise<AIPromptResult<AIPromptTemplate[]>>;
|
|
8
|
-
save(template: AIPromptTemplate): Promise<AIPromptResult<void>>;
|
|
9
|
-
delete(id: string): Promise<AIPromptResult<void>>;
|
|
10
|
-
exists(id: string): Promise<boolean>;
|
|
11
|
-
}
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Face Preservation Prompt Builder
|
|
3
|
-
* Dynamic prompt builder for AI image generation with strict face identity preservation
|
|
4
|
-
* Supports any number of people (1, 2, 3, N)
|
|
5
|
-
*
|
|
6
|
-
* SINGLE RESPONSIBILITY: Face identity preservation ONLY
|
|
7
|
-
* - Face identity lock techniques
|
|
8
|
-
* - @imageN reference anchors
|
|
9
|
-
* - Explicit preservation and negative constraints
|
|
10
|
-
*
|
|
11
|
-
* For interaction/positioning rules, use interaction-style-builder.ts
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
// =============================================================================
|
|
15
|
-
// Types
|
|
16
|
-
// =============================================================================
|
|
17
|
-
|
|
18
|
-
export interface FacePreservationOptions {
|
|
19
|
-
/** The scenario/scene description */
|
|
20
|
-
scenarioPrompt: string;
|
|
21
|
-
/** Number of people in the generation */
|
|
22
|
-
personCount: number;
|
|
23
|
-
/** Optional custom preservation rules from main app */
|
|
24
|
-
customRules?: string[];
|
|
25
|
-
/** Optional custom forbidden actions from main app */
|
|
26
|
-
customForbidden?: string[];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// =============================================================================
|
|
30
|
-
// Constants
|
|
31
|
-
// =============================================================================
|
|
32
|
-
|
|
33
|
-
const FACE_LOCK_RULES = [
|
|
34
|
-
"Face identity locked - exact facial structure must be preserved",
|
|
35
|
-
"Same jawline, eye shape, eye color, nose, lips, skin tone",
|
|
36
|
-
"No facial morphing, no face swap, no face modification",
|
|
37
|
-
"Identity consistency enabled - high facial similarity required",
|
|
38
|
-
] as const;
|
|
39
|
-
|
|
40
|
-
const FORBIDDEN_ACTIONS = [
|
|
41
|
-
"Do NOT generate a new face",
|
|
42
|
-
"Do NOT modify facial structure or proportions",
|
|
43
|
-
"Do NOT alter skin tone, texture, or natural marks",
|
|
44
|
-
"Do NOT smooth skin or remove natural features",
|
|
45
|
-
"Do NOT change eye color or shape",
|
|
46
|
-
] as const;
|
|
47
|
-
|
|
48
|
-
// =============================================================================
|
|
49
|
-
// Builder Functions
|
|
50
|
-
// =============================================================================
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Generate person reference instructions for N people
|
|
54
|
-
*/
|
|
55
|
-
function buildPersonReferences(count: number): string {
|
|
56
|
-
if (count === 1) {
|
|
57
|
-
return "Use @image1 as the ONLY reference. The face must remain 100% identical to this image.";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const refs = Array.from({ length: count }, (_, i) => {
|
|
61
|
-
const num = i + 1;
|
|
62
|
-
return `Person ${num}: Use @image${num} - preserve 100% identical facial appearance`;
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return refs.join("\n");
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Build face preservation prompt dynamically
|
|
70
|
-
* Supports any number of people (1, 2, 3, N)
|
|
71
|
-
*/
|
|
72
|
-
export function buildFacePreservationPrompt(options: FacePreservationOptions): string {
|
|
73
|
-
const { scenarioPrompt, personCount, customRules, customForbidden } = options;
|
|
74
|
-
|
|
75
|
-
const rules = [...FACE_LOCK_RULES, ...(customRules ?? [])];
|
|
76
|
-
const forbidden = [...FORBIDDEN_ACTIONS, ...(customForbidden ?? [])];
|
|
77
|
-
|
|
78
|
-
const personRefs = buildPersonReferences(personCount);
|
|
79
|
-
const personWord = personCount === 1 ? "person" : "people";
|
|
80
|
-
|
|
81
|
-
return `CRITICAL FACE PRESERVATION: Create a photorealistic image of EXACTLY the ${personCount} ${personWord} from the provided reference photo${personCount > 1 ? "s" : ""}.
|
|
82
|
-
|
|
83
|
-
REFERENCE IMAGES:
|
|
84
|
-
${personRefs}
|
|
85
|
-
|
|
86
|
-
FACE LOCK RULES:
|
|
87
|
-
${rules.map((r) => `- ${r}`).join("\n")}
|
|
88
|
-
|
|
89
|
-
FORBIDDEN:
|
|
90
|
-
${forbidden.map((f) => `- ${f}`).join("\n")}
|
|
91
|
-
|
|
92
|
-
SCENARIO:
|
|
93
|
-
${scenarioPrompt}
|
|
94
|
-
|
|
95
|
-
OUTPUT REQUIREMENTS:
|
|
96
|
-
- Photorealistic photograph quality (professional DSLR)
|
|
97
|
-
- Natural expressions and poses
|
|
98
|
-
- High resolution, detailed textures
|
|
99
|
-
- Each person's face must be 100% identical to their reference photo
|
|
100
|
-
|
|
101
|
-
FINAL VERIFICATION: Before output, confirm all faces match reference images exactly.`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Build a minimal face preservation prompt (for API character limits)
|
|
106
|
-
*/
|
|
107
|
-
export function buildMinimalFacePreservationPrompt(options: FacePreservationOptions): string {
|
|
108
|
-
const { scenarioPrompt, personCount } = options;
|
|
109
|
-
const personRefs = buildPersonReferences(personCount);
|
|
110
|
-
|
|
111
|
-
return `FACE IDENTITY LOCK: ${personCount} person(s) from reference photos.
|
|
112
|
-
${personRefs}
|
|
113
|
-
RULES: Preserve 100% facial identity, no modifications.
|
|
114
|
-
SCENARIO: ${scenarioPrompt}
|
|
115
|
-
OUTPUT: Photorealistic, faces identical to references.`;
|
|
116
|
-
}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interaction Style Prompt Builder
|
|
3
|
-
* Dynamic prompt builder for AI image generation with interaction/positioning rules
|
|
4
|
-
* Supports any number of people (1, 2, 3, N) and interaction styles
|
|
5
|
-
*
|
|
6
|
-
* Separate from face preservation - this handles:
|
|
7
|
-
* - Body positioning and proximity
|
|
8
|
-
* - Emotional expressions
|
|
9
|
-
* - Body language and poses
|
|
10
|
-
* - Interaction rules between people
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
// =============================================================================
|
|
14
|
-
// Types
|
|
15
|
-
// =============================================================================
|
|
16
|
-
|
|
17
|
-
/** Interaction style between people in the image */
|
|
18
|
-
export type InteractionStyle = "friendly" | "professional" | "neutral";
|
|
19
|
-
|
|
20
|
-
export interface InteractionStyleOptions {
|
|
21
|
-
/** Interaction style between people */
|
|
22
|
-
style: InteractionStyle;
|
|
23
|
-
/** Number of people in the generation */
|
|
24
|
-
personCount: number;
|
|
25
|
-
/** Optional custom rules from main app */
|
|
26
|
-
customRules?: string[];
|
|
27
|
-
/** Optional custom forbidden actions from main app */
|
|
28
|
-
customForbidden?: string[];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// =============================================================================
|
|
32
|
-
// Constants
|
|
33
|
-
// =============================================================================
|
|
34
|
-
|
|
35
|
-
/** Interaction style rules - what TO DO for each style */
|
|
36
|
-
const INTERACTION_RULES: Record<InteractionStyle, readonly string[]> = {
|
|
37
|
-
friendly: [
|
|
38
|
-
"Casual comfortable proximity",
|
|
39
|
-
"Genuine friendly smiles",
|
|
40
|
-
"Relaxed natural poses",
|
|
41
|
-
"Warm friendly body language",
|
|
42
|
-
"Standing or sitting close to each other comfortably",
|
|
43
|
-
],
|
|
44
|
-
professional: [
|
|
45
|
-
"Appropriate professional distance",
|
|
46
|
-
"Confident pleasant expressions",
|
|
47
|
-
"Professional posture and positioning",
|
|
48
|
-
"Formal but friendly body language",
|
|
49
|
-
],
|
|
50
|
-
neutral: [],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
/** Interaction style forbidden - what NOT to do for each style */
|
|
54
|
-
const INTERACTION_FORBIDDEN: Record<InteractionStyle, readonly string[]> = {
|
|
55
|
-
friendly: [
|
|
56
|
-
"Do NOT use cold or unfriendly expressions",
|
|
57
|
-
"Do NOT create awkward distancing",
|
|
58
|
-
"Do NOT make poses stiff or formal",
|
|
59
|
-
],
|
|
60
|
-
professional: [
|
|
61
|
-
"Do NOT use overly casual positioning",
|
|
62
|
-
"Do NOT use sloppy or unprofessional poses",
|
|
63
|
-
],
|
|
64
|
-
neutral: [],
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
// =============================================================================
|
|
68
|
-
// Builder Functions
|
|
69
|
-
// =============================================================================
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get interaction rules for a given style
|
|
73
|
-
*/
|
|
74
|
-
export function getInteractionRules(
|
|
75
|
-
style: InteractionStyle,
|
|
76
|
-
): readonly string[] {
|
|
77
|
-
return INTERACTION_RULES[style];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Get forbidden actions for a given style
|
|
82
|
-
*/
|
|
83
|
-
export function getInteractionForbidden(
|
|
84
|
-
style: InteractionStyle,
|
|
85
|
-
): readonly string[] {
|
|
86
|
-
return INTERACTION_FORBIDDEN[style];
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Build interaction style prompt section
|
|
91
|
-
* Can be appended to any prompt (face preservation, scenario, etc.)
|
|
92
|
-
*/
|
|
93
|
-
export function buildInteractionStylePrompt(
|
|
94
|
-
options: InteractionStyleOptions,
|
|
95
|
-
): string {
|
|
96
|
-
const { style, personCount, customRules, customForbidden } = options;
|
|
97
|
-
|
|
98
|
-
// No rules for neutral or single person
|
|
99
|
-
if (style === "neutral" || personCount < 2) {
|
|
100
|
-
return "";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const rules = [...INTERACTION_RULES[style], ...(customRules ?? [])];
|
|
104
|
-
const forbidden = [...INTERACTION_FORBIDDEN[style], ...(customForbidden ?? [])];
|
|
105
|
-
|
|
106
|
-
if (rules.length === 0 && forbidden.length === 0) {
|
|
107
|
-
return "";
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const sections: string[] = [];
|
|
111
|
-
|
|
112
|
-
sections.push(`INTERACTION STYLE: ${style.toUpperCase()}`);
|
|
113
|
-
|
|
114
|
-
if (rules.length > 0) {
|
|
115
|
-
sections.push(`POSITIONING RULES:\n${rules.map((r) => `- ${r}`).join("\n")}`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (forbidden.length > 0) {
|
|
119
|
-
sections.push(
|
|
120
|
-
`POSITIONING FORBIDDEN:\n${forbidden.map((f) => `- ${f}`).join("\n")}`,
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return sections.join("\n\n");
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Build a minimal interaction style prompt (for API character limits)
|
|
129
|
-
*/
|
|
130
|
-
export function buildMinimalInteractionStylePrompt(
|
|
131
|
-
options: InteractionStyleOptions,
|
|
132
|
-
): string {
|
|
133
|
-
const { style, personCount } = options;
|
|
134
|
-
|
|
135
|
-
if (style === "neutral" || personCount < 2) {
|
|
136
|
-
return "";
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const styleDescriptions: Record<InteractionStyle, string> = {
|
|
140
|
-
friendly: "casual proximity, friendly smiles, relaxed poses",
|
|
141
|
-
professional: "appropriate distance, confident expressions",
|
|
142
|
-
neutral: "",
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
return `STYLE: ${style} - ${styleDescriptions[style]}`;
|
|
146
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { IPromptHistoryRepository } from '../../domain/repositories/IPromptHistoryRepository';
|
|
2
|
-
import type { GeneratedPrompt } from '../../domain/entities/GeneratedPrompt';
|
|
3
|
-
import type { AIPromptResult } from '../../domain/entities/types';
|
|
4
|
-
|
|
5
|
-
export class PromptHistoryRepository implements IPromptHistoryRepository {
|
|
6
|
-
private storage: GeneratedPrompt[] = [];
|
|
7
|
-
private readonly maxStorageSize = 100;
|
|
8
|
-
|
|
9
|
-
save(prompt: GeneratedPrompt): Promise<AIPromptResult<void>> {
|
|
10
|
-
this.storage.push(prompt);
|
|
11
|
-
this.trimStorage();
|
|
12
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
findRecent(limit: number = 50): Promise<AIPromptResult<GeneratedPrompt[]>> {
|
|
16
|
-
const prompts = this.storage.slice(-limit);
|
|
17
|
-
return Promise.resolve({ success: true, data: prompts });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
findByTemplateId(
|
|
21
|
-
templateId: string,
|
|
22
|
-
limit: number = 20
|
|
23
|
-
): Promise<AIPromptResult<GeneratedPrompt[]>> {
|
|
24
|
-
const prompts = this.storage
|
|
25
|
-
.filter(prompt => prompt.templateId === templateId)
|
|
26
|
-
.slice(-limit);
|
|
27
|
-
return Promise.resolve({ success: true, data: prompts });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
delete(id: string): Promise<AIPromptResult<void>> {
|
|
31
|
-
this.storage = this.storage.filter(prompt => prompt.id !== id);
|
|
32
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
clear(): Promise<AIPromptResult<void>> {
|
|
36
|
-
this.storage = [];
|
|
37
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private trimStorage(): void {
|
|
41
|
-
if (this.storage.length > this.maxStorageSize) {
|
|
42
|
-
this.storage = this.storage.slice(-this.maxStorageSize);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import type { ITemplateRepository } from '../../domain/repositories/ITemplateRepository';
|
|
2
|
-
import type { AIPromptTemplate } from '../../domain/entities/AIPromptTemplate';
|
|
3
|
-
import type { AIPromptCategory, AIPromptResult } from '../../domain/entities/types';
|
|
4
|
-
|
|
5
|
-
export class TemplateRepository implements ITemplateRepository {
|
|
6
|
-
private storage = new Map<string, AIPromptTemplate>();
|
|
7
|
-
|
|
8
|
-
findById(id: string): Promise<AIPromptResult<AIPromptTemplate | null>> {
|
|
9
|
-
try {
|
|
10
|
-
const template = this.storage.get(id) || null;
|
|
11
|
-
return Promise.resolve({ success: true, data: template });
|
|
12
|
-
} catch {
|
|
13
|
-
return Promise.resolve({
|
|
14
|
-
success: false,
|
|
15
|
-
error: 'STORAGE_ERROR',
|
|
16
|
-
message: 'Failed to retrieve template'
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
findByCategory(category: AIPromptCategory): Promise<AIPromptResult<AIPromptTemplate[]>> {
|
|
22
|
-
try {
|
|
23
|
-
const templates = Array.from(this.storage.values())
|
|
24
|
-
.filter(template => template.category === category);
|
|
25
|
-
return Promise.resolve({ success: true, data: templates });
|
|
26
|
-
} catch {
|
|
27
|
-
return Promise.resolve({
|
|
28
|
-
success: false,
|
|
29
|
-
error: 'STORAGE_ERROR',
|
|
30
|
-
message: 'Failed to retrieve templates by category'
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
findAll(): Promise<AIPromptResult<AIPromptTemplate[]>> {
|
|
36
|
-
try {
|
|
37
|
-
const templates = Array.from(this.storage.values());
|
|
38
|
-
return Promise.resolve({ success: true, data: templates });
|
|
39
|
-
} catch {
|
|
40
|
-
return Promise.resolve({
|
|
41
|
-
success: false,
|
|
42
|
-
error: 'STORAGE_ERROR',
|
|
43
|
-
message: 'Failed to retrieve all templates'
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
save(template: AIPromptTemplate): Promise<AIPromptResult<void>> {
|
|
49
|
-
try {
|
|
50
|
-
this.storage.set(template.id, template);
|
|
51
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
52
|
-
} catch {
|
|
53
|
-
return Promise.resolve({
|
|
54
|
-
success: false,
|
|
55
|
-
error: 'STORAGE_ERROR',
|
|
56
|
-
message: 'Failed to save template'
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
delete(id: string): Promise<AIPromptResult<void>> {
|
|
62
|
-
try {
|
|
63
|
-
this.storage.delete(id);
|
|
64
|
-
return Promise.resolve({ success: true, data: undefined });
|
|
65
|
-
} catch {
|
|
66
|
-
return Promise.resolve({
|
|
67
|
-
success: false,
|
|
68
|
-
error: 'STORAGE_ERROR',
|
|
69
|
-
message: 'Failed to delete template'
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
exists(id: string): Promise<boolean> {
|
|
75
|
-
return Promise.resolve(this.storage.has(id));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ImagePromptBuilder - Fluent builder for AI image generation prompts
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
IDENTITY_SEGMENTS,
|
|
7
|
-
IDENTITY_NEGATIVE_SEGMENTS,
|
|
8
|
-
ANIME_STYLE_SEGMENTS,
|
|
9
|
-
QUALITY_SEGMENTS,
|
|
10
|
-
QUALITY_NEGATIVE_SEGMENTS,
|
|
11
|
-
ANTI_REALISM_SEGMENTS,
|
|
12
|
-
ANATOMY_NEGATIVE_SEGMENTS,
|
|
13
|
-
} from "../../domain/entities/image-prompt-segments";
|
|
14
|
-
import type { ImagePromptResult, ImagePromptBuilderOptions, AnimeSelfiePromptResult } from "./image-prompt-builder.types";
|
|
15
|
-
|
|
16
|
-
// Export types
|
|
17
|
-
export type { ImagePromptResult, ImagePromptBuilderOptions, AnimeSelfiePromptResult };
|
|
18
|
-
|
|
19
|
-
export class ImagePromptBuilder {
|
|
20
|
-
private positiveSegments: string[] = [];
|
|
21
|
-
private negativeSegments: string[] = [];
|
|
22
|
-
private readonly separator: string;
|
|
23
|
-
|
|
24
|
-
private constructor(options?: ImagePromptBuilderOptions) {
|
|
25
|
-
this.separator = options?.separator ?? ", ";
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static create(options?: ImagePromptBuilderOptions): ImagePromptBuilder {
|
|
29
|
-
return new ImagePromptBuilder(options);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
withIdentityPreservation(): this {
|
|
33
|
-
this.positiveSegments.push(...Object.values(IDENTITY_SEGMENTS));
|
|
34
|
-
this.negativeSegments.push(...Object.values(IDENTITY_NEGATIVE_SEGMENTS));
|
|
35
|
-
return this;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
withAnimeStyle(): this {
|
|
39
|
-
this.positiveSegments.push(...Object.values(ANIME_STYLE_SEGMENTS));
|
|
40
|
-
this.negativeSegments.push(...Object.values(ANTI_REALISM_SEGMENTS));
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
withQuality(): this {
|
|
45
|
-
this.positiveSegments.push(...Object.values(QUALITY_SEGMENTS));
|
|
46
|
-
this.negativeSegments.push(...Object.values(QUALITY_NEGATIVE_SEGMENTS));
|
|
47
|
-
return this;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
withAnatomySafety(): this {
|
|
51
|
-
this.negativeSegments.push(...Object.values(ANATOMY_NEGATIVE_SEGMENTS));
|
|
52
|
-
return this;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
withAntiRealism(): this {
|
|
56
|
-
this.negativeSegments.push(...Object.values(ANTI_REALISM_SEGMENTS));
|
|
57
|
-
return this;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
withSegments(segments: string[]): this {
|
|
61
|
-
this.positiveSegments.push(...segments);
|
|
62
|
-
return this;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
withNegativeSegments(segments: string[]): this {
|
|
66
|
-
this.negativeSegments.push(...segments);
|
|
67
|
-
return this;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
withSegment(segment: string): this {
|
|
71
|
-
this.positiveSegments.push(segment);
|
|
72
|
-
return this;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
withNegativeSegment(segment: string): this {
|
|
76
|
-
this.negativeSegments.push(segment);
|
|
77
|
-
return this;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
prependSegments(segments: string[]): this {
|
|
81
|
-
this.positiveSegments.unshift(...segments);
|
|
82
|
-
return this;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
extend(): ImagePromptBuilder {
|
|
86
|
-
const builder = ImagePromptBuilder.create({ separator: this.separator });
|
|
87
|
-
builder.positiveSegments = [...this.positiveSegments];
|
|
88
|
-
builder.negativeSegments = [...this.negativeSegments];
|
|
89
|
-
return builder;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
build(): ImagePromptResult {
|
|
93
|
-
const uniquePositive = [...new Set(this.positiveSegments)].filter(Boolean);
|
|
94
|
-
const uniqueNegative = [...new Set(this.negativeSegments)].filter(Boolean);
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
prompt: uniquePositive.join(this.separator),
|
|
98
|
-
negativePrompt: uniqueNegative.join(this.separator),
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Export utility functions
|
|
104
|
-
export { createAnimeSelfiePrompt, createStyleTransferPrompt } from "../utils/prompt-creators.util";
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import type {IPromptGenerationService} from '../../domain/repositories/IAIPromptServices';
|
|
2
|
-
import type {AIPromptTemplate} from '../../domain/entities/AIPromptTemplate';
|
|
3
|
-
import type {AIPromptResult} from '../../domain/entities/types';
|
|
4
|
-
|
|
5
|
-
export class PromptGenerationService implements IPromptGenerationService {
|
|
6
|
-
generateFromTemplate(
|
|
7
|
-
template: AIPromptTemplate,
|
|
8
|
-
variables: Record<string, unknown>
|
|
9
|
-
): Promise<AIPromptResult<string>> {
|
|
10
|
-
return new Promise((resolve) => {
|
|
11
|
-
try {
|
|
12
|
-
const validation = this.validateVariables(template, variables);
|
|
13
|
-
if (!validation.success) {
|
|
14
|
-
resolve(validation as AIPromptResult<string>);
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const generatedText = this.replaceTemplateVariables(template.template, variables);
|
|
19
|
-
resolve({ success: true, data: generatedText });
|
|
20
|
-
} catch {
|
|
21
|
-
resolve({
|
|
22
|
-
success: false,
|
|
23
|
-
error: 'GENERATION_FAILED',
|
|
24
|
-
message: 'Failed to generate prompt'
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
validateVariables(
|
|
31
|
-
template: AIPromptTemplate,
|
|
32
|
-
variables: Record<string, unknown>
|
|
33
|
-
): AIPromptResult<void> {
|
|
34
|
-
for (const variable of template.variables) {
|
|
35
|
-
if (variable.required && !(variable.name in variables)) {
|
|
36
|
-
return {
|
|
37
|
-
success: false,
|
|
38
|
-
error: 'INVALID_VARIABLES',
|
|
39
|
-
message: `Required variable ${variable.name} is missing`
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return { success: true, data: undefined };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
replaceTemplateVariables(
|
|
47
|
-
template: string,
|
|
48
|
-
variables: Record<string, unknown>
|
|
49
|
-
): string {
|
|
50
|
-
let result = template;
|
|
51
|
-
|
|
52
|
-
Object.entries(variables).forEach(([key, value]) => {
|
|
53
|
-
const regex = new RegExp(`\\$\\{${key}\\}`, 'g');
|
|
54
|
-
result = result.replace(regex, String(value || ''));
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Image Prompt Builder Types
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface ImagePromptResult {
|
|
6
|
-
prompt: string;
|
|
7
|
-
negativePrompt: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface AnimeSelfiePromptResult {
|
|
11
|
-
prompt: string;
|
|
12
|
-
guidance_scale: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ImagePromptBuilderOptions {
|
|
16
|
-
separator?: string;
|
|
17
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompt Creation Utilities
|
|
3
|
-
* Provides helper functions for creating specific types of prompts
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import type { ImagePromptResult, AnimeSelfiePromptResult } from "../services/ImagePromptBuilder";
|
|
7
|
-
import { ImagePromptBuilder } from "../services/ImagePromptBuilder";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Create anime selfie prompt for Kontext model
|
|
11
|
-
* Kontext uses instruction-based editing that preserves character identity automatically
|
|
12
|
-
*/
|
|
13
|
-
export function createAnimeSelfiePrompt(customStyle?: string): AnimeSelfiePromptResult {
|
|
14
|
-
const stylePrefix = customStyle ? `${customStyle} anime style` : "anime style";
|
|
15
|
-
|
|
16
|
-
const prompt = [
|
|
17
|
-
`Transform this person into a ${stylePrefix} illustration.`,
|
|
18
|
-
"IMPORTANT: Preserve the exact same gender - if male keep male, if female keep female.",
|
|
19
|
-
"Keep the same face structure, hair color, eye color, skin tone, and facial expression.",
|
|
20
|
-
"Make it look like a high-quality Japanese anime character portrait.",
|
|
21
|
-
"Use vibrant anime colors, clean lineart, and cel-shaded rendering.",
|
|
22
|
-
"Large expressive anime eyes with detailed iris, smooth anime skin with subtle blush.",
|
|
23
|
-
].join(" ");
|
|
24
|
-
|
|
25
|
-
return {
|
|
26
|
-
prompt,
|
|
27
|
-
guidance_scale: 4.0,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Create a style transfer prompt with identity preservation
|
|
33
|
-
*/
|
|
34
|
-
export function createStyleTransferPrompt(style: string): ImagePromptResult {
|
|
35
|
-
return ImagePromptBuilder.create()
|
|
36
|
-
.withSegment(`${style} style`)
|
|
37
|
-
.withIdentityPreservation()
|
|
38
|
-
.withQuality()
|
|
39
|
-
.withAnatomySafety()
|
|
40
|
-
.build();
|
|
41
|
-
}
|