@zodic/shared 0.0.315 → 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.
- package/app/api/index.ts +114 -16
- package/app/services/ArchetypeService.ts +738 -1244
- package/app/services/LeonardoService.ts +187 -288
- package/app/workflow/ArchetypeWorkflow.ts +40 -558
- package/package.json +1 -1
package/app/api/index.ts
CHANGED
|
@@ -46,20 +46,20 @@ export const Api = (env: BackendBindings) => ({
|
|
|
46
46
|
messages,
|
|
47
47
|
...options,
|
|
48
48
|
});
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
if (!response.choices[0].message.content) {
|
|
51
51
|
throw new Error('Content is null');
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
|
|
54
54
|
// ✅ Extract API usage data
|
|
55
55
|
const { usage } = response;
|
|
56
56
|
if (usage) {
|
|
57
57
|
console.log(`📊 API Usage: Tokens - ${usage.total_tokens}`);
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
if (env.KV_API_USAGE) {
|
|
60
60
|
// ✅ Check how many usage logs exist
|
|
61
61
|
const { keys } = await env.KV_API_USAGE.list({ prefix: 'usage:' });
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
if (keys.length < 10) {
|
|
64
64
|
// ✅ Store new entry ONLY if there are less than 10
|
|
65
65
|
const timestamp = new Date().toISOString();
|
|
@@ -70,22 +70,27 @@ export const Api = (env: BackendBindings) => ({
|
|
|
70
70
|
completion_tokens: usage.completion_tokens,
|
|
71
71
|
timestamp,
|
|
72
72
|
};
|
|
73
|
-
|
|
74
|
-
await env.KV_API_USAGE.put(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
73
|
+
|
|
74
|
+
await env.KV_API_USAGE.put(
|
|
75
|
+
`usage:${timestamp}`,
|
|
76
|
+
JSON.stringify(logEntry),
|
|
77
|
+
{
|
|
78
|
+
expirationTtl: 60 * 60 * 24 * 7, // ✅ Store for 7 days
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
78
82
|
console.log(`✅ Logged API usage (Entry ${keys.length + 1}/10)`);
|
|
79
83
|
} else {
|
|
80
|
-
console.log(
|
|
84
|
+
console.log(
|
|
85
|
+
`⏳ API usage logging skipped: 10 records already exist.`
|
|
86
|
+
);
|
|
81
87
|
}
|
|
82
88
|
}
|
|
83
89
|
} else {
|
|
84
90
|
console.warn('⚠️ API Usage Data Missing');
|
|
85
91
|
}
|
|
86
|
-
|
|
92
|
+
|
|
87
93
|
return response.choices[0].message.content.trim();
|
|
88
|
-
|
|
89
94
|
} catch (err: any) {
|
|
90
95
|
console.error('❌ Error calling Together API:', err.message);
|
|
91
96
|
throw err;
|
|
@@ -263,9 +268,9 @@ export const Api = (env: BackendBindings) => ({
|
|
|
263
268
|
prompt,
|
|
264
269
|
width,
|
|
265
270
|
height,
|
|
266
|
-
controlNets = [],
|
|
267
|
-
initImageId = null,
|
|
268
|
-
initStrength = 0.2,
|
|
271
|
+
controlNets = [],
|
|
272
|
+
initImageId = null,
|
|
273
|
+
initStrength = 0.2,
|
|
269
274
|
quantity = 3,
|
|
270
275
|
negPrompt = null,
|
|
271
276
|
}: LeonardoGenerateImageParams & {
|
|
@@ -297,7 +302,6 @@ export const Api = (env: BackendBindings) => ({
|
|
|
297
302
|
num_images: quantity,
|
|
298
303
|
};
|
|
299
304
|
|
|
300
|
-
// ✅ Dynamically add `controlNets` based on available settings
|
|
301
305
|
if (controlNets.length > 0) {
|
|
302
306
|
// @ts-expect-error
|
|
303
307
|
body['controlnets'] = controlNets.map((net) => {
|
|
@@ -342,6 +346,100 @@ export const Api = (env: BackendBindings) => ({
|
|
|
342
346
|
throw err;
|
|
343
347
|
}
|
|
344
348
|
},
|
|
349
|
+
|
|
350
|
+
generatePresignedUrl: async (): Promise<{
|
|
351
|
+
id: string;
|
|
352
|
+
fields: string;
|
|
353
|
+
key: string;
|
|
354
|
+
url: string;
|
|
355
|
+
}> => {
|
|
356
|
+
const endpoint = 'https://cloud.leonardo.ai/api/rest/v1/init-image';
|
|
357
|
+
const headers = {
|
|
358
|
+
Authorization: `Bearer ${env.LEONARDO_API_KEY}`,
|
|
359
|
+
'Content-Type': 'application/json',
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
const response = await fetch(endpoint, {
|
|
364
|
+
method: 'POST',
|
|
365
|
+
headers,
|
|
366
|
+
body: JSON.stringify({}),
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
if (!response.ok) {
|
|
370
|
+
const error = await response.json();
|
|
371
|
+
console.error(
|
|
372
|
+
'❌ Error generating presigned URL from Leonardo API:',
|
|
373
|
+
error
|
|
374
|
+
);
|
|
375
|
+
throw new Error(`Leonardo API Error: ${response.status}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const data = await response.json() as any;
|
|
379
|
+
const result = data.uploadInitImage;
|
|
380
|
+
|
|
381
|
+
if (
|
|
382
|
+
!result ||
|
|
383
|
+
!result.id ||
|
|
384
|
+
!result.url ||
|
|
385
|
+
!result.fields ||
|
|
386
|
+
!result.key
|
|
387
|
+
) {
|
|
388
|
+
console.error('❌ Invalid response from Leonardo API:', data);
|
|
389
|
+
throw new Error('Invalid response structure from Leonardo API');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
id: result.id,
|
|
394
|
+
fields: result.fields,
|
|
395
|
+
key: result.key,
|
|
396
|
+
url: result.url,
|
|
397
|
+
};
|
|
398
|
+
} catch (err: any) {
|
|
399
|
+
console.error('❌ Error generating presigned URL:', err.message);
|
|
400
|
+
throw err;
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
uploadImageToPresignedUrl: async (
|
|
405
|
+
file: File,
|
|
406
|
+
presignedResponse: { fields: string; url: string }
|
|
407
|
+
): Promise<void> => {
|
|
408
|
+
const rawFields = presignedResponse.fields;
|
|
409
|
+
const fields = JSON.parse(rawFields);
|
|
410
|
+
const url = presignedResponse.url;
|
|
411
|
+
|
|
412
|
+
const formData = new FormData();
|
|
413
|
+
|
|
414
|
+
// Append all fields from the presigned response
|
|
415
|
+
Object.entries(fields).forEach(([key, value]) => {
|
|
416
|
+
formData.append(key, value as string);
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Append the file as the last field, as required by Leonardo.ai
|
|
420
|
+
formData.append('file', file);
|
|
421
|
+
|
|
422
|
+
try {
|
|
423
|
+
const response = await fetch(url, {
|
|
424
|
+
method: 'POST',
|
|
425
|
+
body: formData,
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
if (!response.ok) {
|
|
429
|
+
const errorText = await response.text();
|
|
430
|
+
console.error(
|
|
431
|
+
'❌ Error uploading image to presigned URL:',
|
|
432
|
+
errorText
|
|
433
|
+
);
|
|
434
|
+
throw new Error(`Failed to upload image: ${response.status}`);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
console.log('✅ Successfully uploaded image to Leonardo.ai');
|
|
438
|
+
} catch (err: any) {
|
|
439
|
+
console.error('❌ Error uploading image:', err.message);
|
|
440
|
+
throw err;
|
|
441
|
+
}
|
|
442
|
+
},
|
|
345
443
|
},
|
|
346
444
|
callImageDescriber: async (imageUrl: string): Promise<string> => {
|
|
347
445
|
const mimeType = 'image/png';
|