@zodic/shared 0.0.338 → 0.0.340
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 +82 -29
- package/app/services/index.ts +1 -2
- package/package.json +1 -1
- package/app/services/ArtifactService.ts +0 -104
package/app/api/index.ts
CHANGED
|
@@ -785,43 +785,96 @@ export const Api = (env: BackendBindings) => ({
|
|
|
785
785
|
Authorization: `Bearer ${env.PIAPI_API_KEY}`,
|
|
786
786
|
'Content-Type': 'application/json',
|
|
787
787
|
};
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
788
|
+
|
|
789
|
+
// Validate image URLs before making the request
|
|
790
|
+
const validateImageUrl = async (url: string, label: string): Promise<void> => {
|
|
791
|
+
try {
|
|
792
|
+
const response = await fetch(url, { method: 'HEAD' });
|
|
793
|
+
if (!response.ok) {
|
|
794
|
+
throw new Error(`${label} is inaccessible: ${response.status} ${response.statusText}`);
|
|
795
|
+
}
|
|
796
|
+
const contentType = response.headers.get('Content-Type');
|
|
797
|
+
if (!contentType || !contentType.startsWith('image/')) {
|
|
798
|
+
throw new Error(`${label} is not a valid image: Content-Type is ${contentType}`);
|
|
799
|
+
}
|
|
800
|
+
} catch (err: any) {
|
|
801
|
+
console.error(`Error validating ${label}:`, err.message);
|
|
802
|
+
throw new Error(`Invalid ${label}: ${err.message}`);
|
|
803
|
+
}
|
|
804
|
+
};
|
|
805
|
+
|
|
805
806
|
try {
|
|
807
|
+
// Validate image URLs
|
|
808
|
+
await validateImageUrl(sourceImageUrl, 'Source image URL');
|
|
809
|
+
await validateImageUrl(targetImageUrl, 'Target image URL');
|
|
810
|
+
|
|
811
|
+
const body = JSON.stringify({
|
|
812
|
+
model: 'Qubico/image-toolkit',
|
|
813
|
+
type: 'faceswap',
|
|
814
|
+
input: {
|
|
815
|
+
source_image_url: sourceImageUrl,
|
|
816
|
+
target_image_url: targetImageUrl,
|
|
817
|
+
},
|
|
818
|
+
config: {
|
|
819
|
+
webhook_config: {
|
|
820
|
+
endpoint:
|
|
821
|
+
'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
|
|
822
|
+
// secret: '',
|
|
823
|
+
},
|
|
824
|
+
},
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
console.log('Sending FaceSwap request:', { sourceImageUrl, targetImageUrl });
|
|
828
|
+
|
|
806
829
|
const response = await fetch(endpoint, {
|
|
807
830
|
method: 'POST',
|
|
808
831
|
headers,
|
|
809
832
|
body,
|
|
810
833
|
});
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
834
|
+
|
|
835
|
+
// Log the HTTP status and headers for debugging
|
|
836
|
+
console.log('PiAPI FaceSwap Response Status:', response.status);
|
|
837
|
+
console.log('PiAPI FaceSwap Response Headers:', [...response.headers.entries()]);
|
|
838
|
+
|
|
839
|
+
// Read the response body as text first to inspect it
|
|
840
|
+
const responseText = await response.text();
|
|
841
|
+
console.log('PiAPI FaceSwap Raw Response Body:', responseText);
|
|
842
|
+
|
|
843
|
+
// Check for the expected 201 Created status
|
|
844
|
+
if (response.status !== 201) {
|
|
845
|
+
let errorData;
|
|
846
|
+
try {
|
|
847
|
+
errorData = JSON.parse(responseText);
|
|
848
|
+
} catch {
|
|
849
|
+
errorData = { message: responseText || 'Unknown error' };
|
|
850
|
+
}
|
|
851
|
+
console.error('Error from PiAPI FaceSwap:', errorData);
|
|
852
|
+
throw new Error(`PiAPI FaceSwap Error: ${response.status} - ${errorData.message || 'Unknown error'}`);
|
|
816
853
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
854
|
+
|
|
855
|
+
// Check if the response body is empty
|
|
856
|
+
if (!responseText) {
|
|
857
|
+
console.error('PiAPI FaceSwap response body is empty');
|
|
858
|
+
throw new Error('PiAPI FaceSwap Error: Empty response body');
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// Try to parse the response as JSON
|
|
862
|
+
let data;
|
|
863
|
+
try {
|
|
864
|
+
data = JSON.parse(responseText) as { task_id: string; message: string };
|
|
865
|
+
} catch (err) {
|
|
866
|
+
console.error('Failed to parse PiAPI FaceSwap response as JSON:', responseText);
|
|
867
|
+
throw new Error('PiAPI FaceSwap Error: Invalid JSON response');
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Validate the response structure
|
|
871
|
+
if (!data.task_id || !data.message) {
|
|
872
|
+
console.error('PiAPI FaceSwap response missing required fields:', data);
|
|
873
|
+
throw new Error('PiAPI FaceSwap Error: Invalid response structure');
|
|
874
|
+
}
|
|
875
|
+
|
|
823
876
|
console.log('FaceSwap task created successfully:', data);
|
|
824
|
-
|
|
877
|
+
|
|
825
878
|
return {
|
|
826
879
|
taskId: data.task_id,
|
|
827
880
|
message: data.message,
|
package/app/services/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { inject, injectable } from 'inversify';
|
|
2
|
-
import { and, eq } from 'drizzle-orm';
|
|
3
|
-
import { AppContext, schema } from '../..';
|
|
4
|
-
import { BackendCtx } from '../../types/backend';
|
|
5
|
-
import { ArtifactList } from '../../types';
|
|
6
|
-
|
|
7
|
-
@injectable()
|
|
8
|
-
export class ArtifactService {
|
|
9
|
-
constructor(@inject(AppContext) private context: AppContext) {}
|
|
10
|
-
|
|
11
|
-
private async log(
|
|
12
|
-
level: 'info' | 'debug' | 'warn' | 'error',
|
|
13
|
-
message: string,
|
|
14
|
-
context: Record<string, any> = {}
|
|
15
|
-
) {
|
|
16
|
-
const logId = `artifact-service:${Date.now()}`;
|
|
17
|
-
const logMessage = `[${level.toUpperCase()}] ${message}`;
|
|
18
|
-
|
|
19
|
-
console[level](logMessage, context);
|
|
20
|
-
const db = this.context.drizzle();
|
|
21
|
-
try {
|
|
22
|
-
await db
|
|
23
|
-
.insert(schema.logs)
|
|
24
|
-
.values({
|
|
25
|
-
id: logId,
|
|
26
|
-
level,
|
|
27
|
-
message,
|
|
28
|
-
context: JSON.stringify(context),
|
|
29
|
-
createdAt: new Date().getTime(),
|
|
30
|
-
})
|
|
31
|
-
.execute();
|
|
32
|
-
} catch (error) {
|
|
33
|
-
console.error('[ERROR] Failed to persist log to database:', {
|
|
34
|
-
error,
|
|
35
|
-
logId,
|
|
36
|
-
message,
|
|
37
|
-
context,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async generateCosmicMirror(
|
|
43
|
-
artifactId: string,
|
|
44
|
-
userId: string,
|
|
45
|
-
generatedImageId: string,
|
|
46
|
-
archetypeDataId: string,
|
|
47
|
-
size: string
|
|
48
|
-
) {
|
|
49
|
-
await this.log('info', 'Starting cosmic mirror generation', {
|
|
50
|
-
artifactId,
|
|
51
|
-
userId,
|
|
52
|
-
generatedImageId,
|
|
53
|
-
archetypeDataId,
|
|
54
|
-
size
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const drizzle = this.context.drizzle();
|
|
58
|
-
const { artifacts, userArtifacts, generations, userConcepts } = schema;
|
|
59
|
-
|
|
60
|
-
// Implementation will be moved from ArtifactController
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async cleanupStaleCosmicMirror(
|
|
64
|
-
userArtifact: typeof schema.userArtifacts.$inferSelect
|
|
65
|
-
): Promise<void> {
|
|
66
|
-
await this.log('info', 'Cleaning up stale cosmic mirror', {
|
|
67
|
-
userArtifactId: userArtifact.id
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
const drizzle = this.context.drizzle();
|
|
71
|
-
const { generations } = schema;
|
|
72
|
-
|
|
73
|
-
// Delete KV entries
|
|
74
|
-
const kvKeys = await this.context.kvCosmicMirrorManagementStore().list({
|
|
75
|
-
prefix: `cosmic-mirror:${userArtifact.id}:`
|
|
76
|
-
});
|
|
77
|
-
for (const key of kvKeys.keys) {
|
|
78
|
-
await this.context.kvCosmicMirrorManagementStore().delete(key.name);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Delete generations
|
|
82
|
-
await drizzle
|
|
83
|
-
.delete(generations)
|
|
84
|
-
.where(eq(generations.userArtifactId, userArtifact.id));
|
|
85
|
-
|
|
86
|
-
// Delete user artifact
|
|
87
|
-
await drizzle
|
|
88
|
-
.delete(schema.userArtifacts)
|
|
89
|
-
.where(eq(schema.userArtifacts.id, userArtifact.id));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async retryStaleCosmicMirror(
|
|
93
|
-
userArtifact: typeof schema.userArtifacts.$inferSelect
|
|
94
|
-
): Promise<any> {
|
|
95
|
-
await this.log('info', 'Retrying stale cosmic mirror', {
|
|
96
|
-
userArtifactId: userArtifact.id
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
const drizzle = this.context.drizzle();
|
|
100
|
-
const { users, artifactFaceswap } = schema;
|
|
101
|
-
|
|
102
|
-
// Implementation will be moved from ArtifactController
|
|
103
|
-
}
|
|
104
|
-
}
|