@zodic/shared 0.0.144 β†’ 0.0.146

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.
@@ -4,7 +4,11 @@ import 'reflect-metadata';
4
4
  import { v4 as uuidv4 } from 'uuid';
5
5
  import { schema } from '../..';
6
6
  import { Concept, ControlNetConfig, Languages } from '../../types';
7
- import { KVConcept, sizes, StructuredConceptContent } from '../../types/scopes/legacy';
7
+ import {
8
+ KVConcept,
9
+ sizes,
10
+ StructuredConceptContent,
11
+ } from '../../types/scopes/legacy';
8
12
  import { leonardoInitImages } from '../../utils/initImages';
9
13
  import { buildConceptKVKey } from '../../utils/KVKeysBuilders';
10
14
  import { AppContext } from '../base/AppContext';
@@ -24,98 +28,119 @@ export class ConceptService {
24
28
  console.log(
25
29
  `πŸš€ Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`
26
30
  );
27
-
31
+
28
32
  const kvStore = this.context.kvConceptsStore();
29
33
  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);
34
+ const kvKeyEN = buildConceptKVKey('en-us', conceptSlug, combinationString);
35
+ const kvKeyPT = buildConceptKVKey('pt-br', conceptSlug, combinationString);
32
36
  const failureKey = `failures:basic-info:${conceptSlug}:${combinationString}`;
33
-
37
+
34
38
  // βœ… Check if data already exists
35
39
  if (!override) {
36
40
  const existingEN = await this.getKVConcept(kvKeyEN);
37
41
  const existingPT = await this.getKVConcept(kvKeyPT);
38
-
42
+
39
43
  if (
40
- existingEN.name && existingEN.description && existingEN.poem &&
41
- existingPT.name && existingPT.description && existingPT.poem
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
42
52
  ) {
43
- console.log(`⚑ Basic info already exists for ${conceptSlug}, combination: ${combinationString}. Skipping.`);
53
+ console.log(
54
+ `⚑ Basic info already exists for ${conceptSlug}, combination: ${combinationString}. Skipping.`
55
+ );
44
56
  return; // βœ… Skip regeneration
45
57
  }
46
58
  }
47
-
59
+
48
60
  let attempts = 0;
49
61
  const maxAttempts = 3;
50
-
62
+
51
63
  while (attempts < maxAttempts) {
52
- let phase = "generation"; // πŸ“Œ Track the phase
64
+ let phase = 'generation'; // πŸ“Œ Track the phase
53
65
  try {
54
66
  attempts++;
55
67
  console.log(`πŸ”„ Attempt ${attempts} to generate basic info...`);
56
-
68
+
57
69
  // βœ… Build the messages to request content
58
- const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
59
- combination: combinationString,
60
- conceptSlug,
61
- });
62
-
70
+ const messages = this.context
71
+ .buildLLMMessages()
72
+ .generateConceptBasicInfo({
73
+ combination: combinationString,
74
+ conceptSlug,
75
+ });
76
+
63
77
  // βœ… Call ChatGPT API
64
- const response = await this.context.api().callChatGPT.single(messages, {});
78
+ const response = await this.context
79
+ .api()
80
+ .callChatGPT.single(messages, {});
65
81
  if (!response) {
66
82
  throw new Error(`❌ AI returned an empty response`);
67
83
  }
68
-
69
- phase = "parsing"; // βœ… Switch to parsing phase
70
-
84
+
85
+ phase = 'parsing'; // βœ… Switch to parsing phase
86
+
71
87
  // βœ… Parse response for both languages
72
88
  const { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT } =
73
89
  this.parseBasicInfoResponse(response);
74
-
90
+
75
91
  // 🌍 English version
76
92
  const conceptEN = await this.getKVConcept(kvKeyEN);
77
93
  Object.assign(conceptEN, {
78
94
  name: nameEN,
79
95
  description: descriptionEN,
80
96
  poem: poemEN,
81
- status: "idle",
97
+ status: 'idle',
82
98
  });
83
99
  await kvStore.put(kvKeyEN, JSON.stringify(conceptEN));
84
-
100
+
85
101
  // πŸ‡§πŸ‡· Portuguese version
86
102
  const conceptPT = await this.getKVConcept(kvKeyPT);
87
103
  Object.assign(conceptPT, {
88
104
  name: namePT,
89
105
  description: descriptionPT,
90
106
  poem: poemPT,
91
- status: "idle",
107
+ status: 'idle',
92
108
  });
93
109
  await kvStore.put(kvKeyPT, JSON.stringify(conceptPT));
