@zodic/shared 0.0.316 → 0.0.317
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/app/services/ArchetypeService.ts +231 -159
- package/package.json +1 -1
- package/utils/buildMessages.ts +73 -58
|
@@ -6,6 +6,19 @@ import { ZodiacSignSlug } from '../../types/scopes/legacy';
|
|
|
6
6
|
import { generateArchetypePrompt } from '../../utils/archetypeNamesMessages';
|
|
7
7
|
import { AppContext } from '../base';
|
|
8
8
|
|
|
9
|
+
interface ParsedDescriptionAndVirtues {
|
|
10
|
+
descriptionEN: string;
|
|
11
|
+
descriptionPTM: string;
|
|
12
|
+
descriptionPTF: string;
|
|
13
|
+
virtuesEN: string[];
|
|
14
|
+
virtuesPT: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface LeonardoPrompt {
|
|
18
|
+
malePrompt: string;
|
|
19
|
+
femalePrompt: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
9
22
|
@injectable()
|
|
10
23
|
export class ArchetypeService {
|
|
11
24
|
constructor(@inject(AppContext) private context: AppContext) {}
|
|
@@ -241,7 +254,7 @@ export class ArchetypeService {
|
|
|
241
254
|
gender,
|
|
242
255
|
language,
|
|
243
256
|
});
|
|
244
|
-
|
|
257
|
+
|
|
245
258
|
const db = this.context.drizzle();
|
|
246
259
|
const archetypes = await db
|
|
247
260
|
.select()
|
|
@@ -254,12 +267,12 @@ export class ArchetypeService {
|
|
|
254
267
|
)
|
|
255
268
|
)
|
|
256
269
|
.execute();
|
|
257
|
-
|
|
270
|
+
|
|
258
271
|
await this.log('info', 'Fetched archetypes for description generation', {
|
|
259
272
|
archetypesCount: archetypes.length,
|
|
260
273
|
names: archetypes.map((a) => a.name),
|
|
261
274
|
});
|
|
262
|
-
|
|
275
|
+
|
|
263
276
|
const descVirtueMessages = this.context
|
|
264
277
|
.buildLLMMessages()
|
|
265
278
|
.generateCosmicMirrorDescriptionAndVirtues({
|
|
@@ -271,7 +284,7 @@ export class ArchetypeService {
|
|
|
271
284
|
archetypes[2].essenceLine,
|
|
272
285
|
],
|
|
273
286
|
});
|
|
274
|
-
|
|
287
|
+
|
|
275
288
|
await this.log('debug', 'Calling API for descriptions and virtues', {
|
|
276
289
|
messages: descVirtueMessages,
|
|
277
290
|
});
|
|
@@ -289,50 +302,83 @@ export class ArchetypeService {
|
|
|
289
302
|
await this.log('info', 'Received descriptions and virtues response', {
|
|
290
303
|
responseLength: descVirtueResponse.length,
|
|
291
304
|
});
|
|
292
|
-
|
|
293
|
-
const parsedDescVirtues =
|
|
294
|
-
this.parseDescriptionAndVirtuesResponse(descVirtueResponse);
|
|
305
|
+
|
|
306
|
+
const parsedDescVirtues = this.parseDescriptionAndVirtuesResponse(descVirtueResponse);
|
|
295
307
|
await this.log('info', 'Parsed descriptions and virtues', {
|
|
296
308
|
parsedDescVirtues,
|
|
297
309
|
});
|
|
298
|
-
|
|
310
|
+
|
|
299
311
|
for (let i = 0; i < 3; i++) {
|
|
300
312
|
const index = (i + 1).toString();
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
.set({
|
|
320
|
-
description: descriptionField,
|
|
321
|
-
virtues: JSON.stringify(parsedDescVirtues[i].virtues),
|
|
322
|
-
updatedAt: new Date().getTime(),
|
|
323
|
-
})
|
|
324
|
-
.where(
|
|
325
|
-
and(
|
|
326
|
-
eq(schema.archetypesData.id, id),
|
|
327
|
-
eq(schema.archetypesData.language, lang)
|
|
328
|
-
)
|
|
313
|
+
|
|
314
|
+
// Update English entry (en-us)
|
|
315
|
+
const enId = `${combinationString}:${gender}:${index}`;
|
|
316
|
+
await this.log('debug', `Updating description and virtues for ${enId}`, {
|
|
317
|
+
description: parsedDescVirtues[i].descriptionEN,
|
|
318
|
+
virtues: parsedDescVirtues[i].virtuesEN,
|
|
319
|
+
});
|
|
320
|
+
await db
|
|
321
|
+
.update(schema.archetypesData)
|
|
322
|
+
.set({
|
|
323
|
+
description: parsedDescVirtues[i].descriptionEN,
|
|
324
|
+
virtues: JSON.stringify(parsedDescVirtues[i].virtuesEN),
|
|
325
|
+
updatedAt: new Date().getTime(),
|
|
326
|
+
})
|
|
327
|
+
.where(
|
|
328
|
+
and(
|
|
329
|
+
eq(schema.archetypesData.id, enId),
|
|
330
|
+
eq(schema.archetypesData.language, 'en-us')
|
|
329
331
|
)
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
332
|
+
)
|
|
333
|
+
.execute();
|
|
334
|
+
await this.log('info', `Updated description and virtues for ${enId}`);
|
|
335
|
+
|
|
336
|
+
// Update Portuguese entries (pt-br) for both male and female
|
|
337
|
+
const ptIdMale = `${combinationString}:${gender}:${index}:pt`;
|
|
338
|
+
await this.log('debug', `Updating description and virtues for ${ptIdMale} (male)`, {
|
|
339
|
+
description: parsedDescVirtues[i].descriptionPTM,
|
|
340
|
+
virtues: parsedDescVirtues[i].virtuesPT,
|
|
341
|
+
});
|
|
342
|
+
await db
|
|
343
|
+
.update(schema.archetypesData)
|
|
344
|
+
.set({
|
|
345
|
+
description: parsedDescVirtues[i].descriptionPTM,
|
|
346
|
+
virtues: JSON.stringify(parsedDescVirtues[i].virtuesPT),
|
|
347
|
+
updatedAt: new Date().getTime(),
|
|
348
|
+
})
|
|
349
|
+
.where(
|
|
350
|
+
and(
|
|
351
|
+
eq(schema.archetypesData.id, ptIdMale),
|
|
352
|
+
eq(schema.archetypesData.language, 'pt-br'),
|
|
353
|
+
eq(schema.archetypesData.gender, 'male')
|
|
354
|
+
)
|
|
355
|
+
)
|
|
356
|
+
.execute();
|
|
357
|
+
await this.log('info', `Updated description and virtues for ${ptIdMale} (male)`);
|
|
358
|
+
|
|
359
|
+
const ptIdFemale = `${combinationString}:${gender}:${index}:pt`;
|
|
360
|
+
await this.log('debug', `Updating description and virtues for ${ptIdFemale} (female)`, {
|
|
361
|
+
description: parsedDescVirtues[i].descriptionPTF,
|
|
362
|
+
virtues: parsedDescVirtues[i].virtuesPT,
|
|
363
|
+
});
|
|
364
|
+
await db
|
|
365
|
+
.update(schema.archetypesData)
|
|
366
|
+
.set({
|
|
367
|
+
description: parsedDescVirtues[i].descriptionPTF,
|
|
368
|
+
virtues: JSON.stringify(parsedDescVirtues[i].virtuesPT),
|
|
369
|
+
updatedAt: new Date().getTime(),
|
|
370
|
+
})
|
|
371
|
+
.where(
|
|
372
|
+
and(
|
|
373
|
+
eq(schema.archetypesData.id, ptIdFemale),
|
|
374
|
+
eq(schema.archetypesData.language, 'pt-br'),
|
|
375
|
+
eq(schema.archetypesData.gender, 'female')
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
.execute();
|
|
379
|
+
await this.log('info', `Updated description and virtues for ${ptIdFemale} (female)`);
|
|
334
380
|
}
|
|
335
|
-
|
|
381
|
+
|
|
336
382
|
await this.log('info', 'Completed generateDescriptionsAndVirtues', {
|
|
337
383
|
combinationString,
|
|
338
384
|
gender,
|
|
@@ -341,126 +387,136 @@ export class ArchetypeService {
|
|
|
341
387
|
return parsedDescVirtues;
|
|
342
388
|
}
|
|
343
389
|
|
|
344
|
-
|
|
390
|
+
|
|
391
|
+
private parseDescriptionAndVirtuesResponse(response: string): ParsedDescriptionAndVirtues[] {
|
|
345
392
|
this.log('debug', 'Starting parseDescriptionAndVirtuesResponse', {
|
|
346
393
|
responseLength: response.length,
|
|
347
394
|
});
|
|
348
|
-
|
|
395
|
+
|
|
349
396
|
const entries = response
|
|
350
397
|
.split(/---/)
|
|
351
398
|
.map((block) => block.trim())
|
|
352
399
|
.filter((block) => block.length > 0);
|
|
353
|
-
|
|
400
|
+
|
|
354
401
|
this.log('debug', 'Split response into entries', {
|
|
355
402
|
entriesCount: entries.length,
|
|
356
403
|
});
|
|
357
|
-
|
|
404
|
+
|
|
405
|
+
if (entries.length !== 3) {
|
|
406
|
+
this.log('error', 'Expected exactly 3 archetype entries', {
|
|
407
|
+
entriesCount: entries.length,
|
|
408
|
+
response,
|
|
409
|
+
});
|
|
410
|
+
throw new Error(`Expected exactly 3 archetype entries, but got ${entries.length}`);
|
|
411
|
+
}
|
|
412
|
+
|
|
358
413
|
const result = entries.map((entry, entryIndex) => {
|
|
359
414
|
this.log('debug', `Processing entry ${entryIndex + 1}`, { entry });
|
|
360
|
-
|
|
361
|
-
const lines = entry.split('\n').
|
|
415
|
+
|
|
416
|
+
const lines = entry.split('\n').map((line) => line.trim()).filter((line) => line);
|
|
362
417
|
this.log('debug', `Split entry ${entryIndex + 1} into lines`, {
|
|
363
418
|
linesCount: lines.length,
|
|
364
419
|
lines,
|
|
365
420
|
});
|
|
366
|
-
|
|
421
|
+
|
|
367
422
|
let descriptionEN = '';
|
|
368
423
|
let descriptionPTM = '';
|
|
369
424
|
let descriptionPTF = '';
|
|
370
|
-
let
|
|
425
|
+
let virtuesEN: string[] = [];
|
|
426
|
+
let virtuesPT: string[] = [];
|
|
371
427
|
let currentField = '';
|
|
372
|
-
|
|
373
|
-
for (
|
|
428
|
+
|
|
429
|
+
for (let i = 0; i < lines.length; i++) {
|
|
430
|
+
let line = lines[i];
|
|
431
|
+
|
|
432
|
+
// Remove markdown bold (**...**) from field names
|
|
433
|
+
line = line.replace(/\*\*(.*?)\*\*/g, '$1');
|
|
434
|
+
|
|
435
|
+
if (line.startsWith('1.') || line.startsWith('2.') || line.startsWith('3.')) {
|
|
436
|
+
continue; // Skip entry number lines
|
|
437
|
+
}
|
|
438
|
+
|
|
374
439
|
if (line.startsWith('• Description EN:')) {
|
|
375
440
|
currentField = 'descriptionEN';
|
|
376
441
|
descriptionEN = line.split('• Description EN:')[1]?.trim() || '';
|
|
377
|
-
this.log(
|
|
378
|
-
'debug',
|
|
379
|
-
`Extracted descriptionEN for entry ${entryIndex + 1}`,
|
|
380
|
-
{ descriptionEN }
|
|
381
|
-
);
|
|
442
|
+
this.log('debug', `Extracted descriptionEN for entry ${entryIndex + 1}`, { descriptionEN });
|
|
382
443
|
} else if (line.startsWith('• Description PT-M:')) {
|
|
383
444
|
currentField = 'descriptionPTM';
|
|
384
445
|
descriptionPTM = line.split('• Description PT-M:')[1]?.trim() || '';
|
|
385
|
-
this.log(
|
|
386
|
-
'debug',
|
|
387
|
-
`Extracted descriptionPTM for entry ${entryIndex + 1}`,
|
|
388
|
-
{ descriptionPTM }
|
|
389
|
-
);
|
|
446
|
+
this.log('debug', `Extracted descriptionPTM for entry ${entryIndex + 1}`, { descriptionPTM });
|
|
390
447
|
} else if (line.startsWith('• Description PT-F:')) {
|
|
391
448
|
currentField = 'descriptionPTF';
|
|
392
449
|
descriptionPTF = line.split('• Description PT-F:')[1]?.trim() || '';
|
|
393
|
-
this.log(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
450
|
+
this.log('debug', `Extracted descriptionPTF for entry ${entryIndex + 1}`, { descriptionPTF });
|
|
451
|
+
} else if (line.startsWith('• Virtues EN:')) {
|
|
452
|
+
currentField = 'virtuesEN';
|
|
453
|
+
virtuesEN = line
|
|
454
|
+
.split('• Virtues EN:')[1]
|
|
455
|
+
?.split(',')
|
|
456
|
+
.map((v) => v.trim())
|
|
457
|
+
.filter((v) => v)
|
|
458
|
+
.slice(0, 3);
|
|
459
|
+
this.log('debug', `Extracted virtuesEN for entry ${entryIndex + 1}`, { virtuesEN });
|
|
460
|
+
} else if (line.startsWith('• Virtues PT:')) {
|
|
461
|
+
currentField = 'virtuesPT';
|
|
462
|
+
virtuesPT = line
|
|
463
|
+
.split('• Virtues PT:')[1]
|
|
464
|
+
?.split(',')
|
|
465
|
+
.map((v) => v.trim())
|
|
466
|
+
.filter((v) => v)
|
|
467
|
+
.slice(0, 3);
|
|
468
|
+
this.log('debug', `Extracted virtuesPT for entry ${entryIndex + 1}`, { virtuesPT });
|
|
398
469
|
} else if (line.startsWith('• Virtues:')) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
470
|
+
// Fallback for older response format: use English virtues and attempt to translate
|
|
471
|
+
currentField = 'virtuesEN';
|
|
472
|
+
virtuesEN = line
|
|
473
|
+
.split('• Virtues:')[1]
|
|
474
|
+
?.split(',')
|
|
475
|
+
.map((v) => v.trim())
|
|
476
|
+
.filter((v) => v)
|
|
477
|
+
.slice(0, 3);
|
|
478
|
+
this.log('debug', `Extracted virtuesEN (fallback) for entry ${entryIndex + 1}`, { virtuesEN });
|
|
479
|
+
|
|
480
|
+
// Simple translation mapping for common virtues (as a fallback)
|
|
481
|
+
const virtueTranslations: { [key: string]: string } = {
|
|
482
|
+
Harmony: 'Harmonia',
|
|
483
|
+
Intuition: 'Intuição',
|
|
484
|
+
Grace: 'Graça',
|
|
485
|
+
// Add more translations as needed
|
|
486
|
+
};
|
|
487
|
+
virtuesPT = virtuesEN.map((v) => virtueTranslations[v] || v); // Fallback to English if no translation
|
|
488
|
+
this.log('debug', `Generated virtuesPT (fallback) for entry ${entryIndex + 1}`, { virtuesPT });
|
|
489
|
+
} else if (currentField && !currentField.startsWith('virtues')) {
|
|
410
490
|
if (currentField === 'descriptionEN') {
|
|
411
|
-
descriptionEN += ' ' + line
|
|
412
|
-
this.log(
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
descriptionPTM += ' ' + line.trim();
|
|
420
|
-
this.log(
|
|
421
|
-
'debug',
|
|
422
|
-
`Appended to descriptionPTM for entry ${entryIndex + 1}`,
|
|
423
|
-
{ descriptionPTM }
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
if (currentField === 'descriptionPTF') {
|
|
427
|
-
descriptionPTF += ' ' + line.trim();
|
|
428
|
-
this.log(
|
|
429
|
-
'debug',
|
|
430
|
-
`Appended to descriptionPTF for entry ${entryIndex + 1}`,
|
|
431
|
-
{ descriptionPTF }
|
|
432
|
-
);
|
|
491
|
+
descriptionEN += ' ' + line;
|
|
492
|
+
this.log('debug', `Appended to descriptionEN for entry ${entryIndex + 1}`, { descriptionEN });
|
|
493
|
+
} else if (currentField === 'descriptionPTM') {
|
|
494
|
+
descriptionPTM += ' ' + line;
|
|
495
|
+
this.log('debug', `Appended to descriptionPTM for entry ${entryIndex + 1}`, { descriptionPTM });
|
|
496
|
+
} else if (currentField === 'descriptionPTF') {
|
|
497
|
+
descriptionPTF += ' ' + line;
|
|
498
|
+
this.log('debug', `Appended to descriptionPTF for entry ${entryIndex + 1}`, { descriptionPTF });
|
|
433
499
|
}
|
|
434
500
|
}
|
|
435
501
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
{
|
|
449
|
-
descriptionEN,
|
|
450
|
-
descriptionPTM,
|
|
451
|
-
descriptionPTF,
|
|
452
|
-
virtues,
|
|
453
|
-
response: entry,
|
|
454
|
-
}
|
|
455
|
-
);
|
|
502
|
+
|
|
503
|
+
// Validate the parsed data
|
|
504
|
+
if (!descriptionEN || !descriptionPTM || !descriptionPTF || virtuesEN.length !== 3 || virtuesPT.length !== 3) {
|
|
505
|
+
this.log('warn', `Malformed description and virtues response for entry ${entryIndex + 1}`, {
|
|
506
|
+
descriptionEN,
|
|
507
|
+
descriptionPTM,
|
|
508
|
+
descriptionPTF,
|
|
509
|
+
virtuesEN,
|
|
510
|
+
virtuesPT,
|
|
511
|
+
response: entry,
|
|
512
|
+
});
|
|
513
|
+
throw new Error(`Malformed response for entry ${entryIndex + 1}: Missing required fields`);
|
|
456
514
|
}
|
|
457
|
-
|
|
458
|
-
return { descriptionEN, descriptionPTM, descriptionPTF,
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
this.log('info', 'Completed parseDescriptionAndVirtuesResponse', {
|
|
462
|
-
result,
|
|
515
|
+
|
|
516
|
+
return { descriptionEN, descriptionPTM, descriptionPTF, virtuesEN, virtuesPT };
|
|
463
517
|
});
|
|
518
|
+
|
|
519
|
+
this.log('info', 'Completed parseDescriptionAndVirtuesResponse', { result });
|
|
464
520
|
return result;
|
|
465
521
|
}
|
|
466
522
|
|
|
@@ -819,51 +875,67 @@ export class ArchetypeService {
|
|
|
819
875
|
return parsedPrompts;
|
|
820
876
|
}
|
|
821
877
|
|
|
822
|
-
private parseLeonardoPromptResponse(response: string) {
|
|
878
|
+
private parseLeonardoPromptResponse(response: string): LeonardoPrompt[] {
|
|
823
879
|
this.log('debug', 'Starting parseLeonardoPromptResponse', {
|
|
824
880
|
responseLength: response.length,
|
|
825
881
|
});
|
|
826
|
-
|
|
882
|
+
|
|
827
883
|
const lines = response.split('\n').filter((line) => line.trim());
|
|
828
884
|
this.log('debug', 'Split response into lines', {
|
|
829
885
|
linesCount: lines.length,
|
|
830
886
|
lines,
|
|
831
887
|
});
|
|
832
|
-
|
|
833
|
-
const prompts:
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
'
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
888
|
+
|
|
889
|
+
const prompts: LeonardoPrompt[] = [];
|
|
890
|
+
let currentArchetype = 0;
|
|
891
|
+
|
|
892
|
+
for (let i = 0; i < lines.length; i += 4) {
|
|
893
|
+
// Expect pairs of label and prompt: "1.m", male prompt, "1.f", female prompt
|
|
894
|
+
const maleLabel = lines[i]; // "1.m"
|
|
895
|
+
const malePromptLine = lines[i + 1]; // Male prompt text
|
|
896
|
+
const femaleLabel = lines[i + 2]; // "1.f"
|
|
897
|
+
const femalePromptLine = lines[i + 3]; // Female prompt text
|
|
898
|
+
|
|
899
|
+
currentArchetype++;
|
|
900
|
+
const expectedMaleLabel = `${currentArchetype}.m`;
|
|
901
|
+
const expectedFemaleLabel = `${currentArchetype}.f`;
|
|
902
|
+
|
|
903
|
+
if (!maleLabel?.startsWith(expectedMaleLabel) || !femaleLabel?.startsWith(expectedFemaleLabel)) {
|
|
904
|
+
this.log('warn', `Malformed Leonardo prompt format for archetype ${currentArchetype}`, {
|
|
905
|
+
maleLabel,
|
|
906
|
+
malePromptLine,
|
|
907
|
+
femaleLabel,
|
|
908
|
+
femalePromptLine,
|
|
909
|
+
lines,
|
|
910
|
+
});
|
|
911
|
+
throw new Error(`Expected ${expectedMaleLabel} and ${expectedFemaleLabel} at lines ${i} and ${i + 2}`);
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
const malePrompt = malePromptLine?.trim() || '';
|
|
915
|
+
const femalePrompt = femalePromptLine?.trim() || '';
|
|
916
|
+
|
|
853
917
|
if (!malePrompt || !femalePrompt) {
|
|
854
|
-
this.log(
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
femaleLine,
|
|
862
|
-
}
|
|
863
|
-
);
|
|
918
|
+
this.log('warn', `Empty Leonardo prompt for archetype ${currentArchetype}`, {
|
|
919
|
+
malePrompt,
|
|
920
|
+
femalePrompt,
|
|
921
|
+
malePromptLine,
|
|
922
|
+
femalePromptLine,
|
|
923
|
+
});
|
|
924
|
+
throw new Error(`Empty prompt for archetype ${currentArchetype}`);
|
|
864
925
|
}
|
|
926
|
+
|
|
927
|
+
prompts.push({ malePrompt, femalePrompt });
|
|
928
|
+
this.log('debug', `Parsed prompts for archetype ${currentArchetype}`, { malePrompt, femalePrompt });
|
|
865
929
|
}
|
|
866
|
-
|
|
930
|
+
|
|
931
|
+
if (prompts.length !== 3) {
|
|
932
|
+
this.log('error', 'Expected exactly 3 archetype prompts', {
|
|
933
|
+
promptsCount: prompts.length,
|
|
934
|
+
response,
|
|
935
|
+
});
|
|
936
|
+
throw new Error(`Expected exactly 3 archetype prompts, but got ${prompts.length}`);
|
|
937
|
+
}
|
|
938
|
+
|
|
867
939
|
this.log('info', 'Completed parseLeonardoPromptResponse', { prompts });
|
|
868
940
|
return prompts;
|
|
869
941
|
}
|
package/package.json
CHANGED
package/utils/buildMessages.ts
CHANGED
|
@@ -34,38 +34,52 @@ export const buildLLMMessages = (env: BackendBindings) => ({
|
|
|
34
34
|
• Portuguese — masculine version
|
|
35
35
|
• Portuguese — feminine version
|
|
36
36
|
|
|
37
|
-
2. Three symbolic **Virtues** for each archetype
|
|
37
|
+
2. Three symbolic **Virtues** for each archetype, in both English and Portuguese:
|
|
38
|
+
• English Virtues (e.g., Harmony, Intuition, Grace)
|
|
39
|
+
• Portuguese Virtues (e.g., Harmonia, Intuição, Graça)
|
|
38
40
|
|
|
39
41
|
—
|
|
40
42
|
|
|
41
|
-
✳️ Use the following format exactly for the response:
|
|
43
|
+
✳️ Use the following format exactly for the response. Ensure each section is separated by a line break, and virtues are comma-separated on a single line. Do not use markdown (e.g., **bold**) in the field names:
|
|
42
44
|
|
|
43
45
|
---
|
|
44
46
|
|
|
45
47
|
1.
|
|
46
48
|
|
|
47
|
-
• Description EN:
|
|
48
|
-
• Description PT-M:
|
|
49
|
-
• Description PT-F:
|
|
50
|
-
• Virtues: Virtue1, Virtue2, Virtue3
|
|
49
|
+
• Description EN: [Description in English]
|
|
50
|
+
• Description PT-M: [Description in Portuguese, masculine]
|
|
51
|
+
• Description PT-F: [Description in Portuguese, feminine]
|
|
52
|
+
• Virtues EN: Virtue1, Virtue2, Virtue3
|
|
53
|
+
• Virtues PT: Virtude1, Virtude2, Virtude3
|
|
51
54
|
|
|
52
55
|
---
|
|
53
56
|
|
|
54
57
|
2.
|
|
55
58
|
|
|
56
|
-
• Description EN:
|
|
57
|
-
• Description PT-M:
|
|
58
|
-
• Description PT-F:
|
|
59
|
-
• Virtues: Virtue1, Virtue2, Virtue3
|
|
59
|
+
• Description EN: [Description in English]
|
|
60
|
+
• Description PT-M: [Description in Portuguese, masculine]
|
|
61
|
+
• Description PT-F: [Description in Portuguese, feminine]
|
|
62
|
+
• Virtues EN: Virtue1, Virtue2, Virtue3
|
|
63
|
+
• Virtues PT: Virtude1, Virtude2, Virtude3
|
|
60
64
|
|
|
61
65
|
---
|
|
62
66
|
|
|
63
67
|
3.
|
|
64
68
|
|
|
65
|
-
• Description EN:
|
|
66
|
-
• Description PT-M:
|
|
67
|
-
• Description PT-F:
|
|
68
|
-
• Virtues: Virtue1, Virtue2, Virtue3
|
|
69
|
+
• Description EN: [Description in English]
|
|
70
|
+
• Description PT-M: [Description in Portuguese, masculine]
|
|
71
|
+
• Description PT-F: [Description in Portuguese, feminine]
|
|
72
|
+
• Virtues EN: Virtue1, Virtue2, Virtue3
|
|
73
|
+
• Virtues PT: Virtude1, Virtude2, Virtude3
|
|
74
|
+
|
|
75
|
+
—
|
|
76
|
+
|
|
77
|
+
✳️ Rules:
|
|
78
|
+
- Do not include extra text outside the specified format.
|
|
79
|
+
- Do not use markdown (e.g., **bold**, *italic*) in field names like "Description EN" or "Virtues EN".
|
|
80
|
+
- Ensure each description is 80–100 words.
|
|
81
|
+
- Virtues must be exactly three per archetype, comma-separated, on a single line.
|
|
82
|
+
- Use proper grammar and avoid ambiguity in translations.
|
|
69
83
|
`,
|
|
70
84
|
},
|
|
71
85
|
{
|
|
@@ -211,56 +225,57 @@ export const buildLLMMessages = (env: BackendBindings) => ({
|
|
|
211
225
|
{
|
|
212
226
|
role: 'system',
|
|
213
227
|
content: `
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
228
|
+
You are an expert in fantasy image generation. Your task is to transform archetype names and symbolic descriptions into highly detailed prompts for generating photorealistic fantasy characters using Leonardo.ai.
|
|
229
|
+
|
|
230
|
+
For each archetype, generate two prompts:
|
|
231
|
+
- One for a male character
|
|
232
|
+
- One for a female character
|
|
233
|
+
|
|
234
|
+
Instructions:
|
|
235
|
+
- Focus primarily on the character design—their appearance, clothing, and demeanor. This is more important than the background or setting.
|
|
236
|
+
- The setting should remain fantasy-inspired, but avoid over-specification. General hints like “enchanted realm” or “mystical battlefield” are enough unless the archetype demands more.
|
|
237
|
+
- The character must reflect the symbolic and mythic tone of the archetype name and description.
|
|
238
|
+
- Make sure male characters have short, cropped, or bald hair. Never long.
|
|
239
|
+
- Female characters may have long, flowing, or styled hair if it suits the archetype.
|
|
240
|
+
- The outfit should be rich in fantasy elements: armor, cloaks, robes, accessories. Avoid modern or casual clothing.
|
|
241
|
+
- The character must always be facing the camera, with a clear, visible face.
|
|
242
|
+
- Rendering instructions must include: 8K, HDR, Unreal Engine, photorealism, cinematic lighting, full body, fantasy aesthetic.
|
|
243
|
+
|
|
244
|
+
Each prompt must:
|
|
245
|
+
- Be under 1200 characters (including spaces).
|
|
246
|
+
- Clearly distinguish between the male and female versions only by adapting gender-specific features.
|
|
247
|
+
- Maintain identical structure, setting, and tone between both versions.
|
|
248
|
+
- Be written on a single line (no line breaks within the prompt text).
|
|
249
|
+
|
|
250
|
+
Output Format (each prompt on a new line, no extra spaces or lines):
|
|
251
|
+
|
|
252
|
+
1.m
|
|
253
|
+
[Prompt for the first archetype made for a male character]
|
|
254
|
+
1.f
|
|
255
|
+
[Prompt for the first archetype made for a female character (same as the male prompt but adapted for gender-specific traits)]
|
|
256
|
+
2.m
|
|
257
|
+
[Prompt for the second archetype made for a male character]
|
|
258
|
+
2.f
|
|
259
|
+
[Prompt for the second archetype made for a female character]
|
|
260
|
+
3.m
|
|
261
|
+
[Prompt for the third archetype made for a male character]
|
|
262
|
+
3.f
|
|
263
|
+
[Prompt for the third archetype made for a female character]
|
|
264
|
+
|
|
265
|
+
Rules:
|
|
266
|
+
- Do not include extra text, spaces, or line breaks outside the specified format.
|
|
267
|
+
- Each prompt must be a single line.
|
|
268
|
+
- Ensure exactly 3 archetypes are provided, with both male and female prompts for each.
|
|
269
|
+
`,
|
|
255
270
|
},
|
|
256
271
|
{
|
|
257
272
|
role: 'user',
|
|
258
273
|
content: archetypes
|
|
259
274
|
.map((a, idx) =>
|
|
260
275
|
`
|
|
261
|
-
${idx + 1}.
|
|
262
|
-
- Name: ${a.name}
|
|
263
|
-
- Description: ${a.description}`.trim()
|
|
276
|
+
${idx + 1}.
|
|
277
|
+
- Name: ${a.name}
|
|
278
|
+
- Description: ${a.description}`.trim()
|
|
264
279
|
)
|
|
265
280
|
.join('\n\n'),
|
|
266
281
|
},
|