@zodic/shared 0.0.199 → 0.0.201
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 +44 -125
- package/data/index.ts +1 -0
- package/index.ts +1 -0
- package/package.json +1 -1
|
@@ -29,181 +29,100 @@ export class ConceptService {
|
|
|
29
29
|
combinationString: string,
|
|
30
30
|
override: boolean = false
|
|
31
31
|
): Promise<void> {
|
|
32
|
-
console.log(
|
|
33
|
-
|
|
34
|
-
);
|
|
35
|
-
|
|
32
|
+
console.log(`🚀 Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`);
|
|
33
|
+
|
|
36
34
|
const kvStore = this.context.kvConceptsStore();
|
|
37
35
|
const kvFailuresStore = this.context.kvConceptFailuresStore();
|
|
38
36
|
const kvKeyEN = buildConceptKVKey('en-us', conceptSlug, combinationString);
|
|
39
37
|
const kvKeyPT = buildConceptKVKey('pt-br', conceptSlug, combinationString);
|
|
40
|
-
|
|
38
|
+
|
|
41
39
|
// ✅ Use Durable Object stub
|
|
42
40
|
const id = this.context.env.CONCEPT_NAMES_DO.idFromName(conceptSlug);
|
|
43
41
|
const stub = this.context.env.CONCEPT_NAMES_DO.get(id);
|
|
44
|
-
|
|
42
|
+
|
|
45
43
|
console.log(`📡 Fetching existing KV data for ${conceptSlug}...`);
|
|
46
44
|
const existingEN = await this.getKVConcept(kvKeyEN);
|
|
47
45
|
const existingPT = await this.getKVConcept(kvKeyPT);
|
|
48
|
-
|
|
49
|
-
// ✅ IMMEDIATE SKIP if already exists and override is false
|
|
46
|
+
|
|
50
47
|
if (!override && existingEN.name && existingPT.name) {
|
|
51
48
|
console.log(`⚡ Basic info already exists for ${conceptSlug}, skipping.`);
|
|
52
49
|
return;
|
|
53
50
|
}
|
|
54
|
-
|
|
51
|
+
|
|
55
52
|
let attempts = 0;
|
|
56
53
|
const maxAttempts = 3;
|
|
57
|
-
|
|
54
|
+
|
|
58
55
|
while (attempts < maxAttempts) {
|
|
59
56
|
let phase = 'generation';
|
|
60
57
|
try {
|
|
61
58
|
attempts++;
|
|
62
|
-
console.log(
|
|
63
|
-
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
// ✅ Fetch the latest name list from Durable Object
|
|
67
|
-
console.log(
|
|
68
|
-
`📡 Fetching names from Durable Object for ${conceptSlug}...`
|
|
69
|
-
);
|
|
59
|
+
console.log(`🔄 Attempt ${attempts} to generate basic info for ${conceptSlug}...`);
|
|
60
|
+
|
|
70
61
|
let allNamesEN: string[] = [];
|
|
71
62
|
let allNamesPT: string[] = [];
|
|
72
63
|
const response = await stub.fetch(`https://internal/names`);
|
|
73
|
-
|
|
64
|
+
|
|
74
65
|
if (response.ok) {
|
|
75
|
-
const data = (await response.json()) as {
|
|
76
|
-
'en-us': string[];
|
|
77
|
-
'pt-br': string[];
|
|
78
|
-
};
|
|
66
|
+
const data = (await response.json()) as { 'en-us': string[]; 'pt-br': string[] };
|
|
79
67
|
allNamesEN = data['en-us'] || [];
|
|
80
68
|
allNamesPT = data['pt-br'] || [];
|
|
81
69
|
}
|
|
82
|
-
|
|
70
|
+
|
|
83
71
|
console.log(`✏️ Generating new name...`);
|
|
84
|
-
const messages = this.context
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
let aiResponse = await this.context
|
|
93
|
-
.api()
|
|
94
|
-
.callTogether.single(messages, {});
|
|
72
|
+
const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
|
|
73
|
+
combination: combinationString,
|
|
74
|
+
conceptSlug,
|
|
75
|
+
existingNames: allNamesEN.length > 100 ? allNamesEN.slice(-100) : allNamesEN,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
let aiResponse = await this.context.api().callTogether.single(messages, {});
|
|
95
79
|
if (!aiResponse) throw new Error(`❌ AI returned an empty response`);
|
|
96
|
-
|
|
80
|
+
|
|
97
81
|
phase = 'cleaning';
|
|
98
82
|
aiResponse = this.cleanAIResponse(aiResponse);
|
|
99
|
-
|
|
83
|
+
|
|
100
84
|
phase = 'parsing';
|
|
101
|
-
let { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } =
|
|
102
|
-
|
|
103
|
-
|
|
85
|
+
let { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } = this.parseBasicInfoResponse(aiResponse, conceptSlug);
|
|
86
|
+
|
|
104
87
|
console.log(`🎭 Generated names: EN - "${nameEN}", PT - "${namePT}"`);
|
|
105
|
-
|
|
106
|
-
// ✅
|
|
107
|
-
const MAX_NAME_LENGTH = 44;
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
console.warn(
|
|
113
|
-
`⚠️ Name too long: "${nameEN}" | "${namePT}". Retrying...`
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
// ✅ **Register name in Durable Object as blocked**
|
|
117
|
-
await stub.fetch(`https://internal/add-name`, {
|
|
118
|
-
method: 'POST',
|
|
119
|
-
body: JSON.stringify({ language: 'en-us', name: nameEN }),
|
|
120
|
-
headers: { 'Content-Type': 'application/json' },
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
await stub.fetch(`https://internal/add-name`, {
|
|
124
|
-
method: 'POST',
|
|
125
|
-
body: JSON.stringify({ language: 'pt-br', name: namePT }),
|
|
126
|
-
headers: { 'Content-Type': 'application/json' },
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
console.log(`✅ Added long name to DO blocklist, retrying...`);
|
|
88
|
+
|
|
89
|
+
// ✅ Name length check
|
|
90
|
+
const MAX_NAME_LENGTH = 44;
|
|
91
|
+
if (nameEN.length > MAX_NAME_LENGTH || namePT.length > MAX_NAME_LENGTH) {
|
|
92
|
+
console.warn(`⚠️ Name too long: "${nameEN}" | "${namePT}". Retrying...`);
|
|
93
|
+
allNamesEN.push(nameEN);
|
|
94
|
+
allNamesPT.push(namePT);
|
|
130
95
|
continue;
|
|
131
96
|
}
|
|
132
|
-
|
|
97
|
+
|
|
133
98
|
// ✅ Check uniqueness before storing
|
|
134
99
|
if (allNamesEN.includes(nameEN) || allNamesPT.includes(namePT)) {
|
|
135
|
-
console.warn(
|
|
136
|
-
`⚠️ Duplicate Name Detected: "${nameEN}" or "${namePT}"`
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
// ✅ **On third attempt, store the name anyway & register in kvFailures**
|
|
100
|
+
console.warn(`⚠️ Duplicate Name Detected: "${nameEN}" or "${namePT}"`);
|
|
140
101
|
if (attempts >= maxAttempts) {
|
|
141
|
-
console.log(
|
|
142
|
-
`🚨 Max attempts reached. Storing name despite duplicate.`
|
|
143
|
-
);
|
|
144
|
-
|
|
102
|
+
console.log(`🚨 Max attempts reached. Storing name despite duplicate.`);
|
|
145
103
|
await kvFailuresStore.put(
|
|
146
104
|
`failures:duplicates:${conceptSlug}:${combinationString}`,
|
|
147
|
-
JSON.stringify({
|
|
148
|
-
nameEN,
|
|
149
|
-
namePT,
|
|
150
|
-
attempts,
|
|
151
|
-
conceptSlug,
|
|
152
|
-
combinationString,
|
|
153
|
-
timestamp: new Date().toISOString(),
|
|
154
|
-
})
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
console.log(
|
|
158
|
-
`✅ Stored duplicate name after max retries: ${nameEN}, ${namePT}`
|
|
105
|
+
JSON.stringify({ nameEN, namePT, attempts, conceptSlug, combinationString, timestamp: new Date().toISOString() })
|
|
159
106
|
);
|
|
160
107
|
break;
|
|
161
108
|
}
|
|
162
|
-
|
|
163
|
-
console.log('🔁 Retrying due to duplicate name...');
|
|
164
109
|
continue;
|
|
165
110
|
}
|
|
166
|
-
|
|
111
|
+
|
|
167
112
|
console.log(`📝 Storing names in Durable Object...`);
|
|
168
|
-
|
|
169
|
-
await stub.fetch(`https://internal/add-name`, {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
headers: { 'Content-Type': 'application/json' },
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await stub.fetch(`https://internal/add-name`, {
|
|
176
|
-
method: 'POST',
|
|
177
|
-
body: JSON.stringify({ language: 'pt-br', name: namePT }),
|
|
178
|
-
headers: { 'Content-Type': 'application/json' },
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
// ✅ Store the generated basic info in KV
|
|
182
|
-
Object.assign(existingEN, {
|
|
183
|
-
name: nameEN,
|
|
184
|
-
description: descriptionEN,
|
|
185
|
-
poem: poemEN,
|
|
186
|
-
status: 'idle',
|
|
187
|
-
});
|
|
113
|
+
await stub.fetch(`https://internal/add-name`, { method: 'POST', body: JSON.stringify({ language: 'en-us', name: nameEN }), headers: { 'Content-Type': 'application/json' } });
|
|
114
|
+
await stub.fetch(`https://internal/add-name`, { method: 'POST', body: JSON.stringify({ language: 'pt-br', name: namePT }), headers: { 'Content-Type': 'application/json' } });
|
|
115
|
+
|
|
116
|
+
Object.assign(existingEN, { name: nameEN, description: descriptionEN, poem: poemEN, status: 'idle' });
|
|
188
117
|
await kvStore.put(kvKeyEN, JSON.stringify(existingEN));
|
|
189
|
-
|
|
190
|
-
Object.assign(existingPT, {
|
|
191
|
-
name: namePT,
|
|
192
|
-
description: descriptionPT,
|
|
193
|
-
poem: poemPT,
|
|
194
|
-
status: 'idle',
|
|
195
|
-
});
|
|
118
|
+
|
|
119
|
+
Object.assign(existingPT, { name: namePT, description: descriptionPT, poem: poemPT, status: 'idle' });
|
|
196
120
|
await kvStore.put(kvKeyPT, JSON.stringify(existingPT));
|
|
197
|
-
|
|
198
|
-
console.log(
|
|
199
|
-
`✅ Stored basic info for ${conceptSlug}, combination: ${combinationString}.`
|
|
200
|
-
);
|
|
121
|
+
|
|
122
|
+
console.log(`✅ Stored basic info for ${conceptSlug}, combination: ${combinationString}.`);
|
|
201
123
|
return;
|
|
202
124
|
} catch (error) {
|
|
203
|
-
console.error(
|
|
204
|
-
`❌ Attempt ${attempts} failed at phase: ${phase}`,
|
|
205
|
-
(error as Error).message
|
|
206
|
-
);
|
|
125
|
+
console.error(`❌ Attempt ${attempts} failed at phase: ${phase}`, error);
|
|
207
126
|
}
|
|
208
127
|
}
|
|
209
128
|
}
|
package/data/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './zodiacSignCombinations';
|
package/index.ts
CHANGED