@zodic/shared 0.0.371 → 0.0.373

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.
@@ -342,14 +342,14 @@ export class ConceptService {
342
342
  console.log(
343
343
  `[${new Date().toISOString()}] 🚀 Generating Leonardo prompt for concept: ${conceptSlug}, combination: ${combinationString}, override: ${override}`
344
344
  );
345
-
345
+
346
346
  const db = drizzle(this.context.env.DB); // ✅ Initialize Drizzle with Cloudflare D1
347
-
347
+
348
348
  // ✅ Fetch concept data from D1 for both languages
349
349
  console.log(
350
350
  `[${new Date().toISOString()}] 📡 Fetching concept data for ${conceptSlug}:${combinationString}`
351
351
  );
352
-
352
+
353
353
  const conceptEntries = await db
354
354
  .select({
355
355
  id: conceptsData.id,
@@ -368,28 +368,34 @@ export class ConceptService {
368
368
  )
369
369
  )
370
370
  .execute();
371
-
371
+
372
372
  if (conceptEntries.length !== 2) {
373
373
  throw new Error(
374
374
  `❌ Missing concept data for ${conceptSlug}:${combinationString}. Ensure basic info is populated first.`
375
375
  );
376
376
  }
377
-
377
+
378
378
  const conceptEN = conceptEntries.find((c) => c.language === 'en-us');
379
379
  const conceptPT = conceptEntries.find((c) => c.language === 'pt-br');
380
-
380
+
381
381
  if (!conceptEN || !conceptPT) {
382
382
  throw new Error(`❌ Could not find both EN and PT versions.`);
383
383
  }
384
-
384
+
385
+ const leonardoPromptExistsEN =
386
+ conceptEN.leonardoPrompt && conceptEN.leonardoPrompt.length > 4;
387
+
388
+ const leonardoPromptExistsPT =
389
+ conceptPT.leonardoPrompt && conceptPT.leonardoPrompt.length > 4;
390
+
385
391
  // ✅ Check if prompt already exists and skip if override is false
386
- if (!override && conceptEN.leonardoPrompt && conceptPT.leonardoPrompt) {
392
+ if (!override && leonardoPromptExistsEN && leonardoPromptExistsPT) {
387
393
  console.log(
388
394
  `[${new Date().toISOString()}] ⚡ Leonardo prompt already exists for ${conceptSlug}, skipping.`
389
395
  );
390
- return { generatedPrompt: conceptEN.leonardoPrompt };
396
+ return { generatedPrompt: conceptEN.leonardoPrompt! };
391
397
  }
392
-
398
+
393
399
  // ✅ Ensure basic info is present
394
400
  if (
395
401
  !conceptEN.name ||
@@ -403,7 +409,7 @@ export class ConceptService {
403
409
  `❌ Basic info must be populated before generating Leonardo prompt for concept: ${conceptSlug}`
404
410
  );
405
411
  }
406
-
412
+
407
413
  // ✅ Generate prompt request
408
414
  const messages = this.context
409
415
  .buildLLMMessages()
@@ -411,7 +417,7 @@ export class ConceptService {
411
417
  conceptSlug,
412
418
  combination: combinationString,
413
419
  });
414
-
420
+
415
421
  // ✅ Call ChatGPT API
416
422
  const response = await this.context.api().callTogether.single(messages, {});
417
423
  if (!response) {
@@ -419,25 +425,28 @@ export class ConceptService {
419
425
  `❌ Failed to generate Leonardo prompt for concept: ${conceptSlug}`
420
426
  );
421
427
  }
422
-
428
+
423
429
  // Clean the response to remove unwanted elements
424
430
  let generatedPrompt = response.trim();
425
-
431
+
426
432
  // Step 1: Remove **Prompt:** or Prompt: from the start
427
- generatedPrompt = generatedPrompt.replace(/^(?:\*\*Prompt:\*\*|Prompt:)\s*/, '');
428
-
433
+ generatedPrompt = generatedPrompt.replace(
434
+ /^(?:\*\*Prompt:\*\*|Prompt:)\s*/,
435
+ ''
436
+ );
437
+
429
438
  // Step 2: Remove character count suffix (e.g., *(Character count: 749)* or *(1498 characters)*)
430
439
  generatedPrompt = generatedPrompt.replace(/\s*\*\([^()]*\)*\s*$/, '');
431
-
440
+
432
441
  // Step 3: Remove surrounding quotes if they wrap the entire prompt
433
442
  if (generatedPrompt.startsWith('"') && generatedPrompt.endsWith('"')) {
434
443
  generatedPrompt = generatedPrompt.slice(1, -1).trim();
435
444
  }
436
-
445
+
437
446
  console.log(
438
447
  `[${new Date().toISOString()}] ✨ Cleaned generated prompt: "${generatedPrompt}"`
439
448
  );
440
-
449
+
441
450
  // ✅ Store the generated prompt in D1 for both languages
442
451
  console.log(
443
452
  `[${new Date().toISOString()}] 💾 Storing Leonardo prompt for ${conceptSlug}:${combinationString} in D1...`
@@ -462,11 +471,11 @@ export class ConceptService {
462
471
  )
463
472
  ),
464
473
  ]);
