@zodic/shared 0.0.372 → 0.0.374
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 +510 -392
- package/app/services/LeonardoService.ts +21 -16
- package/app/workflow/ArchetypeWorkflow.ts +171 -168
- package/package.json +1 -1
- package/types/scopes/generic.ts +1 -1
|
@@ -28,42 +28,42 @@ export class ArchetypeService {
|
|
|
28
28
|
message: string,
|
|
29
29
|
context: Record<string, any> = {}
|
|
30
30
|
) {
|
|
31
|
-
const logMessage = `[${level.toUpperCase()}] ${message}`;
|
|
32
|
-
|
|
33
|
-
console
|
|
34
|
-
// try {
|
|
35
|
-
// await db
|
|
36
|
-
// .insert(schema.logs)
|
|
37
|
-
// .values({
|
|
38
|
-
// id: logId,
|
|
39
|
-
// level,
|
|
40
|
-
// message,
|
|
41
|
-
// context: JSON.stringify(context),
|
|
42
|
-
// createdAt: new Date().getTime(),
|
|
43
|
-
// })
|
|
44
|
-
// .execute();
|
|
45
|
-
// } catch (error) {
|
|
46
|
-
// console.error('[ERROR] Failed to persist log to database:', {
|
|
47
|
-
// error,
|
|
48
|
-
// logId,
|
|
49
|
-
// message,
|
|
50
|
-
// context,
|
|
51
|
-
// });
|
|
52
|
-
// }
|
|
31
|
+
const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
|
|
32
|
+
|
|
33
|
+
console[level](logMessage, context);
|
|
53
34
|
}
|
|
54
35
|
|
|
55
|
-
// Replace generateArchetypeNames and generateArchetypeNamesBatch
|
|
56
36
|
async generateArchetypeNames(
|
|
57
37
|
combinationString: string,
|
|
58
|
-
|
|
38
|
+
override: boolean = false,
|
|
59
39
|
indexesToGenerate: number[] = [1, 2, 3]
|
|
60
40
|
) {
|
|
61
41
|
await this.log('info', 'Starting generateArchetypeNames', {
|
|
62
42
|
combinationString,
|
|
63
|
-
|
|
43
|
+
override,
|
|
64
44
|
indexesToGenerate,
|
|
65
45
|
});
|
|
66
46
|
|
|
47
|
+
const db = this.context.drizzle();
|
|
48
|
+
const existingArchetypes = await db
|
|
49
|
+
.select()
|
|
50
|
+
.from(schema.archetypesData)
|
|
51
|
+
.where(eq(schema.archetypesData.combination, combinationString))
|
|
52
|
+
.orderBy(schema.archetypesData.archetypeIndex)
|
|
53
|
+
.execute();
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
!override &&
|
|
57
|
+
existingArchetypes.length >= 3 * 2 * 2 && // 3 indexes * 2 genders * 2 languages
|
|
58
|
+
existingArchetypes.every((a) => a.name && a.essenceLine)
|
|
59
|
+
) {
|
|
60
|
+
await this.log('info', 'Skipping archetype names generation', {
|
|
61
|
+
reason: 'All archetypes have names and essence lines',
|
|
62
|
+
existingCount: existingArchetypes.length,
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
67
|
const [sun, ascendant, moon] = combinationString.split(
|
|
68
68
|
'-'
|
|
69
69
|
) as ZodiacSignSlug[];
|
|
@@ -95,8 +95,6 @@ export class ArchetypeService {
|
|
|
95
95
|
portugueseVariants,
|
|
96
96
|
});
|
|
97
97
|
|
|
98
|
-
const db = this.context.drizzle();
|
|
99
|
-
|
|
100
98
|
async function isEnglishNameDuplicate(name: string): Promise<boolean> {
|
|
101
99
|
const result = await db
|
|
102
100
|
.select({ name: schema.archetypesData.name })
|
|
@@ -121,7 +119,10 @@ export class ArchetypeService {
|
|
|
121
119
|
await this.log(
|
|
122
120
|
'debug',
|
|
123
121
|
`Skipping index ${index} as it is not in indexesToGenerate`,
|
|
124
|
-
{
|
|
122
|
+
{
|
|
123
|
+
index,
|
|
124
|
+
indexesToGenerate,
|
|
125
|
+
}
|
|
125
126
|
);
|
|
126
127
|
continue;
|
|
127
128
|
}
|
|
@@ -134,7 +135,7 @@ export class ArchetypeService {
|
|
|
134
135
|
continue;
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
for (const gender of ['male', 'female']) {
|
|
138
|
+
for (const gender of ['male', 'female'] as Gender[]) {
|
|
138
139
|
for (const lang of ['en-us', 'pt-br']) {
|
|
139
140
|
const id = `${combinationString}:${gender}:${index}${
|
|
140
141
|
lang === 'pt-br' ? ':pt' : ''
|
|
@@ -148,9 +149,22 @@ export class ArchetypeService {
|
|
|
148
149
|
const essenceLine =
|
|
149
150
|
lang === 'en-us' ? entry.essenceLine : ptVariant.essenceLine;
|
|
150
151
|
|
|
152
|
+
const existing = existingArchetypes.find((a) => a.id === id);
|
|
153
|
+
if (existing && !override && existing.name && existing.essenceLine) {
|
|
154
|
+
await this.log('debug', `Skipping existing archetype ${id}`, {
|
|
155
|
+
name: existing.name,
|
|
156
|
+
essenceLine: existing.essenceLine,
|
|
157
|
+
archetypeIndex: index,
|
|
158
|
+
});
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
151
162
|
await this.log('debug', `Saving archetype name for ${id}`, {
|
|
152
163
|
name,
|
|
153
164
|
essenceLine,
|
|
165
|
+
archetypeIndex: index,
|
|
166
|
+
gender,
|
|
167
|
+
language: lang,
|
|
154
168
|
});
|
|
155
169
|
|
|
156
170
|
await db
|
|
@@ -171,6 +185,7 @@ export class ArchetypeService {
|
|
|
171
185
|
name,
|
|
172
186
|
essenceLine,
|
|
173
187
|
updatedAt: new Date().getTime(),
|
|
188
|
+
status: 'idle',
|
|
174
189
|
},
|
|
175
190
|
});
|
|
176
191
|
|
|
@@ -200,6 +215,13 @@ export class ArchetypeService {
|
|
|
200
215
|
blocksCount: blocks.length,
|
|
201
216
|
});
|
|
202
217
|
|
|
218
|
+
if (blocks.length !== 3) {
|
|
219
|
+
this.log('error', 'Expected exactly 3 archetype blocks', {
|
|
220
|
+
blocksCount: blocks.length,
|
|
221
|
+
});
|
|
222
|
+
throw new Error(`Expected 3 archetype blocks, got ${blocks.length}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
203
225
|
const english: Array<{ name: string; essenceLine: string }> = [];
|
|
204
226
|
const portuguese: Array<{
|
|
205
227
|
masc: string;
|
|
@@ -207,7 +229,7 @@ export class ArchetypeService {
|
|
|
207
229
|
essenceLine: string;
|
|
208
230
|
}> = [];
|
|
209
231
|
|
|
210
|
-
|
|
232
|
+
blocks.forEach((block, index) => {
|
|
211
233
|
const nameMatch = block.match(/- Name: (.+)/);
|
|
212
234
|
const essenceLineMatch = block.match(/- Essence Line: (.+)/);
|
|
213
235
|
const ptMascMatch = block.match(/- Portuguese \(Masc\): (.+)/);
|
|
@@ -230,10 +252,21 @@ export class ArchetypeService {
|
|
|
230
252
|
fem: ptFemMatch[1].trim(),
|
|
231
253
|
essenceLine: ptEssenceLineMatch[1].trim(),
|
|
232
254
|
});
|
|
255
|
+
this.log('debug', `Parsed block for archetypeIndex ${index + 1}`, {
|
|
256
|
+
english: english[index],
|
|
257
|
+
portuguese: portuguese[index],
|
|
258
|
+
});
|
|
233
259
|
} else {
|
|
234
|
-
this.log(
|
|
260
|
+
this.log(
|
|
261
|
+
'error',
|
|
262
|
+
`Malformed archetype name block for index ${index + 1}`,
|
|
263
|
+
{ block }
|
|
264
|
+
);
|
|
265
|
+
throw new Error(
|
|
266
|
+
`Malformed archetype name block for index ${index + 1}`
|
|
267
|
+
);
|
|
235
268
|
}
|
|
236
|
-
}
|
|
269
|
+
});
|
|
237
270
|
|
|
238
271
|
this.log('info', 'Completed parseArchetypeNameBlocks', {
|
|
239
272
|
english,
|
|
@@ -244,42 +277,82 @@ export class ArchetypeService {
|
|
|
244
277
|
|
|
245
278
|
async generateDescriptionsAndVirtues(
|
|
246
279
|
combinationString: string,
|
|
247
|
-
gender: Gender,
|
|
248
|
-
language: string
|
|
280
|
+
gender: Gender, // Used for compatibility, but processes both genders
|
|
281
|
+
language: string,
|
|
282
|
+
override: boolean = false
|
|
249
283
|
): Promise<ParsedDescriptionAndVirtues[]> {
|
|
250
284
|
await this.log('info', 'Starting generateDescriptionsAndVirtues', {
|
|
251
285
|
combinationString,
|
|
252
286
|
gender,
|
|
253
287
|
language,
|
|
288
|
+
override,
|
|
254
289
|
});
|
|
255
290
|
|
|
256
291
|
const db = this.context.drizzle();
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
292
|
+
const allGenders: Gender[] = ['male', 'female'];
|
|
293
|
+
const archetypesByGender: Record<Gender, any[]> = { male: [], female: [] };
|
|
294
|
+
|
|
295
|
+
for (const g of allGenders) {
|
|
296
|
+
const archetypes = await db
|
|
297
|
+
.select()
|
|
298
|
+
.from(schema.archetypesData)
|
|
299
|
+
.where(
|
|
300
|
+
and(
|
|
301
|
+
eq(schema.archetypesData.combination, combinationString),
|
|
302
|
+
eq(schema.archetypesData.gender, g),
|
|
303
|
+
eq(schema.archetypesData.language, language)
|
|
304
|
+
)
|
|
265
305
|
)
|
|
266
|
-
|
|
267
|
-
|
|
306
|
+
.orderBy(schema.archetypesData.archetypeIndex)
|
|
307
|
+
.execute();
|
|
308
|
+
archetypesByGender[g] = archetypes;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const needsGeneration = allGenders.some(
|
|
312
|
+
(g) =>
|
|
313
|
+
archetypesByGender[g].length !== 3 ||
|
|
314
|
+
archetypesByGender[g].some((a) => !a.description || a.virtues === '[]')
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
if (!override && !needsGeneration) {
|
|
318
|
+
await this.log('info', 'Skipping descriptions and virtues generation', {
|
|
319
|
+
reason: 'Descriptions and virtues already exist for all archetypes',
|
|
320
|
+
});
|
|
321
|
+
return archetypesByGender['male'].map((a, i) => ({
|
|
322
|
+
descriptionEN: a.description || '',
|
|
323
|
+
descriptionPTM: archetypesByGender['male'][i].description || '',
|
|
324
|
+
descriptionPTF: archetypesByGender['female'][i].description || '',
|
|
325
|
+
virtuesEN: JSON.parse(a.virtues || '[]'),
|
|
326
|
+
virtuesPT: JSON.parse(a.virtues || '[]'),
|
|
327
|
+
}));
|
|
328
|
+
}
|
|
268
329
|
|
|
269
330
|
await this.log('info', 'Fetched archetypes for description generation', {
|
|
270
|
-
|
|
271
|
-
|
|
331
|
+
maleArchetypes: archetypesByGender['male'].map((a) => ({
|
|
332
|
+
id: a.id,
|
|
333
|
+
name: a.name,
|
|
334
|
+
index: a.archetypeIndex,
|
|
335
|
+
})),
|
|
336
|
+
femaleArchetypes: archetypesByGender['female'].map((a) => ({
|
|
337
|
+
id: a.id,
|
|
338
|
+
name: a.name,
|
|
339
|
+
index: a.archetypeIndex,
|
|
340
|
+
})),
|
|
272
341
|
});
|
|
273
342
|
|
|
274
343
|
const descVirtueMessages = this.context
|
|
275
344
|
.buildLLMMessages()
|
|
276
345
|
.generateCosmicMirrorDescriptionAndVirtues({
|
|
277
346
|
combination: combinationString,
|
|
278
|
-
names: [
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
347
|
+
names: archetypesByGender['male'].map((a) => a.name) as [
|
|
348
|
+
string,
|
|
349
|
+
string,
|
|
350
|
+
string
|
|
351
|
+
],
|
|
352
|
+
essenceLines: archetypesByGender['male'].map((a) => a.essenceLine) as [
|
|
353
|
+
string,
|
|
354
|
+
string,
|
|
355
|
+
string
|
|
283
356
|
],
|
|
284
357
|
});
|
|
285
358
|
|
|
@@ -289,9 +362,7 @@ export class ArchetypeService {
|
|
|
289
362
|
const descVirtueResponse = await this.context
|
|
290
363
|
.api()
|
|
291
364
|
.callTogether.single(descVirtueMessages, {
|
|
292
|
-
options: {
|
|
293
|
-
temperature: 0.5,
|
|
294
|
-
},
|
|
365
|
+
options: { temperature: 0.3 },
|
|
295
366
|
});
|
|
296
367
|
if (!descVirtueResponse) {
|
|
297
368
|
await this.log('error', 'No response for descriptions and virtues', {
|
|
@@ -313,87 +384,79 @@ export class ArchetypeService {
|
|
|
313
384
|
|
|
314
385
|
for (let i = 0; i < 3; i++) {
|
|
315
386
|
const index = (i + 1).toString();
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
and(
|
|
332
|
-
eq(schema.archetypesData.id, enId),
|
|
333
|
-
eq(schema.archetypesData.language, 'en-us')
|
|
334
|
-
)
|
|
335
|
-
)
|
|
336
|
-
.execute();
|
|
337
|
-
await this.log('info', `Updated description and virtues for ${enId}`);
|
|
338
|
-
|
|
339
|
-
// Update Portuguese entries (pt-br) for both male and female
|
|
340
|
-
const ptIdMale = `${combinationString}:${gender}:${index}:pt`;
|
|
341
|
-
await this.log(
|
|
342
|
-
'debug',
|
|
343
|
-
`Updating description and virtues for ${ptIdMale} (male)`,
|
|
344
|
-
{
|
|
345
|
-
description: parsedDescVirtues[i].descriptionPTM,
|
|
346
|
-
virtues: parsedDescVirtues[i].virtuesPT,
|
|
387
|
+
for (const g of allGenders) {
|
|
388
|
+
const archetype = archetypesByGender[g][i];
|
|
389
|
+
if (!archetype || archetype.archetypeIndex !== index) {
|
|
390
|
+
await this.log(
|
|
391
|
+
'error',
|
|
392
|
+
`Archetype index mismatch for gender ${g} at position ${i + 1}`,
|
|
393
|
+
{
|
|
394
|
+
expectedIndex: index,
|
|
395
|
+
actualIndex: archetype?.archetypeIndex,
|
|
396
|
+
archetypeId: archetype?.id,
|
|
397
|
+
}
|
|
398
|
+
);
|
|
399
|
+
throw new Error(
|
|
400
|
+
`Archetype index mismatch for gender ${g}: expected ${index}, got ${archetype?.archetypeIndex}`
|
|
401
|
+
);
|
|
347
402
|
}
|
|
348
|
-
);
|
|
349
|
-
await db
|
|
350
|
-
.update(schema.archetypesData)
|
|
351
|
-
.set({
|
|
352
|
-
description: parsedDescVirtues[i].descriptionPTM,
|
|
353
|
-
virtues: JSON.stringify(parsedDescVirtues[i].virtuesPT),
|
|
354
|
-
updatedAt: new Date().getTime(),
|
|
355
|
-
})
|
|
356
|
-
.where(
|
|
357
|
-
and(
|
|
358
|
-
eq(schema.archetypesData.id, ptIdMale),
|
|
359
|
-
eq(schema.archetypesData.language, 'pt-br'),
|
|
360
|
-
eq(schema.archetypesData.gender, 'male')
|
|
361
|
-
)
|
|
362
|
-
)
|
|
363
|
-
.execute();
|
|
364
|
-
await this.log(
|
|
365
|
-
'info',
|
|
366
|
-
`Updated description and virtues for ${ptIdMale} (male)`
|
|
367
|
-
);
|
|
368
403
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
404
|
+
const id = `${combinationString}:${g}:${index}${
|
|
405
|
+
language === 'pt-br' ? ':pt' : ''
|
|
406
|
+
}`;
|
|
407
|
+
if (!override && archetype.description && archetype.virtues !== '[]') {
|
|
408
|
+
await this.log(
|
|
409
|
+
'debug',
|
|
410
|
+
`Skipping existing description and virtues for ${id}`,
|
|
411
|
+
{
|
|
412
|
+
description: archetype.description,
|
|
413
|
+
virtues: archetype.virtues,
|
|
414
|
+
archetypeIndex: index,
|
|
415
|
+
gender: g,
|
|
416
|
+
language,
|
|
417
|
+
}
|
|
418
|
+
);
|
|
419
|
+
continue;
|
|
376
420
|
}
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
421
|
+
|
|
422
|
+
const description =
|
|
423
|
+
language === 'en-us'
|
|
424
|
+
? parsedDescVirtues[i].descriptionEN
|
|
425
|
+
: g === 'male'
|
|
426
|
+
? parsedDescVirtues[i].descriptionPTM
|
|
427
|
+
: parsedDescVirtues[i].descriptionPTF;
|
|
428
|
+
const virtues =
|
|
429
|
+
language === 'en-us'
|
|
430
|
+
? parsedDescVirtues[i].virtuesEN
|
|
431
|
+
: parsedDescVirtues[i].virtuesPT;
|
|
432
|
+
|
|
433
|
+
await this.log('debug', `Updating description and virtues for ${id}`, {
|
|
434
|
+
description,
|
|
435
|
+
virtues,
|
|
436
|
+
archetypeIndex: index,
|
|
437
|
+
gender: g,
|
|
438
|
+
language,
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
await db
|
|
442
|
+
.update(schema.archetypesData)
|
|
443
|
+
.set({
|
|
444
|
+
description,
|
|
445
|
+
virtues: JSON.stringify(virtues),
|
|
446
|
+
updatedAt: new Date().getTime(),
|
|
447
|
+
})
|
|
448
|
+
.where(
|
|
449
|
+
and(
|
|
450
|
+
eq(schema.archetypesData.id, id),
|
|
451
|
+
eq(schema.archetypesData.language, language),
|
|
452
|
+
eq(schema.archetypesData.gender, g),
|
|
453
|
+
eq(schema.archetypesData.archetypeIndex, index)
|
|
454
|
+
)
|
|
390
455
|
)
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
`Updated description and virtues for ${ptIdFemale} (female)`
|
|
396
|
-
);
|
|
456
|
+
.execute();
|
|
457
|
+
|
|
458
|
+
await this.log('info', `Updated description and virtues for ${id}`);
|
|
459
|
+
}
|
|
397
460
|
}
|
|
398
461
|
|
|
399
462
|
await this.log('info', 'Completed generateDescriptionsAndVirtues', {
|
|
@@ -442,6 +505,22 @@ export class ArchetypeService {
|
|
|
442
505
|
lines,
|
|
443
506
|
});
|
|
444
507
|
|
|
508
|
+
if (lines[0] !== `${entryIndex + 1}.`) {
|
|
509
|
+
this.log(
|
|
510
|
+
'error',
|
|
511
|
+
`Invalid archetype index in entry ${entryIndex + 1}`,
|
|
512
|
+
{
|
|
513
|
+
expected: `${entryIndex + 1}.`,
|
|
514
|
+
found: lines[0],
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
throw new Error(
|
|
518
|
+
`Invalid archetype index in entry ${entryIndex + 1}: expected ${
|
|
519
|
+
entryIndex + 1
|
|
520
|
+
}, got ${lines[0]}`
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
|
|
445
524
|
let descriptionEN = '';
|
|
446
525
|
let descriptionPTM = '';
|
|
447
526
|
let descriptionPTF = '';
|
|
@@ -449,20 +528,10 @@ export class ArchetypeService {
|
|
|
449
528
|
let virtuesPT: string[] = [];
|
|
450
529
|
let currentField = '';
|
|
451
530
|
|
|
452
|
-
for (let i =
|
|
531
|
+
for (let i = 1; i < lines.length; i++) {
|
|
453
532
|
let line = lines[i];
|
|
454
|
-
|
|
455
|
-
// Remove markdown bold (**...**) from field names
|
|
456
533
|
line = line.replace(/\*\*(.*?)\*\*/g, '$1');
|
|
457
534
|
|
|
458
|
-
if (
|
|
459
|
-
line.startsWith('1.') ||
|
|
460
|
-
line.startsWith('2.') ||
|
|
461
|
-
line.startsWith('3.')
|
|
462
|
-
) {
|
|
463
|
-
continue; // Skip entry number lines
|
|
464
|
-
}
|
|
465
|
-
|
|
466
535
|
if (line.startsWith('• Description EN:')) {
|
|
467
536
|
currentField = 'descriptionEN';
|
|
468
537
|
descriptionEN = line.split('• Description EN:')[1]?.trim() || '';
|
|
@@ -510,7 +579,6 @@ export class ArchetypeService {
|
|
|
510
579
|
virtuesPT,
|
|
511
580
|
});
|
|
512
581
|
} else if (line.startsWith('• Virtues:')) {
|
|
513
|
-
// Fallback for older response format: use English virtues and attempt to translate
|
|
514
582
|
currentField = 'virtuesEN';
|
|
515
583
|
virtuesEN = line
|
|
516
584
|
.split('• Virtues:')[1]
|
|
@@ -524,14 +592,12 @@ export class ArchetypeService {
|
|
|
524
592
|
{ virtuesEN }
|
|
525
593
|
);
|
|
526
594
|
|
|
527
|
-
// Simple translation mapping for common virtues (as a fallback)
|
|
528
595
|
const virtueTranslations: { [key: string]: string } = {
|
|
529
596
|
Harmony: 'Harmonia',
|
|
530
597
|
Intuition: 'Intuição',
|
|
531
598
|
Grace: 'Graça',
|
|
532
|
-
// Add more translations as needed
|
|
533
599
|
};
|
|
534
|
-
virtuesPT = virtuesEN.map((v) => virtueTranslations[v] || v);
|
|
600
|
+
virtuesPT = virtuesEN.map((v) => virtueTranslations[v] || v);
|
|
535
601
|
this.log(
|
|
536
602
|
'debug',
|
|
537
603
|
`Generated virtuesPT (fallback) for entry ${entryIndex + 1}`,
|
|
@@ -563,7 +629,6 @@ export class ArchetypeService {
|
|
|
563
629
|
}
|
|
564
630
|
}
|
|
565
631
|
|
|
566
|
-
// Validate the parsed data
|
|
567
632
|
if (
|
|
568
633
|
!descriptionEN ||
|
|
569
634
|
!descriptionPTM ||
|
|
@@ -572,7 +637,7 @@ export class ArchetypeService {
|
|
|
572
637
|
virtuesPT.length !== 3
|
|
573
638
|
) {
|
|
574
639
|
this.log(
|
|
575
|
-
'
|
|
640
|
+
'error',
|
|
576
641
|
`Malformed description and virtues response for entry ${
|
|
577
642
|
entryIndex + 1
|
|
578
643
|
}`,
|
|
@@ -592,13 +657,19 @@ export class ArchetypeService {
|
|
|
592
657
|
);
|
|
593
658
|
}
|
|
594
659
|
|
|
595
|
-
|
|
660
|
+
const parsed = {
|
|
596
661
|
descriptionEN,
|
|
597
662
|
descriptionPTM,
|
|
598
663
|
descriptionPTF,
|
|
599
664
|
virtuesEN,
|
|
600
665
|
virtuesPT,
|
|
601
666
|
};
|
|
667
|
+
this.log(
|
|
668
|
+
'debug',
|
|
669
|
+
`Parsed description and virtues for archetypeIndex ${entryIndex + 1}`,
|
|
670
|
+
{ parsed }
|
|
671
|
+
);
|
|
672
|
+
return parsed;
|
|
602
673
|
});
|
|
603
674
|
|
|
604
675
|
this.log('info', 'Completed parseDescriptionAndVirtuesResponse', {
|
|
@@ -609,85 +680,156 @@ export class ArchetypeService {
|
|
|
609
680
|
|
|
610
681
|
async generateContent(
|
|
611
682
|
combinationString: string,
|
|
612
|
-
gender: Gender,
|
|
683
|
+
gender: Gender, // Used for compatibility, but processes both genders
|
|
613
684
|
language: string,
|
|
614
|
-
descriptions: Array<{ descriptionEN: string }
|
|
685
|
+
descriptions: Array<{ descriptionEN: string }>,
|
|
686
|
+
override: boolean = false
|
|
615
687
|
) {
|
|
616
688
|
await this.log('info', 'Starting generateContent', {
|
|
617
689
|
combinationString,
|
|
618
690
|
gender,
|
|
619
691
|
language,
|
|
692
|
+
override,
|
|
620
693
|
});
|
|
621
694
|
|
|
622
695
|
const db = this.context.drizzle();
|
|
623
|
-
const
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
696
|
+
const allGenders: Gender[] = ['male', 'female'];
|
|
697
|
+
const archetypesByGender: Record<Gender, any[]> = { male: [], female: [] };
|
|
698
|
+
|
|
699
|
+
for (const g of allGenders) {
|
|
700
|
+
const archetypes = await db
|
|
701
|
+
.select()
|
|
702
|
+
.from(schema.archetypesData)
|
|
703
|
+
.where(
|
|
704
|
+
and(
|
|
705
|
+
eq(schema.archetypesData.combination, combinationString),
|
|
706
|
+
eq(schema.archetypesData.gender, g),
|
|
707
|
+
eq(schema.archetypesData.language, language)
|
|
708
|
+
)
|
|
631
709
|
)
|
|
632
|
-
|
|
633
|
-
|
|
710
|
+
.orderBy(schema.archetypesData.archetypeIndex)
|
|
711
|
+
.execute();
|
|
712
|
+
archetypesByGender[g] = archetypes;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const needsGeneration = allGenders.some(
|
|
716
|
+
(g) =>
|
|
717
|
+
archetypesByGender[g].length !== 3 ||
|
|
718
|
+
archetypesByGender[g].some((a) => a.content === '[]')
|
|
719
|
+
);
|
|
720
|
+
|
|
721
|
+
if (!override && !needsGeneration) {
|
|
722
|
+
await this.log('info', 'Skipping content generation', {
|
|
723
|
+
reason: 'Content already exists for all archetypes',
|
|
724
|
+
});
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
634
727
|
|
|
635
728
|
await this.log('info', 'Fetched archetypes for content generation', {
|
|
636
|
-
|
|
637
|
-
|
|
729
|
+
maleArchetypes: archetypesByGender['male'].map((a) => ({
|
|
730
|
+
id: a.id,
|
|
731
|
+
name: a.name,
|
|
732
|
+
index: a.archetypeIndex,
|
|
733
|
+
})),
|
|
734
|
+
femaleArchetypes: archetypesByGender['female'].map((a) => ({
|
|
735
|
+
id: a.id,
|
|
736
|
+
name: a.name,
|
|
737
|
+
index: a.archetypeIndex,
|
|
738
|
+
})),
|
|
638
739
|
});
|
|
639
740
|
|
|
640
741
|
const contentResults = [];
|
|
641
742
|
for (let i = 0; i < 3; i++) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
743
|
+
const index = (i + 1).toString();
|
|
744
|
+
for (const g of allGenders) {
|
|
745
|
+
const archetype = archetypesByGender[g][i];
|
|
746
|
+
if (!archetype || archetype.archetypeIndex !== index) {
|
|
747
|
+
await this.log(
|
|
748
|
+
'error',
|
|
749
|
+
`Archetype index mismatch for gender ${g} at position ${i + 1}`,
|
|
750
|
+
{
|
|
751
|
+
expectedIndex: index,
|
|
752
|
+
actualIndex: archetype?.archetypeIndex,
|
|
753
|
+
archetypeId: archetype?.id,
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
throw new Error(
|
|
757
|
+
`Archetype index mismatch for gender ${g}: expected ${index}, got ${archetype?.archetypeIndex}`
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
const id = `${combinationString}:${g}:${index}${
|
|
762
|
+
language === 'pt-br' ? ':pt' : ''
|
|
763
|
+
}`;
|
|
764
|
+
if (!override && archetype.content !== '[]') {
|
|
765
|
+
await this.log('debug', `Skipping existing content for ${id}`, {
|
|
766
|
+
content: archetype.content,
|
|
767
|
+
archetypeIndex: index,
|
|
768
|
+
gender: g,
|
|
769
|
+
language,
|
|
770
|
+
});
|
|
771
|
+
if (g === 'male') contentResults.push({}); // Placeholder for male only
|
|
772
|
+
continue;
|
|
773
|
+
}
|
|
652
774
|
|
|
653
|
-
await this.log('debug', `Calling API for content of archetype ${i + 1}`, {
|
|
654
|
-
messages: contentMessages,
|
|
655
|
-
});
|
|
656
|
-
const contentResponse = await this.context
|
|
657
|
-
.api()
|
|
658
|
-
.callTogether.single(contentMessages, {});
|
|
659
|
-
if (!contentResponse) {
|
|
660
775
|
await this.log(
|
|
661
|
-
'
|
|
662
|
-
`
|
|
663
|
-
{
|
|
776
|
+
'debug',
|
|
777
|
+
`Generating content for archetype ${index} (${g})`,
|
|
778
|
+
{
|
|
779
|
+
name: archetype.name,
|
|
780
|
+
}
|
|
664
781
|
);
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
782
|
+
const contentMessages = this.context
|
|
783
|
+
.buildLLMMessages()
|
|
784
|
+
.generateCosmicMirrorArchetypeContent({
|
|
785
|
+
combination: combinationString,
|
|
786
|
+
name: archetype.name,
|
|
787
|
+
description: descriptions[i].descriptionEN,
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
await this.log(
|
|
791
|
+
'debug',
|
|
792
|
+
`Calling API for content of archetype ${index} (${g})`,
|
|
793
|
+
{
|
|
794
|
+
messages: contentMessages,
|
|
795
|
+
}
|
|
796
|
+
);
|
|
797
|
+
const contentResponse = await this.context
|
|
798
|
+
.api()
|
|
799
|
+
.callTogether.single(contentMessages, {});
|
|
800
|
+
if (!contentResponse) {
|
|
801
|
+
await this.log(
|
|
802
|
+
'error',
|
|
803
|
+
`No response for content of archetype ${index} (${g})`,
|
|
804
|
+
{
|
|
805
|
+
combinationString,
|
|
806
|
+
archetype: archetype.name,
|
|
807
|
+
}
|
|
808
|
+
);
|
|
809
|
+
throw new Error(
|
|
810
|
+
`Failed to generate content for archetype ${index} (${g}) of: ${combinationString}`
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
await this.log(
|
|
814
|
+
'info',
|
|
815
|
+
`Received content response for archetype ${index} (${g})`,
|
|
816
|
+
{
|
|
817
|
+
responseLength: contentResponse.length,
|
|
818
|
+
}
|
|
669
819
|
);
|
|
670
|
-
}
|
|
671
|
-
await this.log(
|
|
672
|
-
'info',
|
|
673
|
-
`Received content response for archetype ${i + 1}`,
|
|
674
|
-
{ responseLength: contentResponse.length }
|
|
675
|
-
);
|
|
676
820
|
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
821
|
+
await this.log(
|
|
822
|
+
'debug',
|
|
823
|
+
`Parsing content response for archetype ${index} (${g})`
|
|
824
|
+
);
|
|
825
|
+
const parsedContent = this.parseContentResponse(contentResponse);
|
|
826
|
+
if (g === 'male') contentResults.push(parsedContent);
|
|
827
|
+
await this.log('info', `Parsed content for archetype ${index} (${g})`, {
|
|
828
|
+
parsedContent,
|
|
829
|
+
});
|
|
686
830
|
|
|
687
|
-
const index = (i + 1).toString();
|
|
688
|
-
for (const lang of ['en-us', 'pt-br']) {
|
|
689
831
|
const contentLangIndex =
|
|
690
|
-
|
|
832
|
+
language === 'en-us' ? 0 : g === 'male' ? 1 : 2;
|
|
691
833
|
const content = [
|
|
692
834
|
{
|
|
693
835
|
section: 'voiceOfTheSoul',
|
|
@@ -715,10 +857,12 @@ export class ArchetypeService {
|
|
|
715
857
|
},
|
|
716
858
|
];
|
|
717
859
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
860
|
+
await this.log('debug', `Updating content for ${id}`, {
|
|
861
|
+
content,
|
|
862
|
+
archetypeIndex: index,
|
|
863
|
+
gender: g,
|
|
864
|
+
language,
|
|
865
|
+
});
|
|
722
866
|
|
|
723
867
|
await db
|
|
724
868
|
.update(schema.archetypesData)
|
|
@@ -729,7 +873,9 @@ export class ArchetypeService {
|
|
|
729
873
|
.where(
|
|
730
874
|
and(
|
|
731
875
|
eq(schema.archetypesData.id, id),
|
|
732
|
-
eq(schema.archetypesData.language,
|
|
876
|
+
eq(schema.archetypesData.language, language),
|
|
877
|
+
eq(schema.archetypesData.gender, g),
|
|
878
|
+
eq(schema.archetypesData.archetypeIndex, index)
|
|
733
879
|
)
|
|
734
880
|
)
|
|
735
881
|
.execute();
|
|
@@ -759,6 +905,14 @@ export class ArchetypeService {
|
|
|
759
905
|
sectionsCount: sections.length,
|
|
760
906
|
});
|
|
761
907
|
|
|
908
|
+
if (sections.length !== 3) {
|
|
909
|
+
this.log('error', 'Expected exactly 3 content sections', {
|
|
910
|
+
sectionsCount: sections.length,
|
|
911
|
+
response,
|
|
912
|
+
});
|
|
913
|
+
throw new Error(`Expected 3 content sections, got ${sections.length}`);
|
|
914
|
+
}
|
|
915
|
+
|
|
762
916
|
const result = sections.map((section, sectionIndex) => {
|
|
763
917
|
this.log('debug', `Processing section ${sectionIndex + 1}`, { section });
|
|
764
918
|
|
|
@@ -768,24 +922,27 @@ export class ArchetypeService {
|
|
|
768
922
|
lines,
|
|
769
923
|
});
|
|
770
924
|
|
|
925
|
+
const expectedHeader =
|
|
926
|
+
sectionIndex === 0 ? 'EN:' : sectionIndex === 1 ? 'PT-M:' : 'PT-F:';
|
|
927
|
+
if (lines[0] !== expectedHeader) {
|
|
928
|
+
this.log(
|
|
929
|
+
'error',
|
|
930
|
+
`Invalid language header in section ${sectionIndex + 1}`,
|
|
931
|
+
{
|
|
932
|
+
expected: expectedHeader,
|
|
933
|
+
found: lines[0],
|
|
934
|
+
}
|
|
935
|
+
);
|
|
936
|
+
throw new Error(
|
|
937
|
+
`Invalid language header in section ${sectionIndex + 1}`
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
|
|
771
941
|
const content: Record<string, string> = {};
|
|
772
942
|
let currentSection = '';
|
|
773
943
|
let currentText: string[] = [];
|
|
774
944
|
|
|
775
|
-
for (const line of lines) {
|
|
776
|
-
if (
|
|
777
|
-
line.startsWith('EN:') ||
|
|
778
|
-
line.startsWith('PT-M:') ||
|
|
779
|
-
line.startsWith('PT-F:')
|
|
780
|
-
) {
|
|
781
|
-
this.log(
|
|
782
|
-
'debug',
|
|
783
|
-
`Skipping language header in section ${sectionIndex + 1}`,
|
|
784
|
-
{ line }
|
|
785
|
-
);
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
|
|
945
|
+
for (const line of lines.slice(1)) {
|
|
789
946
|
if (line.startsWith('#')) {
|
|
790
947
|
if (currentSection && currentText.length > 0) {
|
|
791
948
|
const key = currentSection
|
|
@@ -798,7 +955,10 @@ export class ArchetypeService {
|
|
|
798
955
|
`Extracted section ${currentSection} in section ${
|
|
799
956
|
sectionIndex + 1
|
|
800
957
|
}`,
|
|
801
|
-
{
|
|
958
|
+
{
|
|
959
|
+
key,
|
|
960
|
+
text: content[key],
|
|
961
|
+
}
|
|
802
962
|
);
|
|
803
963
|
}
|
|
804
964
|
currentSection = line.replace('# ', '');
|
|
@@ -825,7 +985,10 @@ export class ArchetypeService {
|
|
|
825
985
|
`Extracted final section ${currentSection} in section ${
|
|
826
986
|
sectionIndex + 1
|
|
827
987
|
}`,
|
|
828
|
-
{
|
|
988
|
+
{
|
|
989
|
+
key,
|
|
990
|
+
text: content[key],
|
|
991
|
+
}
|
|
829
992
|
);
|
|
830
993
|
}
|
|
831
994
|
|
|
@@ -845,15 +1008,21 @@ export class ArchetypeService {
|
|
|
845
1008
|
|
|
846
1009
|
if (Object.values(parsedContent).some((value) => !value)) {
|
|
847
1010
|
this.log(
|
|
848
|
-
'
|
|
1011
|
+
'error',
|
|
849
1012
|
`Malformed content response for section ${sectionIndex + 1}`,
|
|
850
1013
|
{
|
|
851
1014
|
parsedContent,
|
|
852
1015
|
response: section,
|
|
853
1016
|
}
|
|
854
1017
|
);
|
|
1018
|
+
throw new Error(
|
|
1019
|
+
`Malformed content response for section ${sectionIndex + 1}`
|
|
1020
|
+
);
|
|
855
1021
|
}
|
|
856
1022
|
|
|
1023
|
+
this.log('debug', `Parsed content for section ${sectionIndex + 1}`, {
|
|
1024
|
+
parsedContent,
|
|
1025
|
+
});
|
|
857
1026
|
return parsedContent;
|
|
858
1027
|
});
|
|
859
1028
|
|
|
@@ -863,26 +1032,21 @@ export class ArchetypeService {
|
|
|
863
1032
|
|
|
864
1033
|
async generateLeonardoPrompts(
|
|
865
1034
|
combinationString: string,
|
|
866
|
-
gender: Gender, //
|
|
867
|
-
language: string,
|
|
868
|
-
descriptions: Array<{ descriptionEN: string }
|
|
1035
|
+
gender: Gender, // Used for compatibility, but processes both genders
|
|
1036
|
+
language: string,
|
|
1037
|
+
descriptions: Array<{ descriptionEN: string }>,
|
|
1038
|
+
override: boolean = false
|
|
869
1039
|
) {
|
|
870
1040
|
await this.log('info', 'Starting generateLeonardoPrompts', {
|
|
871
1041
|
combinationString,
|
|
872
1042
|
gender,
|
|
873
1043
|
language,
|
|
1044
|
+
override,
|
|
874
1045
|
});
|
|
875
1046
|
|
|
876
1047
|
const db = this.context.drizzle();
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
// Fetch archetypes for male and female with language = 'en-us'
|
|
881
|
-
const allGenders: Binary[] = ['male', 'female'];
|
|
882
|
-
const archetypesByGender: Record<Binary, any[]> = {
|
|
883
|
-
male: [],
|
|
884
|
-
female: [],
|
|
885
|
-
};
|
|
1048
|
+
const allGenders: Gender[] = ['male', 'female'];
|
|
1049
|
+
const archetypesByGender: Record<Gender, any[]> = { male: [], female: [] };
|
|
886
1050
|
|
|
887
1051
|
for (const g of allGenders) {
|
|
888
1052
|
const archetypes = await db
|
|
@@ -892,41 +1056,40 @@ export class ArchetypeService {
|
|
|
892
1056
|
and(
|
|
893
1057
|
eq(schema.archetypesData.combination, combinationString),
|
|
894
1058
|
eq(schema.archetypesData.gender, g),
|
|
895
|
-
eq(schema.archetypesData.language,
|
|
1059
|
+
eq(schema.archetypesData.language, language)
|
|
896
1060
|
)
|
|
897
1061
|
)
|
|
1062
|
+
.orderBy(schema.archetypesData.archetypeIndex)
|
|
898
1063
|
.execute();
|
|
899
1064
|
archetypesByGender[g] = archetypes;
|
|
900
1065
|
}
|
|
901
1066
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
throw new Error(
|
|
914
|
-
`Expected 3 archetypes for gender ${g}, but found ${archetypesByGender[g].length}`
|
|
915
|
-
);
|
|
916
|
-
}
|
|
1067
|
+
const needsGeneration = allGenders.some(
|
|
1068
|
+
(g) =>
|
|
1069
|
+
archetypesByGender[g].length !== 3 ||
|
|
1070
|
+
archetypesByGender[g].some((a) => !a.leonardoPrompt)
|
|
1071
|
+
);
|
|
1072
|
+
|
|
1073
|
+
if (!override && !needsGeneration) {
|
|
1074
|
+
await this.log('info', 'Skipping Leonardo prompts generation', {
|
|
1075
|
+
reason: 'Leonardo prompts already exist for all archetypes',
|
|
1076
|
+
});
|
|
1077
|
+
return;
|
|
917
1078
|
}
|
|
918
1079
|
|
|
919
1080
|
await this.log('info', 'Fetched archetypes for Leonardo prompts', {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1081
|
+
maleArchetypes: archetypesByGender['male'].map((a) => ({
|
|
1082
|
+
id: a.id,
|
|
1083
|
+
name: a.name,
|
|
1084
|
+
index: a.archetypeIndex,
|
|
1085
|
+
})),
|
|
1086
|
+
femaleArchetypes: archetypesByGender['female'].map((a) => ({
|
|
1087
|
+
id: a.id,
|
|
1088
|
+
name: a.name,
|
|
1089
|
+
index: a.archetypeIndex,
|
|
1090
|
+
})),
|
|
926
1091
|
});
|
|
927
1092
|
|
|
928
|
-
// Since descriptions are provided as an input (from generateDescriptionsAndVirtues),
|
|
929
|
-
// we can use the same descriptions for all genders, as they are gender-neutral (en-us)
|
|
930
1093
|
const promptMessages = this.context
|
|
931
1094
|
.buildLLMMessages()
|
|
932
1095
|
.generateCosmicMirrorArchetypeLeonardoPrompts(
|
|
@@ -957,115 +1120,73 @@ export class ArchetypeService {
|
|
|
957
1120
|
const parsedPrompts = this.parseLeonardoPromptResponse(promptResponse);
|
|
958
1121
|
await this.log('info', 'Parsed Leonardo prompts', { parsedPrompts });
|
|
959
1122
|
|
|
960
|
-
// Update archetypes for all genders
|
|
961
1123
|
for (const g of allGenders) {
|
|
962
1124
|
for (let i = 0; i < 3; i++) {
|
|
1125
|
+
const archetype = archetypesByGender[g][i];
|
|
963
1126
|
const index = (i + 1).toString();
|
|
964
|
-
|
|
965
|
-
g === 'male'
|
|
966
|
-
? parsedPrompts[i].malePrompt
|
|
967
|
-
: parsedPrompts[i].femalePrompt;
|
|
968
|
-
|
|
969
|
-
// Update English entry (en-us)
|
|
970
|
-
const enId = `${combinationString}:${g}:${index}`;
|
|
971
|
-
await this.log(
|
|
972
|
-
'debug',
|
|
973
|
-
`Updating Leonardo prompt for ${enId} (en-us)`,
|
|
974
|
-
{
|
|
975
|
-
leonardoPrompt,
|
|
976
|
-
}
|
|
977
|
-
);
|
|
978
|
-
|
|
979
|
-
const enUpdateResult = await db
|
|
980
|
-
.update(schema.archetypesData)
|
|
981
|
-
.set({
|
|
982
|
-
leonardoPrompt,
|
|
983
|
-
updatedAt: new Date().getTime(),
|
|
984
|
-
})
|
|
985
|
-
.where(
|
|
986
|
-
and(
|
|
987
|
-
eq(schema.archetypesData.id, enId),
|
|
988
|
-
eq(schema.archetypesData.language, 'en-us'),
|
|
989
|
-
eq(schema.archetypesData.gender, g)
|
|
990
|
-
)
|
|
991
|
-
)
|
|
992
|
-
.execute();
|
|
993
|
-
|
|
994
|
-
await this.log('info', `Updated Leonardo prompt for ${enId} (en-us)`, {
|
|
995
|
-
rowsAffected: enUpdateResult.rowsAffected,
|
|
996
|
-
});
|
|
997
|
-
|
|
998
|
-
if (enUpdateResult.rowsAffected === 0) {
|
|
1127
|
+
if (!archetype || archetype.archetypeIndex !== index) {
|
|
999
1128
|
await this.log(
|
|
1000
1129
|
'error',
|
|
1001
|
-
`
|
|
1130
|
+
`Archetype index mismatch for gender ${g} at position ${i + 1}`,
|
|
1002
1131
|
{
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1132
|
+
expectedIndex: index,
|
|
1133
|
+
actualIndex: archetype?.archetypeIndex,
|
|
1134
|
+
archetypeId: archetype?.id,
|
|
1006
1135
|
}
|
|
1007
1136
|
);
|
|
1008
1137
|
throw new Error(
|
|
1009
|
-
`
|
|
1138
|
+
`Archetype index mismatch for gender ${g}: expected ${index}, got ${archetype?.archetypeIndex}`
|
|
1010
1139
|
);
|
|
1011
1140
|
}
|
|
1012
1141
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
? parsedPrompts[i].malePrompt
|
|
1021
|
-
: parsedPrompts[i].femalePrompt;
|
|
1142
|
+
const leonardoPrompt =
|
|
1143
|
+
g === 'male'
|
|
1144
|
+
? parsedPrompts[i].malePrompt
|
|
1145
|
+
: parsedPrompts[i].femalePrompt;
|
|
1146
|
+
const id = `${combinationString}:${g}:${index}${
|
|
1147
|
+
language === 'pt-br' ? ':pt' : ''
|
|
1148
|
+
}`;
|
|
1022
1149
|
|
|
1150
|
+
if (!override && archetype.leonardoPrompt) {
|
|
1023
1151
|
await this.log(
|
|
1024
1152
|
'debug',
|
|
1025
|
-
`
|
|
1153
|
+
`Skipping existing Leonardo prompt for ${id}`,
|
|
1026
1154
|
{
|
|
1027
|
-
leonardoPrompt:
|
|
1155
|
+
leonardoPrompt: archetype.leonardoPrompt,
|
|
1156
|
+
archetypeIndex: index,
|
|
1157
|
+
gender: g,
|
|
1158
|
+
language,
|
|
1028
1159
|
}
|
|
1029
1160
|
);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1030
1163
|
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
.where(
|
|
1038
|
-
and(
|
|
1039
|
-
eq(schema.archetypesData.id, ptId),
|
|
1040
|
-
eq(schema.archetypesData.language, 'pt-br'),
|
|
1041
|
-
eq(schema.archetypesData.gender, ptGender)
|
|
1042
|
-
)
|
|
1043
|
-
)
|
|
1044
|
-
.execute();
|
|
1164
|
+
await this.log('debug', `Updating Leonardo prompt for ${id}`, {
|
|
1165
|
+
leonardoPrompt,
|
|
1166
|
+
archetypeIndex: index,
|
|
1167
|
+
gender: g,
|
|
1168
|
+
language,
|
|
1169
|
+
});
|
|
1045
1170
|
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1171
|
+
const updateResult = await db
|
|
1172
|
+
.update(schema.archetypesData)
|
|
1173
|
+
.set({
|
|
1174
|
+
leonardoPrompt,
|
|
1175
|
+
updatedAt: new Date().getTime(),
|
|
1176
|
+
})
|
|
1177
|
+
.where(
|
|
1178
|
+
and(
|
|
1179
|
+
eq(schema.archetypesData.id, id),
|
|
1180
|
+
eq(schema.archetypesData.language, language),
|
|
1181
|
+
eq(schema.archetypesData.gender, g),
|
|
1182
|
+
eq(schema.archetypesData.archetypeIndex, index)
|
|
1183
|
+
)
|
|
1184
|
+
)
|
|
1185
|
+
.execute();
|
|
1053
1186
|
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
`Failed to update Leonardo prompt for ${ptId} (pt-br, gender: ${ptGender})`,
|
|
1058
|
-
{
|
|
1059
|
-
ptId,
|
|
1060
|
-
language: 'pt-br',
|
|
1061
|
-
gender: ptGender,
|
|
1062
|
-
}
|
|
1063
|
-
);
|
|
1064
|
-
throw new Error(
|
|
1065
|
-
`Failed to update Leonardo prompt for ${ptId} (pt-br, gender: ${ptGender})`
|
|
1066
|
-
);
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1187
|
+
await this.log('info', `Updated Leonardo prompt for ${id}`, {
|
|
1188
|
+
rowsAffected: updateResult.rowsAffected,
|
|
1189
|
+
});
|
|
1069
1190
|
}
|
|
1070
1191
|
}
|
|
1071
1192
|
|
|
@@ -1088,39 +1209,45 @@ export class ArchetypeService {
|
|
|
1088
1209
|
lines,
|
|
1089
1210
|
});
|
|
1090
1211
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1212
|
+
if (lines.length !== 12) {
|
|
1213
|
+
this.log('error', 'Expected exactly 12 lines for 3 archetype prompts', {
|
|
1214
|
+
linesCount: lines.length,
|
|
1215
|
+
response,
|
|
1216
|
+
});
|
|
1217
|
+
throw new Error(
|
|
1218
|
+
`Expected 12 lines for 3 archetype prompts, got ${lines.length}`
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1093
1221
|
|
|
1222
|
+
const prompts: LeonardoPrompt[] = [];
|
|
1094
1223
|
for (let i = 0; i < lines.length; i += 4) {
|
|
1095
|
-
|
|
1096
|
-
const maleLabel = lines[i];
|
|
1097
|
-
const malePromptLine = lines[i + 1];
|
|
1098
|
-
const femaleLabel = lines[i + 2];
|
|
1099
|
-
const femalePromptLine = lines[i + 3];
|
|
1224
|
+
const archetypeIndex = i / 4 + 1;
|
|
1225
|
+
const maleLabel = lines[i];
|
|
1226
|
+
const malePromptLine = lines[i + 1];
|
|
1227
|
+
const femaleLabel = lines[i + 2];
|
|
1228
|
+
const femalePromptLine = lines[i + 3];
|
|
1100
1229
|
|
|
1101
|
-
|
|
1102
|
-
const
|
|
1103
|
-
const expectedFemaleLabel = `${currentArchetype}.f`;
|
|
1230
|
+
const expectedMaleLabel = `${archetypeIndex}.m`;
|
|
1231
|
+
const expectedFemaleLabel = `${archetypeIndex}.f`;
|
|
1104
1232
|
|
|
1105
1233
|
if (
|
|
1106
1234
|
!maleLabel?.startsWith(expectedMaleLabel) ||
|
|
1107
1235
|
!femaleLabel?.startsWith(expectedFemaleLabel)
|
|
1108
1236
|
) {
|
|
1109
1237
|
this.log(
|
|
1110
|
-
'
|
|
1111
|
-
`Malformed Leonardo prompt format for archetype ${
|
|
1238
|
+
'error',
|
|
1239
|
+
`Malformed Leonardo prompt format for archetype ${archetypeIndex}`,
|
|
1112
1240
|
{
|
|
1113
1241
|
maleLabel,
|
|
1114
1242
|
malePromptLine,
|
|
1115
1243
|
femaleLabel,
|
|
1116
1244
|
femalePromptLine,
|
|
1117
|
-
|
|
1245
|
+
expectedMaleLabel,
|
|
1246
|
+
expectedFemaleLabel,
|
|
1118
1247
|
}
|
|
1119
1248
|
);
|
|
1120
1249
|
throw new Error(
|
|
1121
|
-
`
|
|
1122
|
-
i + 2
|
|
1123
|
-
}`
|
|
1250
|
+
`Malformed prompt format for archetype ${archetypeIndex}`
|
|
1124
1251
|
);
|
|
1125
1252
|
}
|
|
1126
1253
|
|
|
@@ -1129,42 +1256,30 @@ export class ArchetypeService {
|
|
|
1129
1256
|
|
|
1130
1257
|
if (!malePrompt || !femalePrompt) {
|
|
1131
1258
|
this.log(
|
|
1132
|
-
'
|
|
1133
|
-
`Empty Leonardo prompt for archetype ${
|
|
1259
|
+
'error',
|
|
1260
|
+
`Empty Leonardo prompt for archetype ${archetypeIndex}`,
|
|
1134
1261
|
{
|
|
1135
1262
|
malePrompt,
|
|
1136
1263
|
femalePrompt,
|
|
1137
|
-
malePromptLine,
|
|
1138
|
-
femalePromptLine,
|
|
1139
1264
|
}
|
|
1140
1265
|
);
|
|
1141
|
-
throw new Error(`Empty prompt for archetype ${
|
|
1266
|
+
throw new Error(`Empty prompt for archetype ${archetypeIndex}`);
|
|
1142
1267
|
}
|
|
1143
1268
|
|
|
1144
1269
|
prompts.push({ malePrompt, femalePrompt });
|
|
1145
|
-
this.log('debug', `Parsed prompts for
|
|
1270
|
+
this.log('debug', `Parsed prompts for archetypeIndex ${archetypeIndex}`, {
|
|
1146
1271
|
malePrompt,
|
|
1147
1272
|
femalePrompt,
|
|
1148
1273
|
});
|
|
1149
1274
|
}
|
|
1150
1275
|
|
|
1151
|
-
if (prompts.length !== 3) {
|
|
1152
|
-
this.log('error', 'Expected exactly 3 archetype prompts', {
|
|
1153
|
-
promptsCount: prompts.length,
|
|
1154
|
-
response,
|
|
1155
|
-
});
|
|
1156
|
-
throw new Error(
|
|
1157
|
-
`Expected exactly 3 archetype prompts, but got ${prompts.length}`
|
|
1158
|
-
);
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
1276
|
this.log('info', 'Completed parseLeonardoPromptResponse', { prompts });
|
|
1162
1277
|
return prompts;
|
|
1163
1278
|
}
|
|
1164
1279
|
|
|
1165
1280
|
async fetchArchetypesFromDB(
|
|
1166
1281
|
combinationString: string,
|
|
1167
|
-
gender: Gender,
|
|
1282
|
+
gender: Gender | null, // null to fetch both genders
|
|
1168
1283
|
language: string
|
|
1169
1284
|
) {
|
|
1170
1285
|
await this.log('debug', 'Executing fetchArchetypesFromDB', {
|
|
@@ -1173,20 +1288,23 @@ export class ArchetypeService {
|
|
|
1173
1288
|
language,
|
|
1174
1289
|
});
|
|
1175
1290
|
const db = this.context.drizzle();
|
|
1291
|
+
const conditions = [
|
|
1292
|
+
eq(schema.archetypesData.combination, combinationString),
|
|
1293
|
+
eq(schema.archetypesData.language, language),
|
|
1294
|
+
];
|
|
1295
|
+
if (gender) {
|
|
1296
|
+
conditions.push(eq(schema.archetypesData.gender, gender));
|
|
1297
|
+
}
|
|
1176
1298
|
const result = await db
|
|
1177
1299
|
.select()
|
|
1178
1300
|
.from(schema.archetypesData)
|
|
1179
|
-
.where(
|
|
1180
|
-
|
|
1181
|
-
eq(schema.archetypesData.combination, combinationString),
|
|
1182
|
-
eq(schema.archetypesData.gender, gender),
|
|
1183
|
-
eq(schema.archetypesData.language, language)
|
|
1184
|
-
)
|
|
1185
|
-
)
|
|
1301
|
+
.where(and(...conditions))
|
|
1302
|
+
.orderBy(schema.archetypesData.archetypeIndex)
|
|
1186
1303
|
.execute();
|
|
1187
1304
|
await this.log('debug', 'fetchArchetypesFromDB result', {
|
|
1188
1305
|
resultCount: result.length,
|
|
1189
|
-
result,
|
|
1306
|
+
indexes: result.map((r) => r.archetypeIndex),
|
|
1307
|
+
genders: result.map((r) => r.gender),
|
|
1190
1308
|
});
|
|
1191
1309
|
return result;
|
|
1192
1310
|
}
|