@framers/agentos 0.1.163 → 0.1.165
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/dist/api/generateImage.d.ts +6 -0
- package/dist/api/generateImage.d.ts.map +1 -1
- package/dist/api/generateImage.js +18 -0
- package/dist/api/generateImage.js.map +1 -1
- package/dist/api/index.d.ts +4 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +4 -0
- package/dist/api/index.js.map +1 -1
- package/dist/api/types.d.ts +71 -0
- package/dist/api/types.d.ts.map +1 -1
- package/dist/api/types.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/llm/routing/index.d.ts +10 -0
- package/dist/core/llm/routing/index.d.ts.map +1 -0
- package/dist/core/llm/routing/index.js +9 -0
- package/dist/core/llm/routing/index.js.map +1 -0
- package/dist/media/avatar/AvatarPipeline.d.ts +56 -0
- package/dist/media/avatar/AvatarPipeline.d.ts.map +1 -0
- package/dist/media/avatar/AvatarPipeline.js +308 -0
- package/dist/media/avatar/AvatarPipeline.js.map +1 -0
- package/dist/media/avatar/index.d.ts +8 -0
- package/dist/media/avatar/index.d.ts.map +1 -0
- package/dist/media/avatar/index.js +7 -0
- package/dist/media/avatar/index.js.map +1 -0
- package/dist/media/avatar/prompts.d.ts +48 -0
- package/dist/media/avatar/prompts.d.ts.map +1 -0
- package/dist/media/avatar/prompts.js +88 -0
- package/dist/media/avatar/prompts.js.map +1 -0
- package/dist/media/avatar/types.d.ts +101 -0
- package/dist/media/avatar/types.d.ts.map +1 -0
- package/dist/media/avatar/types.js +8 -0
- package/dist/media/avatar/types.js.map +1 -0
- package/dist/media/images/face/IFaceEmbeddingService.d.ts +69 -0
- package/dist/media/images/face/IFaceEmbeddingService.d.ts.map +1 -0
- package/dist/media/images/face/IFaceEmbeddingService.js +40 -0
- package/dist/media/images/face/IFaceEmbeddingService.js.map +1 -0
- package/dist/media/images/face/ReplicateFaceEmbeddingService.d.ts +57 -0
- package/dist/media/images/face/ReplicateFaceEmbeddingService.d.ts.map +1 -0
- package/dist/media/images/face/ReplicateFaceEmbeddingService.js +151 -0
- package/dist/media/images/face/ReplicateFaceEmbeddingService.js.map +1 -0
- package/dist/media/images/face/index.d.ts +7 -0
- package/dist/media/images/face/index.d.ts.map +1 -0
- package/dist/media/images/face/index.js +7 -0
- package/dist/media/images/face/index.js.map +1 -0
- package/dist/media/images/index.d.ts +2 -0
- package/dist/media/images/index.d.ts.map +1 -1
- package/dist/media/images/index.js +2 -0
- package/dist/media/images/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file AvatarPipeline.ts
|
|
3
|
+
* Core orchestrator for staged avatar image generation.
|
|
4
|
+
*
|
|
5
|
+
* Executes the avatar pipeline stages in order — neutral portrait, face
|
|
6
|
+
* embedding extraction, expression sheet, animated emotes, full body —
|
|
7
|
+
* with cosine-similarity drift checking against the anchor face embedding.
|
|
8
|
+
* Images that drift too far from the anchor are regenerated up to a
|
|
9
|
+
* configurable maximum number of attempts.
|
|
10
|
+
*/
|
|
11
|
+
import { randomUUID } from 'crypto';
|
|
12
|
+
import { AVATAR_EMOTIONS, buildPortraitPrompt, buildExpressionPrompt, buildEmotePrompt } from './prompts.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Default thresholds
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
const DEFAULT_DRIFT_SIMILARITY = 0.6;
|
|
17
|
+
const DEFAULT_REJECT_BELOW_THRESHOLD = true;
|
|
18
|
+
const DEFAULT_MAX_REGEN_ATTEMPTS = 3;
|
|
19
|
+
const ALL_STAGES = [
|
|
20
|
+
'neutral_portrait',
|
|
21
|
+
'face_embedding',
|
|
22
|
+
'expression_sheet',
|
|
23
|
+
'animated_emotes',
|
|
24
|
+
'full_body',
|
|
25
|
+
];
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Pipeline
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/**
|
|
30
|
+
* Orchestrates multi-stage avatar image generation with drift detection.
|
|
31
|
+
*
|
|
32
|
+
* Stages run in dependency order. The expression sheet and animated emote
|
|
33
|
+
* stages drift-check each generated image against the anchor face embedding
|
|
34
|
+
* and regenerate on low similarity.
|
|
35
|
+
*/
|
|
36
|
+
export class AvatarPipeline {
|
|
37
|
+
/**
|
|
38
|
+
* @param faceService - Face embedding extraction and comparison service.
|
|
39
|
+
* @param generateImage - Image generation function (prompt → URL).
|
|
40
|
+
*/
|
|
41
|
+
constructor(faceService, generateImage) {
|
|
42
|
+
this.faceService = faceService;
|
|
43
|
+
this.generateImage = generateImage;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Execute the avatar generation pipeline.
|
|
47
|
+
*
|
|
48
|
+
* @param request - Generation request with identity, stages, and config.
|
|
49
|
+
* @returns Result containing the identity package, job records, and drift report.
|
|
50
|
+
*/
|
|
51
|
+
async generate(request) {
|
|
52
|
+
const startTime = Date.now();
|
|
53
|
+
const stages = request.stages ?? ALL_STAGES;
|
|
54
|
+
const jobs = [];
|
|
55
|
+
const driftConfig = {
|
|
56
|
+
faceSimilarity: request.driftGuard?.faceSimilarity ?? DEFAULT_DRIFT_SIMILARITY,
|
|
57
|
+
rejectBelowThreshold: request.driftGuard?.rejectBelowThreshold ?? DEFAULT_REJECT_BELOW_THRESHOLD,
|
|
58
|
+
maxRegenerationAttempts: request.driftGuard?.maxRegenerationAttempts ?? DEFAULT_MAX_REGEN_ATTEMPTS,
|
|
59
|
+
};
|
|
60
|
+
// Mutable state accumulated across stages
|
|
61
|
+
let neutralPortraitUrl = request.existingAnchors?.neutralPortrait ?? '';
|
|
62
|
+
let faceEmbedding = request.existingAnchors?.faceEmbedding;
|
|
63
|
+
const expressionSheet = {};
|
|
64
|
+
const animatedEmotes = {};
|
|
65
|
+
let fullBodyUrl;
|
|
66
|
+
const driftScores = {};
|
|
67
|
+
const driftRejected = [];
|
|
68
|
+
const driftRegenerated = [];
|
|
69
|
+
// -----------------------------------------------------------------------
|
|
70
|
+
// Stage: neutral_portrait
|
|
71
|
+
// -----------------------------------------------------------------------
|
|
72
|
+
if (stages.includes('neutral_portrait') && !neutralPortraitUrl) {
|
|
73
|
+
const job = this.createJob('neutral_portrait', 'neutral_portrait');
|
|
74
|
+
const jobStart = Date.now();
|
|
75
|
+
try {
|
|
76
|
+
job.status = 'running';
|
|
77
|
+
const prompt = buildPortraitPrompt(request.identity);
|
|
78
|
+
neutralPortraitUrl = await this.generateImage(prompt, {
|
|
79
|
+
seed: request.generationConfig.seed,
|
|
80
|
+
negativePrompt: request.generationConfig.negativePrompt,
|
|
81
|
+
stylePreset: request.generationConfig.stylePreset,
|
|
82
|
+
policyTier: request.policyTier,
|
|
83
|
+
});
|
|
84
|
+
job.imageUrl = neutralPortraitUrl;
|
|
85
|
+
job.status = 'completed';
|
|
86
|
+
job.attempts = 1;
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
job.status = 'failed';
|
|
90
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
91
|
+
}
|
|
92
|
+
job.durationMs = Date.now() - jobStart;
|
|
93
|
+
jobs.push(job);
|
|
94
|
+
}
|
|
95
|
+
// -----------------------------------------------------------------------
|
|
96
|
+
// Stage: face_embedding
|
|
97
|
+
// -----------------------------------------------------------------------
|
|
98
|
+
if (stages.includes('face_embedding') && !faceEmbedding && neutralPortraitUrl) {
|
|
99
|
+
const job = this.createJob('face_embedding', 'face_embedding');
|
|
100
|
+
const jobStart = Date.now();
|
|
101
|
+
try {
|
|
102
|
+
job.status = 'running';
|
|
103
|
+
const result = await this.faceService.extractEmbedding(neutralPortraitUrl);
|
|
104
|
+
faceEmbedding = result.vector;
|
|
105
|
+
job.status = 'completed';
|
|
106
|
+
job.attempts = 1;
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
job.status = 'failed';
|
|
110
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
111
|
+
}
|
|
112
|
+
job.durationMs = Date.now() - jobStart;
|
|
113
|
+
jobs.push(job);
|
|
114
|
+
}
|
|
115
|
+
// -----------------------------------------------------------------------
|
|
116
|
+
// Stage: expression_sheet
|
|
117
|
+
// -----------------------------------------------------------------------
|
|
118
|
+
if (stages.includes('expression_sheet')) {
|
|
119
|
+
for (const emotion of AVATAR_EMOTIONS) {
|
|
120
|
+
// Neutral portrait is already the anchor; skip re-generating it
|
|
121
|
+
if (emotion === 'neutral') {
|
|
122
|
+
if (neutralPortraitUrl) {
|
|
123
|
+
expressionSheet.neutral = neutralPortraitUrl;
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
const label = `expression:${emotion}`;
|
|
128
|
+
const job = this.createJob('expression_sheet', label);
|
|
129
|
+
const jobStart = Date.now();
|
|
130
|
+
try {
|
|
131
|
+
job.status = 'running';
|
|
132
|
+
const prompt = buildExpressionPrompt(request.identity, emotion);
|
|
133
|
+
let imageUrl;
|
|
134
|
+
let bestScore = -1;
|
|
135
|
+
let attempts = 0;
|
|
136
|
+
while (attempts < driftConfig.maxRegenerationAttempts) {
|
|
137
|
+
attempts++;
|
|
138
|
+
const url = await this.generateImage(prompt, {
|
|
139
|
+
seed: request.generationConfig.seed,
|
|
140
|
+
negativePrompt: request.generationConfig.negativePrompt,
|
|
141
|
+
stylePreset: request.generationConfig.stylePreset,
|
|
142
|
+
policyTier: request.policyTier,
|
|
143
|
+
referenceImageUrl: neutralPortraitUrl || undefined,
|
|
144
|
+
});
|
|
145
|
+
// Drift check against anchor embedding
|
|
146
|
+
if (faceEmbedding) {
|
|
147
|
+
try {
|
|
148
|
+
const generated = await this.faceService.extractEmbedding(url);
|
|
149
|
+
const comparison = this.faceService.compareFaces(faceEmbedding, generated.vector, driftConfig.faceSimilarity);
|
|
150
|
+
if (comparison.similarity > bestScore) {
|
|
151
|
+
bestScore = comparison.similarity;
|
|
152
|
+
imageUrl = url;
|
|
153
|
+
}
|
|
154
|
+
if (comparison.match) {
|
|
155
|
+
break; // Acceptable drift
|
|
156
|
+
}
|
|
157
|
+
if (attempts > 1) {
|
|
158
|
+
driftRegenerated.push(label);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// If face extraction fails on the generated image, accept it
|
|
163
|
+
imageUrl = url;
|
|
164
|
+
break;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
// No anchor embedding available — accept the first result
|
|
169
|
+
imageUrl = url;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (imageUrl) {
|
|
174
|
+
expressionSheet[emotion] = imageUrl;
|
|
175
|
+
job.imageUrl = imageUrl;
|
|
176
|
+
job.driftScore = bestScore >= 0 ? bestScore : undefined;
|
|
177
|
+
job.status = 'completed';
|
|
178
|
+
if (bestScore >= 0) {
|
|
179
|
+
driftScores[label] = bestScore;
|
|
180
|
+
if (bestScore < driftConfig.faceSimilarity && driftConfig.rejectBelowThreshold) {
|
|
181
|
+
driftRejected.push(label);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
job.status = 'failed';
|
|
187
|
+
job.error = 'All regeneration attempts failed drift check.';
|
|
188
|
+
}
|
|
189
|
+
job.attempts = attempts;
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
job.status = 'failed';
|
|
193
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
194
|
+
}
|
|
195
|
+
job.durationMs = Date.now() - jobStart;
|
|
196
|
+
jobs.push(job);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// -----------------------------------------------------------------------
|
|
200
|
+
// Stage: animated_emotes
|
|
201
|
+
// -----------------------------------------------------------------------
|
|
202
|
+
if (stages.includes('animated_emotes')) {
|
|
203
|
+
for (const emotion of AVATAR_EMOTIONS) {
|
|
204
|
+
const label = `emote:${emotion}`;
|
|
205
|
+
const job = this.createJob('animated_emotes', label);
|
|
206
|
+
const jobStart = Date.now();
|
|
207
|
+
try {
|
|
208
|
+
job.status = 'running';
|
|
209
|
+
const prompt = buildEmotePrompt(emotion);
|
|
210
|
+
const url = await this.generateImage(prompt, {
|
|
211
|
+
seed: request.generationConfig.seed,
|
|
212
|
+
negativePrompt: request.generationConfig.negativePrompt,
|
|
213
|
+
policyTier: request.policyTier,
|
|
214
|
+
});
|
|
215
|
+
animatedEmotes[emotion] = url;
|
|
216
|
+
job.imageUrl = url;
|
|
217
|
+
job.status = 'completed';
|
|
218
|
+
job.attempts = 1;
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
job.status = 'failed';
|
|
222
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
223
|
+
}
|
|
224
|
+
job.durationMs = Date.now() - jobStart;
|
|
225
|
+
jobs.push(job);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// -----------------------------------------------------------------------
|
|
229
|
+
// Stage: full_body
|
|
230
|
+
// -----------------------------------------------------------------------
|
|
231
|
+
if (stages.includes('full_body')) {
|
|
232
|
+
const job = this.createJob('full_body', 'full_body');
|
|
233
|
+
const jobStart = Date.now();
|
|
234
|
+
try {
|
|
235
|
+
job.status = 'running';
|
|
236
|
+
const basePrompt = buildPortraitPrompt(request.identity);
|
|
237
|
+
const prompt = basePrompt.replace(/^portrait of/, 'full body shot of');
|
|
238
|
+
fullBodyUrl = await this.generateImage(prompt, {
|
|
239
|
+
seed: request.generationConfig.seed,
|
|
240
|
+
negativePrompt: request.generationConfig.negativePrompt,
|
|
241
|
+
stylePreset: request.generationConfig.stylePreset,
|
|
242
|
+
policyTier: request.policyTier,
|
|
243
|
+
referenceImageUrl: neutralPortraitUrl || undefined,
|
|
244
|
+
});
|
|
245
|
+
job.imageUrl = fullBodyUrl;
|
|
246
|
+
job.status = 'completed';
|
|
247
|
+
job.attempts = 1;
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
job.status = 'failed';
|
|
251
|
+
job.error = err instanceof Error ? err.message : String(err);
|
|
252
|
+
}
|
|
253
|
+
job.durationMs = Date.now() - jobStart;
|
|
254
|
+
jobs.push(job);
|
|
255
|
+
}
|
|
256
|
+
// -----------------------------------------------------------------------
|
|
257
|
+
// Assemble identity package
|
|
258
|
+
// -----------------------------------------------------------------------
|
|
259
|
+
const now = new Date().toISOString();
|
|
260
|
+
const identityPackage = {
|
|
261
|
+
id: randomUUID(),
|
|
262
|
+
characterId: request.characterId,
|
|
263
|
+
identity: request.identity,
|
|
264
|
+
anchors: {
|
|
265
|
+
neutralPortrait: neutralPortraitUrl,
|
|
266
|
+
expressionSheet: Object.keys(expressionSheet).length > 0 ? expressionSheet : undefined,
|
|
267
|
+
animatedEmotes: Object.keys(animatedEmotes).length > 0 ? animatedEmotes : undefined,
|
|
268
|
+
fullBody: fullBodyUrl,
|
|
269
|
+
},
|
|
270
|
+
faceEmbedding,
|
|
271
|
+
driftGuard: driftConfig,
|
|
272
|
+
generationConfig: request.generationConfig,
|
|
273
|
+
createdAt: now,
|
|
274
|
+
updatedAt: now,
|
|
275
|
+
};
|
|
276
|
+
// -----------------------------------------------------------------------
|
|
277
|
+
// Drift report
|
|
278
|
+
// -----------------------------------------------------------------------
|
|
279
|
+
let driftReport;
|
|
280
|
+
if (faceEmbedding) {
|
|
281
|
+
driftReport = {
|
|
282
|
+
anchorEmbeddingDim: faceEmbedding.length,
|
|
283
|
+
scores: driftScores,
|
|
284
|
+
rejected: driftRejected,
|
|
285
|
+
regenerated: [...new Set(driftRegenerated)],
|
|
286
|
+
passed: driftRejected.length === 0,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
return {
|
|
290
|
+
identityPackage,
|
|
291
|
+
jobs,
|
|
292
|
+
driftReport,
|
|
293
|
+
totalDurationMs: Date.now() - startTime,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// -------------------------------------------------------------------------
|
|
297
|
+
// Helpers
|
|
298
|
+
// -------------------------------------------------------------------------
|
|
299
|
+
createJob(stage, label) {
|
|
300
|
+
return {
|
|
301
|
+
stage,
|
|
302
|
+
label,
|
|
303
|
+
status: 'pending',
|
|
304
|
+
attempts: 0,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=AvatarPipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AvatarPipeline.js","sourceRoot":"","sources":["../../../src/media/avatar/AvatarPipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* Barrel export for the avatar generation pipeline.
|
|
4
|
+
*/
|
|
5
|
+
export { AvatarPipeline, type ImageGeneratorFn } from './AvatarPipeline.js';
|
|
6
|
+
export type { AvatarGenerationStage, AvatarGenerationRequest, AvatarGenerationJob, DriftAuditReport, AvatarGenerationResult, } from './types.js';
|
|
7
|
+
export { AVATAR_EMOTIONS, type AvatarEmotion, buildPortraitPrompt, buildExpressionPrompt, buildEmotePrompt, } from './prompts.js';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/media/avatar/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5E,YAAY,EACV,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,eAAe,EACf,KAAK,aAAa,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file index.ts
|
|
3
|
+
* Barrel export for the avatar generation pipeline.
|
|
4
|
+
*/
|
|
5
|
+
export { AvatarPipeline } from './AvatarPipeline.js';
|
|
6
|
+
export { AVATAR_EMOTIONS, buildPortraitPrompt, buildExpressionPrompt, buildEmotePrompt, } from './prompts.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/media/avatar/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,cAAc,EAAyB,MAAM,qBAAqB,CAAC;AAU5E,OAAO,EACL,eAAe,EAEf,mBAAmB,EACnB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file prompts.ts
|
|
3
|
+
* Prompt construction utilities for avatar image generation.
|
|
4
|
+
*
|
|
5
|
+
* Builds deterministic text prompts from {@link AvatarIdentityDescriptor}
|
|
6
|
+
* fields, producing consistent character depictions across emotion variants,
|
|
7
|
+
* emote animations, and full-body shots.
|
|
8
|
+
*/
|
|
9
|
+
import type { AvatarIdentityDescriptor } from '../../api/types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Canonical set of emotions for expression sheets and animated emotes.
|
|
12
|
+
* The first entry is always "neutral" — it doubles as the anchor portrait.
|
|
13
|
+
*/
|
|
14
|
+
export declare const AVATAR_EMOTIONS: readonly ["neutral", "happy", "sad", "angry", "surprised", "flirty", "fearful"];
|
|
15
|
+
/** Union type of supported avatar emotions. */
|
|
16
|
+
export type AvatarEmotion = (typeof AVATAR_EMOTIONS)[number];
|
|
17
|
+
/**
|
|
18
|
+
* Concatenate all identity descriptor fields into a portrait prompt.
|
|
19
|
+
*
|
|
20
|
+
* Produces a detailed, comma-separated description suitable for
|
|
21
|
+
* text-to-image models. Omits undefined optional fields.
|
|
22
|
+
*
|
|
23
|
+
* @param identity - Character identity descriptors.
|
|
24
|
+
* @returns Prompt string for a neutral portrait.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildPortraitPrompt(identity: AvatarIdentityDescriptor): string;
|
|
27
|
+
/**
|
|
28
|
+
* Build a prompt for a specific emotion expression of the character.
|
|
29
|
+
*
|
|
30
|
+
* Appends the emotion keyword to the base portrait prompt so the model
|
|
31
|
+
* generates the same face with the requested expression.
|
|
32
|
+
*
|
|
33
|
+
* @param identity - Character identity descriptors.
|
|
34
|
+
* @param emotion - Target emotion expression.
|
|
35
|
+
* @returns Prompt string for an emotion-specific portrait.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildExpressionPrompt(identity: AvatarIdentityDescriptor, emotion: AvatarEmotion | string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build a prompt for an animated emote loop of a given emotion.
|
|
40
|
+
*
|
|
41
|
+
* Produces a concise prompt targeting short animation generation models
|
|
42
|
+
* (e.g. Stable Video Diffusion, AnimateDiff).
|
|
43
|
+
*
|
|
44
|
+
* @param emotion - The emotion to animate.
|
|
45
|
+
* @returns Prompt string for an animated emote.
|
|
46
|
+
*/
|
|
47
|
+
export declare function buildEmotePrompt(emotion: AvatarEmotion | string): string;
|
|
48
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/media/avatar/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAMnE;;;GAGG;AACH,eAAO,MAAM,eAAe,iFAQlB,CAAC;AAEX,+CAA+C;AAC/C,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAM7D;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,wBAAwB,GAAG,MAAM,CA6B9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,wBAAwB,EAClC,OAAO,EAAE,aAAa,GAAG,MAAM,GAC9B,MAAM,CAMR;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,GAAG,MAAM,CAExE"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file prompts.ts
|
|
3
|
+
* Prompt construction utilities for avatar image generation.
|
|
4
|
+
*
|
|
5
|
+
* Builds deterministic text prompts from {@link AvatarIdentityDescriptor}
|
|
6
|
+
* fields, producing consistent character depictions across emotion variants,
|
|
7
|
+
* emote animations, and full-body shots.
|
|
8
|
+
*/
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Emotion catalogue
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
/**
|
|
13
|
+
* Canonical set of emotions for expression sheets and animated emotes.
|
|
14
|
+
* The first entry is always "neutral" — it doubles as the anchor portrait.
|
|
15
|
+
*/
|
|
16
|
+
export const AVATAR_EMOTIONS = [
|
|
17
|
+
'neutral',
|
|
18
|
+
'happy',
|
|
19
|
+
'sad',
|
|
20
|
+
'angry',
|
|
21
|
+
'surprised',
|
|
22
|
+
'flirty',
|
|
23
|
+
'fearful',
|
|
24
|
+
];
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Prompt builders
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
/**
|
|
29
|
+
* Concatenate all identity descriptor fields into a portrait prompt.
|
|
30
|
+
*
|
|
31
|
+
* Produces a detailed, comma-separated description suitable for
|
|
32
|
+
* text-to-image models. Omits undefined optional fields.
|
|
33
|
+
*
|
|
34
|
+
* @param identity - Character identity descriptors.
|
|
35
|
+
* @returns Prompt string for a neutral portrait.
|
|
36
|
+
*/
|
|
37
|
+
export function buildPortraitPrompt(identity) {
|
|
38
|
+
const parts = [];
|
|
39
|
+
parts.push(`portrait of ${identity.displayName}`);
|
|
40
|
+
parts.push(`${identity.ageBand.replace(/_/g, ' ')} age`);
|
|
41
|
+
if (identity.bodyType) {
|
|
42
|
+
parts.push(`${identity.bodyType} build`);
|
|
43
|
+
}
|
|
44
|
+
parts.push(identity.faceDescriptor);
|
|
45
|
+
if (identity.hairDescriptor) {
|
|
46
|
+
parts.push(identity.hairDescriptor);
|
|
47
|
+
}
|
|
48
|
+
if (identity.skinDescriptor) {
|
|
49
|
+
parts.push(identity.skinDescriptor);
|
|
50
|
+
}
|
|
51
|
+
if (identity.distinguishingFeatures) {
|
|
52
|
+
parts.push(identity.distinguishingFeatures);
|
|
53
|
+
}
|
|
54
|
+
if (identity.styleNotes) {
|
|
55
|
+
parts.push(identity.styleNotes);
|
|
56
|
+
}
|
|
57
|
+
return parts.join(', ');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Build a prompt for a specific emotion expression of the character.
|
|
61
|
+
*
|
|
62
|
+
* Appends the emotion keyword to the base portrait prompt so the model
|
|
63
|
+
* generates the same face with the requested expression.
|
|
64
|
+
*
|
|
65
|
+
* @param identity - Character identity descriptors.
|
|
66
|
+
* @param emotion - Target emotion expression.
|
|
67
|
+
* @returns Prompt string for an emotion-specific portrait.
|
|
68
|
+
*/
|
|
69
|
+
export function buildExpressionPrompt(identity, emotion) {
|
|
70
|
+
const base = buildPortraitPrompt(identity);
|
|
71
|
+
if (emotion === 'neutral') {
|
|
72
|
+
return base;
|
|
73
|
+
}
|
|
74
|
+
return `${base}, ${emotion} expression`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build a prompt for an animated emote loop of a given emotion.
|
|
78
|
+
*
|
|
79
|
+
* Produces a concise prompt targeting short animation generation models
|
|
80
|
+
* (e.g. Stable Video Diffusion, AnimateDiff).
|
|
81
|
+
*
|
|
82
|
+
* @param emotion - The emotion to animate.
|
|
83
|
+
* @returns Prompt string for an animated emote.
|
|
84
|
+
*/
|
|
85
|
+
export function buildEmotePrompt(emotion) {
|
|
86
|
+
return `animated emote loop, ${emotion} expression, character portrait, seamless loop`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/media/avatar/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,SAAS;IACT,OAAO;IACP,KAAK;IACL,OAAO;IACP,WAAW;IACX,QAAQ;IACR,SAAS;CACD,CAAC;AAKX,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAkC;IACpE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,eAAe,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IAClD,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAEzD,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,QAAQ,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAEpC,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,QAAQ,CAAC,sBAAsB,EAAE,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC;IAC9C,CAAC;IAED,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAkC,EAClC,OAA+B;IAE/B,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,GAAG,IAAI,KAAK,OAAO,aAAa,CAAC;AAC1C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAA+B;IAC9D,OAAO,wBAAwB,OAAO,gDAAgD,CAAC;AACzF,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file types.ts
|
|
3
|
+
* Type definitions for the avatar generation pipeline.
|
|
4
|
+
*
|
|
5
|
+
* Covers the full lifecycle: request → staged jobs → drift audit → result.
|
|
6
|
+
*/
|
|
7
|
+
import type { AvatarIdentityDescriptor, AvatarIdentityPackage } from '../../api/types.js';
|
|
8
|
+
import type { PolicyTier } from '../../core/llm/routing/UncensoredModelCatalog.js';
|
|
9
|
+
/**
|
|
10
|
+
* Discrete stages of the avatar generation pipeline, executed in order.
|
|
11
|
+
*
|
|
12
|
+
* - `neutral_portrait` — Generate the canonical neutral-expression portrait.
|
|
13
|
+
* - `face_embedding` — Extract a 512-dim face vector from the neutral portrait.
|
|
14
|
+
* - `expression_sheet` — Generate emotion variants and drift-check each one.
|
|
15
|
+
* - `animated_emotes` — Generate animated emote loops per emotion.
|
|
16
|
+
* - `full_body` — Generate a full-body reference image.
|
|
17
|
+
* - `additional_angles` — Generate extra viewpoint references (3/4, profile).
|
|
18
|
+
*/
|
|
19
|
+
export type AvatarGenerationStage = 'neutral_portrait' | 'face_embedding' | 'expression_sheet' | 'animated_emotes' | 'full_body' | 'additional_angles';
|
|
20
|
+
/** Input to the avatar generation pipeline. */
|
|
21
|
+
export interface AvatarGenerationRequest {
|
|
22
|
+
/** Character identifier for the generated identity package. */
|
|
23
|
+
characterId: string;
|
|
24
|
+
/** Identity descriptors driving image generation prompts. */
|
|
25
|
+
identity: AvatarIdentityDescriptor;
|
|
26
|
+
/** Which stages to execute (defaults to all). */
|
|
27
|
+
stages?: AvatarGenerationStage[];
|
|
28
|
+
/** Content policy tier forwarded to the image generator. */
|
|
29
|
+
policyTier?: PolicyTier;
|
|
30
|
+
/** Image generation parameters. */
|
|
31
|
+
generationConfig: {
|
|
32
|
+
/** Model identifier (e.g. "black-forest-labs/flux-schnell"). */
|
|
33
|
+
baseModel: string;
|
|
34
|
+
/** Provider identifier (e.g. "replicate"). */
|
|
35
|
+
provider: string;
|
|
36
|
+
/** Random seed for reproducible output. */
|
|
37
|
+
seed?: number;
|
|
38
|
+
/** Negative prompt to avoid unwanted artefacts. */
|
|
39
|
+
negativePrompt?: string;
|
|
40
|
+
/** Named style preset (provider-specific). */
|
|
41
|
+
stylePreset?: string;
|
|
42
|
+
};
|
|
43
|
+
/** Drift-guard thresholds. */
|
|
44
|
+
driftGuard?: {
|
|
45
|
+
/** Minimum cosine similarity to the anchor face embedding. */
|
|
46
|
+
faceSimilarity?: number;
|
|
47
|
+
/** Reject images below the similarity threshold. */
|
|
48
|
+
rejectBelowThreshold?: boolean;
|
|
49
|
+
/** Maximum retries when generated face drifts. */
|
|
50
|
+
maxRegenerationAttempts?: number;
|
|
51
|
+
};
|
|
52
|
+
/** Pre-existing anchors to reuse instead of regenerating. */
|
|
53
|
+
existingAnchors?: {
|
|
54
|
+
neutralPortrait?: string;
|
|
55
|
+
faceEmbedding?: number[];
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Tracking record for a single pipeline job. */
|
|
59
|
+
export interface AvatarGenerationJob {
|
|
60
|
+
/** Which stage this job belongs to. */
|
|
61
|
+
stage: AvatarGenerationStage;
|
|
62
|
+
/** Human-readable label (e.g. "neutral_portrait", "expression:happy"). */
|
|
63
|
+
label: string;
|
|
64
|
+
/** Job status. */
|
|
65
|
+
status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped';
|
|
66
|
+
/** Generated image URL on success. */
|
|
67
|
+
imageUrl?: string;
|
|
68
|
+
/** Drift similarity score (for expression/emote stages). */
|
|
69
|
+
driftScore?: number;
|
|
70
|
+
/** Number of regeneration attempts for this job. */
|
|
71
|
+
attempts: number;
|
|
72
|
+
/** Error message on failure. */
|
|
73
|
+
error?: string;
|
|
74
|
+
/** Wall-clock duration in milliseconds. */
|
|
75
|
+
durationMs?: number;
|
|
76
|
+
}
|
|
77
|
+
/** Aggregate drift audit across all generated assets. */
|
|
78
|
+
export interface DriftAuditReport {
|
|
79
|
+
/** Anchor face embedding used as the reference. */
|
|
80
|
+
anchorEmbeddingDim: number;
|
|
81
|
+
/** Per-image drift scores keyed by label. */
|
|
82
|
+
scores: Record<string, number>;
|
|
83
|
+
/** Labels of images that were rejected for excessive drift. */
|
|
84
|
+
rejected: string[];
|
|
85
|
+
/** Labels of images that were regenerated (at least once). */
|
|
86
|
+
regenerated: string[];
|
|
87
|
+
/** Overall pass/fail for the entire batch. */
|
|
88
|
+
passed: boolean;
|
|
89
|
+
}
|
|
90
|
+
/** Output of a complete avatar generation pipeline run. */
|
|
91
|
+
export interface AvatarGenerationResult {
|
|
92
|
+
/** The assembled identity package. */
|
|
93
|
+
identityPackage: AvatarIdentityPackage;
|
|
94
|
+
/** Per-stage job records for observability. */
|
|
95
|
+
jobs: AvatarGenerationJob[];
|
|
96
|
+
/** Drift audit report (present when face_embedding stage ran). */
|
|
97
|
+
driftReport?: DriftAuditReport;
|
|
98
|
+
/** Total wall-clock time in milliseconds. */
|
|
99
|
+
totalDurationMs: number;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/media/avatar/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kDAAkD,CAAC;AAMnF;;;;;;;;;GASG;AACH,MAAM,MAAM,qBAAqB,GAC7B,kBAAkB,GAClB,gBAAgB,GAChB,kBAAkB,GAClB,iBAAiB,GACjB,WAAW,GACX,mBAAmB,CAAC;AAMxB,+CAA+C;AAC/C,MAAM,WAAW,uBAAuB;IACtC,+DAA+D;IAC/D,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,EAAE,wBAAwB,CAAC;IACnC,iDAAiD;IACjD,MAAM,CAAC,EAAE,qBAAqB,EAAE,CAAC;IACjC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,mCAAmC;IACnC,gBAAgB,EAAE;QAChB,gEAAgE;QAChE,SAAS,EAAE,MAAM,CAAC;QAClB,8CAA8C;QAC9C,QAAQ,EAAE,MAAM,CAAC;QACjB,2CAA2C;QAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,mDAAmD;QACnD,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,8CAA8C;QAC9C,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,8BAA8B;IAC9B,UAAU,CAAC,EAAE;QACX,8DAA8D;QAC9D,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,oDAAoD;QACpD,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,kDAAkD;QAClD,uBAAuB,CAAC,EAAE,MAAM,CAAC;KAClC,CAAC;IACF,6DAA6D;IAC7D,eAAe,CAAC,EAAE;QAChB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACH;AAED,iDAAiD;AACjD,MAAM,WAAW,mBAAmB;IAClC,uCAAuC;IACvC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB;IAClB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IACnE,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yDAAyD;AACzD,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,8DAA8D;IAC9D,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,8CAA8C;IAC9C,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,2DAA2D;AAC3D,MAAM,WAAW,sBAAsB;IACrC,sCAAsC;IACtC,eAAe,EAAE,qBAAqB,CAAC;IACvC,+CAA+C;IAC/C,IAAI,EAAE,mBAAmB,EAAE,CAAC;IAC5B,kEAAkE;IAClE,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,6CAA6C;IAC7C,eAAe,EAAE,MAAM,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/media/avatar/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|