@zodic/shared 0.0.139 β†’ 0.0.141

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.
@@ -25,40 +25,19 @@ export class AppContext {
25
25
  kvConceptsStore() {
26
26
  if (!this.env.KV_CONCEPTS) {
27
27
  throw new Error(
28
- 'KV_COSMIC_MIRROR_ARCHETYPES is not defined in the environment.'
28
+ 'KV_CONCEPTS is not defined in the environment.'
29
29
  );
30
30
  }
31
31
  return this.env.KV_CONCEPTS;
32
32
  }
33
33
 
34
- kvGenerationStore() {
35
- if (!this.env.KV_GENERATION_MANAGEMENT) {
34
+ kvConceptFailuresStore() {
35
+ if (!this.env.KV_CONCEPT_FAILURES) {
36
36
  throw new Error(
37
- 'KV_GENERATION_MANAGEMENT is not defined in the environment.'
37
+ 'KV_CONCEPT_FAILURES is not defined in the environment.'
38
38
  );
39
39
  }
40
- return this.env.KV_GENERATION_MANAGEMENT;
41
- }
42
-
43
- kvUserGenerationStore() {
44
- if (!this.env.KV_USER_GENERATIONS) {
45
- throw new Error('KV_USER_GENERATIONS is not defined in the environment.');
46
- }
47
- return this.env.KV_GENERATION_MANAGEMENT;
48
- }
49
-
50
- kvPromptsStore() {
51
- if (!this.env.KV_LEONARDO_PROMPTS) {
52
- throw new Error('KV_LEONARDO_PROMPTS is not defined in the environment.');
53
- }
54
- return this.env.KV_LEONARDO_PROMPTS;
55
- }
56
-
57
- kvUserProductStatus() {
58
- if (!this.env.KV_USER_PRODUCT_STATUS) {
59
- throw new Error('KV_LEONARDO_PROMPTS is not defined in the environment.');
60
- }
61
- return this.env.KV_USER_PRODUCT_STATUS;
40
+ return this.env.KV_CONCEPT_FAILURES;
62
41
  }
63
42
 
64
43
  kvConceptsManagementStore() {
@@ -16,40 +16,109 @@ export class ConceptService {
16
16
  /**
17
17
  * Generate basic info for a concept: name, description, and poem.
18
18
  */
19
- async generateBasicInfo(conceptSlug: Concept, combinationString: string): Promise<void> {
20
- console.log(`πŸš€ Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}`);
19
+ async generateBasicInfo(
20
+ conceptSlug: Concept,
21
+ combinationString: string,
22
+ override: boolean = false // βœ… New optional override param
23
+ ): Promise<void> {
24
+ console.log(
25
+ `πŸš€ Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`
26
+ );
21
27
 
22
- // βœ… Build the messages to request content
23
- const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
24
- combination: combinationString,
25
- conceptSlug,
26
- });
28
+ const kvStore = this.context.kvConceptsStore();
29
+ const kvFailuresStore = this.context.kvConceptFailuresStore(); // πŸ”΄ Replace with actual KV store
30
+ const kvKeyEN = buildConceptKVKey("en-us", conceptSlug, combinationString);
31
+ const kvKeyPT = buildConceptKVKey("pt-br", conceptSlug, combinationString);
32
+ const failureKey = `failures:${conceptSlug}:${combinationString}`;
27
33
 
28
- // βœ… Call ChatGPT API
29
- const response = await this.context.api().callChatGPT.single(messages, {});
30
- if (!response) {
31
- throw new Error(`❌ Failed to generate basic info for concept: ${conceptSlug}`);
34
+ // βœ… Check if data already exists
35
+ if (!override) {
36
+ const existingEN = await this.getKVConcept(kvKeyEN);
37
+ const existingPT = await this.getKVConcept(kvKeyPT);
38
+
39
+ if (
40
+ existingEN.name && existingEN.description && existingEN.poem &&
41
+ existingPT.name && existingPT.description && existingPT.poem
42
+ ) {
43
+ console.log(`⚑ Basic info already exists for ${conceptSlug}, combination: ${combinationString}. Skipping.`);
44
+ return; // βœ… Skip regeneration
45
+ }
32
46
  }
33
47
 
34
- // βœ… Parse response for both languages
35
- const { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } = this.parseBasicInfoResponse(response);
48
+ let attempts = 0;
49
+ const maxAttempts = 3;
36
50
 
37
- // βœ… Store in KV for both languages
38
- const kvStore = this.context.kvConceptsStore();
39
-
40
- // 🌍 English version
41
- const kvKeyEN = buildConceptKVKey("en-us", conceptSlug, combinationString);
42
- const conceptEN = await this.getKVConcept(kvKeyEN);
43
- Object.assign(conceptEN, { name: nameEN, description: descriptionEN, poem: poemEN, status: "idle" });
44
- await kvStore.put(kvKeyEN, JSON.stringify(conceptEN));
51
+ while (attempts < maxAttempts) {
52
+ let phase = "generation"; // πŸ“Œ Track the phase
53
+ try {
54
+ attempts++;
55
+ console.log(`πŸ”„ Attempt ${attempts} to generate basic info...`);
45
56
 
46
- // πŸ‡§πŸ‡· Portuguese version
47
- const kvKeyPT = buildConceptKVKey("pt-br", conceptSlug, combinationString);
48
- const conceptPT = await this.getKVConcept(kvKeyPT);
49
- Object.assign(conceptPT, { name: namePT, description: descriptionPT, poem: poemPT, status: "idle" });
50
- await kvStore.put(kvKeyPT, JSON.stringify(conceptPT));
57
+ // βœ… Build the messages to request content
58
+ const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
59
+ combination: combinationString,
60
+ conceptSlug,
61
+ });
62
+
63
+ // βœ… Call ChatGPT API
64
+ const response = await this.context.api().callChatGPT.single(messages, {});
65
+ if (!response) {
66
+ throw new Error(`❌ AI returned an empty response`);
67
+ }
68
+
69
+ phase = "parsing"; // βœ… Switch to parsing phase
70
+
71
+ // βœ… Parse response for both languages
72
+ const { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } =
73
+ this.parseBasicInfoResponse(response);
74
+
75
+ // 🌍 English version
76
+ const conceptEN = await this.getKVConcept(kvKeyEN);
77
+ Object.assign(conceptEN, {
78
+ name: nameEN,
79
+ description: descriptionEN,
80
+ poem: poemEN,
81
+ status: "idle",
82
+ });
83
+ await kvStore.put(kvKeyEN, JSON.stringify(conceptEN));
84
+
85
+ // πŸ‡§πŸ‡· Portuguese version
86
+ const conceptPT = await this.getKVConcept(kvKeyPT);
87
+ Object.assign(conceptPT, {
88
+ name: namePT,
89
+ description: descriptionPT,
90
+ poem: poemPT,
91
+ status: "idle",
92
+ });
93
+ await kvStore.put(kvKeyPT, JSON.stringify(conceptPT));
51
94
 
52
- console.log(`βœ… Basic info stored for ${conceptSlug}, combination: ${combinationString}, in both languages.`);
95
+ console.log(
96
+ `βœ… Basic info stored for ${conceptSlug}, combination: ${combinationString}, in both languages.`
97
+ );
98
+ return; // βœ… Exit loop if successful
99
+
100
+ } catch (error) {
101
+ console.error(`❌ Attempt ${attempts} failed at phase: ${phase}`, (error as Error).message);
102
+
103
+ // βœ… Store failure details in KV for manual review
104
+ await kvFailuresStore.put(failureKey, JSON.stringify({
105
+ error: (error as Error).message,
106
+ attempt: attempts,
107
+ phase, // βœ… Identify if failure occurred in "generation" or "parsing"
108
+ conceptSlug,
109
+ combinationString,
110
+ timestamp: new Date().toISOString(),
111
+ }));
112
+
113
+ if (attempts >= maxAttempts) {
114
+ console.error(`🚨 All ${maxAttempts} attempts failed during ${phase}. Logged failure.`);
115
+ throw new Error(`Failed to generate basic info after ${maxAttempts} attempts`);
116
+ }
117
+
118
+ console.log("πŸ” Retrying...");
119
+ await new Promise((resolve) => setTimeout(resolve, 2000)); // ⏳ Small delay before retrying
120
+ }
121
+ }
53
122
  }
54
123
 
55
124
  private parseBasicInfoResponse(response: string): {
@@ -60,30 +129,29 @@ export class ConceptService {
60
129
  descriptionPT: string;
61
130
  poemPT: string;
62
131
  } {
63
- console.log("πŸ“Œ Parsing basic info response from ChatGPT:", response);
64
-
65
- const nameENMatch = response.match(/EN:\s*β€’\s*Name:\s*(.+)/);
66
- const descriptionENMatch = response.match(/EN:\s*β€’\s*Description:\s*([\s\S]+?)\s*β€’\s*Poetic Passage:/);
67
- const poemENMatch = response.match(/EN:\s*β€’\s*Poetic Passage:\s*([\s\S]+?)\s*PT:/);
68
-
69
- const namePTMatch = response.match(/PT:\s*β€’\s*Nome:\s*(.+)/);
70
- const descriptionPTMatch = response.match(/PT:\s*β€’\s*DescriΓ§Γ£o:\s*([\s\S]+?)\s*β€’\s*Passagem PoΓ©tica:/);
71
- const poemPTMatch = response.match(/PT:\s*β€’\s*Passagem PoΓ©tica:\s*([\s\S]+)/);
72
-
73
- if (!nameENMatch || !descriptionENMatch || !poemENMatch || !namePTMatch || !descriptionPTMatch || !poemPTMatch) {
74
- console.error("❌ Invalid basic info response format:", response);
75
- throw new Error("Invalid basic info response format");
132
+ console.log('πŸ“Œ Parsing basic info response from ChatGPT:', response);
133
+
134
+ const enMatch = response.match(
135
+ /EN:\s*β€’\s*Name:\s*(.+?)\s*β€’\s*Description:\s*([\s\S]+?)\s*β€’\s*Poetic Passage:\s*([\s\S]+?)\s*(?=PT:|$)/
136
+ );
137
+ const ptMatch = response.match(
138
+ /PT:\s*β€’\s*Nome:\s*(.+?)\s*β€’\s*DescriΓ§Γ£o:\s*([\s\S]+?)\s*β€’\s*Passagem PoΓ©tica:\s*([\s\S]+)/
139
+ );
140
+
141
+ if (!enMatch || !ptMatch) {
142
+ console.error('❌ Invalid basic info response format:', response);
143
+ throw new Error('Invalid basic info response format');
76
144
  }
77
-
78
- const nameEN = nameENMatch[1].trim();
79
- const descriptionEN = descriptionENMatch[1].trim();
80
- const poemEN = poemENMatch[1].trim();
81
-
82
- const namePT = namePTMatch[1].trim();
83
- const descriptionPT = descriptionPTMatch[1].trim();
84
- const poemPT = poemPTMatch[1].trim();
85
-
86
- console.log("βœ… Parsed basic info:", {
145
+
146
+ const nameEN = enMatch[1].trim();
147
+ const descriptionEN = enMatch[2].trim();
148
+ const poemEN = enMatch[3].trim();
149
+
150
+ const namePT = ptMatch[1].trim();
151
+ const descriptionPT = ptMatch[2].trim();
152
+ const poemPT = ptMatch[3].trim();
153
+
154
+ console.log('βœ… Successfully parsed basic info:', {
87
155
  nameEN,
88
156
  descriptionEN,
89
157
  poemEN,
@@ -91,7 +159,7 @@ export class ConceptService {
91
159
  descriptionPT,
92
160
  poemPT,
93
161
  });
94
-
162
+
95
163
  return { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT };
96
164
  }
97
165
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.139",
3
+ "version": "0.0.141",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -17,15 +17,11 @@ export type CentralBindings = {
17
17
  DESCRIBER_API_KEY: string;
18
18
  DESCRIBER_APP_ID: string;
19
19
  AKOOL_API_KEY: string;
20
- KV_GENERATION_MANAGEMENT: KVNamespace;
21
- KV_USER_GENERATIONS: KVNamespace;
22
20
  KV_COSMIC_MIRROR_ARCHETYPES: KVNamespace;
23
21
  KV_CONCEPTS: KVNamespace;
24
22
  KV_CONCEPTS_MANAGEMENT: KVNamespace;
25
- KV_LEONARDO_PROMPTS: KVNamespace;
26
23
  KV_ASTRO: KVNamespace;
27
- KV_TEST: KVNamespace;
28
- KV_USER_PRODUCT_STATUS: KVNamespace;
24
+ KV_CONCEPT_FAILURES: KVNamespace;
29
25
  CONCEPT_GENERATION_QUEUE: Queue;
30
26
 
31
27
  PROMPT_IMAGE_DESCRIBER: string;
@@ -86,12 +82,11 @@ export type BackendBindings = Env &
86
82
  | 'DESCRIBER_API_KEY'
87
83
  | 'DESCRIBER_APP_ID'
88
84
  | 'AKOOL_API_KEY'
89
- | 'KV_GENERATION_MANAGEMENT'
90
- | 'KV_USER_GENERATIONS'
91
85
  | 'KV_COSMIC_MIRROR_ARCHETYPES'
92
86
  | 'KV_CONCEPTS'
93
- | 'KV_LEONARDO_PROMPTS'
94
87
  | 'KV_ASTRO'
88
+ | 'KV_CONCEPTS_MANAGEMENT'
89
+ | 'KV_CONCEPT_FAILURES'
95
90
  | 'PROMPT_IMAGE_DESCRIBER'
96
91
  | 'PROMPT_GENERATE_ARCHETYPE_CONTENT'
97
92
  | 'PROMPT_GENERATE_ARCHETYPE_LEONARDO_PROMPTS'
@@ -109,10 +104,8 @@ export type BackendBindings = Env &
109
104
  | 'ASTROLOGY_PDF_API_KEY'
110
105
  | 'ASTROLOGY_PDF_USER_ID'
111
106
  | 'AI'
112
- | 'KV_USER_PRODUCT_STATUS'
113
107
  | 'PIAPI_API_KEY'
114
108
  | 'CONCEPT_GENERATION_QUEUE'
115
- | 'KV_CONCEPTS_MANAGEMENT'
116
109
  | 'DEEPSEEK_API_KEY'
117
110
  | 'PROMPT_GENERATE_ARCHETYPE_BASIC_INFO'
118
111
  >;