94
-
110
+
95
111
  console.log(
96
112
  `βœ… Basic info stored for ${conceptSlug}, combination: ${combinationString}, in both languages.`
97
113
  );
98
114
  return; // βœ… Exit loop if successful
99
-
100
115
  } catch (error) {
101
- console.error(`❌ Attempt ${attempts} failed at phase: ${phase}`, (error as Error).message);
102
-
116
+ console.error(
117
+ `❌ Attempt ${attempts} failed at phase: ${phase}`,
118
+ (error as Error).message
119
+ );
120
+
103
121
  // βœ… 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
-
122
+ await kvFailuresStore.put(
123
+ failureKey,
124
+ JSON.stringify({
125
+ error: (error as Error).message,
126
+ attempt: attempts,
127
+ phase, // βœ… Identify if failure occurred in "generation" or "parsing"
128
+ conceptSlug,
129
+ combinationString,
130
+ timestamp: new Date().toISOString(),
131
+ })
132
+ );
133
+
113
134
  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`);
135
+ console.error(
136
+ `🚨 All ${maxAttempts} attempts failed during ${phase}. Logged failure.`
137
+ );
138
+ throw new Error(
139
+ `Failed to generate basic info after ${maxAttempts} attempts`
140
+ );
116
141
  }
117
-
118
- console.log("πŸ” Retrying...");
142
+
143
+ console.log('πŸ” Retrying...');
119
144
  await new Promise((resolve) => setTimeout(resolve, 2000)); // ⏳ Small delay before retrying
120
145
  }
121
146
  }
@@ -130,27 +155,33 @@ export class ConceptService {
130
155
  poemPT: string[];
131
156
  } {
132
157
  console.log('πŸ“Œ Parsing basic info response from ChatGPT:', response);
133
-
158
+
134
159
  const enMatch = response.match(
135
160
  /EN:\s*β€’\s*Name:\s*(.+?)\s*β€’\s*Description:\s*([\s\S]+?)\s*β€’\s*Poetic Passage:\s*([\s\S]+?)\s*(?=PT:|$)/
136
161
  );
137
162
  const ptMatch = response.match(
138
163
  /PT:\s*β€’\s*Nome:\s*(.+?)\s*β€’\s*DescriΓ§Γ£o:\s*([\s\S]+?)\s*β€’\s*Passagem PoΓ©tica:\s*([\s\S]+)/
139
164
  );
140
-
165
+
141
166
  if (!enMatch || !ptMatch) {
142
167
  console.error('❌ Invalid basic info response format:', response);
143
168
  throw new Error('Invalid basic info response format');
144
169
  }
145
-
170
+
146
171
  const nameEN = enMatch[1].trim();
147
172
  const descriptionEN = enMatch[2].trim();
148
- const poemEN = enMatch[3].trim().split(/\n+/).map(line => line.trim()); // βœ… Split into array
149
-
173
+ const poemEN = enMatch[3]
174
+ .trim()
175
+ .split(/\n+/)
176
+ .map((line) => line.trim()); // βœ… Split into array
177
+
150
178
  const namePT = ptMatch[1].trim();
151
179
  const descriptionPT = ptMatch[2].trim();
152
- const poemPT = ptMatch[3].trim().split(/\n+/).map(line => line.trim()); // βœ… Split into array
153
-
180
+ const poemPT = ptMatch[3]
181
+ .trim()
182
+ .split(/\n+/)
183
+ .map((line) => line.trim()); // βœ… Split into array
184
+
154
185
  console.log('βœ… Successfully parsed basic info:', {
155
186
  nameEN,
156
187
  descriptionEN,
@@ -159,7 +190,7 @@ export class ConceptService {
159
190
  descriptionPT,
160
191
  poemPT,
161
192
  });
162
-
193
+
163
194
  return { nameEN, descriptionEN, poemEN, namePT, descriptionPT, poemPT };
164
195
  }
165
196
 
@@ -215,94 +246,114 @@ export class ConceptService {
215
246
  console.log(
216
247
  `πŸš€ Generating content for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`
217
248
  );
218
-
249
+
219
250
  const kvStore = this.context.kvConceptsStore();
220
251
  const kvFailuresStore = this.context.kvConceptFailuresStore(); // πŸ”΄ Replace with actual KV store
221
- const kvKeyEN = buildConceptKVKey("en-us", conceptSlug, combinationString);
222
- const kvKeyPT = buildConceptKVKey("pt-br", conceptSlug, combinationString);
252
+ const kvKeyEN = buildConceptKVKey('en-us', conceptSlug, combinationString);
253
+ const kvKeyPT = buildConceptKVKey('pt-br', conceptSlug, combinationString);
223
254
  const failureKey = `failures:content:${conceptSlug}:${combinationString}`;
224
-
255
+
225
256
  // βœ… Ensure basic info is available before generating content
226
257
  const conceptEN = await this.getKVConcept(kvKeyEN);
227
258
  const conceptPT = await this.getKVConcept(kvKeyPT);
228
-
259
+
229
260
  if (
230
- !conceptEN.name || !conceptEN.description || !conceptEN.poem ||
231
- !conceptPT.name || !conceptPT.description || !conceptPT.poem
261
+ !conceptEN.name ||
262
+ !conceptEN.description ||
263
+ !conceptEN.poem ||
264
+ !conceptPT.name ||
265
+ !conceptPT.description ||
266
+ !conceptPT.poem
232
267
  ) {
233
268
  throw new Error(
234
269
  `❌ Basic info must be populated before generating content for ${conceptSlug}`
235
270
  );
236
271
  }
237
-
238
- // βœ… Check if content already exists
239
- if (!override && conceptEN.content && conceptPT.content) {
272
+
273
+ if (
274
+ !override &&
275
+ conceptEN.content?.length > 0 &&
276
+ conceptPT.content?.length > 0
277
+ ) {
240
278
  console.log(`⚑ Content already exists for ${conceptSlug}, skipping.`);
241
279
  return; // βœ… Skip regeneration
242
280
  }
243
-
281
+
244
282
  let attempts = 0;
245
283
  const maxAttempts = 3;
246
-
284
+
247
285
  while (attempts < maxAttempts) {
248
- let phase = "generation"; // πŸ“Œ Track phase
286
+ let phase = 'generation'; // πŸ“Œ Track phase
249
287
  try {
250
288
  attempts++;
251
289
  console.log(`πŸ”„ Attempt ${attempts} to generate content...`);
252
-
290
+
253
291
  // βœ… Build messages for LLM
254
- const messages = this.context.buildLLMMessages().generateConceptContent({
255
- conceptSlug,
256
- combination: combinationString,
257
- name: conceptEN.name, // Use English name since both languages match in meaning
258
- description: conceptEN.description,
259
- poem: conceptEN.poem,
260
- });
261
-
292
+ const messages = this.context
293
+ .buildLLMMessages()
294
+ .generateConceptContent({
295
+ conceptSlug,
296
+ combination: combinationString,
297
+ name: conceptEN.name, // Use English name since both languages match in meaning
298
+ description: conceptEN.description,
299
+ poem: conceptEN.poem,
300
+ });
301
+
262
302
  // βœ… Call ChatGPT API
263
- const response = await this.context.api().callChatGPT.single(messages, {});
303
+ const response = await this.context
304
+ .api()
305
+ .callChatGPT.single(messages, {});
264
306
  if (!response) {
265
307
  throw new Error(`❌ AI returned an empty response`);
266
308
  }
267
-
268
- phase = "parsing"; // βœ… Switch to parsing phase
269
-
309
+
310
+ phase = 'parsing'; // βœ… Switch to parsing phase
311
+
270
312
  // βœ… Parse structured content for both languages
271
313
  const { structuredContentEN, structuredContentPT } =
272
314
  this.parseStructuredContent(response);
273
-
315
+
274
316
  // 🌍 Store English content
275
317
  Object.assign(conceptEN, { content: structuredContentEN });
276
318
  await kvStore.put(kvKeyEN, JSON.stringify(conceptEN));
277
-
319
+
278
320
  // πŸ‡§πŸ‡· Store Portuguese content
279
321
  Object.assign(conceptPT, { content: structuredContentPT });
280
322
  await kvStore.put(kvKeyPT, JSON.stringify(conceptPT));
281
-
323
+
282
324
  console.log(
283
325
  `βœ… Structured content stored for ${conceptSlug}, combination: ${combinationString}, in both languages.`
284
326
  );
285
327
  return; // βœ… Exit loop if successful
286
-
287
328
  } catch (error) {
288
- console.error(`❌ Attempt ${attempts} failed at phase: ${phase}`, (error as Error).message);
289
-
329
+ console.error(
330
+ `❌ Attempt ${attempts} failed at phase: ${phase}`,
331
+ (error as Error).message
332
+ );
333
+
290
334
  // βœ… Store failure details in KV for manual review
291
- await kvFailuresStore.put(failureKey, JSON.stringify({
292
- error: (error as Error).message,
293
- attempt: attempts,
294
- phase, // βœ… Identify failure phase
295
- conceptSlug,
296
- combinationString,
297
- timestamp: new Date().toISOString(),
298
- }));
299
-
335
+ await kvFailuresStore.put(
336
+ failureKey,
337
+ JSON.stringify({
338
+ error: (error as Error).message,
339
+ attempt: attempts,
340
+ phase, // βœ… Identify failure phase
341
+ conceptSlug,
342
+ combinationString,
343
+ timestamp: new Date().toISOString(),
344
+ })
345
+ );
346
+
300
347
  if (attempts >= maxAttempts) {
301
- console.error(`🚨 All ${maxAttempts} attempts failed at phase ${phase}. Logged failure.`);
302
- throw new Error(`Failed to generate content after ${maxAttempts} attempts`);
348
+ console.error(
349
+ `🚨 All ${maxAttempts} attempts failed at phase ${phase}. Logged failure.`
350
+ );
351
+ throw new Error(
352
+ `Failed to generate content after ${maxAttempts} attempts`
353
+ );
303
354
  }
304
-
305
- console.log("πŸ” Retrying...");
355
+
356
+ console.log('πŸ” Retrying...');
306
357
  await new Promise((resolve) => setTimeout(resolve, 2000)); // ⏳ Small delay before retrying
307
358
  }
308
359
  }
@@ -312,51 +363,57 @@ export class ConceptService {
312
363
  structuredContentEN: StructuredConceptContent;
313
364
  structuredContentPT: StructuredConceptContent;
314
365
  } {
315
- console.log('πŸ“Œ Parsing structured content from ChatGPT response:', response);
316
-
366
+ console.log(
367
+ 'πŸ“Œ Parsing structured content from ChatGPT response:',
368
+ response
369
+ );
370
+
317
371
  const sections = [
318
- "Core Identity",
319
- "Strengths and Challenges",
320
- "Path to Fulfillment",
321
- "Emotional Depth",
322
- "Vision and Aspirations"
372
+ 'Core Identity',
373
+ 'Strengths and Challenges',
374
+ 'Path to Fulfillment',
375
+ 'Emotional Depth',
376
+ 'Vision and Aspirations',
323
377
  ];
324
-
378
+
325
379
  const sectionsPT = [
326
- "Identidade Essencial",
327
- "ForΓ§as e Desafios",
328
- "Caminho para a Plenitude",
329
- "Profundidade Emocional",
330
- "VisΓ£o e AspiraΓ§Γ΅es"
380
+ 'Identidade Essencial',
381
+ 'ForΓ§as e Desafios',
382
+ 'Caminho para a Plenitude',
383
+ 'Profundidade Emocional',
384
+ 'VisΓ£o e AspiraΓ§Γ΅es',
331
385
  ];
332
-
386
+
333
387
  // βœ… Match English and Portuguese content separately
334
388
  const enMatches = response.match(/EN:\s*([\s\S]+?)\s*PT:/);
335
389
  const ptMatches = response.match(/PT:\s*([\s\S]+)/);
336
-
390
+
337
391
  if (!enMatches || !ptMatches) {
338
- throw new Error("❌ Missing English or Portuguese content in response.");
392
+ throw new Error('❌ Missing English or Portuguese content in response.');
339
393
  }
340
-
394
+
341
395
  const enContent = enMatches[1].trim();
342
396
  const ptContent = ptMatches[1].trim();
343
-
397
+
344
398
  function extractSections(text: string, sectionTitles: string[]) {
345
399
  return sectionTitles.map((title) => {
346
400
  const regex = new RegExp(`${title}:\\s*([\\s\\S]+?)(?=\\n\\d|$)`);
347
401
  const match = text.match(regex);
348
-
402
+
349
403
  if (!match) {
350
- return { type: "section", title, content: ["❌ Section Missing"] };
404
+ return { type: 'section', title, content: ['❌ Section Missing'] };
351
405
  }
352
-
406
+
353
407
  // βœ… Split content into paragraphs
354
- const paragraphs = match[1].trim().split(/\n\n+/).map((p) => p.trim());
355
-
356
- return { type: "section", title, content: paragraphs };
408
+ const paragraphs = match[1]
409
+ .trim()
410
+ .split(/\n\n+/)
411
+ .map((p) => p.trim());
412
+
413
+ return { type: 'section', title, content: paragraphs };
357
414
  });
358
415
  }
359
-
416
+
360
417
  return {
361
418
  structuredContentEN: extractSections(enContent, sections),
362
419
  structuredContentPT: extractSections(ptContent, sectionsPT),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.144",
3
+ "version": "0.0.146",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {