@zodic/shared 0.0.372 → 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, inArray } 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,205 +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
- const logMessage = `[${level.toUpperCase()}] ${message}`;
24
-
20
+ const logMessage = `[${new Date().toISOString()}] [${level.toUpperCase()}] ${message}`;
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'
27
+ language: Languages,
28
+ override: boolean = false,
29
+ userId?: string
52
30
  ) {
53
- await this.log('info', 'Starting ArchetypeWorkflow', {
31
+ await this.log('info', 'Starting ArchetypeWorkflow.execute', {
54
32
  combinationString,
55
33
  gender,
56
34
  language,
35
+ override,
36
+ userId,
57
37
  });
58
-
59
- // Step 1: Check if archetypes exist, if not, generate names
60
- let archetypes = await this.archetypeService.fetchArchetypesFromDB(
61
- combinationString,
62
- gender,
63
- language
64
- );
65
- if (archetypes.length === 0) {
66
- await this.log('info', 'No archetypes found, generating names', {
38
+
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);
43
+
44
+ // Step 2: Generate descriptions and virtues for both genders
45
+ await this.log('debug', 'Generating descriptions and virtues', {
67
46
  combinationString,
68
47
  gender,
69
48
  language,
49
+ override,
50
+ userId,
70
51
  });
71
- await this.archetypeService.generateArchetypeNames(combinationString);
72
- archetypes = await this.archetypeService.fetchArchetypesFromDB(
52
+ const descriptions = await this.archetypeService.generateDescriptionsAndVirtues(
73
53
  combinationString,
74
- gender,
75
- language
76
- );
77
- }
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
- }
54
+ gender, // Service processes both genders internally
55
+ language,
56
+ override
112
57
  );
113
- return { message: 'Images are being processed, please try again later.' };
114
- }
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', {
58
+
59
+ // Step 3: Generate content for both genders
60
+ await this.log('debug', 'Generating content', {
131
61
  combinationString,
132
62
  gender,
133
63
  language,
134
- archetypesNeedingTextCount: archetypesNeedingText.length,
135
- archetypeIds: archetypesNeedingText.map((a) => a.id),
64
+ override,
65
+ userId,
136
66
  });
137
-
138
- const descVirtues =
139
- await this.archetypeService.generateDescriptionsAndVirtues(
140
- combinationString,
141
- gender,
142
- language
143
- );
144
67
  await this.archetypeService.generateContent(
145
68
  combinationString,
146
- gender,
69
+ gender, // Service processes both genders internally
147
70
  language,
148
- descVirtues
71
+ descriptions,
72
+ override
149
73
  );
74
+
75
+ // Step 4: Generate Leonardo prompts for both genders
76
+ await this.log('debug', 'Generating Leonardo prompts', {
77
+ combinationString,
78
+ gender,
79
+ language,
80
+ override,
81
+ userId,
82
+ });
150
83
  await this.archetypeService.generateLeonardoPrompts(
84
+ combinationString,
85
+ gender, // Service processes both genders internally
86
+ language,
87
+ descriptions,
88
+ override
89
+ );
90
+
91
+ // Step 5: Fetch archetypes for the requested gender only for image generation
92
+ await this.log('debug', 'Fetching archetypes for image generation', {
151
93
  combinationString,
152
94
  gender,
153
95
  language,
154
- descVirtues
96
+ userId,
97
+ });
98
+ const archetypes = await this.archetypeService.fetchArchetypesFromDB(
99
+ combinationString,
100
+ gender, // Fetch only the requested gender
101
+ language
155
102
  );
156
- } else {
157
- await this.log('info', 'No textual content generation needed', {
103
+
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
+ }
115
+
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
+ }
132
+
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
+ }
151
+
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', {
158
154
  combinationString,
159
155
  gender,
160
156
  language,
157
+ userId,
161
158
  });
162
- }
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
178
- );
179
-
180
- 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),
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;
187
174
  }
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,
175
+
176
+ if (imageCount >= 3) {
177
+ await db
178
+ .update(schema.archetypesData)
179
+ .set({
180
+ status: 'completed',
181
+ updatedAt: new Date().getTime(),
182
+ })
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,
205
+ });
206
+ }
207
+ }
208
+
209
+ await this.log('info', 'Completed ArchetypeWorkflow.execute', {
210
+ combinationString,
211
+ gender,
212
+ language,
213
+ userId,
198
214
  });
199
- await this.context.env.ARCHETYPE_POPULATION_QUEUE.sendBatch(batch);
200
- await this.log('info', 'Successfully queued image generation', {
201
- batchCount: batch.length,
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),
202
222
  });
203
-
204
- return { message: 'Images are being processed, please try again later.' };
223
+ throw error;
205
224
  }
206
-
207
- await this.log('info', 'Archetypes fully processed and ready', {
208
- updatedArchetypes,
209
- });
210
- return {
211
- archetypes: updatedArchetypes.map(
212
- ({ id, name, essenceLine, description, virtues, images }) => ({
213
- id,
214
- name,
215
- essenceLine,
216
- description,
217
- virtues: JSON.parse(virtues),
218
- images: JSON.parse(images),
219
- })
220
- ),
221
- };
222
225
  }
223
- }
226
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.372",
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