Spaces:
Running
Running
update app
Browse files
Home.tsx
CHANGED
|
@@ -1,9 +1,8 @@
|
|
| 1 |
/**
|
| 2 |
* @license
|
| 3 |
* SPDX-License-Identifier: Apache-2.0
|
| 4 |
-
*/
|
| 5 |
/* tslint:disable */
|
| 6 |
-
import {GoogleGenAI, Modality} from '@google/genai';
|
| 7 |
import {
|
| 8 |
ChevronDown,
|
| 9 |
Library,
|
|
@@ -19,25 +18,31 @@ import {
|
|
| 19 |
} from 'lucide-react';
|
| 20 |
import {useEffect, useRef, useState} from 'react';
|
| 21 |
|
| 22 |
-
|
| 23 |
-
|
| 24 |
function parseError(error: string) {
|
| 25 |
-
const regex = /{"error":(.*)}/gm;
|
| 26 |
-
const m = regex.exec(error);
|
| 27 |
try {
|
| 28 |
-
|
| 29 |
-
const
|
| 30 |
-
return
|
| 31 |
} catch (e) {
|
| 32 |
-
return error
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
}
|
| 34 |
}
|
| 35 |
|
| 36 |
export default function Home() {
|
| 37 |
-
const canvasRef = useRef(null);
|
| 38 |
-
const fileInputRef = useRef(null);
|
| 39 |
-
const backgroundImageRef = useRef(null);
|
| 40 |
-
const dropdownRef = useRef(null);
|
| 41 |
const [isDrawing, setIsDrawing] = useState(false);
|
| 42 |
const [prompt, setPrompt] = useState('');
|
| 43 |
const [generatedImage, setGeneratedImage] = useState<string | null>(null);
|
|
@@ -119,6 +124,7 @@ export default function Home() {
|
|
| 119 |
// Initialize canvas with white background
|
| 120 |
const initializeCanvas = () => {
|
| 121 |
const canvas = canvasRef.current;
|
|
|
|
| 122 |
const ctx = canvas.getContext('2d');
|
| 123 |
ctx.fillStyle = '#FFFFFF';
|
| 124 |
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
@@ -182,8 +188,8 @@ export default function Home() {
|
|
| 182 |
};
|
| 183 |
|
| 184 |
// Get the correct coordinates based on canvas scaling
|
| 185 |
-
const getCoordinates = (e) => {
|
| 186 |
-
const canvas = canvasRef.current
|
| 187 |
const rect = canvas.getBoundingClientRect();
|
| 188 |
const scaleX = canvas.width / rect.width;
|
| 189 |
const scaleY = canvas.height / rect.height;
|
|
@@ -197,9 +203,9 @@ export default function Home() {
|
|
| 197 |
};
|
| 198 |
};
|
| 199 |
|
| 200 |
-
const startDrawing = (e) => {
|
| 201 |
-
const canvas = canvasRef.current
|
| 202 |
-
const ctx = canvas.getContext('2d')
|
| 203 |
const {x, y} = getCoordinates(e);
|
| 204 |
if (e.type === 'touchstart') {
|
| 205 |
e.preventDefault();
|
|
@@ -209,13 +215,13 @@ export default function Home() {
|
|
| 209 |
setIsDrawing(true);
|
| 210 |
};
|
| 211 |
|
| 212 |
-
const draw = (e) => {
|
| 213 |
if (!isDrawing) return;
|
| 214 |
if (e.type === 'touchmove') {
|
| 215 |
e.preventDefault();
|
| 216 |
}
|
| 217 |
-
const canvas = canvasRef.current
|
| 218 |
-
const ctx = canvas.getContext('2d')
|
| 219 |
const {x, y} = getCoordinates(e);
|
| 220 |
ctx.lineWidth = 5;
|
| 221 |
ctx.lineCap = 'round';
|
|
@@ -275,7 +281,6 @@ export default function Home() {
|
|
| 275 |
|
| 276 |
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
| 277 |
processFiles(e.target.files);
|
| 278 |
-
// Reset file input to allow uploading the same file again
|
| 279 |
e.target.value = '';
|
| 280 |
};
|
| 281 |
|
|
@@ -303,7 +308,8 @@ export default function Home() {
|
|
| 303 |
);
|
| 304 |
};
|
| 305 |
|
| 306 |
-
|
|
|
|
| 307 |
e.preventDefault();
|
| 308 |
setIsLoading(true);
|
| 309 |
|
|
@@ -322,30 +328,22 @@ export default function Home() {
|
|
| 322 |
|
| 323 |
const parts: any[] = [];
|
| 324 |
|
|
|
|
| 325 |
if (mode === 'imageGen') {
|
| 326 |
const tempCanvas = document.createElement('canvas');
|
| 327 |
tempCanvas.width = 960;
|
| 328 |
tempCanvas.height = 540;
|
| 329 |
-
const tempCtx = tempCanvas.getContext('2d')
|
| 330 |
-
// Fill with white
|
| 331 |
tempCtx.fillStyle = '#FFFFFF';
|
| 332 |
tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
|
| 333 |
-
|
| 334 |
-
tempCtx.
|
| 335 |
-
tempCtx.fillRect(0, 0, 1, 1); // At the top-left corner
|
| 336 |
const imageB64 = tempCanvas.toDataURL('image/png').split(',')[1];
|
| 337 |
parts.push({inlineData: {data: imageB64, mimeType: 'image/png'}});
|
| 338 |
} else if (mode === 'canvas') {
|
| 339 |
if (!canvasRef.current) return;
|
| 340 |
const canvas = canvasRef.current;
|
| 341 |
-
const
|
| 342 |
-
tempCanvas.width = canvas.width;
|
| 343 |
-
tempCanvas.height = canvas.height;
|
| 344 |
-
const tempCtx = tempCanvas.getContext('2d');
|
| 345 |
-
tempCtx.fillStyle = '#FFFFFF';
|
| 346 |
-
tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
|
| 347 |
-
tempCtx.drawImage(canvas, 0, 0);
|
| 348 |
-
const imageB64 = tempCanvas.toDataURL('image/png').split(',')[1];
|
| 349 |
parts.push({inlineData: {data: imageB64, mimeType: 'image/png'}});
|
| 350 |
} else if (mode === 'editor' && generatedImage) {
|
| 351 |
const mimeType = generatedImage.substring(
|
|
@@ -364,30 +362,50 @@ export default function Home() {
|
|
| 364 |
|
| 365 |
parts.push({text: prompt});
|
| 366 |
|
| 367 |
-
|
| 368 |
-
|
| 369 |
-
contents: { parts
|
| 370 |
-
|
| 371 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 372 |
},
|
|
|
|
| 373 |
});
|
| 374 |
|
| 375 |
-
|
| 376 |
-
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
|
| 380 |
-
}
|
| 381 |
-
|
| 382 |
-
|
| 383 |
-
|
| 384 |
-
|
| 385 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
}
|
|
|
|
|
|
|
| 387 |
}
|
| 388 |
|
| 389 |
-
if (
|
| 390 |
-
const imageUrl = `data:image/png;base64,${
|
| 391 |
if (mode === 'multi-img-edit') {
|
| 392 |
setGeneratedImage(imageUrl);
|
| 393 |
setMultiImages([]);
|
|
@@ -397,11 +415,11 @@ export default function Home() {
|
|
| 397 |
}
|
| 398 |
} else {
|
| 399 |
setErrorMessage(
|
| 400 |
-
|
| 401 |
);
|
| 402 |
setShowErrorModal(true);
|
| 403 |
}
|
| 404 |
-
} catch (error) {
|
| 405 |
console.error('Error submitting:', error);
|
| 406 |
setErrorMessage(error.message || 'An unexpected error occurred.');
|
| 407 |
setShowErrorModal(true);
|
|
@@ -418,7 +436,7 @@ export default function Home() {
|
|
| 418 |
const canvas = canvasRef.current;
|
| 419 |
if (!canvas) return;
|
| 420 |
|
| 421 |
-
const preventTouchDefault = (e) => {
|
| 422 |
if (isDrawing) {
|
| 423 |
e.preventDefault();
|
| 424 |
}
|
|
|
|
| 1 |
/**
|
| 2 |
* @license
|
| 3 |
* SPDX-License-Identifier: Apache-2.0
|
| 4 |
+
*/
|
| 5 |
/* tslint:disable */
|
|
|
|
| 6 |
import {
|
| 7 |
ChevronDown,
|
| 8 |
Library,
|
|
|
|
| 18 |
} from 'lucide-react';
|
| 19 |
import {useEffect, useRef, useState} from 'react';
|
| 20 |
|
| 21 |
+
// This function remains useful for parsing potential error messages
|
|
|
|
| 22 |
function parseError(error: string) {
|
|
|
|
|
|
|
| 23 |
try {
|
| 24 |
+
// Attempt to parse the error as a JSON object which the proxy might send
|
| 25 |
+
const errObj = JSON.parse(error);
|
| 26 |
+
return errObj.message || error;
|
| 27 |
} catch (e) {
|
| 28 |
+
// If it's not JSON, return the original error string
|
| 29 |
+
const regex = /{"error":(.*)}/gm;
|
| 30 |
+
const m = regex.exec(error);
|
| 31 |
+
try {
|
| 32 |
+
const e = m[1];
|
| 33 |
+
const err = JSON.parse(e);
|
| 34 |
+
return err.message || error;
|
| 35 |
+
} catch (e) {
|
| 36 |
+
return error;
|
| 37 |
+
}
|
| 38 |
}
|
| 39 |
}
|
| 40 |
|
| 41 |
export default function Home() {
|
| 42 |
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
| 43 |
+
const fileInputRef = useRef<HTMLInputElement>(null);
|
| 44 |
+
const backgroundImageRef = useRef<HTMLImageElement | null>(null);
|
| 45 |
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
| 46 |
const [isDrawing, setIsDrawing] = useState(false);
|
| 47 |
const [prompt, setPrompt] = useState('');
|
| 48 |
const [generatedImage, setGeneratedImage] = useState<string | null>(null);
|
|
|
|
| 124 |
// Initialize canvas with white background
|
| 125 |
const initializeCanvas = () => {
|
| 126 |
const canvas = canvasRef.current;
|
| 127 |
+
if (!canvas) return;
|
| 128 |
const ctx = canvas.getContext('2d');
|
| 129 |
ctx.fillStyle = '#FFFFFF';
|
| 130 |
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
| 188 |
};
|
| 189 |
|
| 190 |
// Get the correct coordinates based on canvas scaling
|
| 191 |
+
const getCoordinates = (e: any) => {
|
| 192 |
+
const canvas = canvasRef.current!;
|
| 193 |
const rect = canvas.getBoundingClientRect();
|
| 194 |
const scaleX = canvas.width / rect.width;
|
| 195 |
const scaleY = canvas.height / rect.height;
|
|
|
|
| 203 |
};
|
| 204 |
};
|
| 205 |
|
| 206 |
+
const startDrawing = (e: any) => {
|
| 207 |
+
const canvas = canvasRef.current!;
|
| 208 |
+
const ctx = canvas.getContext('2d')!;
|
| 209 |
const {x, y} = getCoordinates(e);
|
| 210 |
if (e.type === 'touchstart') {
|
| 211 |
e.preventDefault();
|
|
|
|
| 215 |
setIsDrawing(true);
|
| 216 |
};
|
| 217 |
|
| 218 |
+
const draw = (e: any) => {
|
| 219 |
if (!isDrawing) return;
|
| 220 |
if (e.type === 'touchmove') {
|
| 221 |
e.preventDefault();
|
| 222 |
}
|
| 223 |
+
const canvas = canvasRef.current!;
|
| 224 |
+
const ctx = canvas.getContext('2d')!;
|
| 225 |
const {x, y} = getCoordinates(e);
|
| 226 |
ctx.lineWidth = 5;
|
| 227 |
ctx.lineCap = 'round';
|
|
|
|
| 281 |
|
| 282 |
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
| 283 |
processFiles(e.target.files);
|
|
|
|
| 284 |
e.target.value = '';
|
| 285 |
};
|
| 286 |
|
|
|
|
| 308 |
);
|
| 309 |
};
|
| 310 |
|
| 311 |
+
// *** MODIFIED FUNCTION ***
|
| 312 |
+
const handleSubmit = async (e: React.FormEvent) => {
|
| 313 |
e.preventDefault();
|
| 314 |
setIsLoading(true);
|
| 315 |
|
|
|
|
| 328 |
|
| 329 |
const parts: any[] = [];
|
| 330 |
|
| 331 |
+
// This logic for building the 'parts' array is correct.
|
| 332 |
if (mode === 'imageGen') {
|
| 333 |
const tempCanvas = document.createElement('canvas');
|
| 334 |
tempCanvas.width = 960;
|
| 335 |
tempCanvas.height = 540;
|
| 336 |
+
const tempCtx = tempCanvas.getContext('2d')!;
|
|
|
|
| 337 |
tempCtx.fillStyle = '#FFFFFF';
|
| 338 |
tempCtx.fillRect(0, 0, tempCanvas.width, tempCanvas.height);
|
| 339 |
+
tempCtx.fillStyle = '#FEFEFE';
|
| 340 |
+
tempCtx.fillRect(0, 0, 1, 1);
|
|
|
|
| 341 |
const imageB64 = tempCanvas.toDataURL('image/png').split(',')[1];
|
| 342 |
parts.push({inlineData: {data: imageB64, mimeType: 'image/png'}});
|
| 343 |
} else if (mode === 'canvas') {
|
| 344 |
if (!canvasRef.current) return;
|
| 345 |
const canvas = canvasRef.current;
|
| 346 |
+
const imageB64 = canvas.toDataURL('image/png').split(',')[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 347 |
parts.push({inlineData: {data: imageB64, mimeType: 'image/png'}});
|
| 348 |
} else if (mode === 'editor' && generatedImage) {
|
| 349 |
const mimeType = generatedImage.substring(
|
|
|
|
| 362 |
|
| 363 |
parts.push({text: prompt});
|
| 364 |
|
| 365 |
+
// Construct the request body for the Gemini REST API
|
| 366 |
+
const requestBody = {
|
| 367 |
+
contents: [{role: 'USER', parts}],
|
| 368 |
+
};
|
| 369 |
+
|
| 370 |
+
// Define the proxy endpoint
|
| 371 |
+
const proxyUrl =
|
| 372 |
+
'/api-proxy/v1beta/models/gemini-2.5-flash-image-preview:generateContent';
|
| 373 |
+
|
| 374 |
+
// Use fetch to send the request to your proxy server
|
| 375 |
+
const response = await fetch(proxyUrl, {
|
| 376 |
+
method: 'POST',
|
| 377 |
+
headers: {
|
| 378 |
+
'Content-Type': 'application/json',
|
| 379 |
},
|
| 380 |
+
body: JSON.stringify(requestBody),
|
| 381 |
});
|
| 382 |
|
| 383 |
+
if (!response.ok) {
|
| 384 |
+
const errorData = await response.json();
|
| 385 |
+
throw new Error(
|
| 386 |
+
errorData.error?.message || `HTTP error! status: ${response.status}`,
|
| 387 |
+
);
|
| 388 |
+
}
|
| 389 |
+
|
| 390 |
+
const responseData = await response.json();
|
| 391 |
+
|
| 392 |
+
// Process the response
|
| 393 |
+
const result = {message: '', imageData: null};
|
| 394 |
+
|
| 395 |
+
if (responseData.candidates && responseData.candidates.length > 0) {
|
| 396 |
+
for (const part of responseData.candidates[0].content.parts) {
|
| 397 |
+
if (part.text) {
|
| 398 |
+
result.message = part.text;
|
| 399 |
+
} else if (part.inlineData) {
|
| 400 |
+
result.imageData = part.inlineData.data;
|
| 401 |
+
}
|
| 402 |
}
|
| 403 |
+
} else {
|
| 404 |
+
throw new Error('Invalid response structure from API.');
|
| 405 |
}
|
| 406 |
|
| 407 |
+
if (result.imageData) {
|
| 408 |
+
const imageUrl = `data:image/png;base64,${result.imageData}`;
|
| 409 |
if (mode === 'multi-img-edit') {
|
| 410 |
setGeneratedImage(imageUrl);
|
| 411 |
setMultiImages([]);
|
|
|
|
| 415 |
}
|
| 416 |
} else {
|
| 417 |
setErrorMessage(
|
| 418 |
+
result.message || 'Failed to generate image. Please try again.',
|
| 419 |
);
|
| 420 |
setShowErrorModal(true);
|
| 421 |
}
|
| 422 |
+
} catch (error: any) {
|
| 423 |
console.error('Error submitting:', error);
|
| 424 |
setErrorMessage(error.message || 'An unexpected error occurred.');
|
| 425 |
setShowErrorModal(true);
|
|
|
|
| 436 |
const canvas = canvasRef.current;
|
| 437 |
if (!canvas) return;
|
| 438 |
|
| 439 |
+
const preventTouchDefault = (e: TouchEvent) => {
|
| 440 |
if (isDrawing) {
|
| 441 |
e.preventDefault();
|
| 442 |
}
|