@zodic/shared 0.0.235 → 0.0.236
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/ConceptService.ts +202 -176
- package/package.json +1 -1
- package/utils/conceptPrompts.ts +10 -10
|
@@ -445,7 +445,7 @@ export class ConceptService {
|
|
|
445
445
|
}
|
|
446
446
|
|
|
447
447
|
let attempts = 0;
|
|
448
|
-
const maxAttempts =
|
|
448
|
+
const maxAttempts = 2;
|
|
449
449
|
|
|
450
450
|
while (attempts < maxAttempts) {
|
|
451
451
|
let phase = 'generation'; // 📌 Track phase
|
|
@@ -475,7 +475,7 @@ export class ConceptService {
|
|
|
475
475
|
|
|
476
476
|
// ✅ Parse structured content for both languages
|
|
477
477
|
const { structuredContentEN, structuredContentPT } =
|
|
478
|
-
this.parseStructuredContent(conceptSlug, response);
|
|
478
|
+
await this.parseStructuredContent(conceptSlug, response);
|
|
479
479
|
|
|
480
480
|
// ✅ Store content in D1
|
|
481
481
|
console.log(
|
|
@@ -543,13 +543,13 @@ export class ConceptService {
|
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
545
|
|
|
546
|
-
|
|
546
|
+
async parseStructuredContent(
|
|
547
547
|
conceptSlug: Concept,
|
|
548
548
|
response: string
|
|
549
|
-
): {
|
|
549
|
+
): Promise<{
|
|
550
550
|
structuredContentEN: StructuredConceptContent;
|
|
551
551
|
structuredContentPT: StructuredConceptContent;
|
|
552
|
-
} {
|
|
552
|
+
}> {
|
|
553
553
|
console.log(
|
|
554
554
|
`📌 [START] Parsing structured content for ${conceptSlug} from ChatGPT response.`
|
|
555
555
|
);
|
|
@@ -568,194 +568,220 @@ export class ConceptService {
|
|
|
568
568
|
cleanedResponse.slice(0, 500) + '...'
|
|
569
569
|
);
|
|
570
570
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
571
|
+
try {
|
|
572
|
+
// ✅ Step 2: Define Section Titles Per Concept
|
|
573
|
+
const conceptSections: Record<string, { en: string[]; pt: string[] }> = {
|
|
574
|
+
crown: {
|
|
575
|
+
en: [
|
|
576
|
+
'Core Identity',
|
|
577
|
+
'Strengths and Challenges',
|
|
578
|
+
'Path to Fulfillment',
|
|
579
|
+
'Emotional Depth',
|
|
580
|
+
'Vision and Aspirations',
|
|
581
|
+
],
|
|
582
|
+
pt: [
|
|
583
|
+
'Identidade Essencial',
|
|
584
|
+
'Forças e Desafios',
|
|
585
|
+
'Caminho para a Plenitude',
|
|
586
|
+
'Profundidade Emocional',
|
|
587
|
+
'Visão e Aspirações',
|
|
588
|
+
],
|
|
589
|
+
},
|
|
590
|
+
scepter: {
|
|
591
|
+
en: [
|
|
592
|
+
'The Power of Expression',
|
|
593
|
+
'The Dance of Action and Reaction',
|
|
594
|
+
'Navigating Challenges',
|
|
595
|
+
'The Mirror of Relations',
|
|
596
|
+
'Impact on the World',
|
|
597
|
+
],
|
|
598
|
+
pt: [
|
|
599
|
+
'O Poder da Expressão',
|
|
600
|
+
'A Dança da Ação e Reação',
|
|
601
|
+
'Navegando Desafios',
|
|
602
|
+
'O Espelho das Relações',
|
|
603
|
+
'Impacto no Mundo',
|
|
604
|
+
],
|
|
605
|
+
},
|
|
606
|
+
amulet: {
|
|
607
|
+
en: [
|
|
608
|
+
'The Shield of Protection',
|
|
609
|
+
'The Strength Within',
|
|
610
|
+
'Nurturing Growth',
|
|
611
|
+
'The Cycle of Renewal',
|
|
612
|
+
'The Anchor of Wisdom',
|
|
613
|
+
],
|
|
614
|
+
pt: [
|
|
615
|
+
'O Escudo da Proteção',
|
|
616
|
+
'A Força Interior',
|
|
617
|
+
'Cultivando o Crescimento',
|
|
618
|
+
'O Ciclo da Renovação',
|
|
619
|
+
'A Âncora da Sabedoria',
|
|
620
|
+
],
|
|
621
|
+
},
|
|
622
|
+
ring: {
|
|
623
|
+
en: [
|
|
624
|
+
'Magnetic Pull',
|
|
625
|
+
'Hidden Desires',
|
|
626
|
+
'The Fated Dance',
|
|
627
|
+
'Unveiling the Shadows',
|
|
628
|
+
'Your Love Power',
|
|
629
|
+
],
|
|
630
|
+
pt: [
|
|
631
|
+
'Força Magnética',
|
|
632
|
+
'Desejos Ocultos',
|
|
633
|
+
'A Dança do Destino',
|
|
634
|
+
'Revelando as Sombras',
|
|
635
|
+
'Seu Poder no Amor',
|
|
636
|
+
],
|
|
637
|
+
},
|
|
638
|
+
lantern: {
|
|
639
|
+
en: [
|
|
640
|
+
'The Call to Awakening',
|
|
641
|
+
'Walking Through Shadows',
|
|
642
|
+
'The Inner Flame',
|
|
643
|
+
'Revelations and Truths',
|
|
644
|
+
'Becoming the Light',
|
|
645
|
+
],
|
|
646
|
+
pt: [
|
|
647
|
+
'O Chamado para o Despertar',
|
|
648
|
+
'Caminhando Pelas Sombras',
|
|
649
|
+
'A Chama Interior',
|
|
650
|
+
'Revelações e Verdades',
|
|
651
|
+
'Tornando-se a Luz',
|
|
652
|
+
],
|
|
653
|
+
},
|
|
654
|
+
orb: {
|
|
655
|
+
en: [
|
|
656
|
+
'The Path Unfolding',
|
|
657
|
+
'A Calling Beyond the Self',
|
|
658
|
+
'Turning Points of Fate',
|
|
659
|
+
'Mastering the Journey',
|
|
660
|
+
'Legacy and Impact',
|
|
661
|
+
],
|
|
662
|
+
pt: [
|
|
663
|
+
'O Caminho que se Revela',
|
|
664
|
+
'Um Chamado Além de Si Mesmo',
|
|
665
|
+
'Pontos de Virada do Destino',
|
|
666
|
+
'Dominando a Jornada',
|
|
667
|
+
'Legado e Impacto',
|
|
668
|
+
],
|
|
669
|
+
},
|
|
670
|
+
};
|
|
670
671
|
|
|
671
|
-
|
|
672
|
-
|
|
672
|
+
const sectionsEN = conceptSections[conceptSlug]?.en;
|
|
673
|
+
const sectionsPT = conceptSections[conceptSlug]?.pt;
|
|
673
674
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
675
|
+
if (!sectionsEN || !sectionsPT) {
|
|
676
|
+
throw new Error(`Unknown concept: ${conceptSlug}`);
|
|
677
|
+
}
|
|
677
678
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
679
|
+
// ✅ Step 3: Detect if AI interleaved EN/PT sections
|
|
680
|
+
const interleavedMatches = cleanedResponse.match(
|
|
681
|
+
/(EN:\s*[\s\S]+?PT:\s*[\s\S]+?)(?=EN:|$)/
|
|
682
|
+
);
|
|
683
|
+
let extractedEN = '';
|
|
684
|
+
let extractedPT = '';
|
|
684
685
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
686
|
+
if (interleavedMatches) {
|
|
687
|
+
console.warn(
|
|
688
|
+
'⚠️ Detected interleaved EN/PT sections. Parsing accordingly.'
|
|
689
|
+
);
|
|
690
|
+
extractedEN = interleavedMatches
|
|
691
|
+
.map(
|
|
692
|
+
(pair) => pair.match(/EN:\s*([\s\S]+?)\s*PT:/)?.[1]?.trim() || ''
|
|
693
|
+
)
|
|
694
|
+
.join('\n\n');
|
|
695
|
+
extractedPT = interleavedMatches
|
|
696
|
+
.map((pair) => pair.match(/PT:\s*([\s\S]+)/)?.[1]?.trim() || '')
|
|
697
|
+
.join('\n\n');
|
|
698
|
+
} else {
|
|
699
|
+
console.log(
|
|
700
|
+
'✅ Standard format detected (EN block followed by PT block).'
|
|
701
|
+
);
|
|
702
|
+
extractedEN =
|
|
703
|
+
cleanedResponse.match(/EN:\s*([\s\S]+?)\s*PT:/)?.[1]?.trim() || '';
|
|
704
|
+
extractedPT =
|
|
705
|
+
cleanedResponse.match(/PT:\s*([\s\S]+)/)?.[1]?.trim() || '';
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
console.log(
|
|
709
|
+
'✅ [MATCH SUCCESS] Extracted English Content:',
|
|
710
|
+
extractedEN.slice(0, 500) + '...'
|
|
688
711
|
);
|
|
689
|
-
extractedEN = interleavedMatches
|
|
690
|
-
.map((pair) => pair.match(/EN:\s*([\s\S]+?)\s*PT:/)?.[1]?.trim() || '')
|
|
691
|
-
.join('\n\n');
|
|
692
|
-
extractedPT = interleavedMatches
|
|
693
|
-
.map((pair) => pair.match(/PT:\s*([\s\S]+)/)?.[1]?.trim() || '')
|
|
694
|
-
.join('\n\n');
|
|
695
|
-
} else {
|
|
696
712
|
console.log(
|
|
697
|
-
'✅
|
|
713
|
+
'✅ [MATCH SUCCESS] Extracted Portuguese Content:',
|
|
714
|
+
extractedPT.slice(0, 500) + '...'
|
|
698
715
|
);
|
|
699
|
-
extractedEN =
|
|
700
|
-
cleanedResponse.match(/EN:\s*([\s\S]+?)\s*PT:/)?.[1]?.trim() || '';
|
|
701
|
-
extractedPT = cleanedResponse.match(/PT:\s*([\s\S]+)/)?.[1]?.trim() || '';
|
|
702
|
-
}
|
|
703
716
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
console.log(
|
|
709
|
-
'✅ [MATCH SUCCESS] Extracted Portuguese Content:',
|
|
710
|
-
extractedPT.slice(0, 500) + '...'
|
|
711
|
-
);
|
|
717
|
+
// ✅ Step 4: Extract structured sections dynamically
|
|
718
|
+
function extractSections(text: string, sectionTitles: string[]) {
|
|
719
|
+
return sectionTitles.map((title) => {
|
|
720
|
+
console.log(`🔍 [PROCESSING] Extracting section: "${title}"`);
|
|
712
721
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
722
|
+
const regex = new RegExp(
|
|
723
|
+
`\\d+\\.\\s*${title}:\\s*([\\s\\S]+?)(?=\\n\\d+\\.\\s*[A-Z]|$)`
|
|
724
|
+
);
|
|
725
|
+
const match = text.match(regex);
|
|
717
726
|
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const match = text.match(regex);
|
|
727
|
+
if (!match) {
|
|
728
|
+
throw new Error(`❌ Missing section: "${title}"`);
|
|
729
|
+
}
|
|
722
730
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
731
|
+
const paragraphs = match[1]
|
|
732
|
+
.trim()
|
|
733
|
+
.split(/\n{2,}/)
|
|
734
|
+
.map((p) => p.trim())
|
|
735
|
+
.filter((p) => p.length > 0);
|
|
727
736
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
737
|
+
console.log(
|
|
738
|
+
`✅ [EXTRACTED] "${title}" - Parsed Content:`,
|
|
739
|
+
paragraphs
|
|
740
|
+
);
|
|
741
|
+
return { type: 'section', title, content: paragraphs };
|
|
742
|
+
});
|
|
743
|
+
}
|
|
733
744
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
});
|
|
737
|
-
}
|
|
745
|
+
const structuredContentEN = extractSections(extractedEN, sectionsEN);
|
|
746
|
+
const structuredContentPT = extractSections(extractedPT, sectionsPT);
|
|
738
747
|
|
|
739
|
-
|
|
740
|
-
|
|
748
|
+
console.log(
|
|
749
|
+
'🎯 [FINAL RESULT] Parsed English Content:',
|
|
750
|
+
JSON.stringify(structuredContentEN, null, 2)
|
|
751
|
+
);
|
|
752
|
+
console.log(
|
|
753
|
+
'🎯 [FINAL RESULT] Parsed Portuguese Content:',
|
|
754
|
+
JSON.stringify(structuredContentPT, null, 2)
|
|
755
|
+
);
|
|
741
756
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
);
|
|
746
|
-
console.log(
|
|
747
|
-
'🎯 [FINAL RESULT] Parsed Portuguese Content:',
|
|
748
|
-
JSON.stringify(structuredContentPT, null, 2)
|
|
749
|
-
);
|
|
757
|
+
console.log(
|
|
758
|
+
'✅ [COMPLETE] Structured content parsing finished successfully.'
|
|
759
|
+
);
|
|
750
760
|
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
761
|
+
return {
|
|
762
|
+
structuredContentEN,
|
|
763
|
+
structuredContentPT,
|
|
764
|
+
};
|
|
765
|
+
} catch (error) {
|
|
766
|
+
console.error(`❌ Parsing failed for ${conceptSlug}. Logging failure.`);
|
|
767
|
+
|
|
768
|
+
// ✅ Store failure in KV for debugging
|
|
769
|
+
const kvFailuresStore = this.context.kvConceptFailuresStore();
|
|
770
|
+
const failureKey = `failures:content:parsing:${conceptSlug}:${new Date().toISOString()}`;
|
|
771
|
+
|
|
772
|
+
await kvFailuresStore.put(
|
|
773
|
+
failureKey,
|
|
774
|
+
JSON.stringify({
|
|
775
|
+
error: (error as Error).message,
|
|
776
|
+
conceptSlug,
|
|
777
|
+
cleanedResponse,
|
|
778
|
+
timestamp: new Date().toISOString(),
|
|
779
|
+
})
|
|
780
|
+
);
|
|
754
781
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
};
|
|
782
|
+
console.error(`🚨 Failure logged in KV: ${failureKey}`);
|
|
783
|
+
throw error;
|
|
784
|
+
}
|
|
759
785
|
}
|
|
760
786
|
|
|
761
787
|
// private parseStructuredContent(
|
package/package.json
CHANGED
package/utils/conceptPrompts.ts
CHANGED
|
@@ -440,11 +440,11 @@ Response Format:
|
|
|
440
440
|
|
|
441
441
|
EN:
|
|
442
442
|
|
|
443
|
-
1. Magnetic Pull: Explore what the bearer unconsciously attracts in love, the qualities they draw into their life, and the recurring patterns that shape their relationships.
|
|
444
|
-
2. Hidden Desires: Reveal the unspoken parts of the bearer’s romantic self, the emotions, needs, and passions that influence their approach to love, whether acknowledged or not.
|
|
445
|
-
3. The Fated Dance: Describe how destiny and unseen forces shape the bearer’s relationships, including karmic encounters, serendipitous connections, and lessons bound by fate.
|
|
446
|
-
4. Unveiling the Shadows: Reflect on the hidden lessons of past loves, the patterns that must be understood, and how past relationships contribute to emotional wisdom and healing.
|
|
447
|
-
5. Your Love Power: Explore the bearer’s unique way of loving, their capacity for connection, and how they can embrace and express love in its truest, most fulfilling form.
|
|
443
|
+
1. Magnetic Pull: Explore what the bearer unconsciously attracts in love, the qualities they draw into their life, and the recurring patterns that shape their relationships.
|
|
444
|
+
2. Hidden Desires: Reveal the unspoken parts of the bearer’s romantic self, the emotions, needs, and passions that influence their approach to love, whether acknowledged or not.
|
|
445
|
+
3. The Fated Dance: Describe how destiny and unseen forces shape the bearer’s relationships, including karmic encounters, serendipitous connections, and lessons bound by fate.
|
|
446
|
+
4. Unveiling the Shadows: Reflect on the hidden lessons of past loves, the patterns that must be understood, and how past relationships contribute to emotional wisdom and healing.
|
|
447
|
+
5. Your Love Power: Explore the bearer’s unique way of loving, their capacity for connection, and how they can embrace and express love in its truest, most fulfilling form.
|
|
448
448
|
|
|
449
449
|
PT:
|
|
450
450
|
|
|
@@ -543,11 +543,11 @@ Response Format:
|
|
|
543
543
|
|
|
544
544
|
EN:
|
|
545
545
|
|
|
546
|
-
1. The Path Unfolding: Describe the bearer’s journey toward purpose, the unseen forces that guide them, and how their destiny gradually reveals itself.
|
|
547
|
-
2. A Calling Beyond the Self: Explore the deeper purpose that pulls the bearer forward. How do they sense their role in the world, and what mission feels written in their soul?
|
|
548
|
-
3. Turning Points of Fate: Reflect on the pivotal moments that shape the bearer’s direction—serendipities, choices, and events that act as cosmic signposts along their path.
|
|
549
|
-
4. Mastering the Journey: Discuss how the bearer learns to align with their destiny, embracing both challenges and gifts, and refining their path with clarity and intention.
|
|
550
|
-
5. Legacy and Impact: Examine how the bearer’s purpose extends beyond them. How do they leave their mark on the world, inspire others, or contribute to something greater than themselves?
|
|
546
|
+
1. The Path Unfolding: Describe the bearer’s journey toward purpose, the unseen forces that guide them, and how their destiny gradually reveals itself.
|
|
547
|
+
2. A Calling Beyond the Self: Explore the deeper purpose that pulls the bearer forward. How do they sense their role in the world, and what mission feels written in their soul?
|
|
548
|
+
3. Turning Points of Fate: Reflect on the pivotal moments that shape the bearer’s direction—serendipities, choices, and events that act as cosmic signposts along their path.
|
|
549
|
+
4. Mastering the Journey: Discuss how the bearer learns to align with their destiny, embracing both challenges and gifts, and refining their path with clarity and intention.
|
|
550
|
+
5. Legacy and Impact: Examine how the bearer’s purpose extends beyond them. How do they leave their mark on the world, inspire others, or contribute to something greater than themselves?
|
|
551
551
|
|
|
552
552
|
PT:
|
|
553
553
|
|