465
-
474
+
466
475
  console.log(
467
476
  `[${new Date().toISOString()}] ✅ Leonardo prompt stored for concept: ${conceptSlug}, combination: ${combinationString}, in both languages.`
468
477
  );
469
-
478
+
470
479
  return { generatedPrompt };
471
480
  }
472
481
 
@@ -1817,41 +1826,44 @@ export class ConceptService {
1817
1826
  .limit(1)
1818
1827
  .execute();
1819
1828
 
1820
- return !!conceptData?.leonardoPrompt && conceptData.leonardoPrompt.length > 10;
1829
+ return (
1830
+ !!conceptData?.leonardoPrompt && conceptData.leonardoPrompt.length > 10
1831
+ );
1821
1832
  }
1822
1833
 
1823
- // src/services/ConceptService.ts
1824
- async checkConceptCompletion(
1825
- conceptSlug: Concept,
1826
- combinationString: string,
1827
- lang: string = 'en-us'
1828
- ): Promise<boolean> {
1829
- const db = this.context.drizzle();
1830
- const [conceptData] = await db
1831
- .select({
1832
- leonardoPrompt: schema.conceptsData.leonardoPrompt,
1833
- postImages: schema.conceptsData.postImages,
1834
- reelImages: schema.conceptsData.reelImages,
1835
- })
1836
- .from(schema.conceptsData)
1837
- .where(
1838
- and(
1839
- eq(schema.conceptsData.conceptSlug, conceptSlug),
1840
- eq(schema.conceptsData.combination, combinationString),
1841
- eq(schema.conceptsData.language, lang)
1834
+ // src/services/ConceptService.ts
1835
+ async checkConceptCompletion(
1836
+ conceptSlug: Concept,
1837
+ combinationString: string,
1838
+ lang: string = 'en-us'
1839
+ ): Promise<boolean> {
1840
+ const db = this.context.drizzle();
1841
+ const [conceptData] = await db
1842
+ .select({
1843
+ leonardoPrompt: schema.conceptsData.leonardoPrompt,
1844
+ postImages: schema.conceptsData.postImages,
1845
+ reelImages: schema.conceptsData.reelImages,
1846
+ })
1847
+ .from(schema.conceptsData)
1848
+ .where(
1849
+ and(
1850
+ eq(schema.conceptsData.conceptSlug, conceptSlug),
1851
+ eq(schema.conceptsData.combination, combinationString),
1852
+ eq(schema.conceptsData.language, lang)
1853
+ )
1842
1854
  )
1843
- )
1844
- .limit(1)
1845
- .execute();
1846
-
1847
- if (!conceptData) return false; // No concept data found
1855
+ .limit(1)
1856
+ .execute();
1848
1857
 
1849
- // Check if postImages and reelImages are valid non-empty JSON arrays
1850
- const hasPostImages =
1851
- conceptData.postImages &&
1852
- conceptData.postImages.trim().length > 4 && // Ensures length > 4 to exclude "[]"
1853
- JSON.parse(conceptData.postImages).length > 2;
1858
+ if (!conceptData) return false; // No concept data found
1859
+ const hasPrompt =
1860
+ !!conceptData?.leonardoPrompt && conceptData.leonardoPrompt.length > 10;
1861
+ // Check if postImages and reelImages are valid non-empty JSON arrays
1862
+ const hasPostImages =
1863
+ conceptData.postImages &&
1864
+ conceptData.postImages.trim().length > 4 && // Ensures length > 4 to exclude "[]"
1865
+ JSON.parse(conceptData.postImages).length > 2;
1854
1866
 
1855
- return !!conceptData.leonardoPrompt && !!hasPostImages;
1856
- }
1867
+ return hasPrompt && !!hasPostImages;
1868
+ }
1857
1869
  }
