@zodic/shared 0.0.167 → 0.0.169
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.
|
@@ -31,31 +31,13 @@ export class ConceptService {
|
|
|
31
31
|
|
|
32
32
|
const kvStore = this.context.kvConceptsStore();
|
|
33
33
|
const kvFailuresStore = this.context.kvConceptFailuresStore();
|
|
34
|
-
const kvNamesStore = this.context.kvConceptNamesStore(); // ✅ New Durable Object
|
|
35
34
|
const kvKeyEN = buildConceptKVKey('en-us', conceptSlug, combinationString);
|
|
36
35
|
const kvKeyPT = buildConceptKVKey('pt-br', conceptSlug, combinationString);
|
|
37
36
|
const failureKey = `failures:basic-info:${conceptSlug}:${combinationString}`;
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const existingPT = await this.getKVConcept(kvKeyPT);
|
|
43
|
-
if (
|
|
44
|
-
existingEN.name &&
|
|
45
|
-
existingEN.description &&
|
|
46
|
-
Array.isArray(existingEN.poem) &&
|
|
47
|
-
existingEN.poem.length > 0 &&
|
|
48
|
-
existingPT.name &&
|
|
49
|
-
existingPT.description &&
|
|
50
|
-
Array.isArray(existingPT.poem) &&
|
|
51
|
-
existingPT.poem.length > 0
|
|
52
|
-
) {
|
|
53
|
-
console.log(
|
|
54
|
-
`⚡ Basic info already exists for ${conceptSlug}, skipping.`
|
|
55
|
-
);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
38
|
+
const doUrl = `${this.context.env.API_BASE_URL}/concept-names/${conceptSlug}`;
|
|
39
|
+
|
|
40
|
+
console.log('!-- doUrl: ', doUrl);
|
|
59
41
|
|
|
60
42
|
let attempts = 0;
|
|
61
43
|
const maxAttempts = 3;
|
|
@@ -66,12 +48,10 @@ export class ConceptService {
|
|
|
66
48
|
attempts++;
|
|
67
49
|
console.log(`🔄 Attempt ${attempts} to generate basic info...`);
|
|
68
50
|
|
|
69
|
-
// ✅ Fetch the latest name list
|
|
70
|
-
const response = await fetch(
|
|
71
|
-
`${this.context.env.API_BASE_URL}/concept-names/${conceptSlug}`
|
|
72
|
-
);
|
|
51
|
+
// ✅ Fetch the latest name list from Durable Object
|
|
73
52
|
let allNamesEN: string[] = [];
|
|
74
53
|
let allNamesPT: string[] = [];
|
|
54
|
+
const response = await fetch(doUrl);
|
|
75
55
|
if (response.ok) {
|
|
76
56
|
const data = (await response.json()) as {
|
|
77
57
|
'en-us': string[];
|
|
@@ -81,10 +61,37 @@ export class ConceptService {
|
|
|
81
61
|
allNamesPT = data['pt-br'] || [];
|
|
82
62
|
}
|
|
83
63
|
|
|
84
|
-
|
|
85
|
-
const
|
|
64
|
+
// ✅ Fetch existing KV data to backfill Durable Object if necessary
|
|
65
|
+
const existingEN = await this.getKVConcept(kvKeyEN);
|
|
66
|
+
const existingPT = await this.getKVConcept(kvKeyPT);
|
|
67
|
+
|
|
68
|
+
// 🔥 If names already exist in KV but not in DO, add them
|
|
69
|
+
if (existingEN.name && !allNamesEN.includes(existingEN.name)) {
|
|
70
|
+
console.log(`⚡ Backfilling existing name to DO: ${existingEN.name}`);
|
|
71
|
+
await fetch(`${doUrl}/add`, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
body: JSON.stringify({ language: 'en-us', name: existingEN.name }),
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (existingPT.name && !allNamesPT.includes(existingPT.name)) {
|
|
78
|
+
console.log(`⚡ Backfilling existing name to DO: ${existingPT.name}`);
|
|
79
|
+
await fetch(`${doUrl}/add`, {
|
|
80
|
+
method: 'POST',
|
|
81
|
+
body: JSON.stringify({ language: 'pt-br', name: existingPT.name }),
|
|
82
|
+
headers: { 'Content-Type': 'application/json' },
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ✅ Skip generation if basic info already exists and override is false
|
|
87
|
+
if (!override && existingEN.name && existingPT.name) {
|
|
88
|
+
console.log(
|
|
89
|
+
`⚡ Basic info already exists for ${conceptSlug}, skipping.`
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
const recentNamesEN = allNamesEN.slice(-144);
|
|
88
95
|
const messages = this.context
|
|
89
96
|
.buildLLMMessages()
|
|
90
97
|
.generateConceptBasicInfo({
|
|
@@ -96,80 +103,79 @@ export class ConceptService {
|
|
|
96
103
|
let aiResponse = await this.context
|
|
97
104
|
.api()
|
|
98
105
|
.callTogether.single(messages, {});
|
|
99
|
-
if (!aiResponse)
|
|
100
|
-
throw new Error(`❌ AI returned an empty response`);
|
|
101
|
-
}
|
|
106
|
+
if (!aiResponse) throw new Error(`❌ AI returned an empty response`);
|
|
102
107
|
|
|
103
108
|
phase = 'cleaning';
|
|
104
109
|
aiResponse = this.cleanAIResponse(aiResponse);
|
|
105
110
|
|
|
106
111
|
phase = 'parsing';
|
|
107
|
-
|
|
108
112
|
let { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } =
|
|
109
113
|
this.parseBasicInfoResponse(aiResponse, conceptSlug);
|
|
110
114
|
|
|
111
|
-
// ✅ Check
|
|
115
|
+
// ✅ Check uniqueness before storing
|
|
112
116
|
if (allNamesEN.includes(nameEN) || allNamesPT.includes(namePT)) {
|
|
113
117
|
console.warn(
|
|
114
118
|
`⚠️ Duplicate Name Detected: "${nameEN}" or "${namePT}"`
|
|
115
119
|
);
|
|
116
|
-
if (attempts >= maxAttempts)
|
|
117
|
-
throw new Error(
|
|
118
|
-
`🚨 Could not generate a unique name after ${maxAttempts} attempts.`
|
|
119
|
-
);
|
|
120
|
-
}
|
|
120
|
+
if (attempts >= maxAttempts)
|
|
121
|
+
throw new Error(`🚨 Could not generate a unique name`);
|
|
121
122
|
console.log('🔁 Retrying due to duplicate name...');
|
|
122
123
|
continue;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
// ✅ **Immediately update Durable Object with the new name**
|
|
126
|
-
await fetch(
|
|
127
|
-
|
|
128
|
-
{
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
headers: { 'Content-Type': 'application/json' },
|
|
132
|
-
}
|
|
133
|
-
);
|
|
127
|
+
await fetch(`${doUrl}/add`, {
|
|
128
|
+
method: 'POST',
|
|
129
|
+
body: JSON.stringify({ language: 'en-us', name: nameEN }),
|
|
130
|
+
headers: { 'Content-Type': 'application/json' },
|
|
131
|
+
});
|
|
134
132
|
|
|
135
|
-
await fetch(
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
headers: { 'Content-Type': 'application/json' },
|
|
141
|
-
}
|
|
142
|
-
);
|
|
133
|
+
await fetch(`${doUrl}/add`, {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
body: JSON.stringify({ language: 'pt-br', name: namePT }),
|
|
136
|
+
headers: { 'Content-Type': 'application/json' },
|
|
137
|
+
});
|
|
143
138
|
|
|
144
139
|
// ✅ Store the generated basic info in KV
|
|
145
|
-
|
|
146
|
-
Object.assign(conceptEN, {
|
|
140
|
+
Object.assign(existingEN, {
|
|
147
141
|
name: nameEN,
|
|
148
142
|
description: descriptionEN,
|
|
149
143
|
poem: poemEN,
|
|
150
144
|
status: 'idle',
|
|
151
145
|
});
|
|
152
|
-
await kvStore.put(kvKeyEN, JSON.stringify(
|
|
146
|
+
await kvStore.put(kvKeyEN, JSON.stringify(existingEN));
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
Object.assign(conceptPT, {
|
|
148
|
+
Object.assign(existingPT, {
|
|
156
149
|
name: namePT,
|
|
157
150
|
description: descriptionPT,
|
|
158
151
|
poem: poemPT,
|
|
159
152
|
status: 'idle',
|
|
160
153
|
});
|
|
161
|
-
await kvStore.put(kvKeyPT, JSON.stringify(
|
|
154
|
+
await kvStore.put(kvKeyPT, JSON.stringify(existingPT));
|
|
162
155
|
|
|
163
156
|
console.log(
|
|
164
157
|
`✅ Stored basic info for ${conceptSlug}, combination: ${combinationString}.`
|
|
165
158
|
);
|
|
166
|
-
|
|
167
|
-
return; // ✅ Exit loop if successful
|
|
159
|
+
return;
|
|
168
160
|
} catch (error) {
|
|
169
161
|
console.error(
|
|
170
162
|
`❌ Attempt ${attempts} failed at phase: ${phase}`,
|
|
171
163
|
(error as Error).message
|
|
172
164
|
);
|
|
165
|
+
|
|
166
|
+
// ✅ Store failure details in KV for debugging
|
|
167
|
+
await kvFailuresStore.put(
|
|
168
|
+
failureKey,
|
|
169
|
+
JSON.stringify({
|
|
170
|
+
error: (error as Error).message,
|
|
171
|
+
attempt: attempts,
|
|
172
|
+
phase,
|
|
173
|
+
conceptSlug,
|
|
174
|
+
combinationString,
|
|
175
|
+
timestamp: new Date().toISOString(),
|
|
176
|
+
})
|
|
177
|
+
);
|
|
178
|
+
|
|
173
179
|
if (attempts >= maxAttempts) {
|
|
174
180
|
console.error(`🚨 All ${maxAttempts} attempts failed.`);
|
|
175
181
|
throw new Error(
|
|
@@ -177,7 +183,7 @@ export class ConceptService {
|
|
|
177
183
|
);
|
|
178
184
|
}
|
|
179
185
|
console.log('🔁 Retrying...');
|
|
180
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
186
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
189
|
}
|
package/package.json
CHANGED