@zodic/shared 0.0.313 → 0.0.315

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.
@@ -1,7 +1,7 @@
1
+ import { and, eq } from 'drizzle-orm';
1
2
  import { inject, injectable } from 'inversify';
3
+ import { schema } from '../..';
2
4
  import { Gender } from '../../types';
3
- import { KVArchetype } from '../../types/scopes/legacy';
4
- import { buildCosmicMirrorArchetypeKVKey } from '../../utils/KVKeysBuilders';
5
5
  import { AppContext } from '../base/AppContext';
6
6
  import { ArchetypeService } from '../services/ArchetypeService';
7
7
  import { LeonardoService } from '../services/LeonardoService';
@@ -14,176 +14,728 @@ export class ArchetypeWorkflow {
14
14
  @inject(LeonardoService) private leonardoService: LeonardoService
15
15
  ) {}
16
16
 
17
- async execute(combinationString: string, gender: Gender) {
18
- console.log('Starting ArchetypeWorkflow for:', {
17
+ private async log(
18
+ level: 'info' | 'debug' | 'warn' | 'error',
19
+ message: string,
20
+ context: Record<string, any> = {}
21
+ ) {
22
+ const logId = `archetype-workflow:${Date.now()}`;
23
+ const logMessage = `[${level.toUpperCase()}] ${message}`;
24
+
25
+ console[level](logMessage, context);
26
+
27
+ const db = this.context.drizzle();
28
+ try {
29
+ await db
30
+ .insert(schema.logs)
31
+ .values({
32
+ id: logId,
33
+ level,
34
+ message,
35
+ context: JSON.stringify(context),
36
+ createdAt: new Date().getTime(),
37
+ })
38
+ .execute();
39
+ } catch (error) {
40
+ console.error('[ERROR] Failed to persist log to database:', {
41
+ error,
42
+ logId,
43
+ message,
44
+ context,
45
+ });
46
+ }
47
+ }
48
+
49
+ async execute(
50
+ combinationString: string,
51
+ gender: Gender,
52
+ language: string = 'en-us'
53
+ ) {
54
+ await this.log('info', 'Starting ArchetypeWorkflow', {
19
55
  combinationString,
20
56
  gender,
57
+ language,
21
58
  });
22
59
 
23
- const archetypes = await this.fetchArchetypesFromKV(
60
+ // Fetch archetypes from archetypes_data
61
+ await this.log('debug', 'Fetching archetypes from database', {
62
+ combinationString,
63
+ gender,
64
+ language,
65
+ });
66
+ const archetypes = await this.fetchArchetypesFromDB(
24
67
  combinationString,
25
- gender
68
+ gender,
69
+ language
26
70
  );
71
+ await this.log('info', 'Fetched archetypes', {
72
+ archetypesCount: archetypes.length,
73
+ archetypeIds: archetypes.map((a) => a.id),
74
+ });
27
75
 
28
- if (archetypes.some((arc) => arc.status === 'generating')) {
29
- console.log(
30
- `Archetypes are already being processed for ${combinationString}, gender: ${gender}`
76
+ // Check if any archetypes are already being processed (images are generating)
77
+ const db = this.context.drizzle();
78
+ await this.log('debug', 'Checking for in-progress image generations', {
79
+ combinationString,
80
+ gender,
81
+ });
82
+ const inProgressGenerations = await db
83
+ .select()
84
+ .from(schema.generations)
85
+ .where(
86
+ and(
87
+ eq(schema.generations.status, 'pending'),
88
+ eq(schema.generations.gender, gender),
89
+ eq(schema.generations.conceptCombinationId, combinationString)
90
+ )
91
+ )
92
+ .execute();
93
+
94
+ if (inProgressGenerations.length > 0) {
95
+ await this.log(
96
+ 'warn',
97
+ `Images are already being processed for ${combinationString}, gender: ${gender}`,
98
+ {
99
+ inProgressGenerationsCount: inProgressGenerations.length,
100
+ generationIds: inProgressGenerations.map((g) => g.id),
101
+ }
31
102
  );
32
103
  return { message: 'Images are being processed, please try again later.' };
33
104
  }
105
+ await this.log('info', 'No in-progress image generations found', {
106
+ combinationString,
107
+ gender,
108
+ });
34
109
 
35
- if (archetypes.some((arc) => !arc.name || arc.images.length < 3)) {
36
- console.log(
37
- `Generating missing basic info for: ${combinationString}, gender: ${gender}`
38
- );
39
- await this.archetypeService.generateBasicInfo(combinationString);
110
+ // Step 1: Generate missing textual content (description, virtues, content, leonardoPrompt)
111
+ const archetypesNeedingText = archetypes.filter(
112
+ (arc) =>
113
+ !arc.description ||
114
+ arc.virtues === '[]' ||
115
+ arc.content === '[]' ||
116
+ !arc.leonardoPrompt
117
+ );
118
+
119
+ if (archetypesNeedingText.length > 0) {
120
+ await this.log('info', 'Generating missing textual content', {
121
+ combinationString,
122
+ gender,
123
+ language,
124
+ archetypesNeedingTextCount: archetypesNeedingText.length,
125
+ archetypeIds: archetypesNeedingText.map((a) => a.id),
126
+ });
127
+ await this.generateTextualContent(combinationString, gender, language);
128
+ } else {
129
+ await this.log('info', 'No textual content generation needed', {
130
+ combinationString,
131
+ gender,
132
+ language,
133
+ });
40
134
  }
41
135
 
42
- const updatedArchetypes = await this.fetchArchetypesFromKV(
136
+ // Refetch archetypes after generating textual content
137
+ await this.log(
138
+ 'debug',
139
+ 'Refetching archetypes after textual content generation',
140
+ { combinationString, gender, language }
141
+ );
142
+ const updatedArchetypes = await this.fetchArchetypesFromDB(
43
143
  combinationString,
44
- gender
144
+ gender,
145
+ language
45
146
  );
147
+ await this.log('info', 'Refetched archetypes', {
148
+ updatedArchetypesCount: updatedArchetypes.length,
149
+ archetypeIds: updatedArchetypes.map((a) => a.id),
150
+ });
46
151
 
47
- if (updatedArchetypes.some((arc) => !arc.leonardoPrompt)) {
48
- console.log('Generating missing Leonardo prompts...');
49
- await this.leonardoService.processArchetypesPrompts(combinationString);
50
- }
51
-
152
+ // Step 2: Queue image generation if needed
52
153
  const archetypesNeedingImages = updatedArchetypes.filter(
53
- (arc) => arc.images.length < 3
154
+ (arc) => JSON.parse(arc.images).length < 3
54
155
  );
55
156
 
56
157
  if (archetypesNeedingImages.length > 0) {
57
- console.log('Queuing image generation for missing archetypes...');
58
- await this.updateArchetypeStatus(updatedArchetypes, 'generating', gender);
158
+ await this.log(
159
+ 'info',
160
+ 'Queuing image generation for missing archetypes',
161
+ {
162
+ archetypesNeedingImagesCount: archetypesNeedingImages.length,
163
+ archetypeIds: archetypesNeedingImages.map((a) => a.id),
164
+ }
165
+ );
59
166
 
60
- try {
61
- await this.leonardoService.queueImagesForArchetypes(
62
- combinationString,
63
- gender
64
- );
65
- } catch (error) {
66
- console.error('Error queuing image generation:', error);
67
- await this.updateArchetypeStatus(updatedArchetypes, 'idle', gender);
68
- throw error;
69
- }
167
+ // Queue image generation for all archetypes needing images
168
+ const batch = archetypesNeedingImages.map((arc) => ({
169
+ body: {
170
+ archetypeDataId: arc.id,
171
+ combination: combinationString,
172
+ gender,
173
+ language,
174
+ archetypeIndex: arc.archetypeIndex,
175
+ },
176
+ }));
177
+ await this.log('debug', 'Sending batch to ARCHETYPE_POPULATION_QUEUE', {
178
+ batchCount: batch.length,
179
+ batch,
180
+ });
181
+ await this.context.env.ARCHETYPE_POPULATION_QUEUE.sendBatch(batch);
182
+ await this.log('info', 'Successfully queued image generation', {
183
+ batchCount: batch.length,
184
+ });
70
185
 
71
186
  return { message: 'Images are being processed, please try again later.' };
72
187
  }
73
188
 
74
- await this.updateArchetypeStatus(updatedArchetypes, 'idle', gender);
75
-
76
- console.log('Archetypes fully processed and ready:', updatedArchetypes);
189
+ await this.log('info', 'Archetypes fully processed and ready', {
190
+ updatedArchetypes,
191
+ });
77
192
  return {
78
193
  archetypes: updatedArchetypes.map(
79
- ({ name, content, description, virtues, images }) => ({
194
+ ({ name, essenceLine, description, virtues, images }) => ({
80
195
  name,
81
- content,
196
+ essenceLine,
82
197
  description,
83
- virtues,
84
- images,
198
+ virtues: JSON.parse(virtues),
199
+ images: JSON.parse(images),
85
200
  })
86
201
  ),
87
202
  };
88
203
  }
89
204
 
90
- async generateNames({
91
- combinations,
92
- overrideExisting,
93
- }: {
94
- combinations: string[];
95
- overrideExisting?: boolean;
96
- }): Promise<void> {
97
- if (combinations.length === 0) return;
98
-
99
- if (combinations.length === 1) {
100
- await this.archetypeService.generateArchetypeNames(
101
- combinations[0],
102
- overrideExisting
205
+ private async fetchArchetypesFromDB(
206
+ combinationString: string,
207
+ gender: Gender,
208
+ language: string
209
+ ) {
210
+ await this.log('debug', 'Executing fetchArchetypesFromDB', {
211
+ combinationString,
212
+ gender,
213
+ language,
214
+ });
215
+ const db = this.context.drizzle();
216
+ const result = await db
217
+ .select()
218
+ .from(schema.archetypesData)
219
+ .where(
220
+ and(
221
+ eq(schema.archetypesData.combination, combinationString),
222
+ eq(schema.archetypesData.gender, gender),
223
+ eq(schema.archetypesData.language, language)
224
+ )
225
+ )
226
+ .execute();
227
+ await this.log('debug', 'fetchArchetypesFromDB result', {
228
+ resultCount: result.length,
229
+ result,
230
+ });
231
+ return result;
232
+ }
233
+
234
+ private async generateTextualContent(
235
+ combinationString: string,
236
+ gender: Gender,
237
+ language: string
238
+ ) {
239
+ await this.log('info', 'Starting generateTextualContent', {
240
+ combinationString,
241
+ gender,
242
+ language,
243
+ });
244
+
245
+ const db = this.context.drizzle();
246
+
247
+ // Fetch English archetypes to get names and essence lines
248
+ await this.log(
249
+ 'debug',
250
+ 'Fetching English archetypes for names and essence lines',
251
+ { combinationString, gender }
252
+ );
253
+ const archetypes = await db
254
+ .select()
255
+ .from(schema.archetypesData)
256
+ .where(
257
+ and(
258
+ eq(schema.archetypesData.combination, combinationString),
259
+ eq(schema.archetypesData.gender, gender),
260
+ eq(schema.archetypesData.language, 'en-us')
261
+ )
262
+ )
263
+ .execute();
264
+ await this.log('info', 'Fetched English archetypes', {
265
+ archetypesCount: archetypes.length,
266
+ names: archetypes.map((a) => a.name),
267
+ essenceLines: archetypes.map((a) => a.essenceLine),
268
+ });
269
+
270
+ // Step 1: Generate description and virtues
271
+ await this.log('debug', 'Generating description and virtues', {
272
+ combinationString,
273
+ });
274
+ const descVirtueMessages = this.context
275
+ .buildLLMMessages()
276
+ .generateCosmicMirrorDescriptionAndVirtues({
277
+ combination: combinationString,
278
+ names: [archetypes[0].name, archetypes[1].name, archetypes[2].name],
279
+ essenceLines: [
280
+ archetypes[0].essenceLine,
281
+ archetypes[1].essenceLine,
282
+ archetypes[2].essenceLine,
283
+ ],
284
+ });
285
+
286
+ await this.log('debug', 'Calling API for description and virtues', {
287
+ messages: descVirtueMessages,
288
+ });
289
+ const descVirtueResponse = await this.context
290
+ .api()
291
+ .callTogether.single(descVirtueMessages, {});
292
+ await this.log('info', 'Received description and virtues response', {
293
+ responseLength: descVirtueResponse.length,
294
+ });
295
+
296
+ await this.log('debug', 'Parsing description and virtues response');
297
+ const parsedDescVirtues =
298
+ this.parseDescriptionAndVirtuesResponse(descVirtueResponse);
299
+ await this.log('info', 'Parsed description and virtues', {
300
+ parsedDescVirtues,
301
+ });
302
+
303
+ // Step 2: Generate content for each archetype
304
+ const contentResults = [];
305
+ for (let i = 0; i < 3; i++) {
306
+ await this.log('debug', `Generating content for archetype ${i + 1}`, {
307
+ name: archetypes[i].name,
308
+ });
309
+ const contentMessages = this.context
310
+ .buildLLMMessages()
311
+ .generateCosmicMirrorArchetypeContent({
312
+ combination: combinationString,
313
+ name: archetypes[i].name,
314
+ description: parsedDescVirtues[i].descriptionEN,
315
+ });
316
+
317
+ await this.log('debug', `Calling API for content of archetype ${i + 1}`, {
318
+ messages: contentMessages,
319
+ });
320
+ const contentResponse = await this.context
321
+ .api()
322
+ .callTogether.single(contentMessages, {});
323
+ await this.log(
324
+ 'info',
325
+ `Received content response for archetype ${i + 1}`,
326
+ { responseLength: contentResponse.length }
103
327
  );
104
- } else {
105
- const entries = combinations.map((combination) => ({
106
- combination,
107
- }));
108
328
 
109
- await this.archetypeService.generateArchetypeNamesBatch(
110
- entries,
111
- overrideExisting
329
+ await this.log(
330
+ 'debug',
331
+ `Parsing content response for archetype ${i + 1}`
112
332
  );
333
+ const parsedContent = this.parseContentResponse(contentResponse);
334
+ contentResults.push(parsedContent);
335
+ await this.log('info', `Parsed content for archetype ${i + 1}`, {
336
+ parsedContent,
337
+ });
113
338
  }
114
- }
115
339
 
116
- /**
117
- * Fetch all three archetypes from KV for a given combination and gender.
118
- */
119
- private async fetchArchetypesFromKV(
120
- combinationString: string,
121
- gender: Gender
122
- ): Promise<KVArchetype[]> {
123
- return Promise.all(
124
- Array.from({ length: 3 }, (_, i) => i + 1).map(async (index) => {
125
- const kvKey = buildCosmicMirrorArchetypeKVKey(
126
- 'en-us',
127
- combinationString,
128
- gender,
129
- index
340
+ // Step 3: Generate Leonardo prompts for all archetypes
341
+ await this.log('debug', 'Generating Leonardo prompts for all archetypes');
342
+ const promptMessages = this.context
343
+ .buildLLMMessages()
344
+ .generateCosmicMirrorArchetypeLeonardoPrompts(
345
+ archetypes.map((arc, idx) => ({
346
+ name: arc.name,
347
+ description: parsedDescVirtues[idx].descriptionEN,
348
+ }))
349
+ );
350
+
351
+ await this.log('debug', 'Calling API for Leonardo prompts', {
352
+ messages: promptMessages,
353
+ });
354
+ const promptResponse = await this.context
355
+ .api()
356
+ .callTogether.single(promptMessages, {});
357
+ await this.log('info', 'Received Leonardo prompts response', {
358
+ responseLength: promptResponse.length,
359
+ });
360
+
361
+ await this.log('debug', 'Parsing Leonardo prompts response');
362
+ const parsedPrompts = this.parseLeonardoPromptResponse(promptResponse);
363
+ await this.log('info', 'Parsed Leonardo prompts', { parsedPrompts });
364
+
365
+ // Update archetypes_data with the generated content
366
+ for (let i = 0; i < 3; i++) {
367
+ const archetype = archetypes[i];
368
+ const index = (i + 1).toString();
369
+
370
+ for (const lang of ['en-us', 'pt-br']) {
371
+ const descriptionField =
372
+ lang === 'en-us'
373
+ ? parsedDescVirtues[i].descriptionEN
374
+ : gender === 'male'
375
+ ? parsedDescVirtues[i].descriptionPTM
376
+ : parsedDescVirtues[i].descriptionPTF;
377
+
378
+ const contentLangIndex =
379
+ lang === 'en-us' ? 0 : gender === 'male' ? 1 : 2;
380
+ const content = [
381
+ {
382
+ section: 'voiceOfTheSoul',
383
+ text: contentResults[i][contentLangIndex].voiceOfTheSoul,
384
+ },
385
+ {
386
+ section: 'giftsYouBear',
387
+ text: contentResults[i][contentLangIndex].giftsYouBear,
388
+ },
389
+ {
390
+ section: 'shadowsYouFace',
391
+ text: contentResults[i][contentLangIndex].shadowsYouFace,
392
+ },
393
+ {
394
+ section: 'rhythmOfYourDays',
395
+ text: contentResults[i][contentLangIndex].rhythmOfYourDays,
396
+ },
397
+ {
398
+ section: 'tiesThatBind',
399
+ text: contentResults[i][contentLangIndex].tiesThatBind,
400
+ },
401
+ {
402
+ section: 'lightWithin',
403
+ text: contentResults[i][contentLangIndex].lightWithin,
404
+ },
405
+ ];
406
+
407
+ const leonardoPrompt =
408
+ gender === 'male'
409
+ ? parsedPrompts[i].malePrompt
410
+ : parsedPrompts[i].femalePrompt;
411
+
412
+ await this.log(
413
+ 'debug',
414
+ `Updating archetypes_data for archetype ${index}, language: ${lang}`,
415
+ {
416
+ descriptionField,
417
+ content,
418
+ leonardoPrompt,
419
+ }
130
420
  );
131
- console.log(`Fetching archetype from KV: ${kvKey}`);
132
421
 
133
- try {
134
- return (
135
- (await this.context
136
- .kvCosmicMirrorArchetypesStore()
137
- .get<KVArchetype>(kvKey, 'json')) || this.createEmptyArchetype()
422
+ await db
423
+ .update(schema.archetypesData)
424
+ .set({
425
+ description: descriptionField,
426
+ virtues: JSON.stringify(parsedDescVirtues[i].virtues),
427
+ content: JSON.stringify(content),
428
+ leonardoPrompt,
429
+ updatedAt: new Date().getTime(),
430
+ })
431
+ .where(
432
+ and(
433
+ eq(schema.archetypesData.combination, combinationString),
434
+ eq(schema.archetypesData.gender, gender),
435
+ eq(schema.archetypesData.language, lang),
436
+ eq(schema.archetypesData.archetypeIndex, index)
437
+ )
438
+ )
439
+ .execute();
440
+
441
+ await this.log(
442
+ 'info',
443
+ `Updated archetypes_data for archetype ${index}, language: ${lang}`
444
+ );
445
+ }
446
+ }
447
+
448
+ await this.log('info', 'Completed generateTextualContent', {
449
+ combinationString,
450
+ gender,
451
+ language,
452
+ });
453
+ }
454
+
455
+ private parseDescriptionAndVirtuesResponse(response: string) {
456
+ this.log('debug', 'Starting parseDescriptionAndVirtuesResponse', {
457
+ responseLength: response.length,
458
+ });
459
+
460
+ const entries = response
461
+ .split(/---/)
462
+ .map((block) => block.trim())
463
+ .filter((block) => block.length > 0);
464
+
465
+ this.log('debug', 'Split response into entries', {
466
+ entriesCount: entries.length,
467
+ });
468
+
469
+ const result = entries.map((entry, entryIndex) => {
470
+ this.log('debug', `Processing entry ${entryIndex + 1}`, { entry });
471
+
472
+ const lines = entry.split('\n').filter((line) => line.trim());
473
+ this.log('debug', `Split entry ${entryIndex + 1} into lines`, {
474
+ linesCount: lines.length,
475
+ lines,
476
+ });
477
+
478
+ let descriptionEN = '';
479
+ let descriptionPTM = '';
480
+ let descriptionPTF = '';
481
+ let virtues: string[] = [];
482
+ let currentField = '';
483
+
484
+ for (const line of lines) {
485
+ if (line.startsWith('• Description EN:')) {
486
+ currentField = 'descriptionEN';
487
+ descriptionEN = line.split('• Description EN:')[1]?.trim() || '';
488
+ this.log(
489
+ 'debug',
490
+ `Extracted descriptionEN for entry ${entryIndex + 1}`,
491
+ { descriptionEN }
138
492
  );
139
- } catch (error) {
140
- console.error(
141
- `Error fetching archetype KV for index ${index}:`,
142
- error
493
+ } else if (line.startsWith('• Description PT-M:')) {
494
+ currentField = 'descriptionPTM';
495
+ descriptionPTM = line.split('• Description PT-M:')[1]?.trim() || '';
496
+ this.log(
497
+ 'debug',
498
+ `Extracted descriptionPTM for entry ${entryIndex + 1}`,
499
+ { descriptionPTM }
143
500
  );
144
- return this.createEmptyArchetype();
501
+ } else if (line.startsWith('• Description PT-F:')) {
502
+ currentField = 'descriptionPTF';
503
+ descriptionPTF = line.split('• Description PT-F:')[1]?.trim() || '';
504
+ this.log(
505
+ 'debug',
506
+ `Extracted descriptionPTF for entry ${entryIndex + 1}`,
507
+ { descriptionPTF }
508
+ );
509
+ } else if (line.startsWith('• Virtues:')) {
510
+ currentField = 'virtues';
511
+ virtues =
512
+ line
513
+ .split('• Virtues:')[1]
514
+ ?.split(',')
515
+ .map((v) => v.trim())
516
+ .filter((v) => v) || [];
517
+ this.log('debug', `Extracted virtues for entry ${entryIndex + 1}`, {
518
+ virtues,
519
+ });
520
+ } else if (currentField && currentField !== 'virtues') {
521
+ if (currentField === 'descriptionEN') {
522
+ descriptionEN += ' ' + line.trim();
523
+ this.log(
524
+ 'debug',
525
+ `Appended to descriptionEN for entry ${entryIndex + 1}`,
526
+ { descriptionEN }
527
+ );
528
+ }
529
+ if (currentField === 'descriptionPTM') {
530
+ descriptionPTM += ' ' + line.trim();
531
+ this.log(
532
+ 'debug',
533
+ `Appended to descriptionPTM for entry ${entryIndex + 1}`,
534
+ { descriptionPTM }
535
+ );
536
+ }
537
+ if (currentField === 'descriptionPTF') {
538
+ descriptionPTF += ' ' + line.trim();
539
+ this.log(
540
+ 'debug',
541
+ `Appended to descriptionPTF for entry ${entryIndex + 1}`,
542
+ { descriptionPTF }
543
+ );
544
+ }
145
545
  }
146
- })
147
- );
546
+ }
547
+
548
+ if (
549
+ !descriptionEN ||
550
+ !descriptionPTM ||
551
+ !descriptionPTF ||
552
+ virtues.length !== 3
553
+ ) {
554
+ this.log(
555
+ 'warn',
556
+ `Malformed description and virtues response for entry ${
557
+ entryIndex + 1
558
+ }`,
559
+ {
560
+ descriptionEN,
561
+ descriptionPTM,
562
+ descriptionPTF,
563
+ virtues,
564
+ response: entry,
565
+ }
566
+ );
567
+ }
568
+
569
+ return { descriptionEN, descriptionPTM, descriptionPTF, virtues };
570
+ });
571
+
572
+ this.log('info', 'Completed parseDescriptionAndVirtuesResponse', {
573
+ result,
574
+ });
575
+ return result;
148
576
  }
149
577
 
150
- /**
151
- * Update the status of archetypes in KV.
152
- */
153
- private async updateArchetypeStatus(
154
- archetypes: KVArchetype[],
155
- status: 'idle' | 'generating',
156
- gender: Gender
157
- ): Promise<void> {
158
- await Promise.all(
159
- archetypes.map(async (archetype, index) => {
160
- const kvKey = buildCosmicMirrorArchetypeKVKey(
161
- 'en-us',
162
- archetype.name,
163
- gender,
164
- index + 1
578
+ private parseContentResponse(response: string) {
579
+ this.log('debug', 'Starting parseContentResponse', {
580
+ responseLength: response.length,
581
+ });
582
+
583
+ const sections = response
584
+ .split(/---/)
585
+ .map((block) => block.trim())
586
+ .filter((block) => block.length > 0);
587
+ this.log('debug', 'Split response into sections', {
588
+ sectionsCount: sections.length,
589
+ });
590
+
591
+ const result = sections.map((section, sectionIndex) => {
592
+ this.log('debug', `Processing section ${sectionIndex + 1}`, { section });
593
+
594
+ const lines = section.split('\n').filter((line) => line.trim());
595
+ this.log('debug', `Split section ${sectionIndex + 1} into lines`, {
596
+ linesCount: lines.length,
597
+ lines,
598
+ });
599
+
600
+ const content: Record<string, string> = {};
601
+ let currentSection = '';
602
+ let currentText: string[] = [];
603
+
604
+ for (const line of lines) {
605
+ if (
606
+ line.startsWith('EN:') ||
607
+ line.startsWith('PT-M:') ||
608
+ line.startsWith('PT-F:')
609
+ ) {
610
+ this.log(
611
+ 'debug',
612
+ `Skipping language header in section ${sectionIndex + 1}`,
613
+ { line }
614
+ );
615
+ continue;
616
+ }
617
+
618
+ if (line.startsWith('#')) {
619
+ if (currentSection && currentText.length > 0) {
620
+ const key = currentSection
621
+ .toLowerCase()
622
+ .replace(/\s+/g, '')
623
+ .replace(/([A-Z])/g, (match) => match.toLowerCase());
624
+ content[key] = currentText.join(' ').trim();
625
+ this.log(
626
+ 'debug',
627
+ `Extracted section ${currentSection} in section ${
628
+ sectionIndex + 1
629
+ }`,
630
+ { key, text: content[key] }
631
+ );
632
+ }
633
+ currentSection = line.replace('# ', '');
634
+ currentText = [];
635
+ this.log(
636
+ 'debug',
637
+ `Starting new section ${currentSection} in section ${
638
+ sectionIndex + 1
639
+ }`
640
+ );
641
+ } else {
642
+ currentText.push(line);
643
+ }
644
+ }
645
+
646
+ if (currentSection && currentText.length > 0) {
647
+ const key = currentSection
648
+ .toLowerCase()
649
+ .replace(/\s+/g, '')
650
+ .replace(/([A-Z])/g, (match) => match.toLowerCase());
651
+ content[key] = currentText.join(' ').trim();
652
+ this.log(
653
+ 'debug',
654
+ `Extracted final section ${currentSection} in section ${
655
+ sectionIndex + 1
656
+ }`,
657
+ { key, text: content[key] }
165
658
  );
166
- archetype.status = status;
167
- await this.context
168
- .kvCosmicMirrorArchetypesStore()
169
- .put(kvKey, JSON.stringify(archetype));
170
- })
171
- );
659
+ }
660
+
661
+ const parsedContent = {
662
+ voiceOfTheSoul:
663
+ content['thevoiceofthesoul'] || content['avozdaalma'] || '',
664
+ giftsYouBear:
665
+ content['thegiftsyoubear'] || content['osdonsquevocêcarrega'] || '',
666
+ shadowsYouFace:
667
+ content['theshadowsyouface'] || content['assombrasqueenfrenta'] || '',
668
+ rhythmOfYourDays:
669
+ content['therhythmofyourdays'] || content['oritmodosseusdias'] || '',
670
+ tiesThatBind:
671
+ content['thetiesthatbind'] || content['oslaçosqueteconectam'] || '',
672
+ lightWithin: content['thelightwithin'] || content['aluzinterior'] || '',
673
+ };
674
+
675
+ if (Object.values(parsedContent).some((value) => !value)) {
676
+ this.log(
677
+ 'warn',
678
+ `Malformed content response for section ${sectionIndex + 1}`,
679
+ {
680
+ parsedContent,
681
+ response: section,
682
+ }
683
+ );
684
+ }
685
+
686
+ return parsedContent;
687
+ });
688
+
689
+ this.log('info', 'Completed parseContentResponse', { result });
690
+ return result;
172
691
  }
173
692
 
174
- /**
175
- * Create an empty KVArchetype object when KV data is missing.
176
- */
177
- private createEmptyArchetype(): KVArchetype {
178
- return {
179
- name: '',
180
- description: '',
181
- content: '',
182
- leonardoPrompt: '',
183
- visualDescription: '',
184
- virtues: [],
185
- images: [],
186
- status: 'idle',
187
- };
693
+ private parseLeonardoPromptResponse(response: string) {
694
+ this.log('debug', 'Starting parseLeonardoPromptResponse', {
695
+ responseLength: response.length,
696
+ });
697
+
698
+ const lines = response.split('\n').filter((line) => line.trim());
699
+ this.log('debug', 'Split response into lines', {
700
+ linesCount: lines.length,
701
+ lines,
702
+ });
703
+
704
+ const prompts: Array<{ malePrompt: string; femalePrompt: string }> = [];
705
+
706
+ for (let i = 0; i < lines.length; i += 2) {
707
+ const maleLine = lines[i];
708
+ const femaleLine = lines[i + 1];
709
+
710
+ const malePrompt = maleLine.startsWith(`${Math.floor(i / 2) + 1}.m`)
711
+ ? maleLine.split(`${Math.floor(i / 2) + 1}.m`)[1]?.trim()
712
+ : '';
713
+ const femalePrompt = femaleLine.startsWith(`${Math.floor(i / 2) + 1}.f`)
714
+ ? femaleLine.split(`${Math.floor(i / 2) + 1}.f`)[1]?.trim()
715
+ : '';
716
+
717
+ prompts.push({ malePrompt, femalePrompt });
718
+ this.log(
719
+ 'debug',
720
+ `Parsed prompts for archetype ${Math.floor(i / 2) + 1}`,
721
+ { malePrompt, femalePrompt }
722
+ );
723
+
724
+ if (!malePrompt || !femalePrompt) {
725
+ this.log(
726
+ 'warn',
727
+ `Malformed Leonardo prompt for archetype ${Math.floor(i / 2) + 1}`,
728
+ {
729
+ malePrompt,
730
+ femalePrompt,
731
+ maleLine,
732
+ femaleLine,
733
+ }
734
+ );
735
+ }
736
+ }
737
+
738
+ this.log('info', 'Completed parseLeonardoPromptResponse', { prompts });
739
+ return prompts;
188
740
  }
189
741
  }