@@ -1,4 +1,4 @@
1
- import { and, eq, inArray } from 'drizzle-orm';
1
+ import { and, eq } from 'drizzle-orm';
2
2
  import { inject, injectable } from 'inversify';
3
3
  import { schema } from '../..';
4
4
  import { Gender } from '../../types';
@@ -20,7 +20,7 @@ export class ArchetypeWorkflow {
20
20
  context: Record<string, any> = {}
21
21
  ) {
22
22
  const logId = `archetype-workflow:${Date.now()}`;
23
- const logMessage = `[${level.toUpperCase()}] ${message}`;
23
+ const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
24
24
 
25
25
  console[level](logMessage, context);
26
26
  const db = this.context.drizzle();
@@ -48,167 +48,228 @@ export class ArchetypeWorkflow {
48
48
  async execute(
49
49
  combinationString: string,
50
50
  gender: Gender,
51
- language: string = 'en-us'
51
+ language: string = 'en-us',
52
+ override: boolean = false
52
53
  ) {
53
54
  await this.log('info', 'Starting ArchetypeWorkflow', {
54
55
  combinationString,
55
56
  gender,
56
57
  language,
58
+ override,
57
59
  });
58
-
59
- // Step 1: Check if archetypes exist, if not, generate names
60
+
61
+ // Step 1: Fetch existing archetypes
60
62
  let archetypes = await this.archetypeService.fetchArchetypesFromDB(
61
63
  combinationString,
62
64
  gender,
63
65
  language
64
66
  );
65
- if (archetypes.length === 0) {
66
- await this.log('info', 'No archetypes found, generating names', {
67
+ await this.log('info', 'Fetched existing archetypes', {
68
+ archetypesCount: archetypes.length,
69
+ archetypeIds: archetypes.map((a) => a.id),
70
+ });
71
+
72
+ // Step 2: Generate or update archetype names and essence lines
73
+ if (
74
+ override ||
75
+ archetypes.length === 0 ||
76
+ archetypes.some((a) => !a.name || !a.essenceLine)
77
+ ) {
78
+ await this.log('info', 'Generating or updating archetype names', {
67
79
  combinationString,
68
80
  gender,
69
81
  language,
82
+ override,
70
83
  });
71
- await this.archetypeService.generateArchetypeNames(combinationString);
84
+ await this.archetypeService.generateArchetypeNames(
85
+ combinationString,
86
+ override
87
+ );
72
88
  archetypes = await this.archetypeService.fetchArchetypesFromDB(
73
89
  combinationString,
74
90
  gender,
75
91
  language
76
92
  );
93
+ await this.log('info', 'Refetched archetypes after name generation', {
94
+ archetypesCount: archetypes.length,
95
+ archetypeIds: archetypes.map((a) => a.id),
96
+ });
97
+ } else {
98
+ await this.log('info', 'Skipping archetype names generation', {
99
+ reason: 'Names and essence lines already exist',
100
+ });
77
101
  }
78
- await this.log('info', 'Fetched archetypes', {
79
- archetypesCount: archetypes.length,
80
- archetypeIds: archetypes.map((a) => a.id),
81
- });
82
-
83
- // Step 2: Check if any archetypes are already being processed (images are generating)
84
- const db = this.context.drizzle();
85
- await this.log('debug', 'Checking for in-progress image generations', {
86
- combinationString,
87
- gender,
88
- });
89
- const inProgressGenerations = await db
90
- .select()
91
- .from(schema.generations)
92
- .where(
93
- and(
94
- eq(schema.generations.status, 'pending'),
95
- eq(schema.generations.gender, gender),
96
- inArray(
97
- schema.generations.archetypeDataId,
98
- archetypes.map((a) => a.id)
99
- )
100
- )
101
- )
102
- .execute();
103
-
104
- if (inProgressGenerations.length > 0) {
105
- await this.log(
106
- 'warn',
107
- `Images are already being processed for ${combinationString}, gender: ${gender}`,
108
- {
109
- inProgressGenerationsCount: inProgressGenerations.length,
110
- generationIds: inProgressGenerations.map((g) => g.id),
111
- }
102
+
103
+ // Step 3: Generate or update descriptions and virtues
104
+ let descVirtues: any[] = [];
105
+ if (
106
+ override ||
107
+ archetypes.some((a) => !a.description || a.virtues === '[]')
108
+ ) {
109
+ await this.log('info', 'Generating or updating descriptions and virtues', {
110
+ combinationString,
111
+ gender,
112
+ language,
113
+ override,
114
+ });
115
+ descVirtues = await this.archetypeService.generateDescriptionsAndVirtues(
116
+ combinationString,
117
+ gender,
118
+ language,
119
+ override
112
120
  );
113
- return { message: 'Images are being processed, please try again later.' };
121
+ archetypes = await this.archetypeService.fetchArchetypesFromDB(
122
+ combinationString,
123
+ gender,
124
+ language
125
+ );
126
+ await this.log('info', 'Refetched archetypes after descriptions and virtues', {
127
+ archetypesCount: archetypes.length,
128
+ archetypeIds: archetypes.map((a) => a.id),
129
+ });
130
+ } else {
131
+ await this.log('info', 'Skipping descriptions and virtues generation', {
132
+ reason: 'Descriptions and virtues already exist',
133
+ });
114
134
  }
115
- await this.log('info', 'No in-progress image generations found', {
116
- combinationString,
117
- gender,
118
- });
119
-
120
- // Step 3: Generate missing textual content (description, virtues, content, leonardoPrompt)
121
- const archetypesNeedingText = archetypes.filter(
122
- (arc) =>
123
- !arc.description ||
124
- arc.virtues === '[]' ||
125
- arc.content === '[]' ||
126
- !arc.leonardoPrompt
127
- );
128
-
129
- if (archetypesNeedingText.length > 0) {
130
- await this.log('info', 'Generating missing textual content', {
135
+
136
+ // Step 4: Generate or update content
137
+ if (override || archetypes.some((a) => a.content === '[]')) {
138
+ await this.log('info', 'Generating or updating content', {
131
139
  combinationString,
132
140
  gender,
133
141
  language,
134
- archetypesNeedingTextCount: archetypesNeedingText.length,
135
- archetypeIds: archetypesNeedingText.map((a) => a.id),
136
- });
137
-
138
- const descVirtues =
139
- await this.archetypeService.generateDescriptionsAndVirtues(
140
- combinationString,
141
- gender,
142
- language
143
- );
142
+ override,
143
+ });
144
144
  await this.archetypeService.generateContent(
145
145
  combinationString,
146
146
  gender,
147
147
  language,
148
- descVirtues
148
+ descVirtues,
149
+ override
149
150
  );
150
- await this.archetypeService.generateLeonardoPrompts(
151
+ archetypes = await this.archetypeService.fetchArchetypesFromDB(
151
152
  combinationString,
152
153
  gender,
153
- language,
154
- descVirtues
154
+ language
155
155
  );
156
+ await this.log('info', 'Refetched archetypes after content generation', {
157
+ archetypesCount: archetypes.length,
158
+ archetypeIds: archetypes.map((a) => a.id),
159
+ });
156
160
  } else {
157
- await this.log('info', 'No textual content generation needed', {
161
+ await this.log('info', 'Skipping content generation', {
162
+ reason: 'Content already exists',
163
+ });
164
+ }
165
+
166
+ // Step 5: Generate or update Leonardo prompts
167
+ if (override || archetypes.some((a) => !a.leonardoPrompt)) {
168
+ await this.log('info', 'Generating or updating Leonardo prompts', {
158
169
  combinationString,
159
170
  gender,
160
171
  language,
172
+ override,
173
+ });
174
+ await this.archetypeService.generateLeonardoPrompts(
175
+ combinationString,
176
+ gender,
177
+ language,
178
+ descVirtues,
179
+ override
180
+ );
181
+ archetypes = await this.archetypeService.fetchArchetypesFromDB(
182
+ combinationString,
183
+ gender,
184
+ language
185
+ );
186
+ await this.log('info', 'Refetched archetypes after Leonardo prompts', {
187
+ archetypesCount: archetypes.length,
188
+ archetypeIds: archetypes.map((a) => a.id),
189
+ });
190
+ } else {
191
+ await this.log('info', 'Skipping Leonardo prompts generation', {
192
+ reason: 'Leonardo prompts already exist',
161
193
  });
162
194
  }
163
-
164
- // Refetch archetypes after generating textual content
165
- const updatedArchetypes = await this.archetypeService.fetchArchetypesFromDB(
166
- combinationString,
167
- gender,
168
- language
169
- );
170
- await this.log('info', 'Refetched archetypes', {
171
- updatedArchetypesCount: updatedArchetypes.length,
172
- archetypeIds: updatedArchetypes.map((a) => a.id),
173
- });
174
-
175
- // Step 4: Queue image generation if needed
176
- const archetypesNeedingImages = updatedArchetypes.filter(
177
- (arc) => JSON.parse(arc.images).length < 3
195
+
196
+ // Step 6: Process image generation if needed
197
+ const archetypesNeedingImages = archetypes.filter(
198
+ (arc) => JSON.parse(arc.images).length < 3 || (override && arc.images !== '[]')
178
199
  );
179
-
200
+
180
201
  if (archetypesNeedingImages.length > 0) {
181
- await this.log(
182
- 'info',
183
- 'Queuing image generation for missing archetypes',
184
- {
185
- archetypesNeedingImagesCount: archetypesNeedingImages.length,
186
- archetypeIds: archetypesNeedingImages.map((a) => a.id),
202
+ await this.log('info', 'Processing image generation for archetypes', {
203
+ archetypesNeedingImagesCount: archetypesNeedingImages.length,
204
+ archetypeIds: archetypesNeedingImages.map((a) => a.id),
205
+ });
206
+
207
+ for (const archetype of archetypesNeedingImages) {
208
+ await this.log('debug', 'Processing image generation', {
209
+ archetypeId: archetype.id,
210
+ leonardoPrompt: archetype.leonardoPrompt,
211
+ });
212
+
213
+ // Reset images and status if override is true
214
+ if (override) {
215
+ await this.context.drizzle()
216
+ .update(schema.archetypesData)
217
+ .set({
218
+ images: '[]',
219
+ status: 'idle',
220
+ updatedAt: new Date().getTime(),
221
+ })
222
+ .where(eq(schema.archetypesData.id, archetype.id))
223
+ .execute();
224
+ await this.log('info', 'Reset images and status for archetype', {
225
+ archetypeId: archetype.id,
226
+ });
187
227
  }
188
- );
189
-
190
- const batch = archetypesNeedingImages.map((arc) => ({
191
- body: {
192
- archetypeDataId: arc.id,
193
- },
194
- }));
195
- await this.log('debug', 'Sending batch to ARCHETYPE_POPULATION_QUEUE', {
196
- batchCount: batch.length,
197
- batch,
198
- });
199
- await this.context.env.ARCHETYPE_POPULATION_QUEUE.sendBatch(batch);
200
- await this.log('info', 'Successfully queued image generation', {
201
- batchCount: batch.length,
202
- });
203
-
204
- return { message: 'Images are being processed, please try again later.' };
228
+
229
+ // Process image generation directly
230
+ await this.leonardoService.processArchetypePopulation({
231
+ archetypeDataId: archetype.id,
232
+ });
233
+
234
+ // Note: processArchetypePopulation sets status to 'pending' in the generations table
235
+ // Update archetype status to 'pending' for consistency
236
+ await this.context.drizzle()
237
+ .update(schema.archetypesData)
238
+ .set({
239
+ status: 'pending',
240
+ updatedAt: new Date().getTime(),
241
+ })
242
+ .where(eq(schema.archetypesData.id, archetype.id))
243
+ .execute();
244
+ }
245
+
246
+ await this.log('info', 'Image generation processing initiated', {
247
+ archetypesProcessed: archetypesNeedingImages.length,
248
+ });
249
+ return {
250
+ message: 'Image generation has been queued. Please try again later.',
251
+ };
252
+ }
253
+
254
+ // Step 7: Verify all archetypes are complete
255
+ const incompleteArchetypes = archetypes.filter((a) => a.status !== 'generated');
256
+ if (incompleteArchetypes.length > 0) {
257
+ await this.log('warn', 'Some archetypes are not complete', {
258
+ incompleteArchetypeIds: incompleteArchetypes.map((a) => a.id),
259
+ statuses: incompleteArchetypes.map((a) => a.status),
260
+ });
261
+ return {
262
+ message: 'Archetype generation is still in progress. Please try again later.',
263
+ };
205
264
  }
206
-
207
- await this.log('info', 'Archetypes fully processed and ready', {
208
- updatedArchetypes,
265
+
266
+ await this.log('info', 'All archetypes are complete', {
267
+ archetypesCount: archetypes.length,
268
+ archetypeIds: archetypes.map((a) => a.id),
209
269
  });
270
+
210
271
  return {
211
- archetypes: updatedArchetypes.map(
272
+ archetypes: archetypes.map(
212
273
  ({ id, name, essenceLine, description, virtues, images }) => ({
213
274
  id,
214
275
  name,
@@ -220,4 +281,4 @@ export class ArchetypeWorkflow {
220
281
  ),
221
282
  };
222
283
  }
223
- }
284
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.371",
3
+ "version": "0.0.373",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {