@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.
- package/app/services/ArchetypeService.ts +510 -392
- package/app/services/LeonardoService.ts +21 -16
- package/app/workflow/ArchetypeWorkflow.ts +171 -168
- package/package.json +1 -1
- package/types/scopes/generic.ts +1 -1
|
@@ -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(
|
|
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 {
|
|
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 {
|
|
7
|
-
import { LeonardoService } from '
|
|
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
|
|
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:
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
combinationString,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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.
|
|
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
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
135
|
-
|
|
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
|
-
|
|
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
|
-
|
|
96
|
+
userId,
|
|
97
|
+
});
|
|
98
|
+
const archetypes = await this.archetypeService.fetchArchetypesFromDB(
|
|
99
|
+
combinationString,
|
|
100
|
+
gender, // Fetch only the requested gender
|
|
101
|
+
language
|
|
155
102
|
);
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
-
|
|
200
|
-
await this.log('
|
|
201
|
-
|
|
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
package/types/scopes/generic.ts
CHANGED
|
@@ -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'
|
|
34
|
+
export const VALID_GENDERS_ARRAY = ['male', 'female'] as const;
|
|
35
35
|
|
|
36
36
|
export type Gender = (typeof VALID_GENDERS_ARRAY)[number];
|
|
37
37
|
|