Malaji71 commited on
Commit
5927677
·
verified ·
1 Parent(s): 103923c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +267 -80
app.py CHANGED
@@ -47,6 +47,32 @@ def ensure_directories():
47
  except Exception as e:
48
  print(f"⚠️ Error creating directory {directory}: {e}")
49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  def download_realesrgan_models():
51
  """Download Real-ESRGAN models if not present"""
52
  if not REALESRGAN_AVAILABLE:
@@ -116,6 +142,28 @@ def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
116
  log_message(f"❌ Error initializing Real-ESRGAN: {str(e)}")
117
  return None
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  def upscale_image_realesrgan(input_path, output_path):
120
  """Upscale image using Real-ESRGAN"""
121
  def process_worker():
@@ -209,7 +257,7 @@ def upscale_image_realesrgan(input_path, output_path):
209
  thread.start()
210
 
211
  def upscale_image_4k_fallback(input_path, output_path):
212
- """Fallback upscaling method (your original implementation)"""
213
  try:
214
  log_message("🔄 Using fallback upscaling method")
215
 
@@ -219,7 +267,7 @@ def upscale_image_4k_fallback(input_path, output_path):
219
 
220
  if torch.cuda.is_available():
221
  device = torch.device('cuda')
222
- # Your original GPU implementation
223
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
224
  image_tensor = torch.from_numpy(image_rgb).float().to(device) / 255.0
225
  image_tensor = image_tensor.permute(2, 0, 1).unsqueeze(0)
@@ -264,85 +312,152 @@ def upscale_image_4k_fallback(input_path, output_path):
264
  except Exception as e:
265
  log_message(f"❌ Error in fallback processing: {str(e)}")
266
 
267
- # Update your existing upload endpoint
268
- @app.route('/api/upload', methods=['POST'])
269
- def api_upload():
270
- """Upload and process file for 4K upscaling"""
271
- try:
272
- if 'file' not in request.files:
273
- return jsonify({"success": False, "error": "No file provided"})
274
-
275
- file = request.files['file']
276
- if file.filename == '':
277
- return jsonify({"success": False, "error": "No file selected"})
278
-
279
- if file and allowed_file(file.filename):
280
- file_id = str(uuid.uuid4())
281
- filename = secure_filename(file.filename)
282
- file_ext = filename.rsplit('.', 1)[1].lower()
283
 
284
- input_filename = f"{file_id}_input.{file_ext}"
285
- input_path = os.path.join(UPLOAD_FOLDER, input_filename)
286
- file.save(input_path)
 
 
287
 
288
- output_filename = f"{file_id}_4k.{file_ext}"
289
- output_path = os.path.join(OUTPUT_FOLDER, output_filename)
 
 
 
 
290
 
291
- if file_ext in ['png', 'jpg', 'jpeg', 'gif']:
292
- # Use Real-ESRGAN for images if available
293
- if REALESRGAN_AVAILABLE:
294
- upscale_image_realesrgan(input_path, output_path)
295
- else:
296
- upscale_image_4k_fallback(input_path, output_path)
297
- media_type = "image"
298
- elif file_ext in ['mp4', 'avi', 'mov', 'mkv']:
299
- # Keep your existing video processing
300
- upscale_video_4k(input_path, output_path)
301
- media_type = "video"
302
 
303
- log_message(f"📤 File uploaded: {filename}")
 
 
 
 
 
 
304
 
305
- return jsonify({
306
- "success": True,
307
- "file_id": file_id,
308
- "filename": filename,
309
- "output_filename": output_filename,
310
- "media_type": media_type,
311
- "method": "Real-ESRGAN" if REALESRGAN_AVAILABLE and media_type == "image" else "Traditional",
312
- "message": "Upload successful, processing started"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  })
314
- else:
315
- return jsonify({"success": False, "error": "File type not allowed"})
316
- except Exception as e:
317
- return jsonify({"success": False, "error": str(e)})
 
 
 
 
 
 
 
318
 
319
- # Add new endpoint for model selection
320
- @app.route('/api/select-model', methods=['POST'])
321
- def api_select_model():
322
- """Select Real-ESRGAN model"""
323
- try:
324
- data = request.get_json()
325
- model_name = data.get('model', 'RealESRGAN_x4plus')
326
 
327
- if model_name not in ['RealESRGAN_x4plus', 'RealESRGAN_x2plus', 'RealESRNet_x4plus']:
328
- return jsonify({"success": False, "error": "Invalid model name"})
329
 
330
- scale = 4 if '4' in model_name else 2
331
- upscaler = initialize_realesrgan(model_name, scale)
 
332
 
333
- if upscaler:
334
- return jsonify({
335
- "success": True,
336
- "message": f"Model {model_name} selected",
337
- "current_model": app_state["current_model"]
338
- })
339
- else:
340
- return jsonify({"success": False, "error": "Failed to initialize model"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
 
342
- except Exception as e:
343
- return jsonify({"success": False, "error": str(e)})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
 
345
- # Update system info endpoint
346
  @app.route('/api/system')
347
  def api_system():
348
  """Get system information"""
@@ -358,9 +473,16 @@ def api_system():
358
  info["gpu_memory"] = f"{total_memory / (1024**3):.1f}GB"
359
  info["gpu_memory_used"] = f"{allocated_memory / (1024**3):.1f}GB"
360
  info["gpu_memory_free"] = f"{(total_memory - allocated_memory) / (1024**3):.1f}GB"
 
 
361
  else:
362
  info["gpu_available"] = False
363
  info["gpu_name"] = "CPU Only"
 
 
 
 
 
364
 
365
  # Real-ESRGAN info
366
  info["realesrgan_available"] = REALESRGAN_AVAILABLE
@@ -384,18 +506,83 @@ def api_system():
384
 
385
  info["available_models"] = available_models
386
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
  return jsonify({"success": True, "data": info})
388
  except Exception as e:
389
  return jsonify({"success": False, "error": str(e)})
390
 
391
- # Initialize the app
392
- if __name__ == '__main__':
393
- ensure_directories()
394
- log_message("🚀 4K Upscaler starting...")
395
-
396
- # Initialize Real-ESRGAN if available
397
- if REALESRGAN_AVAILABLE:
398
- log_message("🔧 Initializing Real-ESRGAN...")
399
- initialize_realesrgan()
400
-
401
- app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  except Exception as e:
48
  print(f"⚠️ Error creating directory {directory}: {e}")
49
 
50
+ def allowed_file(filename):
51
+ """Check if file has allowed extension"""
52
+ return '.' in filename and \
53
+ filename.rsplit('.', 1)[1].lower() in ['png', 'jpg', 'jpeg', 'gif', 'mp4', 'avi', 'mov', 'mkv']
54
+
55
+ def get_file_mimetype(filename):
56
+ """Get correct mimetype for file"""
57
+ mimetype, _ = mimetypes.guess_type(filename)
58
+ if mimetype is None:
59
+ ext = filename.lower().rsplit('.', 1)[1] if '.' in filename else ''
60
+ if ext in ['mp4', 'avi', 'mov', 'mkv']:
61
+ mimetype = f'video/{ext}'
62
+ elif ext in ['png', 'jpg', 'jpeg', 'gif']:
63
+ mimetype = f'image/{ext}'
64
+ else:
65
+ mimetype = 'application/octet-stream'
66
+ return mimetype
67
+
68
+ def log_message(message):
69
+ """Add message to log with timestamp"""
70
+ timestamp = datetime.now().strftime("%H:%M:%S")
71
+ app_state["logs"].append(f"[{timestamp}] {message}")
72
+ if len(app_state["logs"]) > 100:
73
+ app_state["logs"] = app_state["logs"][-100:]
74
+ print(f"[{timestamp}] {message}")
75
+
76
  def download_realesrgan_models():
77
  """Download Real-ESRGAN models if not present"""
78
  if not REALESRGAN_AVAILABLE:
 
142
  log_message(f"❌ Error initializing Real-ESRGAN: {str(e)}")
143
  return None
144
 
145
+ def optimize_gpu():
146
+ """Optimize GPU configuration for 4K upscaling"""
147
+ try:
148
+ if torch.cuda.is_available():
149
+ torch.backends.cudnn.benchmark = True
150
+ torch.backends.cudnn.allow_tf32 = True
151
+ torch.backends.cuda.matmul.allow_tf32 = True
152
+ torch.cuda.empty_cache()
153
+
154
+ # Test GPU
155
+ test_tensor = torch.randn(100, 100, device='cuda')
156
+ _ = torch.mm(test_tensor, test_tensor)
157
+
158
+ log_message("✅ GPU optimized for 4K upscaling")
159
+ return True
160
+ else:
161
+ log_message("⚠️ CUDA not available")
162
+ return False
163
+ except Exception as e:
164
+ log_message(f"❌ Error optimizing GPU: {str(e)}")
165
+ return False
166
+
167
  def upscale_image_realesrgan(input_path, output_path):
168
  """Upscale image using Real-ESRGAN"""
169
  def process_worker():
 
257
  thread.start()
258
 
259
  def upscale_image_4k_fallback(input_path, output_path):
260
+ """Fallback upscaling method"""
261
  try:
262
  log_message("🔄 Using fallback upscaling method")
263
 
 
267
 
268
  if torch.cuda.is_available():
269
  device = torch.device('cuda')
270
+ # GPU implementation
271
  image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
272
  image_tensor = torch.from_numpy(image_rgb).float().to(device) / 255.0
273
  image_tensor = image_tensor.permute(2, 0, 1).unsqueeze(0)
 
312
  except Exception as e:
313
  log_message(f"❌ Error in fallback processing: {str(e)}")
314
 
315
+ def upscale_video_4k(input_path, output_path):
316
+ """Upscale video to 4K frame by frame"""
317
+ def process_worker():
318
+ try:
319
+ log_message(f"🎬 Starting 4K video upscaling: {os.path.basename(input_path)}")
320
+ app_state["processing_active"] = True
 
 
 
 
 
 
 
 
 
 
321
 
322
+ # Open video
323
+ cap = cv2.VideoCapture(input_path)
324
+ if not cap.isOpened():
325
+ log_message("❌ Error: Could not open video")
326
+ return
327
 
328
+ # Get video properties
329
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
330
+ frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
331
+ w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
332
+ h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
333
+ log_message(f"📹 Video: {w}x{h}, {fps}FPS, {frame_count} frames")
334
 
335
+ # Configure 4K output
336
+ target_w, target_h = w * 4, h * 4
337
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
338
+ out = cv2.VideoWriter(output_path, fourcc, fps, (target_w, target_h))
 
 
 
 
 
 
 
339
 
340
+ if torch.cuda.is_available():
341
+ device = torch.device('cuda')
342
+ log_message(f"🚀 Processing with GPU: {torch.cuda.get_device_name()}")
343
+ process_frames_gpu(cap, out, device, target_h, target_w, frame_count)
344
+ else:
345
+ log_message("💻 Processing with CPU (may be slower)")
346
+ process_frames_cpu(cap, out, target_h, target_w, frame_count)
347
 
348
+ cap.release()
349
+ out.release()
350
+
351
+ # Verify the output file was created and has content
352
+ if os.path.exists(output_path):
353
+ file_size = os.path.getsize(output_path)
354
+ if file_size > 0:
355
+ log_message(f" 4K video completed: {target_w}x{target_h}")
356
+ log_message(f"📁 Output file size: {file_size / (1024**2):.1f}MB")
357
+ else:
358
+ log_message(f"❌ Output file is empty: {output_path}")
359
+ raise Exception("Output video file is empty")
360
+ else:
361
+ log_message(f"❌ Output file not created: {output_path}")
362
+ raise Exception("Output video file was not created")
363
+
364
+ # Add to processed files list
365
+ app_state["processed_files"].append({
366
+ "input_file": os.path.basename(input_path),
367
+ "output_file": os.path.basename(output_path),
368
+ "original_size": f"{w}x{h}",
369
+ "upscaled_size": f"{target_w}x{target_h}",
370
+ "frame_count": frame_count,
371
+ "fps": fps,
372
+ "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
373
  })
374
+
375
+ except Exception as e:
376
+ log_message(f"❌ Error processing video: {str(e)}")
377
+ finally:
378
+ app_state["processing_active"] = False
379
+ if torch.cuda.is_available():
380
+ torch.cuda.empty_cache()
381
+
382
+ thread = threading.Thread(target=process_worker)
383
+ thread.daemon = True
384
+ thread.start()
385
 
386
+ def process_frames_cpu(cap, out, target_h, target_w, frame_count):
387
+ """Process video frames using CPU"""
388
+ frame_num = 0
389
+ while True:
390
+ ret, frame = cap.read()
391
+ if not ret:
392
+ break
393
 
394
+ frame_num += 1
 
395
 
396
+ # Simple CPU upscaling
397
+ upscaled_frame = cv2.resize(frame, (target_w, target_h), interpolation=cv2.INTER_CUBIC)
398
+ out.write(upscaled_frame)
399
 
400
+ # Progress logging
401
+ if frame_num % 30 == 0:
402
+ progress = (frame_num / frame_count) * 100
403
+ log_message(f"🎞️ Processing frame {frame_num}/{frame_count} ({progress:.1f}%)")
404
+
405
+ def process_frames_gpu(cap, out, device, target_h, target_w, frame_count):
406
+ """Process video frames using GPU with PyTorch"""
407
+ frame_num = 0
408
+ torch.backends.cudnn.benchmark = True
409
+
410
+ while True:
411
+ ret, frame = cap.read()
412
+ if not ret:
413
+ break
414
+
415
+ frame_num += 1
416
+
417
+ try:
418
+ # Convert to tensor
419
+ frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
420
+ frame_tensor = torch.from_numpy(frame_rgb).float().to(device) / 255.0
421
+ frame_tensor = frame_tensor.permute(2, 0, 1).unsqueeze(0)
422
 
423
+ with torch.no_grad():
424
+ upscaled = torch.nn.functional.interpolate(
425
+ frame_tensor,
426
+ size=(target_h, target_w),
427
+ mode='bicubic',
428
+ align_corners=False
429
+ )
430
+
431
+ # Convert back
432
+ result_cpu = upscaled.squeeze(0).permute(1, 2, 0).cpu().numpy()
433
+ result_frame = (result_cpu * 255).astype(np.uint8)
434
+ result_bgr = cv2.cvtColor(result_frame, cv2.COLOR_RGB2BGR)
435
+ out.write(result_bgr)
436
+
437
+ except Exception as e:
438
+ log_message(f"⚠️ GPU processing failed for frame {frame_num}, using CPU fallback")
439
+ # CPU fallback
440
+ upscaled_frame = cv2.resize(frame, (target_w, target_h), interpolation=cv2.INTER_CUBIC)
441
+ out.write(upscaled_frame)
442
+
443
+ # Progress logging
444
+ if frame_num % 30 == 0:
445
+ progress = (frame_num / frame_count) * 100
446
+ log_message(f"🎞️ Processing frame {frame_num}/{frame_count} ({progress:.1f}%)")
447
+
448
+ # Periodic memory cleanup
449
+ if frame_num % 60 == 0 and torch.cuda.is_available():
450
+ torch.cuda.empty_cache()
451
+
452
+ # Initialize directories
453
+ ensure_directories()
454
+
455
+ app = Flask(__name__)
456
+
457
+ @app.route('/')
458
+ def index():
459
+ return render_template('index.html')
460
 
 
461
  @app.route('/api/system')
462
  def api_system():
463
  """Get system information"""
 
473
  info["gpu_memory"] = f"{total_memory / (1024**3):.1f}GB"
474
  info["gpu_memory_used"] = f"{allocated_memory / (1024**3):.1f}GB"
475
  info["gpu_memory_free"] = f"{(total_memory - allocated_memory) / (1024**3):.1f}GB"
476
+ info["cuda_version"] = torch.version.cuda
477
+ info["pytorch_version"] = torch.__version__
478
  else:
479
  info["gpu_available"] = False
480
  info["gpu_name"] = "CPU Only"
481
+ info["gpu_memory"] = "N/A"
482
+ info["gpu_memory_used"] = "N/A"
483
+ info["gpu_memory_free"] = "N/A"
484
+ info["cuda_version"] = "Not available"
485
+ info["pytorch_version"] = torch.__version__
486
 
487
  # Real-ESRGAN info
488
  info["realesrgan_available"] = REALESRGAN_AVAILABLE
 
506
 
507
  info["available_models"] = available_models
508
 
509
+ # Storage info
510
+ if os.path.exists("/data"):
511
+ info["persistent_storage"] = True
512
+ try:
513
+ upload_files = os.listdir(UPLOAD_FOLDER) if os.path.exists(UPLOAD_FOLDER) else []
514
+ output_files = os.listdir(OUTPUT_FOLDER) if os.path.exists(OUTPUT_FOLDER) else []
515
+
516
+ upload_size = sum(os.path.getsize(os.path.join(UPLOAD_FOLDER, f))
517
+ for f in upload_files if os.path.isfile(os.path.join(UPLOAD_FOLDER, f)))
518
+ output_size = sum(os.path.getsize(os.path.join(OUTPUT_FOLDER, f))
519
+ for f in output_files if os.path.isfile(os.path.join(OUTPUT_FOLDER, f)))
520
+
521
+ info["storage_uploads"] = f"{upload_size / (1024**2):.1f}MB"
522
+ info["storage_outputs"] = f"{output_size / (1024**2):.1f}MB"
523
+ info["upload_files_count"] = len(upload_files)
524
+ info["output_files_count"] = len(output_files)
525
+ except Exception as e:
526
+ info["storage_uploads"] = f"Error: {str(e)}"
527
+ info["storage_outputs"] = "N/A"
528
+ info["upload_files_count"] = 0
529
+ info["output_files_count"] = 0
530
+ else:
531
+ info["persistent_storage"] = False
532
+
533
  return jsonify({"success": True, "data": info})
534
  except Exception as e:
535
  return jsonify({"success": False, "error": str(e)})
536
 
537
+ @app.route('/api/upload', methods=['POST'])
538
+ def api_upload():
539
+ """Upload and process file for 4K upscaling"""
540
+ try:
541
+ if 'file' not in request.files:
542
+ return jsonify({"success": False, "error": "No file provided"})
543
+
544
+ file = request.files['file']
545
+ if file.filename == '':
546
+ return jsonify({"success": False, "error": "No file selected"})
547
+
548
+ if file and allowed_file(file.filename):
549
+ file_id = str(uuid.uuid4())
550
+ filename = secure_filename(file.filename)
551
+ file_ext = filename.rsplit('.', 1)[1].lower()
552
+
553
+ input_filename = f"{file_id}_input.{file_ext}"
554
+ input_path = os.path.join(UPLOAD_FOLDER, input_filename)
555
+ file.save(input_path)
556
+
557
+ output_filename = f"{file_id}_4k.{file_ext}"
558
+ output_path = os.path.join(OUTPUT_FOLDER, output_filename)
559
+
560
+ if file_ext in ['png', 'jpg', 'jpeg', 'gif']:
561
+ # Use Real-ESRGAN for images if available
562
+ if REALESRGAN_AVAILABLE:
563
+ upscale_image_realesrgan(input_path, output_path)
564
+ else:
565
+ upscale_image_4k_fallback(input_path, output_path)
566
+ media_type = "image"
567
+ elif file_ext in ['mp4', 'avi', 'mov', 'mkv']:
568
+ upscale_video_4k(input_path, output_path)
569
+ media_type = "video"
570
+
571
+ log_message(f"📤 File uploaded: {filename}")
572
+
573
+ return jsonify({
574
+ "success": True,
575
+ "file_id": file_id,
576
+ "filename": filename,
577
+ "output_filename": output_filename,
578
+ "media_type": media_type,
579
+ "method": "Real-ESRGAN" if REALESRGAN_AVAILABLE and media_type == "image" else "Traditional",
580
+ "message": "Upload successful, processing started"
581
+ })
582
+ else:
583
+ return jsonify({"success": False, "error": "File type not allowed"})
584
+ except Exception as e:
585
+ return jsonify({"success": False, "error": str(e)})
586
+
587
+ @app.route('/api/select-model', methods=['POST'])
588
+ def api_select_model