@zodic/shared 0.0.373 → 0.0.374

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.
@@ -2,7 +2,6 @@ import { eq } from 'drizzle-orm';
2
2
  import { inject, injectable } from 'inversify';
3
3
  import 'reflect-metadata';
4
4
  import { schema } from '../..';
5
- import { Gender } from '../../types';
6
5
  import { AppContext } from '../base/AppContext';
7
6
 
8
7
  interface QueueMessage {
@@ -48,12 +47,11 @@ export class LeonardoService {
48
47
  /**
49
48
  * Processes a message from ARCHETYPE_POPULATION_QUEUE to ensure the archetype has three images.
50
49
  */
51
- async processArchetypePopulation(message: QueueMessage): Promise<void> {
52
- const { archetypeDataId } = message;
50
+ async processArchetypePopulation(archetypeDataId: string): Promise<void> {
53
51
  await this.log('info', 'Processing archetype population', {
54
52
  archetypeDataId,
55
53
  });
56
-
54
+
57
55
  const db = this.context.drizzle();
58
56
  const archetype = await db
59
57
  .select({
@@ -69,14 +67,21 @@ export class LeonardoService {
69
67
  .where(eq(schema.archetypesData.id, archetypeDataId))
70
68
  .limit(1)
71
69
  .execute();
72
-
70
+
73
71
  if (!archetype[0]) {
74
72
  await this.log('error', 'Archetype not found', { archetypeDataId });
75
73
  throw new Error(`Archetype not found: ${archetypeDataId}`);
76
74
  }
77
-
78
- const { combination, gender, language, archetypeIndex, leonardoPrompt, images } = archetype[0];
79
-
75
+
76
+ const {
77
+ combination,
78
+ gender,
79
+ language,
80
+ archetypeIndex,
81
+ leonardoPrompt,
82
+ images,
83
+ } = archetype[0];
84
+
80
85
  await this.log('info', 'Fetched archetype details', {
81
86
  archetypeDataId,
82
87
  combination,
@@ -84,7 +89,7 @@ export class LeonardoService {
84
89
  language,
85
90
  archetypeIndex,
86
91
  });
87
-
92
+
88
93
  const parsedImages = JSON.parse(images || '[]');
89
94
  if (parsedImages.length >= 3) {
90
95
  await this.log('info', 'Archetype already has sufficient images', {
@@ -93,7 +98,7 @@ export class LeonardoService {
93
98
  });
94
99
  return;
95
100
  }
96
-
101
+
97
102
  if (!leonardoPrompt) {
98
103
  await this.log('error', 'Missing Leonardo prompt for archetype', {
99
104
  archetypeDataId,
@@ -102,21 +107,21 @@ export class LeonardoService {
102
107
  `Missing Leonardo prompt for archetype: ${archetypeDataId}`
103
108
  );
104
109
  }
105
-
110
+
106
111
  await this.log('debug', 'Generating images for archetype', {
107
112
  archetypeDataId,
108
113
  prompt: leonardoPrompt,
109
114
  });
110
-
115
+
111
116
  const generationResponse = await this.context
112
117
  .api()
113
118
  .callLeonardo.generateImage({
114
119
  prompt: leonardoPrompt,
115
120
  width: 512,
116
121
  height: 640,
117
- quantity: 3 - parsedImages.length,
122
+ // quantity: 3 - parsedImages.length,
118
123
  });
119
-
124
+
120
125
  const generationId = generationResponse.sdGenerationJob.generationId;
121
126
  if (!generationId) {
122
127
  await this.log(
@@ -126,7 +131,7 @@ export class LeonardoService {
126
131
  );
127
132
  throw new Error('Leonardo generation failed to return a valid ID');
128
133
  }
129
-
134
+
130
135
  await db.insert(schema.generations).values({
131
136
  id: generationId,
132
137
  archetypeIndex: parseInt(archetypeIndex),
@@ -136,7 +141,7 @@ export class LeonardoService {
136
141
  gender,
137
142
  createdAt: new Date(),
138
143
  });
139
-
144
+
140
145
  await this.log('info', 'Queued image generation', {
141
146
  generationId,
142
147
  archetypeDataId,
@@ -1,10 +1,8 @@
1
- import { and, eq } from 'drizzle-orm';
2
1
  import { inject, injectable } from 'inversify';
3
- import { schema } from '../..';
4
- import { Gender } from '../../types';
5
2
  import { AppContext } from '../base';
6
- import { ArchetypeService } from '../services/ArchetypeService';
7
- import { LeonardoService } from '../services/LeonardoService';
3
+ import { Gender, Languages } from '../../types';
4
+ import { ArchetypeService, LeonardoService, schema } from '../..';
5
+ import { and, eq } from 'drizzle-orm';
8
6
 
9
7
  @injectable()
10
8
  export class ArchetypeWorkflow {
@@ -19,266 +17,210 @@ export class ArchetypeWorkflow {
19
17
  message: string,
20
18
  context: Record<string, any> = {}
21
19
  ) {
22
- const logId = `archetype-workflow:${Date.now()}`;
23
20
  const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
24
-
25
21
  console[level](logMessage, context);
26
- const db = this.context.drizzle();
27
- try {
28
- await db
29
- .insert(schema.logs)
30
- .values({
31
- id: logId,
32
- level,
33
- message,
34
- context: JSON.stringify(context),
35
- createdAt: new Date().getTime(),
36
- })
37
- .execute();
38
- } catch (error) {
39
- console.error('[ERROR] Failed to persist log to database:', {
40
- error,
41
- logId,
42
- message,
43
- context,
44
- });
45
- }
46
22
  }
47
23
 
48
24
  async execute(
49
25
  combinationString: string,
50
26
  gender: Gender,
51
- language: string = 'en-us',
52
- override: boolean = false
27
+ language: Languages,
28
+ override: boolean = false,
29
+ userId?: string
53
30
  ) {
54
- await this.log('info', 'Starting ArchetypeWorkflow', {
31
+ await this.log('info', 'Starting ArchetypeWorkflow.execute', {
55
32
  combinationString,
56
33
  gender,
57
34
  language,
58
35
  override,
36
+ userId,
59
37
  });
60
38
 
61
- // Step 1: Fetch existing archetypes
62
- let archetypes = await this.archetypeService.fetchArchetypesFromDB(
63
- combinationString,
64
- gender,
65
- language
66
- );
67
- await this.log('info', 'Fetched existing archetypes', {
68
- archetypesCount: archetypes.length,
69
- archetypeIds: archetypes.map((a) => a.id),
70
- });
39
+ try {
40
+ // Step 1: Generate archetype names for both genders
41
+ await this.log('debug', 'Generating archetype names', { combinationString, override, userId });
42
+ await this.archetypeService.generateArchetypeNames(combinationString, override);
71
43
 
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', {
44
+ // Step 2: Generate descriptions and virtues for both genders
45
+ await this.log('debug', 'Generating descriptions and virtues', {
79
46
  combinationString,
80
47
  gender,
81
48
  language,
82
49
  override,
50
+ userId,
83
51
  });
84
- await this.archetypeService.generateArchetypeNames(
52
+ const descriptions = await this.archetypeService.generateDescriptionsAndVirtues(
85
53
  combinationString,
54
+ gender, // Service processes both genders internally
55
+ language,
86
56
  override
87
57
  );
88
- archetypes = await this.archetypeService.fetchArchetypesFromDB(
89
- combinationString,
90
- gender,
91
- language
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
- });
101
- }
102
58
 
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', {
59
+ // Step 3: Generate content for both genders
60
+ await this.log('debug', 'Generating content', {
110
61
  combinationString,
111
62
  gender,
112
63
  language,
113
64
  override,
65
+ userId,
114
66
  });
115
- descVirtues = await this.archetypeService.generateDescriptionsAndVirtues(
67
+ await this.archetypeService.generateContent(
116
68
  combinationString,
117
- gender,
69
+ gender, // Service processes both genders internally
118
70
  language,
71
+ descriptions,
119
72
  override
120
73
  );
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
- });
134
- }
135
74
 
136
- // Step 4: Generate or update content
137
- if (override || archetypes.some((a) => a.content === '[]')) {
138
- await this.log('info', 'Generating or updating content', {
75
+ // Step 4: Generate Leonardo prompts for both genders
76
+ await this.log('debug', 'Generating Leonardo prompts', {
139
77
  combinationString,
140
78
  gender,
141
79
  language,
142
80
  override,
81
+ userId,
143
82
  });
144
- await this.archetypeService.generateContent(
83
+ await this.archetypeService.generateLeonardoPrompts(
145
84
  combinationString,
146
- gender,
85
+ gender, // Service processes both genders internally
147
86
  language,
148
- descVirtues,
87
+ descriptions,
149
88
  override
150
89
  );
151
- archetypes = await this.archetypeService.fetchArchetypesFromDB(
152
- combinationString,
153
- gender,
154
- language
155
- );
156
- await this.log('info', 'Refetched archetypes after content generation', {
157
- archetypesCount: archetypes.length,
158
- archetypeIds: archetypes.map((a) => a.id),
159
- });
160
- } else {
161
- await this.log('info', 'Skipping content generation', {
162
- reason: 'Content already exists',
163
- });
164
- }
165
90
 
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', {
91
+ // Step 5: Fetch archetypes for the requested gender only for image generation
92
+ await this.log('debug', 'Fetching archetypes for image generation', {
169
93
  combinationString,
170
94
  gender,
171
95
  language,
172
- override,
96
+ userId,
173
97
  });
174
- await this.archetypeService.generateLeonardoPrompts(
98
+ const archetypes = await this.archetypeService.fetchArchetypesFromDB(
175
99
  combinationString,
176
- gender,
177
- language,
178
- descVirtues,
179
- override
180
- );
181
- archetypes = await this.archetypeService.fetchArchetypesFromDB(
182
- combinationString,
183
- gender,
100
+ gender, // Fetch only the requested gender
184
101
  language
185
102
  );
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',
193
- });
194
- }
195
103
 
196
- // Step 6: Process image generation if needed
197
- const archetypesNeedingImages = archetypes.filter(
198
- (arc) => JSON.parse(arc.images).length < 3 || (override && arc.images !== '[]')
199
- );
104
+ if (archetypes.length !== 3) {
105
+ await this.log('error', `Expected 3 archetypes for ${gender}, found ${archetypes.length}`, {
106
+ combinationString,
107
+ gender,
108
+ language,
109
+ userId,
110
+ });
111
+ throw new Error(
112
+ `Expected 3 archetypes for combination ${combinationString}, gender ${gender}, language ${language}, but found ${archetypes.length}`
113
+ );
114
+ }
200
115
 
201
- if (archetypesNeedingImages.length > 0) {
202
- await this.log('info', 'Processing image generation for archetypes', {
203
- archetypesNeedingImagesCount: archetypesNeedingImages.length,
204
- archetypeIds: archetypesNeedingImages.map((a) => a.id),
205
- });
116
+ // Step 6: Process image generation only for the requested gender
117
+ await this.log('info', `Processing image generation for gender ${gender}`, {
118
+ archetypeIds: archetypes.map((a) => a.id),
119
+ archetypeIndexes: archetypes.map((a) => a.archetypeIndex),
120
+ userId,
121
+ });
122
+ for (const archetype of archetypes) {
123
+ if (!archetype.leonardoPrompt) {
124
+ await this.log('warn', `No Leonardo prompt for archetype ${archetype.id}`, {
125
+ archetypeIndex: archetype.archetypeIndex,
126
+ gender,
127
+ language,
128
+ userId,
129
+ });
130
+ continue;
131
+ }
206
132
 
207
- for (const archetype of archetypesNeedingImages) {
208
- await this.log('debug', 'Processing image generation', {
209
- archetypeId: archetype.id,
210
- leonardoPrompt: archetype.leonardoPrompt,
211
- });
133
+ if (override || !archetype.images || archetype.images === '[]') {
134
+ await this.log('debug', `Queueing image generation for archetype ${archetype.id}`, {
135
+ archetypeIndex: archetype.archetypeIndex,
136
+ gender,
137
+ language,
138
+ userId,
139
+ });
140
+ await this.leonardoService.processArchetypePopulation(archetype.id);
141
+ } else {
142
+ await this.log('debug', `Skipping image generation for archetype ${archetype.id}`, {
143
+ reason: 'Images already exist and override is false',
144
+ archetypeIndex: archetype.archetypeIndex,
145
+ gender,
146
+ language,
147
+ userId,
148
+ });
149
+ }
150
+ }
212
151
 
213
- // Reset images and status if override is true
214
- if (override) {
215
- await this.context.drizzle()
152
+ // Step 7: Update status to 'completed' for archetypes with at least 3 images
153
+ await this.log('debug', 'Updating status for archetypes with images', {
154
+ combinationString,
155
+ gender,
156
+ language,
157
+ userId,
158
+ });
159
+ const db = this.context.drizzle();
160
+ for (const archetype of archetypes) {
161
+ let imageCount = 0;
162
+ try {
163
+ const images = archetype.images ? JSON.parse(archetype.images) : [];
164
+ imageCount = Array.isArray(images) ? images.length : 0;
165
+ } catch (error) {
166
+ await this.log('warn', `Failed to parse images for archetype ${archetype.id}`, {
167
+ archetypeIndex: archetype.archetypeIndex,
168
+ gender,
169
+ language,
170
+ userId,
171
+ error: error instanceof Error ? error.message : String(error),
172
+ });
173
+ continue;
174
+ }
175
+
176
+ if (imageCount >= 3) {
177
+ await db
216
178
  .update(schema.archetypesData)
217
179
  .set({
218
- images: '[]',
219
- status: 'idle',
180
+ status: 'completed',
220
181
  updatedAt: new Date().getTime(),
221
182
  })
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,
183
+ .where(
184
+ and(
185
+ eq(schema.archetypesData.id, archetype.id),
186
+ eq(schema.archetypesData.gender, gender),
187
+ eq(schema.archetypesData.language, language),
188
+ eq(schema.archetypesData.archetypeIndex, archetype.archetypeIndex)
189
+ )
190
+ );
191
+ await this.log('info', `Updated status to 'completed' for archetype ${archetype.id}`, {
192
+ archetypeIndex: archetype.archetypeIndex,
193
+ gender,
194
+ language,
195
+ imageCount,
196
+ userId,
197
+ });
198
+ } else {
199
+ await this.log('debug', `Skipping status update for archetype ${archetype.id}`, {
200
+ reason: `Fewer than 3 images (found ${imageCount})`,
201
+ archetypeIndex: archetype.archetypeIndex,
202
+ gender,
203
+ language,
204
+ userId,
226
205
  });
227
206
  }
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
207
  }
245
208
 
246
- await this.log('info', 'Image generation processing initiated', {
247
- archetypesProcessed: archetypesNeedingImages.length,
209
+ await this.log('info', 'Completed ArchetypeWorkflow.execute', {
210
+ combinationString,
211
+ gender,
212
+ language,
213
+ userId,
248
214
  });
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),
215
+ } catch (error) {
216
+ await this.log('error', 'Error in ArchetypeWorkflow.execute', {
217
+ combinationString,
218
+ gender,
219
+ language,
220
+ userId,
221
+ error: error instanceof Error ? error.message : String(error),
260
222
  });
261
- return {
262
- message: 'Archetype generation is still in progress. Please try again later.',
263
- };
223
+ throw error;
264
224
  }
265
-
266
- await this.log('info', 'All archetypes are complete', {
267
- archetypesCount: archetypes.length,
268
- archetypeIds: archetypes.map((a) => a.id),
269
- });
270
-
271
- return {
272
- archetypes: archetypes.map(
273
- ({ id, name, essenceLine, description, virtues, images }) => ({
274
- id,
275
- name,
276
- essenceLine,
277
- description,
278
- virtues: JSON.parse(virtues),
279
- images: JSON.parse(images),
280
- })
281
- ),
282
- };
283
225
  }
284
226
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.373",
3
+ "version": "0.0.374",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -31,7 +31,7 @@ export type PlacementType =
31
31
  | 'karmic_point'
32
32
  | 'arabic_part';
33
33
 
34
- export const VALID_GENDERS_ARRAY = ['male', 'female', 'non-binary'] as const;
34
+ export const VALID_GENDERS_ARRAY = ['male', 'female'] as const;
35
35
 
36
36
  export type Gender = (typeof VALID_GENDERS_ARRAY)[number];
37
37