@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.
@@ -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
- for (const lang of ['en-us', 'pt-br']) {
302
- const descriptionField =
303
- lang === 'en-us'
304
- ? parsedDescVirtues[i].descriptionEN
305
- : gender === 'male'
306
- ? parsedDescVirtues[i].descriptionPTM
307
- : parsedDescVirtues[i].descriptionPTF;
308
-
309
- const id = `${combinationString}:${gender}:${index}${
310
- lang === 'pt-br' ? ':pt' : ''
311
- }`;
312
- await this.log('debug', `Updating description and virtues for ${id}`, {
313
- description: descriptionField,
314
- virtues: parsedDescVirtues[i].virtues,
315
- });
316
-
317
- await db
318
- .update(schema.archetypesData)
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
- .execute();
331
-
332
- await this.log('info', `Updated description and virtues for ${id}`);
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
- private parseDescriptionAndVirtuesResponse(response: string) {
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').filter((line) => line.trim());
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 virtues: string[] = [];
425
+ let virtuesEN: string[] = [];
426
+ let virtuesPT: string[] = [];
371
427
  let currentField = '';
372
-
373
- for (const line of lines) {
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
- 'debug',
395
- `Extracted descriptionPTF for entry ${entryIndex + 1}`,
396
- { descriptionPTF }
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
- currentField = 'virtues';
400
- virtues =
401
- line
402
- .split('• Virtues:')[1]
403
- ?.split(',')
404
- .map((v) => v.trim())
405
- .filter((v) => v) || [];
406
- this.log('debug', `Extracted virtues for entry ${entryIndex + 1}`, {
407
- virtues,
408
- });
409
- } else if (currentField && currentField !== 'virtues') {
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.trim();
412
- this.log(
413
- 'debug',
414
- `Appended to descriptionEN for entry ${entryIndex + 1}`,
415
- { descriptionEN }
416
- );
417
- }
418
- if (currentField === 'descriptionPTM') {
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
- if (
438
- !descriptionEN ||
439
- !descriptionPTM ||
440
- !descriptionPTF ||
441
- virtues.length !== 3
442
- ) {
443
- this.log(
444
- 'warn',
445
- `Malformed description and virtues response for entry ${
446
- entryIndex + 1
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, virtues };
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: Array<{ malePrompt: string; femalePrompt: string }> = [];
834
-
835
- for (let i = 0; i < lines.length; i += 2) {
836
- const maleLine = lines[i];
837
- const femaleLine = lines[i + 1];
838
-
839
- const malePrompt = maleLine.startsWith(`${Math.floor(i / 2) + 1}.m`)
840
- ? maleLine.split(`${Math.floor(i / 2) + 1}.m`)[1]?.trim()
841
- : '';
842
- const femalePrompt = femaleLine.startsWith(`${Math.floor(i / 2) + 1}.f`)
843
- ? femaleLine.split(`${Math.floor(i / 2) + 1}.f`)[1]?.trim()
844
- : '';
845
-
846
- prompts.push({ malePrompt, femalePrompt });
847
- this.log(
848
- 'debug',
849
- `Parsed prompts for archetype ${Math.floor(i / 2) + 1}`,
850
- { malePrompt, femalePrompt }
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
- 'warn',
856
- `Malformed Leonardo prompt for archetype ${Math.floor(i / 2) + 1}`,
857
- {
858
- malePrompt,
859
- femalePrompt,
860
- maleLine,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.316",
3
+ "version": "0.0.317",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -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
- 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.
215
-
216
- For each archetype, generate two prompts:
217
- - One for a male character
218
- - One for a female character
219
-
220
- Instructions:
221
- - Focus primarily on the character design—their appearance, clothing, and demeanor. This is more important than the background or setting.
222
- - 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.
223
- - The character must reflect the symbolic and mythic tone of the archetype name and description.
224
- - Make sure male characters have short, cropped, or bald hair. Never long.
225
- - Female characters may have long, flowing, or styled hair if it suits the archetype.
226
- - The outfit should be rich in fantasy elements: armor, cloaks, robes, accessories. Avoid modern or casual clothing.
227
- - The character must always be facing the camera, with a clear, visible face.
228
- - Rendering instructions must include: 8K, HDR, Unreal Engine, photorealism, cinematic lighting, full body, fantasy aesthetic.
229
-
230
- Each prompt must:
231
- - Be under 1200 characters (including spaces).
232
- - Clearly distinguish between the male and female versions only by adapting gender-specific features.
233
- - Maintain identical structure, setting, and tone between both versions.
234
-
235
- Output Format
236
-
237
- 1.m
238
- [Prompt for the first archetype made for a male character]
239
-
240
- 1.f
241
- [Prompt for the first archetype made for a female character (same as the male prompt but adapted for gender-specific traits)]
242
-
243
- 2.m
244
- [Prompt for the second archetype made for a male character]
245
-
246
- 2.f
247
- [Prompt for the second archetype made for a female character]
248
-
249
- 3.m
250
- [Prompt for the third archetype made for a male character]
251
-
252
- 3.f
253
- [Prompt for the third archetype made for a female character]
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
  },