bibibi12345 commited on
Commit
495f156
·
1 Parent(s): 633140b

change from base64 to file upload

Browse files
Files changed (2) hide show
  1. app.py +52 -0
  2. static/script.js +52 -2
app.py CHANGED
@@ -293,6 +293,58 @@ def upload_file():
293
  print(f"Error in upload endpoint: {str(e)}")
294
  return jsonify({'error': str(e)}), 500
295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  @app.route('/health', methods=['GET'])
297
  def health_check():
298
  """Health check endpoint for container monitoring"""
 
293
  print(f"Error in upload endpoint: {str(e)}")
294
  return jsonify({'error': str(e)}), 500
295
 
296
+ @app.route('/api/upload-to-fal', methods=['POST'])
297
+ def upload_to_fal():
298
+ """Upload base64 image data to FAL storage and return the URL"""
299
+ try:
300
+ data = request.json
301
+ if 'image_data' not in data:
302
+ return jsonify({'error': 'No image data provided'}), 400
303
+
304
+ # Get API key from header or environment
305
+ auth_header = request.headers.get('Authorization', '')
306
+ if auth_header.startswith('Bearer '):
307
+ api_key = auth_header.replace('Bearer ', '')
308
+ elif os.environ.get('FAL_KEY'):
309
+ api_key = os.environ.get('FAL_KEY')
310
+ else:
311
+ return jsonify({'error': 'API key not provided'}), 401
312
+
313
+ # Set API key for this request
314
+ os.environ['FAL_KEY'] = api_key
315
+
316
+ image_data = data['image_data']
317
+
318
+ # If it's a base64 data URL, extract the actual base64 content
319
+ if image_data.startswith('data:'):
320
+ # Extract base64 content from data URL
321
+ header, base64_content = image_data.split(',', 1)
322
+ # Decode base64 to bytes
323
+ image_bytes = base64.b64decode(base64_content)
324
+
325
+ # Save to temporary file
326
+ with tempfile.NamedTemporaryFile(suffix='.png', delete=False) as tmp_file:
327
+ tmp_file.write(image_bytes)
328
+ tmp_file_path = tmp_file.name
329
+
330
+ try:
331
+ # Upload to FAL using asyncio.run
332
+ fal_url = asyncio.run(fal_client.upload_file_async(tmp_file_path))
333
+ print(f"[DEBUG] Uploaded to FAL: {fal_url}")
334
+ return jsonify({'url': fal_url}), 200
335
+ finally:
336
+ # Clean up temporary file
337
+ os.unlink(tmp_file_path)
338
+ else:
339
+ # If it's already a URL, return it as-is
340
+ return jsonify({'url': image_data}), 200
341
+
342
+ except Exception as e:
343
+ print(f"Error uploading to FAL: {str(e)}")
344
+ import traceback
345
+ traceback.print_exc()
346
+ return jsonify({'error': str(e)}), 500
347
+
348
  @app.route('/health', methods=['GET'])
349
  def health_check():
350
  """Health check endpoint for container monitoring"""
static/script.js CHANGED
@@ -368,11 +368,58 @@ function getImageSize() {
368
  return size;
369
  }
370
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  // Prepare image URLs for API
372
  async function getImageUrlsForAPI() {
373
  const urls = [];
374
- urls.push(...uploadedImages);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
 
 
376
  const textUrls = imageUrls.value.trim().split('\n').filter(url => url.trim());
377
  for (const url of textUrls) {
378
  urls.push(url);
@@ -427,7 +474,7 @@ async function generateEdit() {
427
  currentInfo.innerHTML = '';
428
  clearLogs();
429
 
430
- showStatus('Connecting to FAL API...', 'info');
431
  progressLogs.classList.add('active');
432
 
433
  const requestData = {
@@ -438,6 +485,7 @@ async function generateEdit() {
438
  };
439
 
440
  if (!isTextToImage) {
 
441
  requestData.image_urls = imageUrlsArray;
442
  requestData.max_images = parseInt(document.getElementById('maxImages').value);
443
  }
@@ -668,6 +716,8 @@ async function useAsInput(imageId, imageSrc) {
668
  return;
669
  }
670
 
 
 
671
  uploadedImages.push(imageSrc);
672
 
673
  // Get dimensions
 
368
  return size;
369
  }
370
 
371
+ // Upload image to FAL storage
372
+ async function uploadImageToFal(imageData, apiKey) {
373
+ try {
374
+ const response = await fetch('/api/upload-to-fal', {
375
+ method: 'POST',
376
+ headers: {
377
+ 'Content-Type': 'application/json',
378
+ 'Authorization': `Bearer ${apiKey}`
379
+ },
380
+ body: JSON.stringify({ image_data: imageData })
381
+ });
382
+
383
+ if (!response.ok) {
384
+ const error = await response.text();
385
+ throw new Error(error || 'Failed to upload image to FAL');
386
+ }
387
+
388
+ const data = await response.json();
389
+ return data.url;
390
+ } catch (error) {
391
+ console.error('Error uploading to FAL:', error);
392
+ throw error;
393
+ }
394
+ }
395
+
396
  // Prepare image URLs for API
397
  async function getImageUrlsForAPI() {
398
  const urls = [];
399
+ const apiKey = getAPIKey();
400
+
401
+ // Process uploaded base64 images - upload to FAL first
402
+ for (let i = 0; i < uploadedImages.length; i++) {
403
+ const imageData = uploadedImages[i];
404
+
405
+ // If it's a base64 data URL, upload to FAL
406
+ if (imageData.startsWith('data:')) {
407
+ try {
408
+ addLog(`Uploading image ${i + 1} to FAL storage...`);
409
+ const falUrl = await uploadImageToFal(imageData, apiKey);
410
+ urls.push(falUrl);
411
+ addLog(`Image ${i + 1} uploaded successfully`);
412
+ } catch (error) {
413
+ addLog(`Failed to upload image ${i + 1}: ${error.message}`);
414
+ throw error;
415
+ }
416
+ } else {
417
+ // Already a URL, use as-is
418
+ urls.push(imageData);
419
+ }
420
+ }
421
 
422
+ // Add text URLs directly
423
  const textUrls = imageUrls.value.trim().split('\n').filter(url => url.trim());
424
  for (const url of textUrls) {
425
  urls.push(url);
 
474
  currentInfo.innerHTML = '';
475
  clearLogs();
476
 
477
+ showStatus('Preparing images and connecting to FAL API...', 'info');
478
  progressLogs.classList.add('active');
479
 
480
  const requestData = {
 
485
  };
486
 
487
  if (!isTextToImage) {
488
+ // Note: imageUrlsArray will now contain FAL URLs after upload
489
  requestData.image_urls = imageUrlsArray;
490
  requestData.max_images = parseInt(document.getElementById('maxImages').value);
491
  }
 
716
  return;
717
  }
718
 
719
+ // If the image is already a FAL URL (from history), use it directly
720
+ // Otherwise, it's a base64 image that will be uploaded when generating
721
  uploadedImages.push(imageSrc);
722
 
723
  // Get dimensions