@zodic/shared 0.0.306 → 0.0.308
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 +121 -113
- package/package.json +1 -1
- package/utils/archetypeNamesMessages.ts +18 -10
|
@@ -312,44 +312,8 @@ export class ArchetypeService {
|
|
|
312
312
|
return;
|
|
313
313
|
}
|
|
314
314
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
try {
|
|
319
|
-
blocks = response
|
|
320
|
-
.split('-EN')[1]
|
|
321
|
-
.split('-PT')[0]
|
|
322
|
-
.trim()
|
|
323
|
-
.split(/\n\d\.\s*\n?/)
|
|
324
|
-
.filter(Boolean);
|
|
325
|
-
|
|
326
|
-
ptBlocks = response
|
|
327
|
-
.split('-PT')[1]
|
|
328
|
-
.trim()
|
|
329
|
-
.split(/\n\d\.\s*\n?/)
|
|
330
|
-
.filter(Boolean);
|
|
331
|
-
} catch (err) {
|
|
332
|
-
console.error(`❌ [Single] Parsing failed for ${combination}`, err);
|
|
333
|
-
await db.insert(schema.archetypeNameDumps).values({
|
|
334
|
-
id: combination,
|
|
335
|
-
combination,
|
|
336
|
-
rawText: response,
|
|
337
|
-
parsedSuccessfully: 0,
|
|
338
|
-
createdAt: Date.now(),
|
|
339
|
-
});
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const englishNames = blocks.map((block) => ({
|
|
344
|
-
name: block.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
|
|
345
|
-
essenceLine: block.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
|
|
346
|
-
}));
|
|
347
|
-
|
|
348
|
-
const portugueseVariants = ptBlocks.map((block) => ({
|
|
349
|
-
masc: block.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
|
|
350
|
-
fem: block.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
|
|
351
|
-
essenceLine: block.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
|
|
352
|
-
}));
|
|
315
|
+
const { english: englishNames, portuguese: portugueseVariants } =
|
|
316
|
+
this.parseArchetypeNameBlocks(response);
|
|
353
317
|
|
|
354
318
|
async function isEnglishNameDuplicate(name: string): Promise<boolean> {
|
|
355
319
|
const result = await db
|
|
@@ -483,39 +447,7 @@ export class ArchetypeService {
|
|
|
483
447
|
const block = blocks[i];
|
|
484
448
|
console.log(`📦 [Batch] Processing: ${combination}`);
|
|
485
449
|
|
|
486
|
-
|
|
487
|
-
let pt = '';
|
|
488
|
-
try {
|
|
489
|
-
en = block.split('-EN')[1].split('-PT')[0].trim();
|
|
490
|
-
pt = block.split('-PT')[1].trim();
|
|
491
|
-
} catch (err) {
|
|
492
|
-
console.error(`❌ [Batch] Parsing failed for: ${combination}`, err);
|
|
493
|
-
await db.insert(schema.archetypeNameDumps).values({
|
|
494
|
-
id: combination,
|
|
495
|
-
combination,
|
|
496
|
-
rawText: block,
|
|
497
|
-
parsedSuccessfully: 0,
|
|
498
|
-
createdAt: Date.now(),
|
|
499
|
-
});
|
|
500
|
-
continue;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
const english = en
|
|
504
|
-
.split(/\n\d\.\s*\n?/)
|
|
505
|
-
.filter(Boolean)
|
|
506
|
-
.map((line) => ({
|
|
507
|
-
name: line.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
|
|
508
|
-
essenceLine: line.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
|
|
509
|
-
}));
|
|
510
|
-
|
|
511
|
-
const portuguese = pt
|
|
512
|
-
.split(/\n\d\.\s*\n?/)
|
|
513
|
-
.filter(Boolean)
|
|
514
|
-
.map((line) => ({
|
|
515
|
-
masc: line.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
|
|
516
|
-
fem: line.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
|
|
517
|
-
essenceLine: line.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
|
|
518
|
-
}));
|
|
450
|
+
const { english, portuguese } = this.parseArchetypeNameBlocks(block);
|
|
519
451
|
|
|
520
452
|
for (let j = 0; j < 3; j++) {
|
|
521
453
|
const index = (j + 1).toString();
|
|
@@ -678,7 +610,12 @@ export class ArchetypeService {
|
|
|
678
610
|
return;
|
|
679
611
|
}
|
|
680
612
|
|
|
681
|
-
|
|
613
|
+
// Clean up the response by removing unexpected suffixes
|
|
614
|
+
const cleanedResponse = response
|
|
615
|
+
.replace(/###|---\s*###|-\s*###/g, '')
|
|
616
|
+
.trim();
|
|
617
|
+
|
|
618
|
+
const blocks = cleanedResponse
|
|
682
619
|
.split(/Composition \d+/)
|
|
683
620
|
.slice(1)
|
|
684
621
|
.map((b) => b.trim());
|
|
@@ -691,13 +628,13 @@ export class ArchetypeService {
|
|
|
691
628
|
|
|
692
629
|
console.log(`🔄 [Batch] Processing: ${combination}`);
|
|
693
630
|
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
console.error(`❌ [Batch] Parsing failed for: ${combination}
|
|
631
|
+
const { english, portuguese } = this.parseArchetypeNameBlocks(block);
|
|
632
|
+
|
|
633
|
+
if (
|
|
634
|
+
english.length !== indexes.length ||
|
|
635
|
+
portuguese.length !== indexes.length
|
|
636
|
+
) {
|
|
637
|
+
console.error(`❌ [Batch] Parsing failed for: ${combination}`);
|
|
701
638
|
await this.context
|
|
702
639
|
.drizzle()
|
|
703
640
|
.insert(schema.archetypeNameDumps)
|
|
@@ -711,37 +648,27 @@ export class ArchetypeService {
|
|
|
711
648
|
continue;
|
|
712
649
|
}
|
|
713
650
|
|
|
714
|
-
const english = en
|
|
715
|
-
.split(/\n\d\.\s*\n?/)
|
|
716
|
-
.filter(Boolean)
|
|
717
|
-
.map((line) => ({
|
|
718
|
-
name: line.match(/• Name:\s*(.+)/)?.[1]?.trim() || '',
|
|
719
|
-
essenceLine: line.match(/• Essence:\s*(.+)/)?.[1]?.trim() || '',
|
|
720
|
-
}));
|
|
721
|
-
|
|
722
|
-
const portuguese = pt
|
|
723
|
-
.split(/\n\d\.\s*\n?/)
|
|
724
|
-
.filter(Boolean)
|
|
725
|
-
.map((line) => ({
|
|
726
|
-
masc: line.match(/• Masculino:\s*(.+)/)?.[1]?.trim() || '',
|
|
727
|
-
fem: line.match(/• Feminino:\s*(.+)/)?.[1]?.trim() || '',
|
|
728
|
-
essenceLine: line.match(/• Essência:\s*(.+)/)?.[1]?.trim() || '',
|
|
729
|
-
}));
|
|
730
|
-
|
|
731
651
|
for (const index of indexes) {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
652
|
+
const idx = index - 1;
|
|
653
|
+
const englishEntry = english[idx];
|
|
654
|
+
const ptEntry = portuguese[idx];
|
|
655
|
+
|
|
656
|
+
if (!englishEntry || !ptEntry) {
|
|
657
|
+
await this.context
|
|
658
|
+
.drizzle()
|
|
659
|
+
.insert(schema.archetypeNameDumps)
|
|
660
|
+
.values({
|
|
661
|
+
id: `${combination}:${index}:${Date.now()}`,
|
|
662
|
+
combination,
|
|
663
|
+
rawText: block,
|
|
664
|
+
parsedSuccessfully: 0,
|
|
665
|
+
createdAt: Date.now(),
|
|
666
|
+
});
|
|
667
|
+
console.warn(
|
|
668
|
+
`⚠️ [Batch] Skipping index ${index} for ${combination} due to missing parsed block`
|
|
669
|
+
);
|
|
741
670
|
continue;
|
|
742
671
|
}
|
|
743
|
-
const englishEntry = english[index - 1];
|
|
744
|
-
const ptEntry = portuguese[index - 1];
|
|
745
672
|
|
|
746
673
|
for (const gender of ['male', 'female']) {
|
|
747
674
|
const enId = `${combination}:${gender}:${index}`;
|
|
@@ -805,11 +732,13 @@ export class ArchetypeService {
|
|
|
805
732
|
`🎉 [Batch] Completed regenerating ${compositions.length} combinations`
|
|
806
733
|
);
|
|
807
734
|
}
|
|
808
|
-
|
|
735
|
+
|
|
809
736
|
async fetchMissingArchetypeCompositions(): Promise<Composition[]> {
|
|
810
737
|
const db = this.context.drizzle();
|
|
811
738
|
const incomplete = await this.findIncompleteCombinations();
|
|
812
|
-
console.log(
|
|
739
|
+
console.log(
|
|
740
|
+
`🔎 [Fetch] Retrieved ${incomplete.length} incomplete combinations`
|
|
741
|
+
);
|
|
813
742
|
const limited = incomplete.slice(0, 400);
|
|
814
743
|
|
|
815
744
|
const compositions: Composition[] = [];
|
|
@@ -844,13 +773,92 @@ export class ArchetypeService {
|
|
|
844
773
|
moon,
|
|
845
774
|
indexesToGenerate,
|
|
846
775
|
});
|
|
847
|
-
console.log(
|
|
776
|
+
console.log(
|
|
777
|
+
`✅ [Fetch] Will regenerate indexes [${indexesToGenerate.join(
|
|
778
|
+
', '
|
|
779
|
+
)}] for ${combination}`
|
|
780
|
+
);
|
|
848
781
|
}
|
|
849
782
|
}
|
|
850
783
|
|
|
851
|
-
console.log(
|
|
852
|
-
|
|
853
|
-
|
|
784
|
+
console.log(
|
|
785
|
+
`📦 [Fetch] Total compositions to regenerate (limited to 400): ${compositions.length}`
|
|
786
|
+
);
|
|
787
|
+
|
|
854
788
|
return compositions;
|
|
855
789
|
}
|
|
790
|
+
|
|
791
|
+
private parseArchetypeNameBlocks(block: string): {
|
|
792
|
+
english: { name: string; essenceLine: string }[];
|
|
793
|
+
portuguese: { masc: string; fem: string; essenceLine: string }[];
|
|
794
|
+
} {
|
|
795
|
+
const result = {
|
|
796
|
+
english: [] as { name: string; essenceLine: string }[],
|
|
797
|
+
portuguese: [] as { masc: string; fem: string; essenceLine: string }[],
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
try {
|
|
801
|
+
// Normalize the block by replacing multiple spaces with a single space and ensuring newlines
|
|
802
|
+
const normalizedBlock = block
|
|
803
|
+
.replace(/\s+/g, ' ')
|
|
804
|
+
.replace(/-EN\s*/, '-EN\n')
|
|
805
|
+
.replace(/-PT\s*/, '\n-PT\n')
|
|
806
|
+
.trim();
|
|
807
|
+
|
|
808
|
+
// Split into EN and PT sections
|
|
809
|
+
const sections = normalizedBlock.split(/\n?-PT\n/);
|
|
810
|
+
const enSection = sections[0]?.replace(/-EN\n/, '').trim() ?? '';
|
|
811
|
+
const ptSection = sections[1]?.trim() ?? '';
|
|
812
|
+
|
|
813
|
+
// Parse English entries
|
|
814
|
+
result.english = enSection
|
|
815
|
+
.split(/\n?\d+\.\s*\n?/)
|
|
816
|
+
.filter(Boolean)
|
|
817
|
+
.map((entry, i) => {
|
|
818
|
+
const nameMatch = entry.match(/• Name:\s*([^•]+)/);
|
|
819
|
+
const essenceMatch = entry.match(/• Essence:\s*([^•]+)/);
|
|
820
|
+
const name = nameMatch?.[1]?.trim() ?? '';
|
|
821
|
+
const essenceLine = essenceMatch?.[1]?.trim() ?? '';
|
|
822
|
+
if (!name || !essenceLine) {
|
|
823
|
+
console.warn(
|
|
824
|
+
`⚠️ [Parse] Incomplete English entry ${i + 1}:`,
|
|
825
|
+
entry
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
return { name, essenceLine };
|
|
829
|
+
});
|
|
830
|
+
|
|
831
|
+
// Parse Portuguese entries
|
|
832
|
+
result.portuguese = ptSection
|
|
833
|
+
.split(/\n?\d+\.\s*\n?/)
|
|
834
|
+
.filter(Boolean)
|
|
835
|
+
.map((entry, i) => {
|
|
836
|
+
const mascMatch = entry.match(/• Masculino:\s*([^•]+)/);
|
|
837
|
+
const femMatch = entry.match(/• Feminino:\s*([^•]+)/);
|
|
838
|
+
const essenceMatch = entry.match(/• Essência:\s*([^•]+)/);
|
|
839
|
+
const masc = mascMatch?.[1]?.trim() ?? '';
|
|
840
|
+
const fem = femMatch?.[1]?.trim() ?? '';
|
|
841
|
+
const essenceLine = essenceMatch?.[1]?.trim() ?? '';
|
|
842
|
+
if (!masc || !fem || !essenceLine) {
|
|
843
|
+
console.warn(
|
|
844
|
+
`⚠️ [Parse] Incomplete Portuguese entry ${i + 1}:`,
|
|
845
|
+
entry
|
|
846
|
+
);
|
|
847
|
+
}
|
|
848
|
+
// Validate gender consistency
|
|
849
|
+
if (masc.startsWith('A ') && fem.startsWith('O ')) {
|
|
850
|
+
console.warn(
|
|
851
|
+
`⚠️ [Parse] Gender mismatch in Portuguese entry ${i + 1}:`,
|
|
852
|
+
entry
|
|
853
|
+
);
|
|
854
|
+
return { masc: fem, fem: masc, essenceLine }; // Swap to correct the mismatch
|
|
855
|
+
}
|
|
856
|
+
return { masc, fem, essenceLine };
|
|
857
|
+
});
|
|
858
|
+
} catch (error) {
|
|
859
|
+
console.error('❌ [Parse] Failed to parse block:', error);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
856
864
|
}
|
package/package.json
CHANGED
|
@@ -211,6 +211,14 @@ For every composition, return:
|
|
|
211
211
|
Avoid names that sound like objects, titles, or abstract forces (e.g., The Lantern, The Eclipse, The Veil).
|
|
212
212
|
Instead, use names that suggest a personified being or living archetype, such as The Masked Oracle, The Starborn Seeker, or The Dancer of the Falling Sky.
|
|
213
213
|
|
|
214
|
+
**Formatting Rules**:
|
|
215
|
+
- Each composition block must start with "Composition <number>" on its own line.
|
|
216
|
+
- Within each composition block, the English section must start with "-EN" on its own line, followed by the entries.
|
|
217
|
+
- The Portuguese section must start with "-PT" on its own line, followed by the entries.
|
|
218
|
+
- Each entry (e.g., "1.", "2.", "3.") must be on its own line, with its sub-items (e.g., "• Name: ...", "• Masculino: ...") on separate lines.
|
|
219
|
+
- Do not include any extra characters, suffixes, or separators (e.g., "###", "---", or extra newlines) at the end of the response or between composition blocks.
|
|
220
|
+
- Ensure that Portuguese names correctly match the gender: "Masculino" names should use masculine forms (e.g., "O Sábio"), and "Feminino" names should use feminine forms (e.g., "A Sábia").
|
|
221
|
+
|
|
214
222
|
Do not include any commentary or explanations outside the defined output structure. Only return the output block for each composition, exactly as described:`;
|
|
215
223
|
|
|
216
224
|
const compositionBlocks = compositions.map((comp, i) => {
|
|
@@ -219,7 +227,7 @@ Do not include any commentary or explanations outside the defined output structu
|
|
|
219
227
|
const moon = influenceMap.moon[comp.moon];
|
|
220
228
|
const indexes = comp.indexesToGenerate ?? [1, 2, 3];
|
|
221
229
|
|
|
222
|
-
const influences = `\n\
|
|
230
|
+
const influences = `\n\nComposition ${i + 1}
|
|
223
231
|
|
|
224
232
|
• First Influence – ${sun.label}: ${sun.description}
|
|
225
233
|
• Second Influence – ${asc.label}: ${asc.description}
|
|
@@ -228,28 +236,28 @@ Do not include any commentary or explanations outside the defined output structu
|
|
|
228
236
|
const enLines = indexes
|
|
229
237
|
.map(
|
|
230
238
|
(idx) => `${idx}.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
239
|
+
• Name: [Name that emphasizes the ${
|
|
240
|
+
['first', 'second', 'third'][idx - 1]
|
|
241
|
+
} influence, while blending the other two]
|
|
242
|
+
• Essence: [Short poetic description line in English]`
|
|
235
243
|
)
|
|
236
244
|
.join('\n');
|
|
237
245
|
|
|
238
246
|
const ptLines = indexes
|
|
239
247
|
.map(
|
|
240
248
|
(idx) => `${idx}.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
249
|
+
• Masculino: [Portuguese name (masc)]
|
|
250
|
+
• Feminino: [Portuguese name (fem)]
|
|
251
|
+
• Essência: [Short poetic description line in Portuguese]`
|
|
244
252
|
)
|
|
245
253
|
.join('\n');
|
|
246
254
|
|
|
247
255
|
return `${influences}
|
|
248
256
|
|
|
249
|
-
\`\n-EN
|
|
257
|
+
\`\n-EN
|
|
250
258
|
${enLines}
|
|
251
259
|
|
|
252
|
-
-PT
|
|
260
|
+
-PT
|
|
253
261
|
${ptLines}
|
|
254
262
|
\``;
|
|
255
263
|
});
|