@zodic/shared 0.0.314 → 0.0.316

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.
@@ -1,8 +1,8 @@
1
+ import { and, eq } from 'drizzle-orm';
1
2
  import { inject, injectable } from 'inversify';
3
+ import { schema } from '../..';
2
4
  import { Gender } from '../../types';
3
- import { KVArchetype } from '../../types/scopes/legacy';
4
- import { buildCosmicMirrorArchetypeKVKey } from '../../utils/KVKeysBuilders';
5
- import { AppContext } from '../base/AppContext';
5
+ import { AppContext } from '../base';
6
6
  import { ArchetypeService } from '../services/ArchetypeService';
7
7
  import { LeonardoService } from '../services/LeonardoService';
8
8
 
@@ -14,176 +14,210 @@ export class ArchetypeWorkflow {
14
14
  @inject(LeonardoService) private leonardoService: LeonardoService
15
15
  ) {}
16
16
 
17
- async execute(combinationString: string, gender: Gender) {
18
- console.log('Starting ArchetypeWorkflow for:', {
17
+ private async log(
18
+ level: 'info' | 'debug' | 'warn' | 'error',
19
+ message: string,
20
+ context: Record<string, any> = {}
21
+ ) {
22
+ const logId = `archetype-workflow:${Date.now()}`;
23
+ const logMessage = `[${level.toUpperCase()}] ${message}`;
24
+
25
+ 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
+ }
47
+
48
+ async execute(
49
+ combinationString: string,
50
+ gender: Gender,
51
+ language: string = 'en-us'
52
+ ) {
53
+ await this.log('info', 'Starting ArchetypeWorkflow', {
19
54
  combinationString,
20
55
  gender,
56
+ language,
21
57
  });
22
58
 
23
- const archetypes = await this.fetchArchetypesFromKV(
59
+ // Step 1: Check if archetypes exist, if not, generate names
60
+ let archetypes = await this.archetypeService.fetchArchetypesFromDB(
24
61
  combinationString,
25
- gender
62
+ gender,
63
+ language
26
64
  );
65
+ if (archetypes.length === 0) {
66
+ await this.log('info', 'No archetypes found, generating names', {
67
+ combinationString,
68
+ gender,
69
+ language,
70
+ });
71
+ await this.archetypeService.generateArchetypeNames(combinationString);
72
+ archetypes = await this.archetypeService.fetchArchetypesFromDB(
73
+ 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
+ });
27
82
 
28
- if (archetypes.some((arc) => arc.status === 'generating')) {
29
- console.log(
30
- `Archetypes are already being processed for ${combinationString}, gender: ${gender}`
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
+ eq(schema.generations.archetypeDataId, combinationString)
97
+ )
98
+ )
99
+ .execute();
100
+
101
+ if (inProgressGenerations.length > 0) {
102
+ await this.log(
103
+ 'warn',
104
+ `Images are already being processed for ${combinationString}, gender: ${gender}`,
105
+ {
106
+ inProgressGenerationsCount: inProgressGenerations.length,
107
+ generationIds: inProgressGenerations.map((g) => g.id),
108
+ }
31
109
  );
32
110
  return { message: 'Images are being processed, please try again later.' };
33
111
  }
112
+ await this.log('info', 'No in-progress image generations found', {
113
+ combinationString,
114
+ gender,
115
+ });
116
+
117
+ // Step 3: Generate missing textual content (description, virtues, content, leonardoPrompt)
118
+ const archetypesNeedingText = archetypes.filter(
119
+ (arc) =>
120
+ !arc.description ||
121
+ arc.virtues === '[]' ||
122
+ arc.content === '[]' ||
123
+ !arc.leonardoPrompt
124
+ );
34
125
 
35
- if (archetypes.some((arc) => !arc.name || arc.images.length < 3)) {
36
- console.log(
37
- `Generating missing basic info for: ${combinationString}, gender: ${gender}`
126
+ if (archetypesNeedingText.length > 0) {
127
+ await this.log('info', 'Generating missing textual content', {
128
+ combinationString,
129
+ gender,
130
+ language,
131
+ archetypesNeedingTextCount: archetypesNeedingText.length,
132
+ archetypeIds: archetypesNeedingText.map((a) => a.id),
133
+ });
134
+
135
+ const descVirtues =
136
+ await this.archetypeService.generateDescriptionsAndVirtues(
137
+ combinationString,
138
+ gender,
139
+ language
140
+ );
141
+ await this.archetypeService.generateContent(
142
+ combinationString,
143
+ gender,
144
+ language,
145
+ descVirtues
38
146
  );
39
- await this.archetypeService.generateBasicInfo(combinationString);
147
+ await this.archetypeService.generateLeonardoPrompts(
148
+ combinationString,
149
+ gender,
150
+ language,
151
+ descVirtues
152
+ );
153
+ } else {
154
+ await this.log('info', 'No textual content generation needed', {
155
+ combinationString,
156
+ gender,
157
+ language,
158
+ });
40
159
  }
41
160
 
42
- const updatedArchetypes = await this.fetchArchetypesFromKV(
161
+ // Refetch archetypes after generating textual content
162
+ const updatedArchetypes = await this.archetypeService.fetchArchetypesFromDB(
43
163
  combinationString,
44
- gender
164
+ gender,
165
+ language
45
166
  );
167
+ await this.log('info', 'Refetched archetypes', {
168
+ updatedArchetypesCount: updatedArchetypes.length,
169
+ archetypeIds: updatedArchetypes.map((a) => a.id),
170
+ });
46
171
 
47
- if (updatedArchetypes.some((arc) => !arc.leonardoPrompt)) {
48
- console.log('Generating missing Leonardo prompts...');
49
- await this.leonardoService.processArchetypesPrompts(combinationString);
50
- }
51
-
172
+ // Step 4: Queue image generation if needed
52
173
  const archetypesNeedingImages = updatedArchetypes.filter(
53
- (arc) => arc.images.length < 3
174
+ (arc) => JSON.parse(arc.images).length < 3
54
175
  );
55
176
 
56
177
  if (archetypesNeedingImages.length > 0) {
57
- console.log('Queuing image generation for missing archetypes...');
58
- await this.updateArchetypeStatus(updatedArchetypes, 'generating', gender);
178
+ await this.log(
179
+ 'info',
180
+ 'Queuing image generation for missing archetypes',
181
+ {
182
+ archetypesNeedingImagesCount: archetypesNeedingImages.length,
183
+ archetypeIds: archetypesNeedingImages.map((a) => a.id),
184
+ }
185
+ );
59
186
 
60
- try {
61
- await this.leonardoService.queueImagesForArchetypes(
62
- combinationString,
63
- gender
64
- );
65
- } catch (error) {
66
- console.error('Error queuing image generation:', error);
67
- await this.updateArchetypeStatus(updatedArchetypes, 'idle', gender);
68
- throw error;
69
- }
187
+ const batch = archetypesNeedingImages.map((arc) => ({
188
+ body: {
189
+ archetypeDataId: arc.id,
190
+ combination: combinationString,
191
+ gender,
192
+ language,
193
+ archetypeIndex: arc.archetypeIndex,
194
+ },
195
+ }));
196
+ await this.log('debug', 'Sending batch to ARCHETYPE_POPULATION_QUEUE', {
197
+ batchCount: batch.length,
198
+ batch,
199
+ });
200
+ await this.context.env.ARCHETYPE_POPULATION_QUEUE.sendBatch(batch);
201
+ await this.log('info', 'Successfully queued image generation', {
202
+ batchCount: batch.length,
203
+ });
70
204
 
71
205
  return { message: 'Images are being processed, please try again later.' };
72
206
  }
73
207
 
74
- await this.updateArchetypeStatus(updatedArchetypes, 'idle', gender);
75
-
76
- console.log('Archetypes fully processed and ready:', updatedArchetypes);
208
+ await this.log('info', 'Archetypes fully processed and ready', {
209
+ updatedArchetypes,
210
+ });
77
211
  return {
78
212
  archetypes: updatedArchetypes.map(
79
- ({ name, content, description, virtues, images }) => ({
213
+ ({ name, essenceLine, description, virtues, images }) => ({
80
214
  name,
81
- content,
215
+ essenceLine,
82
216
  description,
83
- virtues,
84
- images,
217
+ virtues: JSON.parse(virtues),
218
+ images: JSON.parse(images),
85
219
  })
86
220
  ),
87
221
  };
88
222
  }
89
-
90
- async generateNames({
91
- combinations,
92
- overrideExisting,
93
- }: {
94
- combinations: string[];
95
- overrideExisting?: boolean;
96
- }): Promise<void> {
97
- if (combinations.length === 0) return;
98
-
99
- if (combinations.length === 1) {
100
- await this.archetypeService.generateArchetypeNames(
101
- combinations[0],
102
- overrideExisting
103
- );
104
- } else {
105
- const entries = combinations.map((combination) => ({
106
- combination,
107
- }));
108
-
109
- await this.archetypeService.generateArchetypeNamesBatch(
110
- entries,
111
- overrideExisting
112
- );
113
- }
114
- }
115
-
116
- /**
117
- * Fetch all three archetypes from KV for a given combination and gender.
118
- */
119
- private async fetchArchetypesFromKV(
120
- combinationString: string,
121
- gender: Gender
122
- ): Promise<KVArchetype[]> {
123
- return Promise.all(
124
- Array.from({ length: 3 }, (_, i) => i + 1).map(async (index) => {
125
- const kvKey = buildCosmicMirrorArchetypeKVKey(
126
- 'en-us',
127
- combinationString,
128
- gender,
129
- index
130
- );
131
- console.log(`Fetching archetype from KV: ${kvKey}`);
132
-
133
- try {
134
- return (
135
- (await this.context
136
- .kvCosmicMirrorArchetypesStore()
137
- .get<KVArchetype>(kvKey, 'json')) || this.createEmptyArchetype()
138
- );
139
- } catch (error) {
140
- console.error(
141
- `Error fetching archetype KV for index ${index}:`,
142
- error
143
- );
144
- return this.createEmptyArchetype();
145
- }
146
- })
147
- );
148
- }
149
-
150
- /**
151
- * Update the status of archetypes in KV.
152
- */
153
- private async updateArchetypeStatus(
154
- archetypes: KVArchetype[],
155
- status: 'idle' | 'generating',
156
- gender: Gender
157
- ): Promise<void> {
158
- await Promise.all(
159
- archetypes.map(async (archetype, index) => {
160
- const kvKey = buildCosmicMirrorArchetypeKVKey(
161
- 'en-us',
162
- archetype.name,
163
- gender,
164
- index + 1
165
- );
166
- archetype.status = status;
167
- await this.context
168
- .kvCosmicMirrorArchetypesStore()
169
- .put(kvKey, JSON.stringify(archetype));
170
- })
171
- );
172
- }
173
-
174
- /**
175
- * Create an empty KVArchetype object when KV data is missing.
176
- */
177
- private createEmptyArchetype(): KVArchetype {
178
- return {
179
- name: '',
180
- description: '',
181
- content: '',
182
- leonardoPrompt: '',
183
- visualDescription: '',
184
- virtues: [],
185
- images: [],
186
- status: 'idle',
187
- };
188
- }
189
223
  }
@@ -0,0 +1,10 @@
1
+ CREATE TABLE `logs` (
2
+ `id` text PRIMARY KEY NOT NULL,
3
+ `level` text NOT NULL,
4
+ `message` text NOT NULL,
5
+ `context` text DEFAULT '{}' NOT NULL,
6
+ `created_at` integer DEFAULT CURRENT_TIMESTAMP
7
+ );
8
+ --> statement-breakpoint
9
+ ALTER TABLE `generations` ADD `archetype_data_id` text REFERENCES archetypes_data(id);--> statement-breakpoint
10
+ CREATE INDEX `generations_archetype_data_id_idx` ON `generations` (`archetype_data_id`);