@zodic/shared 0.0.116 → 0.0.118
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/api/index.ts +19 -115
- package/app/services/ConceptService.ts +35 -30
- package/package.json +1 -1
- package/types/scopes/generic.ts +1 -1
- package/types/scopes/legacy.ts +1 -6
- package/utils/initImages.ts +2 -2
package/app/api/index.ts
CHANGED
|
@@ -16,9 +16,7 @@ import {
|
|
|
16
16
|
HouseCuspsReport,
|
|
17
17
|
LeonardoGenerateImageParams,
|
|
18
18
|
LeonardoGenerateImageResponse,
|
|
19
|
-
LeonardoGeneratePresignedUrlParams,
|
|
20
19
|
LeonardoRequestBody,
|
|
21
|
-
LeonardoUploadImageParams,
|
|
22
20
|
NatalHouseCuspReport,
|
|
23
21
|
TimezoneResponse,
|
|
24
22
|
} from '../../types/scopes/legacy';
|
|
@@ -236,13 +234,24 @@ export const Api = (env: BackendBindings) => ({
|
|
|
236
234
|
num_images: quantity,
|
|
237
235
|
};
|
|
238
236
|
|
|
237
|
+
// ✅ Dynamically add `controlNets` based on available settings
|
|
239
238
|
if (controlNets.length > 0) {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
239
|
+
// @ts-expect-error
|
|
240
|
+
body['controlnets'] = controlNets.map((net) => {
|
|
241
|
+
const baseNet = {
|
|
242
|
+
initImageId: net.initImageId,
|
|
243
|
+
initImageType: net.initImageType,
|
|
244
|
+
preprocessorId: net.preprocessorId,
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (net.preprocessorId === 100) {
|
|
248
|
+
return { ...baseNet, strengthType: net.strengthType };
|
|
249
|
+
} else if (net.preprocessorId === 19) {
|
|
250
|
+
return { ...baseNet, weight: net.weight };
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return baseNet;
|
|
254
|
+
});
|
|
246
255
|
}
|
|
247
256
|
|
|
248
257
|
if (initImageId) {
|
|
@@ -259,123 +268,18 @@ export const Api = (env: BackendBindings) => ({
|
|
|
259
268
|
|
|
260
269
|
if (!response.ok) {
|
|
261
270
|
const error = await response.json();
|
|
262
|
-
console.error('Error from Leonardo API:', error);
|
|
271
|
+
console.error('❌ Error from Leonardo API:', error);
|
|
263
272
|
throw new Error(`Leonardo API Error: ${response.status}`);
|
|
264
273
|
}
|
|
265
274
|
|
|
266
275
|
const data = (await response.json()) as LeonardoGenerateImageResponse;
|
|
267
276
|
return data;
|
|
268
277
|
} catch (err: any) {
|
|
269
|
-
console.error('Error calling Leonardo API:', err.message);
|
|
278
|
+
console.error('❌ Error calling Leonardo API:', err.message);
|
|
270
279
|
throw err;
|
|
271
280
|
}
|
|
272
281
|
},
|
|
273
|
-
generatePresignedUrl: async ({
|
|
274
|
-
extension,
|
|
275
|
-
}: LeonardoGeneratePresignedUrlParams): Promise<{
|
|
276
|
-
url: string;
|
|
277
|
-
fields: string;
|
|
278
|
-
id: string;
|
|
279
|
-
key: string;
|
|
280
|
-
}> => {
|
|
281
|
-
console.log('Generating presigned URL with extension:', extension);
|
|
282
|
-
|
|
283
|
-
const endpoint = 'https://cloud.leonardo.ai/api/rest/v1/init-image';
|
|
284
|
-
const headers = {
|
|
285
|
-
Authorization: `Bearer ${env.LEONARDO_API_KEY}`,
|
|
286
|
-
'Content-Type': 'application/json',
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
if (!extension) {
|
|
290
|
-
throw new Error('Invalid MIME type');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const body = JSON.stringify({
|
|
294
|
-
extension,
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
const response = await fetch(endpoint, {
|
|
299
|
-
method: 'POST',
|
|
300
|
-
headers,
|
|
301
|
-
body,
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
if (!response.ok) {
|
|
305
|
-
const error = await response.text();
|
|
306
|
-
console.error('Leonardo API error:', error);
|
|
307
|
-
throw new Error(
|
|
308
|
-
`Presigned URL generation failed: ${response.status}`
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const rawResponse = (await response.json()) as any;
|
|
313
|
-
console.log('Presigned URL response:', rawResponse);
|
|
314
|
-
|
|
315
|
-
if (
|
|
316
|
-
!rawResponse.uploadInitImage ||
|
|
317
|
-
!rawResponse.uploadInitImage.url ||
|
|
318
|
-
!rawResponse.uploadInitImage.fields
|
|
319
|
-
) {
|
|
320
|
-
throw new Error('Invalid presigned URL response');
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return rawResponse.uploadInitImage;
|
|
324
|
-
} catch (error: any) {
|
|
325
|
-
console.error('Error generating presigned URL:', error.message);
|
|
326
|
-
throw error;
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
uploadImage: async ({
|
|
330
|
-
presignedUrl,
|
|
331
|
-
fields,
|
|
332
|
-
file,
|
|
333
|
-
}: LeonardoUploadImageParams) => {
|
|
334
|
-
console.log('Starting image upload to:', presignedUrl);
|
|
335
|
-
|
|
336
|
-
if (!(file instanceof Blob)) {
|
|
337
|
-
throw new Error('Invalid file type for upload');
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
console.log('Parsing fields...');
|
|
342
|
-
const parsedFields = JSON.parse(fields);
|
|
343
|
-
|
|
344
|
-
if (!parsedFields || typeof parsedFields !== 'object') {
|
|
345
|
-
throw new Error('Invalid fields format');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
console.log('Parsed fields:', parsedFields);
|
|
349
|
-
|
|
350
|
-
const formData = new FormData();
|
|
351
|
-
|
|
352
|
-
Object.entries(parsedFields).forEach(([key, value]) => {
|
|
353
|
-
formData.append(key, value as string);
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
formData.append('file', file);
|
|
357
|
-
|
|
358
|
-
console.log('Uploading with FormData:', Array.from(formData.entries()));
|
|
359
|
-
|
|
360
|
-
const response = await fetch(presignedUrl, {
|
|
361
|
-
method: 'POST',
|
|
362
|
-
body: formData,
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
if (!response.ok) {
|
|
366
|
-
const errorDetails = await response.text();
|
|
367
|
-
console.error('Upload failed:', errorDetails);
|
|
368
|
-
throw new Error(`Image upload failed: ${response.status}`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
console.log('Image uploaded successfully');
|
|
372
|
-
} catch (error: any) {
|
|
373
|
-
console.error('Error during uploadImage:', error.message);
|
|
374
|
-
throw error;
|
|
375
|
-
}
|
|
376
|
-
},
|
|
377
282
|
},
|
|
378
|
-
|
|
379
283
|
callImageDescriber: async (imageUrl: string): Promise<string> => {
|
|
380
284
|
const mimeType = 'image/png';
|
|
381
285
|
const endpoint =
|
|
@@ -168,19 +168,19 @@ export class ConceptService {
|
|
|
168
168
|
const drizzle = this.context.drizzle();
|
|
169
169
|
const { width, height } = sizes['alchemy']['post4:5'];
|
|
170
170
|
const { generations, conceptCombinations, concepts } = schema;
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
const kvKey = buildConceptKVKey(language, conceptSlug, combinationString);
|
|
173
173
|
console.log(
|
|
174
174
|
`🚀 Queuing image generation for concept: ${conceptSlug}, combination: ${combinationString}, language: ${language}`
|
|
175
175
|
);
|
|
176
|
-
|
|
176
|
+
|
|
177
177
|
const concept = await this.getKVConcept(kvKey);
|
|
178
178
|
if (!concept.leonardoPrompt) {
|
|
179
179
|
throw new Error(
|
|
180
180
|
`❌ Leonardo prompt must be populated before generating images for concept: ${conceptSlug}`
|
|
181
181
|
);
|
|
182
182
|
}
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
const conceptRecord = await drizzle
|
|
185
185
|
.select({
|
|
186
186
|
id: concepts.id,
|
|
@@ -191,29 +191,29 @@ export class ConceptService {
|
|
|
191
191
|
.from(concepts)
|
|
192
192
|
.where(eq(concepts.slug, conceptSlug))
|
|
193
193
|
.limit(1);
|
|
194
|
-
|
|
194
|
+
|
|
195
195
|
if (conceptRecord.length === 0) {
|
|
196
196
|
throw new Error(`❌ No concept found for slug: ${conceptSlug}`);
|
|
197
197
|
}
|
|
198
|
-
|
|
198
|
+
|
|
199
199
|
const { id: conceptId, planet1, planet2, planet3 } = conceptRecord[0];
|
|
200
200
|
console.log(
|
|
201
201
|
`✅ Retrieved conceptId: ${conceptId} for slug: ${conceptSlug}`
|
|
202
202
|
);
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
const [planet1Sign, planet2Sign, planet3Sign] =
|
|
205
205
|
combinationString.split('-');
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
if (!planet1Sign || !planet2Sign || !planet3Sign) {
|
|
208
208
|
throw new Error(
|
|
209
209
|
`❌ Invalid combinationString: ${combinationString} (Expected format: sign1-sign2-[sign3])`
|
|
210
210
|
);
|
|
211
211
|
}
|
|
212
|
-
|
|
212
|
+
|
|
213
213
|
console.log(
|
|
214
214
|
`🔹 Extracted planet signs: ${planet1} -> ${planet1Sign}, ${planet2} -> ${planet2Sign}, ${planet3} -> ${planet3Sign}`
|
|
215
215
|
);
|
|
216
|
-
|
|
216
|
+
|
|
217
217
|
let [conceptCombination] = await drizzle
|
|
218
218
|
.select({ id: conceptCombinations.id })
|
|
219
219
|
.from(conceptCombinations)
|
|
@@ -224,12 +224,12 @@ export class ConceptService {
|
|
|
224
224
|
)
|
|
225
225
|
)
|
|
226
226
|
.limit(1);
|
|
227
|
-
|
|
227
|
+
|
|
228
228
|
if (!conceptCombination) {
|
|
229
229
|
console.log(
|
|
230
230
|
`🔍 No existing conceptCombination found. Creating new entry for ${conceptSlug}:${combinationString}`
|
|
231
231
|
);
|
|
232
|
-
|
|
232
|
+
|
|
233
233
|
const [insertedCombination] = await drizzle
|
|
234
234
|
.insert(conceptCombinations)
|
|
235
235
|
.values({
|
|
@@ -241,31 +241,36 @@ export class ConceptService {
|
|
|
241
241
|
planet3Sign,
|
|
242
242
|
})
|
|
243
243
|
.returning({ id: conceptCombinations.id });
|
|
244
|
-
|
|
244
|
+
|
|
245
245
|
conceptCombination = insertedCombination;
|
|
246
246
|
}
|
|
247
|
-
|
|
247
|
+
|
|
248
248
|
const conceptCombinationId = conceptCombination.id;
|
|
249
249
|
console.log(
|
|
250
250
|
`✅ Using conceptCombinationId: ${conceptCombinationId} for ${conceptSlug}:${combinationString}`
|
|
251
251
|
);
|
|
252
|
-
|
|
252
|
+
|
|
253
253
|
console.log(`🎨 Requesting Leonardo AI image generation...`);
|
|
254
|
-
|
|
254
|
+
|
|
255
255
|
const initImage = leonardoInitImages.concepts[conceptSlug];
|
|
256
|
-
const controlNets = initImage.imageId
|
|
256
|
+
const controlNets: ControlNetConfig[] = initImage.imageId
|
|
257
257
|
? [
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
258
|
+
initImage.preprocessorId === 100
|
|
259
|
+
? {
|
|
260
|
+
initImageId: initImage.imageId,
|
|
261
|
+
initImageType: 'UPLOADED',
|
|
262
|
+
preprocessorId: 100,
|
|
263
|
+
strengthType: initImage.strengthType!,
|
|
264
|
+
}
|
|
265
|
+
: {
|
|
266
|
+
initImageId: initImage.imageId,
|
|
267
|
+
initImageType: 'UPLOADED',
|
|
268
|
+
preprocessorId: 19,
|
|
269
|
+
weight: initImage.weight!,
|
|
270
|
+
},
|
|
266
271
|
]
|
|
267
272
|
: [];
|
|
268
|
-
|
|
273
|
+
|
|
269
274
|
const leonardoResponse = await this.context
|
|
270
275
|
.api()
|
|
271
276
|
.callLeonardo.generateImage({
|
|
@@ -275,16 +280,16 @@ export class ConceptService {
|
|
|
275
280
|
...(controlNets.length > 0 ? { controlNets } : {}),
|
|
276
281
|
negPrompt: 'person, hands, face, body parts, people, animals, fingers',
|
|
277
282
|
});
|
|
278
|
-
|
|
283
|
+
|
|
279
284
|
const generationId = leonardoResponse?.sdGenerationJob?.generationId;
|
|
280
285
|
if (!generationId) {
|
|
281
286
|
throw new Error(
|
|
282
287
|
`❌ Failed to retrieve generationId from Leonardo response`
|
|
283
288
|
);
|
|
284
289
|
}
|
|
285
|
-
|
|
290
|
+
|
|
286
291
|
console.log(`✅ Leonardo Generation ID received: ${generationId}`);
|
|
287
|
-
|
|
292
|
+
|
|
288
293
|
await drizzle.insert(generations).values({
|
|
289
294
|
id: generationId,
|
|
290
295
|
conceptCombinationId,
|
|
@@ -292,11 +297,11 @@ export class ConceptService {
|
|
|
292
297
|
status: 'pending',
|
|
293
298
|
createdAt: new Date(),
|
|
294
299
|
});
|
|
295
|
-
|
|
300
|
+
|
|
296
301
|
console.log(
|
|
297
302
|
`📝 Generation record created: ${generationId} for ${conceptSlug}:${combinationString}`
|
|
298
303
|
);
|
|
299
|
-
|
|
304
|
+
|
|
300
305
|
console.log(
|
|
301
306
|
`🎨 Leonardo AI image generation triggered for ${conceptSlug}:${combinationString}, tracking ID: ${generationId}`
|
|
302
307
|
);
|
package/package.json
CHANGED
package/types/scopes/generic.ts
CHANGED
package/types/scopes/legacy.ts
CHANGED
|
@@ -157,12 +157,7 @@ export interface LeonardoRequestBody {
|
|
|
157
157
|
modelId: string;
|
|
158
158
|
presetStyle: string;
|
|
159
159
|
alchemy: boolean;
|
|
160
|
-
controlnets?: Array<
|
|
161
|
-
initImageId: string;
|
|
162
|
-
initImageType: string;
|
|
163
|
-
preprocessorId: number;
|
|
164
|
-
strengthType: string;
|
|
165
|
-
}>;
|
|
160
|
+
controlnets?: Array<ControlNetConfig>;
|
|
166
161
|
init_generation_image_id?: string;
|
|
167
162
|
init_strength?: number;
|
|
168
163
|
}
|
package/utils/initImages.ts
CHANGED
|
@@ -29,7 +29,7 @@ export const leonardoInitImages: LeonardoInitImages = {
|
|
|
29
29
|
imageUrl:
|
|
30
30
|
'https://cdn.leonardo.ai/users/b117a933-e5c9-45b2-96aa-4b619c2d74ba/initImages/c489e496-00c4-4958-8bcd-4460a43a43bf.jpg',
|
|
31
31
|
preprocessorId: 19,
|
|
32
|
-
weight:
|
|
32
|
+
weight: 0.3,
|
|
33
33
|
},
|
|
34
34
|
ring: {
|
|
35
35
|
imageId: null,
|
|
@@ -52,7 +52,7 @@ type ControlNetSettings =
|
|
|
52
52
|
imageId: string;
|
|
53
53
|
imageUrl: string;
|
|
54
54
|
preprocessorId: 19;
|
|
55
|
-
weight:
|
|
55
|
+
weight: number;
|
|
56
56
|
strengthType?: null;
|
|
57
57
|
}
|
|
58
58
|
| {
|