@zodic/shared 0.0.75 → 0.0.77
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 +289 -0
- package/app/services/ConceptService.ts +19 -13
- package/app/services/LeonardoService.ts +197 -0
- package/app/workflow/ArchetypeWorkflow.ts +156 -0
- package/app/workflow/ConceptWorkflow.ts +4 -0
- package/package.json +1 -1
- package/utils/KVKeysBuilders.ts +18 -0
- package/utils/index.ts +16 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { inject, injectable } from 'inversify';
|
|
2
|
+
import { KVArchetype } from '../../types/scopes/legacy';
|
|
3
|
+
import { buildCosmicMirrorArchetypeKVKey } from '../../utils/KVKeysBuilders';
|
|
4
|
+
import { AppContext } from '../base';
|
|
5
|
+
|
|
6
|
+
@injectable()
|
|
7
|
+
export class ArchetypeService {
|
|
8
|
+
constructor(@inject(AppContext) private context: AppContext) {}
|
|
9
|
+
|
|
10
|
+
async generateBasicInfo(combinationString: string): Promise<void> {
|
|
11
|
+
console.log(
|
|
12
|
+
`Generating basic info for archetypes of combination: ${combinationString}`
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
const [sun, ascendant, moon] = combinationString.split('-');
|
|
16
|
+
|
|
17
|
+
const messages = this.context
|
|
18
|
+
.buildLLMMessages()
|
|
19
|
+
.generateCosmicMirrorArchetypeBasicInfo({ sun, ascendant, moon });
|
|
20
|
+
|
|
21
|
+
const response = await this.context.api().callDeepSeek.single(messages, {});
|
|
22
|
+
|
|
23
|
+
if (!response) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`Failed to generate basic info for archetypes: ${combinationString}`
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const archetypes = this.parseArchetypeResponse(response);
|
|
30
|
+
|
|
31
|
+
await Promise.all(
|
|
32
|
+
archetypes.map(async (archetype, index) => {
|
|
33
|
+
const archetypeIndex = index + 1;
|
|
34
|
+
|
|
35
|
+
const maleKey = buildCosmicMirrorArchetypeKVKey(
|
|
36
|
+
'en-us',
|
|
37
|
+
combinationString,
|
|
38
|
+
'male',
|
|
39
|
+
archetypeIndex
|
|
40
|
+
);
|
|
41
|
+
const femaleKey = buildCosmicMirrorArchetypeKVKey(
|
|
42
|
+
'en-us',
|
|
43
|
+
combinationString,
|
|
44
|
+
'female',
|
|
45
|
+
archetypeIndex
|
|
46
|
+
);
|
|
47
|
+
const nonBinaryKey = buildCosmicMirrorArchetypeKVKey(
|
|
48
|
+
'en-us',
|
|
49
|
+
combinationString,
|
|
50
|
+
'non-binary',
|
|
51
|
+
archetypeIndex
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const kvDataMale: KVArchetype = {
|
|
55
|
+
name: archetype.name,
|
|
56
|
+
description: archetype.descriptionMale,
|
|
57
|
+
visualDescription: archetype.visualRepresentation,
|
|
58
|
+
content: '',
|
|
59
|
+
leonardoPrompt: '',
|
|
60
|
+
virtues: archetype.virtues,
|
|
61
|
+
images: [],
|
|
62
|
+
status: 'idle',
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const kvDataFemale: KVArchetype = {
|
|
66
|
+
name: archetype.name,
|
|
67
|
+
description: archetype.descriptionFemale,
|
|
68
|
+
visualDescription: archetype.visualRepresentation,
|
|
69
|
+
content: '',
|
|
70
|
+
leonardoPrompt: '',
|
|
71
|
+
virtues: archetype.virtues,
|
|
72
|
+
images: [],
|
|
73
|
+
status: 'idle',
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
await Promise.all([
|
|
77
|
+
this.context
|
|
78
|
+
.kvCosmicMirrorArchetypesStore()
|
|
79
|
+
.put(maleKey, JSON.stringify(kvDataMale)),
|
|
80
|
+
this.context
|
|
81
|
+
.kvCosmicMirrorArchetypesStore()
|
|
82
|
+
.put(femaleKey, JSON.stringify(kvDataFemale)),
|
|
83
|
+
this.context
|
|
84
|
+
.kvCosmicMirrorArchetypesStore()
|
|
85
|
+
.put(nonBinaryKey, JSON.stringify(kvDataFemale)),
|
|
86
|
+
]);
|
|
87
|
+
})
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
console.log(
|
|
91
|
+
`Basic info stored for archetypes of combination: ${combinationString}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private parseArchetypeResponse(response: string): Array<{
|
|
96
|
+
name: string;
|
|
97
|
+
descriptionMale: string;
|
|
98
|
+
descriptionFemale: string;
|
|
99
|
+
visualRepresentation: string;
|
|
100
|
+
virtues: string[];
|
|
101
|
+
}> {
|
|
102
|
+
console.log('Parsing archetype response from ChatGPT');
|
|
103
|
+
|
|
104
|
+
const archetypes: Array<{
|
|
105
|
+
name: string;
|
|
106
|
+
descriptionMale: string;
|
|
107
|
+
descriptionFemale: string;
|
|
108
|
+
visualRepresentation: string;
|
|
109
|
+
virtues: string[];
|
|
110
|
+
}> = [];
|
|
111
|
+
|
|
112
|
+
const entries = response.split(/\n\d+\.\n/).filter(Boolean);
|
|
113
|
+
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const nameMatch = entry.match(/- Name: (.+)/);
|
|
116
|
+
const descriptionMaleMatch = entry.match(
|
|
117
|
+
/- Narrative Description \(Male\): (.+)/
|
|
118
|
+
);
|
|
119
|
+
const descriptionFemaleMatch = entry.match(
|
|
120
|
+
/- Narrative Description \(Female\): (.+)/
|
|
121
|
+
);
|
|
122
|
+
const visualRepresentationMatch = entry.match(
|
|
123
|
+
/- Visual Representation: (.+)/
|
|
124
|
+
);
|
|
125
|
+
const virtuesMatch = entry.match(/- Virtues: (.+)/);
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
nameMatch &&
|
|
129
|
+
descriptionMaleMatch &&
|
|
130
|
+
descriptionFemaleMatch &&
|
|
131
|
+
visualRepresentationMatch &&
|
|
132
|
+
virtuesMatch
|
|
133
|
+
) {
|
|
134
|
+
archetypes.push({
|
|
135
|
+
name: nameMatch[1].trim(),
|
|
136
|
+
descriptionMale: descriptionMaleMatch[1].trim(),
|
|
137
|
+
descriptionFemale: descriptionFemaleMatch[1].trim(),
|
|
138
|
+
visualRepresentation: visualRepresentationMatch[1].trim(),
|
|
139
|
+
virtues: virtuesMatch[1].split(',').map((virtue) => virtue.trim()),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return archetypes;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async generatePrompts(combinationString: string): Promise<void> {
|
|
148
|
+
console.log(
|
|
149
|
+
`Generating Leonardo.ai prompts for archetypes of: ${combinationString}`
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const kvStore = this.context.kvCosmicMirrorArchetypesStore();
|
|
153
|
+
|
|
154
|
+
const kvKeys = [1, 2, 3].map((index) =>
|
|
155
|
+
buildCosmicMirrorArchetypeKVKey(
|
|
156
|
+
'en-us',
|
|
157
|
+
combinationString,
|
|
158
|
+
'male',
|
|
159
|
+
index
|
|
160
|
+
)
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
const archetypeEntries = await Promise.all(
|
|
164
|
+
kvKeys.map((key) => kvStore.get<KVArchetype>(key))
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
if (archetypeEntries.some((entry) => !entry)) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Missing archetype data for combination: ${combinationString}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const messages = this.context
|
|
174
|
+
.buildLLMMessages()
|
|
175
|
+
.generateCosmicMirrorArchetypesLeonardoPrompts(
|
|
176
|
+
archetypeEntries.map((entry) => ({
|
|
177
|
+
name: entry!.name,
|
|
178
|
+
visualDescription: entry!.visualDescription, // Using visual description for prompt
|
|
179
|
+
}))
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const response = await this.context.api().callDeepSeek.single(messages, {});
|
|
183
|
+
if (!response) {
|
|
184
|
+
throw new Error(
|
|
185
|
+
`Failed to generate Leonardo prompts for: ${combinationString}`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const parsedPrompts = this.parseLeonardoPromptResponse(response);
|
|
190
|
+
|
|
191
|
+
await Promise.all(
|
|
192
|
+
parsedPrompts.map(async (promptData, index) => {
|
|
193
|
+
const archetypeIndex = index + 1;
|
|
194
|
+
|
|
195
|
+
const maleKey = buildCosmicMirrorArchetypeKVKey(
|
|
196
|
+
'en-us',
|
|
197
|
+
combinationString,
|
|
198
|
+
'male',
|
|
199
|
+
archetypeIndex
|
|
200
|
+
);
|
|
201
|
+
const femaleKey = buildCosmicMirrorArchetypeKVKey(
|
|
202
|
+
'en-us',
|
|
203
|
+
combinationString,
|
|
204
|
+
'female',
|
|
205
|
+
archetypeIndex
|
|
206
|
+
);
|
|
207
|
+
const nonBinaryKey = buildCosmicMirrorArchetypeKVKey(
|
|
208
|
+
'en-us',
|
|
209
|
+
combinationString,
|
|
210
|
+
'non-binary',
|
|
211
|
+
archetypeIndex
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const updateKV = async (key: string, updatedPrompt: string) => {
|
|
215
|
+
const existingEntry = await kvStore.get<KVArchetype>(key);
|
|
216
|
+
if (existingEntry) {
|
|
217
|
+
await kvStore.put(
|
|
218
|
+
key,
|
|
219
|
+
JSON.stringify({
|
|
220
|
+
...existingEntry,
|
|
221
|
+
leonardoPrompt: updatedPrompt,
|
|
222
|
+
})
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
await Promise.all([
|
|
228
|
+
updateKV(maleKey, promptData.malePrompt),
|
|
229
|
+
updateKV(femaleKey, promptData.femalePrompt),
|
|
230
|
+
updateKV(nonBinaryKey, promptData.nonBinaryPrompt),
|
|
231
|
+
]);
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
console.log(
|
|
236
|
+
`Leonardo prompts stored for archetypes of: ${combinationString}`
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
private parseLeonardoPromptResponse(response: string): Array<{
|
|
241
|
+
malePrompt: string;
|
|
242
|
+
femalePrompt: string;
|
|
243
|
+
nonBinaryPrompt: string;
|
|
244
|
+
}> {
|
|
245
|
+
console.log('Parsing Leonardo prompt response from ChatGPT');
|
|
246
|
+
|
|
247
|
+
const parsedPrompts: Array<{
|
|
248
|
+
malePrompt: string;
|
|
249
|
+
femalePrompt: string;
|
|
250
|
+
nonBinaryPrompt: string;
|
|
251
|
+
}> = [];
|
|
252
|
+
|
|
253
|
+
const entries = response.split(/\n\d+\.\w{1,2}\n/).filter(Boolean);
|
|
254
|
+
|
|
255
|
+
for (let i = 0; i < entries.length; i += 3) {
|
|
256
|
+
const malePrompt = entries[i]?.trim();
|
|
257
|
+
const femalePrompt = entries[i + 1]?.trim();
|
|
258
|
+
const nonBinaryPrompt = entries[i + 2]?.trim();
|
|
259
|
+
|
|
260
|
+
if (malePrompt && femalePrompt && nonBinaryPrompt) {
|
|
261
|
+
parsedPrompts.push({ malePrompt, femalePrompt, nonBinaryPrompt });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return parsedPrompts;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async generateImages(combinationString: string): Promise<void> {
|
|
269
|
+
const kvBaseKey = `archetypes:${combinationString}`;
|
|
270
|
+
console.log(
|
|
271
|
+
`Generating images for archetypes of combination: ${combinationString}`
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
await Promise.all(
|
|
275
|
+
[1, 2, 3].map(async (index) => {
|
|
276
|
+
const kvKey = `${kvBaseKey}:${index}`;
|
|
277
|
+
const archetype = await this.context
|
|
278
|
+
.kvCosmicMirrorArchetypesStore()
|
|
279
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
280
|
+
if (!archetype || !archetype.leonardoPrompt) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Missing Leonardo prompt for archetype ${index} of combination: ${combinationString}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
// Add image generation logic
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { inject, injectable } from 'inversify';
|
|
2
2
|
import 'reflect-metadata';
|
|
3
|
+
import { Languages } from '../../types';
|
|
3
4
|
import { KVConcept, sizes } from '../../types/scopes/legacy';
|
|
5
|
+
import { buildConceptKVKey } from '../../utils/KVKeysBuilders';
|
|
4
6
|
import { AppContext } from '../base/AppContext';
|
|
5
7
|
|
|
6
8
|
@injectable()
|
|
@@ -11,12 +13,13 @@ export class ConceptService {
|
|
|
11
13
|
* Generate basic info for a concept: name, description, and poem.
|
|
12
14
|
*/
|
|
13
15
|
async generateBasicInfo(
|
|
16
|
+
language: Languages,
|
|
14
17
|
conceptSlug: string,
|
|
15
18
|
combinationString: string
|
|
16
19
|
): Promise<void> {
|
|
17
|
-
const kvKey =
|
|
20
|
+
const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
|
|
18
21
|
console.log(
|
|
19
|
-
`Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
22
|
+
`Generating basic info for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
20
23
|
);
|
|
21
24
|
|
|
22
25
|
const messages = this.context.buildLLMMessages().generateConceptBasicInfo({
|
|
@@ -33,13 +36,12 @@ export class ConceptService {
|
|
|
33
36
|
|
|
34
37
|
const { name, description, poem } = this.parseBasicInfoResponse(response);
|
|
35
38
|
|
|
36
|
-
// Save basic info to KV
|
|
37
39
|
const concept = await this.getKVConcept(kvKey);
|
|
38
40
|
Object.assign(concept, { name, description, poem, status: 'idle' });
|
|
39
41
|
|
|
40
42
|
await this.context.kvConceptsStore().put(kvKey, JSON.stringify(concept));
|
|
41
43
|
console.log(
|
|
42
|
-
`Basic info stored for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
44
|
+
`Basic info stored for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
43
45
|
);
|
|
44
46
|
}
|
|
45
47
|
|
|
@@ -68,12 +70,13 @@ export class ConceptService {
|
|
|
68
70
|
* Generate the Leonardo prompt for a concept.
|
|
69
71
|
*/
|
|
70
72
|
async generatePrompt(
|
|
73
|
+
language: Languages,
|
|
71
74
|
conceptSlug: string,
|
|
72
75
|
combinationString: string
|
|
73
76
|
): Promise<void> {
|
|
74
|
-
const kvKey =
|
|
77
|
+
const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
|
|
75
78
|
console.log(
|
|
76
|
-
`Generating Leonardo prompt for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
79
|
+
`Generating Leonardo prompt for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
const concept = await this.getKVConcept(kvKey);
|
|
@@ -100,7 +103,7 @@ export class ConceptService {
|
|
|
100
103
|
concept.leonardoPrompt = response.trim();
|
|
101
104
|
await this.context.kvConceptsStore().put(kvKey, JSON.stringify(concept));
|
|
102
105
|
console.log(
|
|
103
|
-
`Leonardo prompt stored for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
106
|
+
`Leonardo prompt stored for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
104
107
|
);
|
|
105
108
|
}
|
|
106
109
|
|
|
@@ -108,12 +111,13 @@ export class ConceptService {
|
|
|
108
111
|
* Generate additional content for a concept.
|
|
109
112
|
*/
|
|
110
113
|
async generateContent(
|
|
114
|
+
language: Languages,
|
|
111
115
|
conceptSlug: string,
|
|
112
116
|
combinationString: string
|
|
113
117
|
): Promise<void> {
|
|
114
|
-
const kvKey =
|
|
118
|
+
const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
|
|
115
119
|
console.log(
|
|
116
|
-
`Generating additional content for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
120
|
+
`Generating additional content for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
117
121
|
);
|
|
118
122
|
|
|
119
123
|
const concept = await this.getKVConcept(kvKey);
|
|
@@ -139,7 +143,7 @@ export class ConceptService {
|
|
|
139
143
|
concept.content = response.trim();
|
|
140
144
|
await this.context.kvConceptsStore().put(kvKey, JSON.stringify(concept));
|
|
141
145
|
console.log(
|
|
142
|
-
`Content stored for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
146
|
+
`Content stored for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
143
147
|
);
|
|
144
148
|
}
|
|
145
149
|
|
|
@@ -147,12 +151,13 @@ export class ConceptService {
|
|
|
147
151
|
* Queue image generation for a concept.
|
|
148
152
|
*/
|
|
149
153
|
async generateImages(
|
|
154
|
+
language: Languages,
|
|
150
155
|
conceptSlug: string,
|
|
151
156
|
combinationString: string
|
|
152
157
|
): Promise<void> {
|
|
153
|
-
const kvKey =
|
|
158
|
+
const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
|
|
154
159
|
console.log(
|
|
155
|
-
`Queuing image generation for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
160
|
+
`Queuing image generation for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
156
161
|
);
|
|
157
162
|
|
|
158
163
|
const concept = await this.getKVConcept(kvKey);
|
|
@@ -171,7 +176,7 @@ export class ConceptService {
|
|
|
171
176
|
});
|
|
172
177
|
|
|
173
178
|
console.log(
|
|
174
|
-
`Post images queued for concept: ${conceptSlug}, combination: ${combinationString}`
|
|
179
|
+
`Post images queued for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
175
180
|
);
|
|
176
181
|
}
|
|
177
182
|
|
|
@@ -182,6 +187,7 @@ export class ConceptService {
|
|
|
182
187
|
const existingData = await this.context
|
|
183
188
|
.kvConceptsStore()
|
|
184
189
|
.get<KVConcept>(kvKey, 'json');
|
|
190
|
+
|
|
185
191
|
if (existingData) {
|
|
186
192
|
return existingData;
|
|
187
193
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { inject, injectable } from 'inversify';
|
|
2
|
+
import 'reflect-metadata';
|
|
3
|
+
import { schema } from '../..';
|
|
4
|
+
import { Gender, VALID_GENDERS_ARRAY } from '../../types';
|
|
5
|
+
import {
|
|
6
|
+
KVArchetype,
|
|
7
|
+
LeonardoGenerateImageResponse,
|
|
8
|
+
sizes,
|
|
9
|
+
} from '../../types/scopes/legacy';
|
|
10
|
+
import { buildCosmicMirrorArchetypeKVKey } from '../../utils/KVKeysBuilders';
|
|
11
|
+
import { AppContext } from '../base/AppContext';
|
|
12
|
+
|
|
13
|
+
@injectable()
|
|
14
|
+
export class LeonardoService {
|
|
15
|
+
constructor(@inject(AppContext) private context: AppContext) {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Processes and generates missing Leonardo prompts for archetypes.
|
|
19
|
+
*/
|
|
20
|
+
async processArchetypesPrompts(crown: string): Promise<void> {
|
|
21
|
+
console.log(`Processing Leonardo prompts for crown: ${crown}`);
|
|
22
|
+
|
|
23
|
+
const promptsToGenerate: Array<{
|
|
24
|
+
kvKey: string;
|
|
25
|
+
name: string;
|
|
26
|
+
visualDescription: string;
|
|
27
|
+
}> = [];
|
|
28
|
+
|
|
29
|
+
// Fetch archetypes that need prompts
|
|
30
|
+
for (const gender of VALID_GENDERS_ARRAY) {
|
|
31
|
+
for (let index = 1; index <= 3; index++) {
|
|
32
|
+
const kvKey = buildCosmicMirrorArchetypeKVKey(
|
|
33
|
+
'en-us',
|
|
34
|
+
crown,
|
|
35
|
+
gender,
|
|
36
|
+
index
|
|
37
|
+
);
|
|
38
|
+
console.log(`Fetching archetype from KV: ${kvKey}`);
|
|
39
|
+
|
|
40
|
+
const kvData = await this.context
|
|
41
|
+
.kvCosmicMirrorArchetypesStore()
|
|
42
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
43
|
+
if (kvData && !kvData.leonardoPrompt) {
|
|
44
|
+
promptsToGenerate.push({
|
|
45
|
+
kvKey,
|
|
46
|
+
name: kvData.name,
|
|
47
|
+
visualDescription: kvData.visualDescription,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (promptsToGenerate.length === 0) {
|
|
54
|
+
console.log('No archetype prompts need to be generated.');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
console.log('Archetypes requiring prompt generation:', promptsToGenerate);
|
|
59
|
+
|
|
60
|
+
// Generate prompts
|
|
61
|
+
const archetypes = promptsToGenerate.map(({ name, visualDescription }) => ({
|
|
62
|
+
name,
|
|
63
|
+
visualDescription,
|
|
64
|
+
}));
|
|
65
|
+
const leonardoPrompts =
|
|
66
|
+
await this.generateCosmicMirrorArchetypesLeonardoPrompts(archetypes);
|
|
67
|
+
|
|
68
|
+
if (leonardoPrompts.length !== archetypes.length) {
|
|
69
|
+
throw new Error('Mismatch between archetypes and generated prompts.');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Update KV with generated prompts
|
|
73
|
+
for (const [index, promptSet] of leonardoPrompts.entries()) {
|
|
74
|
+
const { kvKey } = promptsToGenerate[index];
|
|
75
|
+
console.log(`Updating KV with prompts for archetype: ${kvKey}`);
|
|
76
|
+
|
|
77
|
+
const kvData = await this.context
|
|
78
|
+
.kvCosmicMirrorArchetypesStore()
|
|
79
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
80
|
+
if (!kvData) {
|
|
81
|
+
console.warn(`KV data not found for key: ${kvKey}. Skipping update.`);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
kvData.leonardoPrompt = promptSet;
|
|
86
|
+
await this.context
|
|
87
|
+
.kvCosmicMirrorArchetypesStore()
|
|
88
|
+
.put(kvKey, JSON.stringify(kvData));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
console.log(`Completed prompt processing for crown: ${crown}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Queues image generation for archetypes if no images exist.
|
|
96
|
+
*/
|
|
97
|
+
async queueImagesForArchetypes(crown: string, gender: Gender): Promise<void> {
|
|
98
|
+
console.log(
|
|
99
|
+
`Queuing image generation for crown: ${crown}, gender: ${gender}`
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
for (let index = 1; index <= 3; index++) {
|
|
103
|
+
const kvKey = buildCosmicMirrorArchetypeKVKey(
|
|
104
|
+
'en-us',
|
|
105
|
+
crown,
|
|
106
|
+
gender,
|
|
107
|
+
index
|
|
108
|
+
);
|
|
109
|
+
console.info(`Fetching KV for archetype: ${kvKey}`);
|
|
110
|
+
|
|
111
|
+
const kvData = await this.context
|
|
112
|
+
.kvCosmicMirrorArchetypesStore()
|
|
113
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
114
|
+
if (!kvData || kvData.images.length >= 3) {
|
|
115
|
+
console.info(
|
|
116
|
+
`Skipping image generation for index ${index}, images already exist.`
|
|
117
|
+
);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.info(`No images found. Queuing generation for index ${index}...`);
|
|
122
|
+
|
|
123
|
+
const generationResponse = await this.queueImageGeneration(
|
|
124
|
+
kvData.leonardoPrompt
|
|
125
|
+
);
|
|
126
|
+
const generationId = generationResponse.sdGenerationJob.generationId;
|
|
127
|
+
|
|
128
|
+
if (!generationId) {
|
|
129
|
+
throw new Error('Leonardo generation failed to return a valid ID.');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
await this.context.drizzle().insert(schema.generations).values({
|
|
133
|
+
id: generationId,
|
|
134
|
+
archetypeIndex: index,
|
|
135
|
+
conceptCombinationId: null,
|
|
136
|
+
type: 'archetype_image',
|
|
137
|
+
status: 'pending',
|
|
138
|
+
createdAt: new Date(),
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
console.info(
|
|
142
|
+
`Queued generation ${generationId} for archetype index ${index}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Generates Leonardo prompts for archetypes.
|
|
149
|
+
*/
|
|
150
|
+
private async generateCosmicMirrorArchetypesLeonardoPrompts(
|
|
151
|
+
archetypes: Array<{ name: string; visualDescription: string }>
|
|
152
|
+
): Promise<string[]> {
|
|
153
|
+
console.log(`Generating Leonardo prompts for archetypes`);
|
|
154
|
+
|
|
155
|
+
const messages = this.context
|
|
156
|
+
.buildLLMMessages()
|
|
157
|
+
.generateCosmicMirrorArchetypesLeonardoPrompts(archetypes);
|
|
158
|
+
const response = await this.context.api().callDeepSeek.single(messages, {});
|
|
159
|
+
|
|
160
|
+
if (!response) {
|
|
161
|
+
throw new Error('Leonardo prompts not generated');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
console.log('Leonardo Prompts from API -> ', response);
|
|
165
|
+
|
|
166
|
+
return response
|
|
167
|
+
.split('\n')
|
|
168
|
+
.map((prompt) => prompt.trim())
|
|
169
|
+
.filter(Boolean);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Queues an image generation request to Leonardo.
|
|
174
|
+
*/
|
|
175
|
+
private async queueImageGeneration(
|
|
176
|
+
prompt: string
|
|
177
|
+
): Promise<LeonardoGenerateImageResponse> {
|
|
178
|
+
console.log(`Queuing Leonardo image generation...`);
|
|
179
|
+
|
|
180
|
+
const { width, height } = sizes['alchemy']['post4:5'];
|
|
181
|
+
|
|
182
|
+
try {
|
|
183
|
+
const response = await this.context
|
|
184
|
+
.api()
|
|
185
|
+
.callLeonardo.generateImage({ width, height, prompt });
|
|
186
|
+
if (!response) {
|
|
187
|
+
throw new Error('Leonardo image generation failed');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log('Leonardo Image Generation Response:', response);
|
|
191
|
+
return response;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
console.error('Error queuing Leonardo image generation:', error);
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { inject, injectable } from 'inversify';
|
|
2
|
+
import { Gender } from '../../types';
|
|
3
|
+
import { KVArchetype } from '../../types/scopes/legacy';
|
|
4
|
+
import { AppContext } from '../base';
|
|
5
|
+
import { ArchetypeService } from '../services/ArchetypeService';
|
|
6
|
+
import { LeonardoService } from '../services/LeonardoService';
|
|
7
|
+
|
|
8
|
+
@injectable()
|
|
9
|
+
export class ArchetypeWorkflow {
|
|
10
|
+
constructor(
|
|
11
|
+
@inject(AppContext) private context: AppContext,
|
|
12
|
+
@inject(ArchetypeService) private archetypeService: ArchetypeService,
|
|
13
|
+
@inject(LeonardoService) private leonardoService: LeonardoService
|
|
14
|
+
) {}
|
|
15
|
+
|
|
16
|
+
async execute(combinationString: string, gender: Gender) {
|
|
17
|
+
const kvKeyBase = `cosmic-mirror:archetypes:${combinationString}:${gender}`;
|
|
18
|
+
|
|
19
|
+
console.log('Starting ArchetypeWorkflow for:', {
|
|
20
|
+
combinationString,
|
|
21
|
+
gender,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const archetypes = await Promise.all(
|
|
25
|
+
Array.from({ length: 3 }, (_, i) => i + 1).map(async (index) => {
|
|
26
|
+
const kvKey = `${kvKeyBase}:${index}`;
|
|
27
|
+
try {
|
|
28
|
+
console.log(`Fetching archetype from KV: ${kvKey}`);
|
|
29
|
+
return await this.context
|
|
30
|
+
.kvCosmicMirrorArchetypesStore()
|
|
31
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(
|
|
34
|
+
`Error fetching archetype KV for index ${index}:`,
|
|
35
|
+
error
|
|
36
|
+
);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
).then((results) => results.filter((result) => result !== null)); // Filter out nulls
|
|
41
|
+
|
|
42
|
+
const isGenerating = archetypes.some(
|
|
43
|
+
(archetype) => archetype?.status === 'generating'
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (isGenerating) {
|
|
47
|
+
console.log(
|
|
48
|
+
`Archetype images are already being generated for: ${combinationString}, gender: ${gender}`
|
|
49
|
+
);
|
|
50
|
+
return { message: 'Images are being processed, please try again later.' };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const missingOrIncomplete =
|
|
54
|
+
archetypes.length < 3 ||
|
|
55
|
+
archetypes.some((archetype) => archetype?.images.length < 3);
|
|
56
|
+
|
|
57
|
+
if (missingOrIncomplete) {
|
|
58
|
+
console.log(
|
|
59
|
+
`Archetypes missing or incomplete for combination: ${combinationString}, gender: ${gender}. Generating...`
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
await this.archetypeService.generateBasicInfo(combinationString);
|
|
63
|
+
|
|
64
|
+
const updatedArchetypes = await Promise.all(
|
|
65
|
+
Array.from({ length: 3 }, (_, i) => i + 1).map(async (index) => {
|
|
66
|
+
const kvKey = `${kvKeyBase}:${index}`;
|
|
67
|
+
try {
|
|
68
|
+
console.log(`Re-fetching archetype from KV: ${kvKey}`);
|
|
69
|
+
return await this.context
|
|
70
|
+
.kvCosmicMirrorArchetypesStore()
|
|
71
|
+
.get<KVArchetype>(kvKey, 'json');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(
|
|
74
|
+
`Error fetching archetype KV after generation for index ${index}:`,
|
|
75
|
+
error
|
|
76
|
+
);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
})
|
|
80
|
+
).then((results) => results.filter((results) => results != null));
|
|
81
|
+
|
|
82
|
+
archetypes.length = 0;
|
|
83
|
+
archetypes.push(...updatedArchetypes);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const missingPrompts = archetypes.some(
|
|
87
|
+
(archetype) => !archetype?.leonardoPrompt
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
if (missingPrompts) {
|
|
91
|
+
console.log('Generating missing prompts...');
|
|
92
|
+
await this.leonardoService.processArchetypesPrompts(combinationString);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const archetypesNeedingImages = archetypes.filter(
|
|
96
|
+
(archetype) => archetype?.images.length < 3
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (archetypesNeedingImages.length > 0) {
|
|
100
|
+
console.log('Queuing image generation for missing archetypes...');
|
|
101
|
+
try {
|
|
102
|
+
await Promise.all(
|
|
103
|
+
archetypesNeedingImages.map(async (archetype, index) => {
|
|
104
|
+
archetype.status = 'generating';
|
|
105
|
+
const kvKey = `${kvKeyBase}:${index + 1}`;
|
|
106
|
+
await this.context
|
|
107
|
+
.kvCosmicMirrorArchetypesStore()
|
|
108
|
+
.put(kvKey, JSON.stringify(archetype));
|
|
109
|
+
})
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
await this.leonardoService.queueImagesForArchetypes(
|
|
113
|
+
combinationString,
|
|
114
|
+
gender
|
|
115
|
+
);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
console.error('Error queuing image generation:', error);
|
|
118
|
+
|
|
119
|
+
await Promise.all(
|
|
120
|
+
archetypesNeedingImages.map(async (archetype, index) => {
|
|
121
|
+
archetype.status = 'idle';
|
|
122
|
+
const kvKey = `${kvKeyBase}:${index + 1}`;
|
|
123
|
+
await this.context
|
|
124
|
+
.kvCosmicMirrorArchetypesStore()
|
|
125
|
+
.put(kvKey, JSON.stringify(archetype));
|
|
126
|
+
})
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { message: 'Images are being processed, please try again later.' };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
await Promise.all(
|
|
136
|
+
archetypes.map(async (archetype, index) => {
|
|
137
|
+
archetype.status = 'idle';
|
|
138
|
+
const kvKey = `${kvKeyBase}:${index + 1}`;
|
|
139
|
+
await this.context
|
|
140
|
+
.kvCosmicMirrorArchetypesStore()
|
|
141
|
+
.put(kvKey, JSON.stringify(archetype));
|
|
142
|
+
})
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
console.log('Archetypes fully processed and ready:', archetypes);
|
|
146
|
+
return {
|
|
147
|
+
archetypes: archetypes.map((arc) => ({
|
|
148
|
+
name: arc?.name,
|
|
149
|
+
content: arc?.content,
|
|
150
|
+
description: arc?.description,
|
|
151
|
+
virtues: arc?.virtues,
|
|
152
|
+
images: arc?.images,
|
|
153
|
+
})),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -18,24 +18,28 @@ export class ConceptWorkflow {
|
|
|
18
18
|
switch (phase) {
|
|
19
19
|
case 'basic-info':
|
|
20
20
|
await this.conceptService.generateBasicInfo(
|
|
21
|
+
'en-us',
|
|
21
22
|
conceptSlug,
|
|
22
23
|
combinationString
|
|
23
24
|
);
|
|
24
25
|
break;
|
|
25
26
|
case 'content':
|
|
26
27
|
await this.conceptService.generateContent(
|
|
28
|
+
'en-us',
|
|
27
29
|
conceptSlug,
|
|
28
30
|
combinationString
|
|
29
31
|
);
|
|
30
32
|
break;
|
|
31
33
|
case 'leonardo-prompt':
|
|
32
34
|
await this.conceptService.generatePrompt(
|
|
35
|
+
'en-us',
|
|
33
36
|
conceptSlug,
|
|
34
37
|
combinationString
|
|
35
38
|
);
|
|
36
39
|
break;
|
|
37
40
|
case 'images':
|
|
38
41
|
await this.conceptService.generateImages(
|
|
42
|
+
'en-us',
|
|
39
43
|
conceptSlug,
|
|
40
44
|
combinationString
|
|
41
45
|
);
|
package/package.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Gender, Languages } from '../types';
|
|
2
|
+
|
|
3
|
+
export const buildCosmicMirrorArchetypeKVKey = (
|
|
4
|
+
lang: Languages,
|
|
5
|
+
crown: string,
|
|
6
|
+
gender: Gender,
|
|
7
|
+
index: number
|
|
8
|
+
): string => {
|
|
9
|
+
return `cosmic_mirror:${lang}:${crown}:${gender}:${index}`;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const buildConceptKVKey = (
|
|
13
|
+
lang: Languages,
|
|
14
|
+
conceptSlug: string,
|
|
15
|
+
combinationString: string
|
|
16
|
+
): string => {
|
|
17
|
+
return `concepts:${lang}:${conceptSlug}:${combinationString}`;
|
|
18
|
+
};
|
package/utils/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jwtVerify } from 'jose';
|
|
2
|
-
import { AuthCtx, Provider, ProviderInfo } from '../types';
|
|
2
|
+
import { AuthCtx, Gender, Provider, ProviderInfo, VALID_GENDERS_ARRAY } from '../types';
|
|
3
3
|
|
|
4
4
|
export const verifyToken = async (
|
|
5
5
|
c: AuthCtx,
|
|
@@ -48,3 +48,18 @@ export const providers: (c: AuthCtx) => Record<Provider, ProviderInfo> = (
|
|
|
48
48
|
resourceUrl: '',
|
|
49
49
|
},
|
|
50
50
|
});
|
|
51
|
+
|
|
52
|
+
export const GENDER_CODE_MAP: Record<string, Gender> =
|
|
53
|
+
VALID_GENDERS_ARRAY.reduce((map, gender) => {
|
|
54
|
+
const key = gender[0];
|
|
55
|
+
map[key] = gender;
|
|
56
|
+
return map;
|
|
57
|
+
}, {} as Record<string, Gender>);
|
|
58
|
+
|
|
59
|
+
export function createEmptyGenderPrompts(): Record<Gender, string> {
|
|
60
|
+
const emptyPrompts: Record<Gender, string> = {} as Record<Gender, string>;
|
|
61
|
+
Object.values(GENDER_CODE_MAP).forEach((gender) => {
|
|
62
|
+
emptyPrompts[gender] = '';
|
|
63
|
+
});
|
|
64
|
+
return emptyPrompts;
|
|
65
|
+
}
|