@zodic/shared 0.0.140 → 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.
- package/app/base/AppContext.ts +5 -26
- package/app/services/ConceptService.ts +97 -48
- package/package.json +1 -1
- package/types/scopes/cloudflare.ts +3 -10
package/app/base/AppContext.ts
CHANGED
|
@@ -25,40 +25,19 @@ export class AppContext {
|
|
|
25
25
|
kvConceptsStore() {
|
|
26
26
|
if (!this.env.KV_CONCEPTS) {
|
|
27
27
|
throw new Error(
|
|
28
|
-
'
|
|
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
|
-
|
|
35
|
-
if (!this.env.
|
|
34
|
+
kvConceptFailuresStore() {
|
|
35
|
+
if (!this.env.KV_CONCEPT_FAILURES) {
|
|
36
36
|
throw new Error(
|
|
37
|
-
'
|
|
37
|
+
'KV_CONCEPT_FAILURES is not defined in the environment.'
|
|
38
38
|
);
|
|
39
39
|
}
|
|
40
|
-
return this.env.
|
|
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() {
|
|
@@ -18,58 +18,107 @@ export class ConceptService {
|
|
|
18
18
|
*/
|
|
19
19
|
async generateBasicInfo(
|
|
20
20
|
conceptSlug: Concept,
|
|
21
|
-
combinationString: string
|
|
21
|
+
combinationString: string,
|
|
22
|
+
override: boolean = false // ✅ New optional override param
|
|
22
23
|
): Promise<void> {
|
|
23
24
|
console.log(
|
|
24
|
-
`🚀 Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
25
|
+
`🚀 Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`
|
|
25
26
|
);
|
|
26
|
-
|
|
27
|
-
// ✅ Build the messages to request content
|
|
28
|
-
const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
|
|
29
|
-
combination: combinationString,
|
|
30
|
-
conceptSlug,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// ✅ Call ChatGPT API
|
|
34
|
-
const response = await this.context.api().callChatGPT.single(messages, {});
|
|
35
|
-
if (!response) {
|
|
36
|
-
throw new Error(
|
|
37
|
-
`❌ Failed to generate basic info for concept: ${conceptSlug}`
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ✅ Parse response for both languages
|
|
42
|
-
const { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } =
|
|
43
|
-
this.parseBasicInfoResponse(response);
|
|
44
|
-
|
|
45
|
-
// ✅ Store in KV for both languages
|
|
27
|
+
|
|
46
28
|
const kvStore = this.context.kvConceptsStore();
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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}`;
|
|
33
|
+
|
|
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
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let attempts = 0;
|
|
49
|
+
const maxAttempts = 3;
|
|
50
|
+
|
|
51
|
+
while (attempts < maxAttempts) {
|
|
52
|
+
let phase = "generation"; // 📌 Track the phase
|
|
53
|
+
try {
|
|
54
|
+
attempts++;
|
|
55
|
+
console.log(`🔄 Attempt ${attempts} to generate basic info...`);
|
|
56
|
+
|
|
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));
|
|
94
|
+
|
|
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
|
+
}
|
|
73
122
|
}
|
|
74
123
|
|
|
75
124
|
private parseBasicInfoResponse(response: string): {
|
package/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
>;
|