@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
- // Check if data already exists
40
- if (!override) {
41
- const existingEN = await this.getKVConcept(kvKeyEN);
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 **directly from Durable Object**
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
- const recentNamesEN = allNamesEN.slice(-144); // 🔥 Only pass the last 144 names
85
- const recentNamesPT = allNamesPT.slice(-144);
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
- // Generate content ensuring uniqueness
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 if generated names are unique **right after parsing**
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
- `${this.context.env.API_BASE_URL}/concept-names/${conceptSlug}/add`,
128
- {
129
- method: 'POST',
130
- body: JSON.stringify({ language: 'en-us', name: nameEN }),
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
- `${this.context.env.API_BASE_URL}/concept-names/${conceptSlug}/add`,
137
- {
138
- method: 'POST',
139
- body: JSON.stringify({ language: 'pt-br', name: namePT }),
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
- const conceptEN = await this.getKVConcept(kvKeyEN);
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(conceptEN));
146
+ await kvStore.put(kvKeyEN, JSON.stringify(existingEN));
153
147
 
154
- const conceptPT = await this.getKVConcept(kvKeyPT);
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(conceptPT));
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)); // ⏳ Small delay before retrying
186
+ await new Promise((resolve) => setTimeout(resolve, 500));
181
187
  }
182
188
  }
183
189
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.167",
3
+ "version": "0.0.169",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  Ai,
3
3
  D1Database,
4
- DurableObject,
5
4
  DurableObjectNamespace,
6
5
  KVNamespace,
7
6
  Queue,