@zodic/shared 0.0.346 → 0.0.348

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.
Files changed (2) hide show
  1. package/app/api/index.ts +97 -46
  2. package/package.json +1 -1
package/app/api/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import OpenAI from 'openai';
2
+ import { v4 } from 'uuid';
2
3
  import {
3
4
  BackendBindings,
4
5
  BatchInputItem,
@@ -785,35 +786,51 @@ export const Api = (env: BackendBindings) => ({
785
786
  'x-api-key': `${env.PIAPI_API_KEY}`,
786
787
  'Content-Type': 'application/json',
787
788
  };
788
-
789
+
789
790
  // Validate image URLs before making the request
790
- const validateImageUrl = async (url: string, label: string): Promise<void> => {
791
+ const validateImageUrl = async (
792
+ url: string,
793
+ label: string
794
+ ): Promise<void> => {
791
795
  try {
792
796
  const response = await fetch(url, { method: 'HEAD' });
793
797
  if (!response.ok) {
794
- throw new Error(`${label} is inaccessible: ${response.status} ${response.statusText}`);
798
+ throw new Error(
799
+ `${label} is inaccessible: ${response.status} ${response.statusText}`
800
+ );
795
801
  }
796
802
  const contentType = response.headers.get('Content-Type');
797
803
  if (!contentType || !contentType.startsWith('image/')) {
798
- throw new Error(`${label} is not a valid image: Content-Type is ${contentType}`);
804
+ throw new Error(
805
+ `${label} is not a valid image: Content-Type is ${contentType}`
806
+ );
799
807
  }
800
808
  } catch (err: any) {
801
809
  console.error(`Error validating ${label}:`, err.message);
802
810
  throw new Error(`Invalid ${label}: ${err.message}`);
803
811
  }
804
812
  };
805
-
813
+
806
814
  // Helper function to resize an image by calling the Express server
807
- const resizeImage = async (url: string, label: string): Promise<ArrayBuffer> => {
808
- const resizeEndpoint = `https://zodiako-image-mounter.onrender.com/resize-image?url=${encodeURIComponent(url)}`; // Replace with your Express server URL
815
+ const resizeImage = async (
816
+ url: string,
817
+ label: string
818
+ ): Promise<ArrayBuffer> => {
819
+ const resizeEndpoint = `https://zodiako-image-mounter.onrender.com/resize-image?url=${encodeURIComponent(
820
+ url
821
+ )}`; // Replace with your Express server URL
809
822
  try {
810
823
  const response = await fetch(resizeEndpoint);
811
824
  if (!response.ok) {
812
- throw new Error(`${label} resize failed: ${response.status} ${response.statusText}`);
825
+ throw new Error(
826
+ `${label} resize failed: ${response.status} ${response.statusText}`
827
+ );
813
828
  }
814
829
  const contentType = response.headers.get('Content-Type');
815
830
  if (!contentType || !contentType.startsWith('image/')) {
816
- throw new Error(`${label} resize response is not an image: Content-Type is ${contentType}`);
831
+ throw new Error(
832
+ `${label} resize response is not an image: Content-Type is ${contentType}`
833
+ );
817
834
  }
818
835
  return await response.arrayBuffer();
819
836
  } catch (err: any) {
@@ -821,34 +838,49 @@ export const Api = (env: BackendBindings) => ({
821
838
  throw new Error(`Failed to resize ${label}: ${err.message}`);
822
839
  }
823
840
  };
824
-
841
+
842
+ const getKey = (label: string) => {
843
+ const timestamp = Date.now();
844
+ const key = `${label.toLowerCase().replace(/ /g, '_')}_${timestamp}.jpg`;
845
+ return key;
846
+ };
847
+
825
848
  // Helper function to upload an image to storage and get a public URL
826
- const uploadImageToStorage = async (imageData: ArrayBuffer, label: string): Promise<string> => {
827
- const fileName = `${label.toLowerCase().replace(/\s+/g, '-')}-${Date.now()}.jpg`;
828
- // Replace this with your actual storage service implementation (e.g., Cloudflare R2, AWS S3)
829
- // Example for Cloudflare R2:
830
- // const r2Response = await env.R2_BUCKET.put(fileName, imageData, {
831
- // httpMetadata: { contentType: 'image/jpeg' },
832
- // });
833
- // return `https://your-r2-bucket-url/${fileName}`;
834
-
835
- // For now, we'll throw an error if this isn't implemented
836
- throw new Error(`Storage service not implemented for ${label}`);
849
+ const uploadImageToStorage = async (
850
+ imageData: ArrayBuffer,
851
+ label: string
852
+ ): Promise<string> => {
853
+ const key = getKey(label);
854
+ await env.PHOTOS_BUCKET.put(key, imageData);
855
+ const imageUrl = `https://pub-c4bb4b3e4ccd46b59eed7fa434c59b60.r2.dev/${key}`;
856
+ return imageUrl;
837
857
  };
838
-
858
+
839
859
  try {
840
860
  // Validate image URLs
841
861
  await validateImageUrl(sourceImageUrl, 'Source image URL');
842
862
  await validateImageUrl(targetImageUrl, 'Target image URL');
843
-
863
+
844
864
  // Resize images by calling the Express server
845
- const resizedSourceData = await resizeImage(sourceImageUrl, 'Source image');
846
- const resizedTargetData = await resizeImage(targetImageUrl, 'Target image');
847
-
865
+ const resizedSourceData = await resizeImage(
866
+ sourceImageUrl,
867
+ 'Source image'
868
+ );
869
+ const resizedTargetData = await resizeImage(
870
+ targetImageUrl,
871
+ 'Target image'
872
+ );
873
+
848
874
  // Upload resized images to storage to get public URLs
849
- const resizedSourceUrl = await uploadImageToStorage(resizedSourceData, 'Source image');
850
- const resizedTargetUrl = await uploadImageToStorage(resizedTargetData, 'Target image');
851
-
875
+ const resizedSourceUrl = await uploadImageToStorage(
876
+ resizedSourceData,
877
+ 'user_photo'
878
+ );
879
+ const resizedTargetUrl = await uploadImageToStorage(
880
+ resizedTargetData,
881
+ 'generated_image'
882
+ );
883
+
852
884
  const body = JSON.stringify({
853
885
  model: 'Qubico/image-toolkit',
854
886
  type: 'face-swap',
@@ -858,28 +890,34 @@ export const Api = (env: BackendBindings) => ({
858
890
  },
859
891
  config: {
860
892
  webhook_config: {
861
- endpoint: 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
893
+ endpoint:
894
+ 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
862
895
  // secret: '',
863
896
  },
864
897
  },
865
898
  });
866
-
867
- console.log('Sending FaceSwap request:', { resizedSourceUrl, resizedTargetUrl });
868
-
899
+
900
+ console.log('Sending FaceSwap request:', {
901
+ resizedSourceUrl,
902
+ resizedTargetUrl,
903
+ });
904
+
869
905
  const response = await fetch(endpoint, {
870
906
  method: 'POST',
871
907
  headers,
872
908
  body,
873
909
  });
874
-
910
+
875
911
  // Log the HTTP status and headers for debugging
876
912
  console.log('PiAPI FaceSwap Response Status:', response.status);
877
- console.log('PiAPI FaceSwap Response Headers:', [...response.headers.entries()]);
878
-
913
+ console.log('PiAPI FaceSwap Response Headers:', [
914
+ ...response.headers.entries(),
915
+ ]);
916
+
879
917
  // Read the response body as text first to inspect it
880
918
  const responseText = await response.text();
881
919
  console.log('PiAPI FaceSwap Raw Response Body:', responseText);
882
-
920
+
883
921
  // Check for the expected 201 Created status
884
922
  if (response.status !== 201) {
885
923
  let errorData;
@@ -889,32 +927,45 @@ export const Api = (env: BackendBindings) => ({
889
927
  errorData = { message: responseText || 'Unknown error' };
890
928
  }
891
929
  console.error('Error from PiAPI FaceSwap:', errorData);
892
- throw new Error(`PiAPI FaceSwap Error: ${response.status} - ${errorData.message || 'Unknown error'}`);
930
+ throw new Error(
931
+ `PiAPI FaceSwap Error: ${response.status} - ${
932
+ errorData.message || 'Unknown error'
933
+ }`
934
+ );
893
935
  }
894
-
936
+
895
937
  // Check if the response body is empty
896
938
  if (!responseText) {
897
939
  console.error('PiAPI FaceSwap response body is empty');
898
940
  throw new Error('PiAPI FaceSwap Error: Empty response body');
899
941
  }
900
-
942
+
901
943
  // Try to parse the response as JSON
902
944
  let data;
903
945
  try {
904
- data = JSON.parse(responseText) as { task_id: string; message: string };
946
+ data = JSON.parse(responseText) as {
947
+ task_id: string;
948
+ message: string;
949
+ };
905
950
  } catch (err) {
906
- console.error('Failed to parse PiAPI FaceSwap response as JSON:', responseText);
951
+ console.error(
952
+ 'Failed to parse PiAPI FaceSwap response as JSON:',
953
+ responseText
954
+ );
907
955
  throw new Error('PiAPI FaceSwap Error: Invalid JSON response');
908
956
  }
909
-
957
+
910
958
  // Validate the response structure
911
959
  if (!data.task_id || !data.message) {
912
- console.error('PiAPI FaceSwap response missing required fields:', data);
960
+ console.error(
961
+ 'PiAPI FaceSwap response missing required fields:',
962
+ data
963
+ );
913
964
  throw new Error('PiAPI FaceSwap Error: Invalid response structure');
914
965
  }
915
-
966
+
916
967
  console.log('FaceSwap task created successfully:', data);
917
-
968
+
918
969
  return {
919
970
  taskId: data.task_id,
920
971
  message: data.message,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zodic/shared",
3
- "version": "0.0.346",
3
+ "version": "0.0.348",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {