@zodic/shared 0.0.76 → 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.
|
@@ -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
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
|
+
}
|