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