@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.
@@ -445,7 +445,7 @@ export class ConceptService {
445
445
  }
446
446
 
447
447
  let attempts = 0;
448
- const maxAttempts = 3;
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
- private parseStructuredContent(
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
- // ✅ Step 2: Define Section Titles Per Concept
572
- const conceptSections: Record<string, { en: string[]; pt: string[] }> = {
573
- crown: {
574
- en: [
575
- 'Core Identity',
576
- 'Strengths and Challenges',
577
- 'Path to Fulfillment',
578
- 'Emotional Depth',
579
- 'Vision and Aspirations',
580
- ],
581
- pt: [
582
- 'Identidade Essencial',
583
- 'Forças e Desafios',
584
- 'Caminho para a Plenitude',
585
- 'Profundidade Emocional',
586
- 'Visão e Aspirações',
587
- ],
588
- },
589
- scepter: {
590
- en: [
591
- 'The Power of Expression',
592
- 'The Dance of Action and Reaction',
593
- 'Navigating Challenges',
594
- 'The Mirror of Relationships',
595
- 'Impact on the World',
596
- ],
597
- pt: [
598
- 'O Poder da Expressão',
599
- 'A Dança da Ação e Reação',
600
- 'Navegando Desafios',
601
- 'O Espelho das Relações',
602
- 'Impacto no Mundo',
603
- ],
604
- },
605
- amulet: {
606
- en: [
607
- 'The Shield of Protection',
608
- 'The Strength Within',
609
- 'Nurturing Growth',
610
- 'The Cycle of Renewal',
611
- 'The Anchor of Wisdom',
612
- ],
613
- pt: [
614
- 'O Escudo da Proteção',
615
- 'A Força Interior',
616
- 'Cultivando o Crescimento',
617
- 'O Ciclo da Renovação',
618
- 'A Âncora da Sabedoria',
619
- ],
620
- },
621
- ring: {
622
- en: [
623
- 'Magnetic Pull',
624
- 'Hidden Desires',
625
- 'The Fated Dance',
626
- 'Unveiling the Shadows',
627
- 'Your Love Power',
628
- ],
629
- pt: [
630
- 'Força Magnética',
631
- 'Desejos Ocultos',
632
- 'A Dança do Destino',
633
- 'Revelando as Sombras',
634
- 'Seu Poder no Amor',
635
- ],
636
- },
637
- lantern: {
638
- en: [
639
- 'The Call to Awakening',
640
- 'Walking Through Shadows',
641
- 'The Inner Flame',
642
- 'Revelations and Truths',
643
- 'Becoming the Light',
644
- ],
645
- pt: [
646
- 'O Chamado para o Despertar',
647
- 'Caminhando Pelas Sombras',
648
- 'A Chama Interior',
649
- 'Revelações e Verdades',
650
- 'Tornando-se a Luz',
651
- ],
652
- },
653
- orb: {
654
- en: [
655
- 'The Path Unfolding',
656
- 'A Calling Beyond the Self',
657
- 'Turning Points of Fate',
658
- 'Mastering the Journey',
659
- 'Legacy and Impact',
660
- ],
661
- pt: [
662
- 'O Caminho que se Revela',
663
- 'Um Chamado Além de Si Mesmo',
664
- 'Pontos de Virada do Destino',
665
- 'Dominando a Jornada',
666
- 'Legado e Impacto',
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
- const sectionsEN = conceptSections[conceptSlug]?.en;
672
- const sectionsPT = conceptSections[conceptSlug]?.pt;
672
+ const sectionsEN = conceptSections[conceptSlug]?.en;
673
+ const sectionsPT = conceptSections[conceptSlug]?.pt;
673
674
 
674
- if (!sectionsEN || !sectionsPT) {
675
- throw new Error(`❌ Unknown concept: ${conceptSlug}`);
676
- }
675
+ if (!sectionsEN || !sectionsPT) {
676
+ throw new Error(`Unknown concept: ${conceptSlug}`);
677
+ }
677
678
 
678
- // ✅ Step 3: Detect if AI interleaved EN/PT sections
679
- const interleavedMatches = cleanedResponse.match(
680
- /(EN:\s*[\s\S]+?PT:\s*[\s\S]+?)(?=EN:|$)/g
681
- );
682
- let extractedEN = '';
683
- let extractedPT = '';
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
- if (interleavedMatches) {
686
- console.warn(
687
- '⚠️ Detected interleaved EN/PT sections. Parsing accordingly.'
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
- '✅ Standard format detected (EN block followed by PT block).'
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
- console.log(
705
- '✅ [MATCH SUCCESS] Extracted English Content:',
706
- extractedEN.slice(0, 500) + '...'
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
- // Step 4: Extract structured sections dynamically
714
- function extractSections(text: string, sectionTitles: string[]) {
715
- return sectionTitles.map((title) => {
716
- console.log(`🔍 [PROCESSING] Extracting section: "${title}"`);
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
- const regex = new RegExp(
719
- `\\d+\\.\\s*${title}:\\s*([\\s\\S]+?)(?=\\n\\d+\\.\\s*[A-Z]|$)`
720
- );
721
- const match = text.match(regex);
727
+ if (!match) {
728
+ throw new Error(`❌ Missing section: "${title}"`);
729
+ }
722
730
 
723
- if (!match) {
724
- console.warn(`⚠️ [WARNING] Missing section: "${title}"`);
725
- return { type: 'section', title, content: ['❌ Section Missing'] };
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
- const paragraphs = match[1]
729
- .trim()
730
- .split(/\n{2,}/)
731
- .map((p) => p.trim())
732
- .filter((p) => p.length > 0);
737
+ console.log(
738
+ `✅ [EXTRACTED] "${title}" - Parsed Content:`,
739
+ paragraphs
740
+ );
741
+ return { type: 'section', title, content: paragraphs };
742
+ });
743
+ }
733
744
 
734
- console.log(`✅ [EXTRACTED] "${title}" - Parsed Content:`, paragraphs);
735
- return { type: 'section', title, content: paragraphs };
736
- });
737
- }
745
+ const structuredContentEN = extractSections(extractedEN, sectionsEN);
746
+ const structuredContentPT = extractSections(extractedPT, sectionsPT);
738
747
 
739
- const structuredContentEN = extractSections(extractedEN, sectionsEN);
740
- const structuredContentPT = extractSections(extractedPT, sectionsPT);
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
- console.log(
743
- '🎯 [FINAL RESULT] Parsed English Content:',
744
- JSON.stringify(structuredContentEN, null, 2)
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
- console.log(
752
- '✅ [COMPLETE] Structured content parsing finished successfully.'
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
- return {
756
- structuredContentEN,
757
- structuredContentPT,
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.235",
3
+ "version": "0.0.236",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -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. [Around 200 words]
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. [Around 200 words]
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. [Around 200 words]
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. [Around 200 words]
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. [Around 200 words]
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. [Around 200 words]
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? [Around 200 words]
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. [Around 200 words]
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. [Around 200 words]
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? [Around 200 words]
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