Harsha1845 commited on
Commit
a98a749
·
verified ·
1 Parent(s): 68ff2ab

Update src/services/geminiService.ts

Browse files
Files changed (1) hide show
  1. src/services/geminiService.ts +27 -21
src/services/geminiService.ts CHANGED
@@ -1,8 +1,8 @@
1
  import { GoogleGenAI } from "@google/genai";
2
  import { Product } from "../types";
3
 
4
- // Extreme compression to stay under free tier token-per-minute limits
5
- const resizeImage = async (base64Str: string, maxWidth = 320): Promise<string> => {
6
  return new Promise((resolve) => {
7
  const img = new Image();
8
  img.src = base64Str;
@@ -26,9 +26,9 @@ const resizeImage = async (base64Str: string, maxWidth = 320): Promise<string> =
26
  canvas.width = width;
27
  canvas.height = height;
28
  const ctx = canvas.getContext('2d');
29
- // High compression (0.5) to save bandwidth and tokens
30
  ctx?.drawImage(img, 0, 0, width, height);
31
- resolve(canvas.toDataURL('image/jpeg', 0.5));
32
  };
33
  });
34
  };
@@ -40,7 +40,7 @@ const cleanBase64 = (data: string) => {
40
  const urlToBase64 = async (url: string): Promise<string> => {
41
  try {
42
  const response = await fetch(url);
43
- if (!response.ok) throw new Error(`Status: ${response.status}`);
44
  const blob = await response.blob();
45
  return await new Promise((resolve, reject) => {
46
  const reader = new FileReader();
@@ -57,11 +57,11 @@ const urlToBase64 = async (url: string): Promise<string> => {
57
  canvas.width = img.width;
58
  canvas.height = img.height;
59
  const ctx = canvas.getContext('2d');
60
- if (!ctx) return reject(new Error("Canvas Fail"));
61
  ctx.drawImage(img, 0, 0);
62
  try { resolve(canvas.toDataURL('image/jpeg')); } catch (e) { reject(e); }
63
  };
64
- img.onerror = () => reject(new Error("Load Fail"));
65
  img.src = url;
66
  });
67
  }
@@ -69,19 +69,19 @@ const urlToBase64 = async (url: string): Promise<string> => {
69
 
70
  export const generateTryOn = async (userImageBase64: string, product: Product): Promise<string> => {
71
  const apiKey = process.env.API_KEY;
72
- if (!apiKey) throw new Error("API Key missing.");
73
 
74
  const ai = new GoogleGenAI({ apiKey });
75
 
76
- // 1. Concurrent extreme resizing
77
  const productRaw = await urlToBase64(product.imageUrl);
78
  const [smallUserImg, smallProductImg] = await Promise.all([
79
- resizeImage(userImageBase64, 320),
80
- resizeImage(productRaw, 320)
81
  ]);
82
 
83
- // Ultra-minimalist prompt (approx 20 tokens)
84
- const prompt = `Fit the ${product.name} from image 2 onto the person in image 1. Keep background same.`;
85
 
86
  const requestParams = {
87
  model: 'gemini-2.5-flash-image',
@@ -95,23 +95,29 @@ export const generateTryOn = async (userImageBase64: string, product: Product):
95
  };
96
 
97
  try {
 
98
  const response = await ai.models.generateContent(requestParams);
99
- const candidate = response.candidates?.[0];
100
 
101
- if (candidate?.finishReason && candidate.finishReason !== 'STOP') {
102
- throw new Error(`AI Limit Hit: ${candidate.finishReason}`);
103
  }
104
 
105
- const part = candidate?.content?.parts?.find(p => p.inlineData);
106
  if (part?.inlineData?.data) {
107
  return `data:${part.inlineData.mimeType || 'image/png'};base64,${part.inlineData.data}`;
108
  }
109
 
110
- throw new Error("AI busy or returned empty.");
111
  } catch (error: any) {
112
- if (error.message?.includes("RESOURCE_EXHAUSTED") || error.message?.includes("429")) {
113
- throw new Error("Free tier limit: 1 request per minute. Please wait for the timer.");
 
 
 
 
 
114
  }
115
- throw new Error(error.message || "AI Service unavailable.");
 
116
  }
117
  };
 
1
  import { GoogleGenAI } from "@google/genai";
2
  import { Product } from "../types";
3
 
4
+ // Atomic compression: 256px is the absolute floor for usable VLM performance
5
+ const resizeImage = async (base64Str: string, maxWidth = 256): Promise<string> => {
6
  return new Promise((resolve) => {
7
  const img = new Image();
8
  img.src = base64Str;
 
26
  canvas.width = width;
27
  canvas.height = height;
28
  const ctx = canvas.getContext('2d');
29
+ // Extreme compression (0.3) to minimize token footprint
30
  ctx?.drawImage(img, 0, 0, width, height);
31
+ resolve(canvas.toDataURL('image/jpeg', 0.3));
32
  };
33
  });
34
  };
 
40
  const urlToBase64 = async (url: string): Promise<string> => {
41
  try {
42
  const response = await fetch(url);
43
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
44
  const blob = await response.blob();
45
  return await new Promise((resolve, reject) => {
46
  const reader = new FileReader();
 
57
  canvas.width = img.width;
58
  canvas.height = img.height;
59
  const ctx = canvas.getContext('2d');
60
+ if (!ctx) return reject(new Error("Canvas fail"));
61
  ctx.drawImage(img, 0, 0);
62
  try { resolve(canvas.toDataURL('image/jpeg')); } catch (e) { reject(e); }
63
  };
64
+ img.onerror = () => reject(new Error("Image load fail"));
65
  img.src = url;
66
  });
67
  }
 
69
 
70
  export const generateTryOn = async (userImageBase64: string, product: Product): Promise<string> => {
71
  const apiKey = process.env.API_KEY;
72
+ if (!apiKey) throw new Error("API Key configuration error.");
73
 
74
  const ai = new GoogleGenAI({ apiKey });
75
 
76
+ // 1. Process images to atomic size
77
  const productRaw = await urlToBase64(product.imageUrl);
78
  const [smallUserImg, smallProductImg] = await Promise.all([
79
+ resizeImage(userImageBase64, 256),
80
+ resizeImage(productRaw, 256)
81
  ]);
82
 
83
+ // Prompt reduced to absolute core
84
+ const prompt = `Put ${product.name} from img 2 on person in img 1. Match lighting.`;
85
 
86
  const requestParams = {
87
  model: 'gemini-2.5-flash-image',
 
95
  };
96
 
97
  try {
98
+ console.log("Sending request to Gemini (Atomic Mode)...");
99
  const response = await ai.models.generateContent(requestParams);
 
100
 
101
+ if (response.candidates?.[0]?.finishReason && response.candidates[0].finishReason !== 'STOP') {
102
+ throw new Error(`AI stopped: ${response.candidates[0].finishReason}`);
103
  }
104
 
105
+ const part = response.candidates?.[0]?.content?.parts?.find(p => p.inlineData);
106
  if (part?.inlineData?.data) {
107
  return `data:${part.inlineData.mimeType || 'image/png'};base64,${part.inlineData.data}`;
108
  }
109
 
110
+ throw new Error("Empty response from AI.");
111
  } catch (error: any) {
112
+ // Log the full error to the console for the developer
113
+ console.error("FULL AI ERROR OBJECT:", JSON.stringify(error, null, 2));
114
+
115
+ const rawMessage = error.message || "Unknown Error";
116
+
117
+ if (rawMessage.includes("RESOURCE_EXHAUSTED") || rawMessage.includes("429")) {
118
+ throw new Error("RATE_LIMIT_EXCEEDED: Free tier allows 1 req/min. Please wait.");
119
  }
120
+
121
+ throw new Error(`AI ERROR: ${rawMessage}`);
122
  }
123
  };