@zodic/shared 0.0.145 β†’ 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,93 +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
- if (!override && conceptEN.content?.length > 0 && conceptPT.content?.length > 0) {
272
+
273
+ if (
274
+ !override &&
275
+ conceptEN.content?.length > 0 &&
276
+ conceptPT.content?.length > 0
277
+ ) {
239
278
  console.log(`⚑ Content already exists for ${conceptSlug}, skipping.`);
240
279
  return; // βœ… Skip regeneration
241
280
  }
242
-
281
+
243
282
  let attempts = 0;
244
283
  const maxAttempts = 3;
245
-
284
+
246
285
  while (attempts < maxAttempts) {
247
- let phase = "generation"; // πŸ“Œ Track phase
286
+ let phase = 'generation'; // πŸ“Œ Track phase
248
287
  try {
249
288
  attempts++;
250
289
  console.log(`πŸ”„ Attempt ${attempts} to generate content...`);
251
-
290
+
252
291
  // βœ… Build messages for LLM
253
- const messages = this.context.buildLLMMessages().generateConceptContent({
254
- conceptSlug,
255
- combination: combinationString,
256
- name: conceptEN.name, // Use English name since both languages match in meaning
257
- description: conceptEN.description,
258
- poem: conceptEN.poem,
259
- });
260
-
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
+
261
302
  // βœ… Call ChatGPT API
262
- const response = await this.context.api().callChatGPT.single(messages, {});
303
+ const response = await this.context
304
+ .api()
305
+ .callChatGPT.single(messages, {});
263
306
  if (!response) {
264
307
  throw new Error(`❌ AI returned an empty response`);
265
308
  }
266
-
267
- phase = "parsing"; // βœ… Switch to parsing phase
268
-
309
+
310
+ phase = 'parsing'; // βœ… Switch to parsing phase
311
+
269
312
  // βœ… Parse structured content for both languages
270
313
  const { structuredContentEN, structuredContentPT } =
271
314
  this.parseStructuredContent(response);
272
-
315
+
273
316
  // 🌍 Store English content
274
317
  Object.assign(conceptEN, { content: structuredContentEN });
275
318
  await kvStore.put(kvKeyEN, JSON.stringify(conceptEN));
276
-
319
+
277
320
  // πŸ‡§πŸ‡· Store Portuguese content
278
321
  Object.assign(conceptPT, { content: structuredContentPT });
279
322
  await kvStore.put(kvKeyPT, JSON.stringify(conceptPT));
280
-
323
+
281
324
  console.log(
282
325
  `βœ… Structured content stored for ${conceptSlug}, combination: ${combinationString}, in both languages.`
283
326
  );
284
327
  return; // βœ… Exit loop if successful
285
-
286
328
  } catch (error) {
287
- console.error(`❌ Attempt ${attempts} failed at phase: ${phase}`, (error as Error).message);
288
-
329
+ console.error(
330
+ `❌ Attempt ${attempts} failed at phase: ${phase}`,
331
+ (error as Error).message
332
+ );
333
+
289
334
  // βœ… Store failure details in KV for manual review
290
- await kvFailuresStore.put(failureKey, JSON.stringify({
291
- error: (error as Error).message,
292
- attempt: attempts,
293
- phase, // βœ… Identify failure phase
294
- conceptSlug,
295
- combinationString,
296
- timestamp: new Date().toISOString(),
297
- }));
298
-
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
+
299
347
  if (attempts >= maxAttempts) {
300
- console.error(`🚨 All ${maxAttempts} attempts failed at phase ${phase}. Logged failure.`);
301
- 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
+ );
302
354
  }
303
-
304
- console.log("πŸ” Retrying...");
355
+
356
+ console.log('πŸ” Retrying...');
305
357
  await new Promise((resolve) => setTimeout(resolve, 2000)); // ⏳ Small delay before retrying
306
358
  }
307
359
  }
@@ -311,51 +363,57 @@ export class ConceptService {
311
363
  structuredContentEN: StructuredConceptContent;
312
364
  structuredContentPT: StructuredConceptContent;
313
365
  } {
314
- console.log('πŸ“Œ Parsing structured content from ChatGPT response:', response);
315
-
366
+ console.log(
367
+ 'πŸ“Œ Parsing structured content from ChatGPT response:',
368
+ response
369
+ );
370
+
316
371
  const sections = [
317
- "Core Identity",
318
- "Strengths and Challenges",
319
- "Path to Fulfillment",
320
- "Emotional Depth",
321
- "Vision and Aspirations"
372
+ 'Core Identity',
373
+ 'Strengths and Challenges',
374
+ 'Path to Fulfillment',
375
+ 'Emotional Depth',
376
+ 'Vision and Aspirations',
322
377
  ];
323
-
378
+
324
379
  const sectionsPT = [
325
- "Identidade Essencial",
326
- "ForΓ§as e Desafios",
327
- "Caminho para a Plenitude",
328
- "Profundidade Emocional",
329
- "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',
330
385
  ];
331
-
386
+
332
387
  // βœ… Match English and Portuguese content separately
333
388
  const enMatches = response.match(/EN:\s*([\s\S]+?)\s*PT:/);
334
389
  const ptMatches = response.match(/PT:\s*([\s\S]+)/);
335
-
390
+
336
391
  if (!enMatches || !ptMatches) {
337
- throw new Error("❌ Missing English or Portuguese content in response.");
392
+ throw new Error('❌ Missing English or Portuguese content in response.');
338
393
  }
339
-
394
+
340
395
  const enContent = enMatches[1].trim();
341
396
  const ptContent = ptMatches[1].trim();
342
-
397
+
343
398
  function extractSections(text: string, sectionTitles: string[]) {
344
399
  return sectionTitles.map((title) => {
345
400
  const regex = new RegExp(`${title}:\\s*([\\s\\S]+?)(?=\\n\\d|$)`);
346
401
  const match = text.match(regex);
347
-
402
+
348
403
  if (!match) {
349
- return { type: "section", title, content: ["❌ Section Missing"] };
404
+ return { type: 'section', title, content: ['❌ Section Missing'] };
350
405
  }
351
-
406
+
352
407
  // βœ… Split content into paragraphs
353
- const paragraphs = match[1].trim().split(/\n\n+/).map((p) => p.trim());
354
-
355
- 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 };
356
414
  });
357
415
  }
358
-
416
+
359
417
  return {
360
418
  structuredContentEN: extractSections(enContent, sections),
361
419
  structuredContentPT: extractSections(ptContent, sectionsPT),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.145",
3
+ "version": "0.0.146",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {