@zodic/shared 0.0.346 → 0.0.347

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 +103 -38
  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,63 @@ 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 = (filePath: string) => {
843
+ const fileNameParts = filePath.split('.');
844
+ const extension = fileNameParts.pop();
845
+ const fileNameWithoutExtension = fileNameParts.join('.');
846
+
847
+ const newFileName = `${fileNameWithoutExtension}-${v4()}.${extension}`;
848
+ const key = `${newFileName.replace(/ /g, '_')}`;
849
+
850
+ return key;
851
+ };
852
+
825
853
  // 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`;
854
+ const uploadImageToStorage = async (
855
+ imageData: ArrayBuffer,
856
+ label: string
857
+ ): Promise<string> => {
858
+ const key = getKey(label);
859
+ await env.PHOTOS_BUCKET.put(key, imageData);
860
+ const imageUrl = `https://pub-c4bb4b3e4ccd46b59eed7fa434c59b60.r2.dev/${key}`;
861
+ return imageUrl;
828
862
  // Replace this with your actual storage service implementation (e.g., Cloudflare R2, AWS S3)
829
863
  // Example for Cloudflare R2:
830
864
  // const r2Response = await env.R2_BUCKET.put(fileName, imageData, {
831
865
  // httpMetadata: { contentType: 'image/jpeg' },
832
866
  // });
833
867
  // return `https://your-r2-bucket-url/${fileName}`;
834
-
868
+
835
869
  // For now, we'll throw an error if this isn't implemented
836
870
  throw new Error(`Storage service not implemented for ${label}`);
837
871
  };
838
-
872
+
839
873
  try {
840
874
  // Validate image URLs
841
875
  await validateImageUrl(sourceImageUrl, 'Source image URL');
842
876
  await validateImageUrl(targetImageUrl, 'Target image URL');
843
-
877
+
844
878
  // Resize images by calling the Express server
845
- const resizedSourceData = await resizeImage(sourceImageUrl, 'Source image');
846
- const resizedTargetData = await resizeImage(targetImageUrl, 'Target image');
847
-
879
+ const resizedSourceData = await resizeImage(
880
+ sourceImageUrl,
881
+ 'Source image'
882
+ );
883
+ const resizedTargetData = await resizeImage(
884
+ targetImageUrl,
885
+ 'Target image'
886
+ );
887
+
848
888
  // 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
-
889
+ const resizedSourceUrl = await uploadImageToStorage(
890
+ resizedSourceData,
891
+ 'Source image'
892
+ );
893
+ const resizedTargetUrl = await uploadImageToStorage(
894
+ resizedTargetData,
895
+ 'Target image'
896
+ );
897
+
852
898
  const body = JSON.stringify({
853
899
  model: 'Qubico/image-toolkit',
854
900
  type: 'face-swap',
@@ -858,28 +904,34 @@ export const Api = (env: BackendBindings) => ({
858
904
  },
859
905
  config: {
860
906
  webhook_config: {
861
- endpoint: 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
907
+ endpoint:
908
+ 'https://zodic-backend.lucdelbel.workers.dev/api/webhook/faceswap',
862
909
  // secret: '',
863
910
  },
864
911
  },
865
912
  });
866
-
867
- console.log('Sending FaceSwap request:', { resizedSourceUrl, resizedTargetUrl });
868
-
913
+
914
+ console.log('Sending FaceSwap request:', {
915
+ resizedSourceUrl,
916
+ resizedTargetUrl,
917
+ });
918
+
869
919
  const response = await fetch(endpoint, {
870
920
  method: 'POST',
871
921
  headers,
872
922
  body,
873
923
  });
874
-
924
+
875
925
  // Log the HTTP status and headers for debugging
876
926
  console.log('PiAPI FaceSwap Response Status:', response.status);
877
- console.log('PiAPI FaceSwap Response Headers:', [...response.headers.entries()]);
878
-
927
+ console.log('PiAPI FaceSwap Response Headers:', [
928
+ ...response.headers.entries(),
929
+ ]);
930
+
879
931
  // Read the response body as text first to inspect it
880
932
  const responseText = await response.text();
881
933
  console.log('PiAPI FaceSwap Raw Response Body:', responseText);
882
-
934
+
883
935
  // Check for the expected 201 Created status
884
936
  if (response.status !== 201) {
885
937
  let errorData;
@@ -889,32 +941,45 @@ export const Api = (env: BackendBindings) => ({
889
941
  errorData = { message: responseText || 'Unknown error' };
890
942
  }
891
943
  console.error('Error from PiAPI FaceSwap:', errorData);
892
- throw new Error(`PiAPI FaceSwap Error: ${response.status} - ${errorData.message || 'Unknown error'}`);
944
+ throw new Error(
945
+ `PiAPI FaceSwap Error: ${response.status} - ${
946
+ errorData.message || 'Unknown error'
947
+ }`
948
+ );
893
949
  }
894
-
950
+
895
951
  // Check if the response body is empty
896
952
  if (!responseText) {
897
953
  console.error('PiAPI FaceSwap response body is empty');
898
954
  throw new Error('PiAPI FaceSwap Error: Empty response body');
899
955
  }
900
-
956
+
901
957
  // Try to parse the response as JSON
902
958
  let data;
903
959
  try {
904
- data = JSON.parse(responseText) as { task_id: string; message: string };
960
+ data = JSON.parse(responseText) as {
961
+ task_id: string;
962
+ message: string;
963
+ };
905
964
  } catch (err) {
906
- console.error('Failed to parse PiAPI FaceSwap response as JSON:', responseText);
965
+ console.error(
966
+ 'Failed to parse PiAPI FaceSwap response as JSON:',
967
+ responseText
968
+ );
907
969
  throw new Error('PiAPI FaceSwap Error: Invalid JSON response');
908
970
  }
909
-
971
+
910
972
  // Validate the response structure
911
973
  if (!data.task_id || !data.message) {
912
- console.error('PiAPI FaceSwap response missing required fields:', data);
974
+ console.error(
975
+ 'PiAPI FaceSwap response missing required fields:',
976
+ data
977
+ );
913
978
  throw new Error('PiAPI FaceSwap Error: Invalid response structure');
914
979
  }
915
-
980
+
916
981
  console.log('FaceSwap task created successfully:', data);
917
-
982
+
918
983
  return {
919
984
  taskId: data.task_id,
920
985
  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.347",
4
4
  "module": "index.ts",
5
5
  "type": "module",
6
6
  "publishConfig": {