Malaji71 commited on
Commit
a28ea54
·
verified ·
1 Parent(s): 9fba2f1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +314 -228
app.py CHANGED
@@ -10,16 +10,23 @@ import uuid
10
  import mimetypes
11
  import numpy as np
12
  from PIL import Image
 
 
 
 
 
13
 
14
- # Real-ESRGAN imports with better error handling
15
  try:
16
  from realesrgan import RealESRGANer
17
  from basicsr.archs.rrdbnet_arch import RRDBNet
18
  REALESRGAN_AVAILABLE = True
19
- print("✅ Real-ESRGAN available")
20
  except ImportError as e:
21
- REALESRGAN_AVAILABLE = False
22
  print(f"⚠️ Real-ESRGAN not available: {e}")
 
 
 
23
 
24
  # Configuration
25
  UPLOAD_FOLDER = '/data/uploads'
@@ -30,6 +37,7 @@ MODEL_FOLDER = '/data/models'
30
  app_state = {
31
  "cuda_available": torch.cuda.is_available(),
32
  "realesrgan_available": REALESRGAN_AVAILABLE,
 
33
  "processing_active": False,
34
  "logs": [],
35
  "processed_files": [],
@@ -45,178 +53,6 @@ def ensure_directories():
45
  os.makedirs(directory, exist_ok=True)
46
  print(f"✅ Directory verified: {directory}")
47
  except Exception as e:
48
- info["storage_uploads"] = "Error"
49
- info["storage_outputs"] = "Error"
50
- info["upload_files_count"] = 0
51
- info["output_files_count"] = 0
52
-
53
- return jsonify({"success": True, "data": info})
54
- except Exception as e:
55
- return jsonify({"success": False, "error": str(e)})
56
-
57
- @app.route('/api/upload', methods=['POST'])
58
- def api_upload():
59
- """Upload and process file for 4K upscaling"""
60
- try:
61
- if 'file' not in request.files:
62
- return jsonify({"success": False, "error": "No file provided"})
63
-
64
- file = request.files['file']
65
- if file.filename == '':
66
- return jsonify({"success": False, "error": "No file selected"})
67
-
68
- if file and allowed_file(file.filename):
69
- file_id = str(uuid.uuid4())
70
- filename = secure_filename(file.filename)
71
- file_ext = filename.rsplit('.', 1)[1].lower()
72
-
73
- input_filename = f"{file_id}_input.{file_ext}"
74
- input_path = os.path.join(UPLOAD_FOLDER, input_filename)
75
- file.save(input_path)
76
-
77
- output_filename = f"{file_id}_4k.{file_ext}"
78
- output_path = os.path.join(OUTPUT_FOLDER, output_filename)
79
-
80
- if file_ext in ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'webp']:
81
- upscale_image_4k(input_path, output_path)
82
- media_type = "image"
83
- elif file_ext in ['mp4', 'avi', 'mov', 'mkv']:
84
- upscale_video_4k(input_path, output_path)
85
- media_type = "video"
86
-
87
- log_message(f"📤 File uploaded: {filename}")
88
- log_message(f"🎯 Starting 4K upscaling process...")
89
-
90
- return jsonify({
91
- "success": True,
92
- "file_id": file_id,
93
- "filename": filename,
94
- "output_filename": output_filename,
95
- "media_type": media_type,
96
- "message": "Upload successful, processing started"
97
- })
98
- else:
99
- return jsonify({"success": False, "error": "File type not allowed"})
100
- except Exception as e:
101
- return jsonify({"success": False, "error": str(e)})
102
-
103
- @app.route('/api/processing-status')
104
- def api_processing_status():
105
- """Get processing status"""
106
- return jsonify({
107
- "success": True,
108
- "processing": app_state["processing_active"],
109
- "processed_files": app_state["processed_files"]
110
- })
111
-
112
- @app.route('/api/download/<filename>')
113
- def api_download(filename):
114
- """Download processed file"""
115
- try:
116
- file_path = os.path.join(OUTPUT_FOLDER, filename)
117
- if os.path.exists(file_path):
118
- mimetype = get_file_mimetype(filename)
119
- return send_file(
120
- file_path,
121
- as_attachment=True,
122
- download_name=f"4k_upscaled_{filename}",
123
- mimetype=mimetype
124
- )
125
- else:
126
- return jsonify({"error": "File not found"}), 404
127
- except Exception as e:
128
- return jsonify({"error": str(e)}), 500
129
-
130
- @app.route('/api/preview/<filename>')
131
- def api_preview(filename):
132
- """Preview processed file"""
133
- try:
134
- file_path = os.path.join(OUTPUT_FOLDER, filename)
135
- if os.path.exists(file_path):
136
- mimetype = get_file_mimetype(filename)
137
- return send_file(file_path, mimetype=mimetype)
138
- else:
139
- return jsonify({"error": "File not found"}), 404
140
- except Exception as e:
141
- return jsonify({"error": str(e)}), 500
142
-
143
- @app.route('/api/logs')
144
- def api_logs():
145
- """Get application logs"""
146
- return jsonify({
147
- "success": True,
148
- "logs": app_state["logs"]
149
- })
150
-
151
- @app.route('/api/clear-logs', methods=['POST'])
152
- def api_clear_logs():
153
- """Clear application logs"""
154
- app_state["logs"] = []
155
- log_message("🧹 Logs cleared")
156
- return jsonify({"success": True, "message": "Logs cleared"})
157
-
158
- @app.route('/api/optimize-gpu', methods=['POST'])
159
- def api_optimize_gpu():
160
- """Optimize GPU for processing"""
161
- try:
162
- success = optimize_gpu()
163
- return jsonify({"success": success})
164
- except Exception as e:
165
- return jsonify({"success": False, "error": str(e)})
166
-
167
- @app.route('/api/init-realesrgan', methods=['POST'])
168
- def api_init_realesrgan():
169
- """Initialize Real-ESRGAN manually"""
170
- try:
171
- if not REALESRGAN_AVAILABLE:
172
- return jsonify({"success": False, "error": "Real-ESRGAN not available"})
173
-
174
- upscaler = initialize_realesrgan()
175
- if upscaler:
176
- return jsonify({"success": True, "message": "Real-ESRGAN initialized successfully"})
177
- else:
178
- return jsonify({"success": False, "error": "Failed to initialize Real-ESRGAN"})
179
- except Exception as e:
180
- return jsonify({"success": False, "error": str(e)})
181
-
182
- @app.route('/api/clear-cache', methods=['POST'])
183
- def api_clear_cache():
184
- """Clear cache and processed files"""
185
- try:
186
- if torch.cuda.is_available():
187
- torch.cuda.empty_cache()
188
-
189
- app_state["processed_files"] = []
190
- log_message("🧹 Cache and history cleared")
191
-
192
- return jsonify({"success": True, "message": "Cache cleared"})
193
- except Exception as e:
194
- return jsonify({"success": False, "error": str(e)})
195
-
196
- if __name__ == '__main__':
197
- # Initialize system
198
- log_message("🚀 4K Upscaler starting...")
199
-
200
- try:
201
- # Optimize GPU if available
202
- if optimize_gpu():
203
- log_message("✅ GPU optimization completed")
204
- else:
205
- log_message("⚠️ Using CPU mode")
206
-
207
- log_message("✅ 4K Upscaler ready")
208
- log_message("📤 Upload images or videos to upscale to 4K resolution")
209
-
210
- except Exception as e:
211
- log_message(f"❌ Initialization error: {str(e)}")
212
- log_message("⚠️ Starting in fallback mode...")
213
-
214
- # Run application
215
- try:
216
- app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
217
- except Exception as e:
218
- log_message(f"❌ Server startup error: {str(e)}")
219
- print(f"Critical error: {str(e)}")
220
  print(f"⚠️ Error creating directory {directory}: {e}")
221
 
222
  def allowed_file(filename):
@@ -248,6 +84,7 @@ def log_message(message):
248
  def download_realesrgan_models():
249
  """Download Real-ESRGAN models if not present"""
250
  if not REALESRGAN_AVAILABLE:
 
251
  return False
252
 
253
  models = {
@@ -267,15 +104,17 @@ def download_realesrgan_models():
267
  except Exception as e:
268
  log_message(f"❌ Failed to download {model_name}: {e}")
269
  return False
 
 
270
  return True
271
  except Exception as e:
272
  log_message(f"❌ Error downloading models: {str(e)}")
273
  return False
274
 
275
  def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
276
- """Initialize Real-ESRGAN upscaler"""
277
  if not REALESRGAN_AVAILABLE:
278
- log_message("❌ Real-ESRGAN not available")
279
  return None
280
 
281
  try:
@@ -290,6 +129,13 @@ def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
290
  log_message("❌ Failed to download models")
291
  return None
292
 
 
 
 
 
 
 
 
293
  # Initialize model architecture
294
  if model_name == 'RealESRGAN_x4plus':
295
  model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
@@ -301,7 +147,7 @@ def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
301
  log_message(f"❌ Unknown model: {model_name}")
302
  return None
303
 
304
- # Always use CPU for compatibility
305
  device = torch.device('cpu')
306
  log_message(f"🖥️ Using device: {device}")
307
 
@@ -310,13 +156,23 @@ def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
310
  scale=netscale,
311
  model_path=model_path,
312
  model=model,
313
- tile=200, # Small tile size for CPU
314
  tile_pad=10,
315
  pre_pad=0,
316
  half=False, # No half precision on CPU
317
  device=device
318
  )
319
 
 
 
 
 
 
 
 
 
 
 
320
  app_state["upscaler"] = upscaler
321
  app_state["current_model"] = model_name
322
  log_message(f"✅ Real-ESRGAN initialized: {model_name} on {device}")
@@ -324,6 +180,7 @@ def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
324
 
325
  except Exception as e:
326
  log_message(f"❌ Error initializing Real-ESRGAN: {str(e)}")
 
327
  app_state["upscaler"] = None
328
  app_state["current_model"] = None
329
  return None
@@ -359,10 +216,19 @@ def upscale_image_4k(input_path, output_path):
359
 
360
  start_time = time.time()
361
 
362
- # Read image
363
- img = cv2.imread(input_path, cv2.IMREAD_COLOR)
 
 
 
 
 
 
 
 
 
364
  if img is None:
365
- log_message("❌ Error: Could not read image")
366
  return
367
 
368
  h, w = img.shape[:2]
@@ -372,27 +238,20 @@ def upscale_image_4k(input_path, output_path):
372
  method_used = "Unknown"
373
 
374
  # Try Real-ESRGAN first if available
375
- if REALESRGAN_AVAILABLE:
376
  try:
377
- if app_state["upscaler"] is None:
378
- log_message("🔧 Initializing Real-ESRGAN...")
379
- upscaler = initialize_realesrgan()
380
- else:
381
- upscaler = app_state["upscaler"]
382
-
383
- if upscaler is not None:
384
- log_message("🧠 Applying Real-ESRGAN neural upscaling...")
385
- output, _ = upscaler.enhance(img, outscale=4)
386
- cv2.imwrite(output_path, output)
387
- method_used = f"Real-ESRGAN ({app_state['current_model']})"
388
- success = True
389
- log_message("✅ Real-ESRGAN upscaling successful")
390
- else:
391
- log_message("⚠️ Real-ESRGAN initialization failed")
392
 
393
  except Exception as e:
394
  log_message(f"⚠️ Real-ESRGAN failed: {str(e)}")
395
  log_message("🔄 Falling back to enhanced bicubic...")
 
 
396
 
397
  # Fallback to enhanced bicubic if Real-ESRGAN failed or not available
398
  if not success:
@@ -481,33 +340,37 @@ def upscale_image_4k(input_path, output_path):
481
 
482
  if success:
483
  # Verify output
484
- final_img = cv2.imread(output_path)
485
- if final_img is not None:
486
- final_h, final_w = final_img.shape[:2]
487
- processing_time = time.time() - start_time
488
-
489
- log_message(f"✅ Upscaling completed: {final_w}x{final_h}")
490
- log_message(f"📈 Scale factor: {final_w/w:.1f}x")
491
- log_message(f"⏱️ Processing time: {processing_time:.1f}s")
492
- log_message(f"🔧 Method used: {method_used}")
493
-
494
- # Add to processed files
495
- app_state["processed_files"].append({
496
- "input_file": os.path.basename(input_path),
497
- "output_file": os.path.basename(output_path),
498
- "original_size": f"{w}x{h}",
499
- "upscaled_size": f"{final_w}x{final_h}",
500
- "method": method_used,
501
- "processing_time": f"{processing_time:.1f}s",
502
- "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
503
- })
504
- else:
505
- log_message("❌ Error: Output file could not be read")
 
 
 
506
  else:
507
  log_message("❌ All upscaling methods failed")
508
 
509
  except Exception as e:
510
  log_message(f"❌ Critical error in upscaling: {str(e)}")
 
511
  finally:
512
  app_state["processing_active"] = False
513
  if torch.cuda.is_available():
@@ -554,7 +417,7 @@ def upscale_video_4k(input_path, output_path):
554
  frame_num += 1
555
 
556
  try:
557
- # Enhanced bicubic for video frames
558
  upscaled_frame = cv2.resize(frame, (target_w, target_h), interpolation=cv2.INTER_CUBIC)
559
 
560
  # Light sharpening
@@ -603,6 +466,7 @@ def upscale_video_4k(input_path, output_path):
603
 
604
  except Exception as e:
605
  log_message(f"❌ Error processing video: {str(e)}")
 
606
  finally:
607
  app_state["processing_active"] = False
608
  if torch.cuda.is_available():
@@ -612,15 +476,15 @@ def upscale_video_4k(input_path, output_path):
612
  thread.daemon = True
613
  thread.start()
614
 
615
- # Initialize directories and try to set up Real-ESRGAN
616
  ensure_directories()
617
 
618
  def force_init_realesrgan():
619
  """Force Real-ESRGAN initialization with detailed logging"""
620
- log_message("🔧 Force initializing Real-ESRGAN...")
621
 
622
  if not REALESRGAN_AVAILABLE:
623
- log_message("❌ Real-ESRGAN package not available")
624
  return False
625
 
626
  try:
@@ -643,13 +507,15 @@ def force_init_realesrgan():
643
 
644
  except Exception as e:
645
  log_message(f"❌ Real-ESRGAN initialization error: {str(e)}")
646
- import traceback
647
  log_message(f"🔍 Traceback: {traceback.format_exc()}")
648
  return False
649
 
650
  # Try to initialize Real-ESRGAN on startup
651
  log_message("🚀 Starting Real-ESRGAN initialization...")
652
- force_init_realesrgan()
 
 
 
653
 
654
  app = Flask(__name__)
655
 
@@ -659,7 +525,7 @@ def index():
659
 
660
  @app.route('/api/system')
661
  def api_system():
662
- """Get system information"""
663
  try:
664
  info = {}
665
 
@@ -687,6 +553,7 @@ def api_system():
687
  info["realesrgan_available"] = REALESRGAN_AVAILABLE
688
  info["realesrgan_initialized"] = app_state["upscaler"] is not None
689
  info["current_model"] = app_state.get("current_model", "None")
 
690
 
691
  # Check if models exist
692
  models_status = {}
@@ -711,4 +578,223 @@ def api_system():
711
  info["storage_outputs"] = f"{output_size / (1024**2):.1f}MB"
712
  info["upload_files_count"] = len(upload_files)
713
  info["output_files_count"] = len(output_files)
714
- except Exception as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  import mimetypes
11
  import numpy as np
12
  from PIL import Image
13
+ import traceback
14
+
15
+ # Real-ESRGAN imports with comprehensive error handling
16
+ REALESRGAN_AVAILABLE = False
17
+ REALESRGAN_ERROR = None
18
 
 
19
  try:
20
  from realesrgan import RealESRGANer
21
  from basicsr.archs.rrdbnet_arch import RRDBNet
22
  REALESRGAN_AVAILABLE = True
23
+ print("✅ Real-ESRGAN successfully imported")
24
  except ImportError as e:
25
+ REALESRGAN_ERROR = str(e)
26
  print(f"⚠️ Real-ESRGAN not available: {e}")
27
+ except Exception as e:
28
+ REALESRGAN_ERROR = str(e)
29
+ print(f"❌ Real-ESRGAN import error: {e}")
30
 
31
  # Configuration
32
  UPLOAD_FOLDER = '/data/uploads'
 
37
  app_state = {
38
  "cuda_available": torch.cuda.is_available(),
39
  "realesrgan_available": REALESRGAN_AVAILABLE,
40
+ "realesrgan_error": REALESRGAN_ERROR,
41
  "processing_active": False,
42
  "logs": [],
43
  "processed_files": [],
 
53
  os.makedirs(directory, exist_ok=True)
54
  print(f"✅ Directory verified: {directory}")
55
  except Exception as e:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  print(f"⚠️ Error creating directory {directory}: {e}")
57
 
58
  def allowed_file(filename):
 
84
  def download_realesrgan_models():
85
  """Download Real-ESRGAN models if not present"""
86
  if not REALESRGAN_AVAILABLE:
87
+ log_message("❌ Real-ESRGAN not available for model download")
88
  return False
89
 
90
  models = {
 
104
  except Exception as e:
105
  log_message(f"❌ Failed to download {model_name}: {e}")
106
  return False
107
+ else:
108
+ log_message(f"✅ Model {model_name} already exists")
109
  return True
110
  except Exception as e:
111
  log_message(f"❌ Error downloading models: {str(e)}")
112
  return False
113
 
114
  def initialize_realesrgan(model_name='RealESRGAN_x4plus', scale=4):
115
+ """Initialize Real-ESRGAN upscaler with robust error handling"""
116
  if not REALESRGAN_AVAILABLE:
117
+ log_message(f"❌ Real-ESRGAN not available: {REALESRGAN_ERROR}")
118
  return None
119
 
120
  try:
 
129
  log_message("❌ Failed to download models")
130
  return None
131
 
132
+ # Verify model file
133
+ if not os.path.exists(model_path) or os.path.getsize(model_path) == 0:
134
+ log_message(f"❌ Model file invalid: {model_path}")
135
+ return None
136
+
137
+ log_message(f"📁 Model file verified: {os.path.getsize(model_path) / (1024*1024):.1f}MB")
138
+
139
  # Initialize model architecture
140
  if model_name == 'RealESRGAN_x4plus':
141
  model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=23, num_grow_ch=32, scale=4)
 
147
  log_message(f"❌ Unknown model: {model_name}")
148
  return None
149
 
150
+ # Use CPU for maximum compatibility
151
  device = torch.device('cpu')
152
  log_message(f"🖥️ Using device: {device}")
153
 
 
156
  scale=netscale,
157
  model_path=model_path,
158
  model=model,
159
+ tile=400, # Reasonable tile size for CPU
160
  tile_pad=10,
161
  pre_pad=0,
162
  half=False, # No half precision on CPU
163
  device=device
164
  )
165
 
166
+ # Test the upscaler with a small image
167
+ log_message("🧪 Testing Real-ESRGAN with sample image...")
168
+ test_img = np.random.randint(0, 255, (64, 64, 3), dtype=np.uint8)
169
+ try:
170
+ _, _ = upscaler.enhance(test_img, outscale=2)
171
+ log_message("✅ Real-ESRGAN test successful")
172
+ except Exception as e:
173
+ log_message(f"❌ Real-ESRGAN test failed: {e}")
174
+ return None
175
+
176
  app_state["upscaler"] = upscaler
177
  app_state["current_model"] = model_name
178
  log_message(f"✅ Real-ESRGAN initialized: {model_name} on {device}")
 
180
 
181
  except Exception as e:
182
  log_message(f"❌ Error initializing Real-ESRGAN: {str(e)}")
183
+ log_message(f"🔍 Traceback: {traceback.format_exc()}")
184
  app_state["upscaler"] = None
185
  app_state["current_model"] = None
186
  return None
 
216
 
217
  start_time = time.time()
218
 
219
+ # Read image with error handling
220
+ try:
221
+ img = cv2.imread(input_path, cv2.IMREAD_COLOR)
222
+ if img is None:
223
+ # Try with PIL as fallback
224
+ pil_img = Image.open(input_path).convert('RGB')
225
+ img = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
226
+ except Exception as e:
227
+ log_message(f"❌ Error reading image: {e}")
228
+ return
229
+
230
  if img is None:
231
+ log_message("❌ Error: Could not read image with any method")
232
  return
233
 
234
  h, w = img.shape[:2]
 
238
  method_used = "Unknown"
239
 
240
  # Try Real-ESRGAN first if available
241
+ if REALESRGAN_AVAILABLE and app_state["upscaler"] is not None:
242
  try:
243
+ log_message("🧠 Applying Real-ESRGAN neural upscaling...")
244
+ output, _ = app_state["upscaler"].enhance(img, outscale=4)
245
+ cv2.imwrite(output_path, output)
246
+ method_used = f"Real-ESRGAN ({app_state['current_model']})"
247
+ success = True
248
+ log_message("✅ Real-ESRGAN upscaling successful")
 
 
 
 
 
 
 
 
 
249
 
250
  except Exception as e:
251
  log_message(f"⚠️ Real-ESRGAN failed: {str(e)}")
252
  log_message("🔄 Falling back to enhanced bicubic...")
253
+ else:
254
+ log_message("⚠️ Real-ESRGAN not available, using enhanced bicubic")
255
 
256
  # Fallback to enhanced bicubic if Real-ESRGAN failed or not available
257
  if not success:
 
340
 
341
  if success:
342
  # Verify output
343
+ try:
344
+ final_img = cv2.imread(output_path)
345
+ if final_img is not None:
346
+ final_h, final_w = final_img.shape[:2]
347
+ processing_time = time.time() - start_time
348
+
349
+ log_message(f" Upscaling completed: {final_w}x{final_h}")
350
+ log_message(f"📈 Scale factor: {final_w/w:.1f}x")
351
+ log_message(f"⏱️ Processing time: {processing_time:.1f}s")
352
+ log_message(f"🔧 Method used: {method_used}")
353
+
354
+ # Add to processed files
355
+ app_state["processed_files"].append({
356
+ "input_file": os.path.basename(input_path),
357
+ "output_file": os.path.basename(output_path),
358
+ "original_size": f"{w}x{h}",
359
+ "upscaled_size": f"{final_w}x{final_h}",
360
+ "method": method_used,
361
+ "processing_time": f"{processing_time:.1f}s",
362
+ "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
363
+ })
364
+ else:
365
+ log_message("❌ Error: Output file could not be read")
366
+ except Exception as e:
367
+ log_message(f"❌ Error verifying output: {e}")
368
  else:
369
  log_message("❌ All upscaling methods failed")
370
 
371
  except Exception as e:
372
  log_message(f"❌ Critical error in upscaling: {str(e)}")
373
+ log_message(f"🔍 Traceback: {traceback.format_exc()}")
374
  finally:
375
  app_state["processing_active"] = False
376
  if torch.cuda.is_available():
 
417
  frame_num += 1
418
 
419
  try:
420
+ # Enhanced bicubic for video frames (faster than Real-ESRGAN)
421
  upscaled_frame = cv2.resize(frame, (target_w, target_h), interpolation=cv2.INTER_CUBIC)
422
 
423
  # Light sharpening
 
466
 
467
  except Exception as e:
468
  log_message(f"❌ Error processing video: {str(e)}")
469
+ log_message(f"🔍 Traceback: {traceback.format_exc()}")
470
  finally:
471
  app_state["processing_active"] = False
472
  if torch.cuda.is_available():
 
476
  thread.daemon = True
477
  thread.start()
478
 
479
+ # Initialize directories
480
  ensure_directories()
481
 
482
  def force_init_realesrgan():
483
  """Force Real-ESRGAN initialization with detailed logging"""
484
+ log_message("🔧 Attempting Real-ESRGAN initialization...")
485
 
486
  if not REALESRGAN_AVAILABLE:
487
+ log_message(f"❌ Real-ESRGAN package not available: {REALESRGAN_ERROR}")
488
  return False
489
 
490
  try:
 
507
 
508
  except Exception as e:
509
  log_message(f"❌ Real-ESRGAN initialization error: {str(e)}")
 
510
  log_message(f"🔍 Traceback: {traceback.format_exc()}")
511
  return False
512
 
513
  # Try to initialize Real-ESRGAN on startup
514
  log_message("🚀 Starting Real-ESRGAN initialization...")
515
+ if REALESRGAN_AVAILABLE:
516
+ force_init_realesrgan()
517
+ else:
518
+ log_message("⚠️ Real-ESRGAN not available, will use enhanced bicubic fallback")
519
 
520
  app = Flask(__name__)
521
 
 
525
 
526
  @app.route('/api/system')
527
  def api_system():
528
+ """Get comprehensive system information"""
529
  try:
530
  info = {}
531
 
 
553
  info["realesrgan_available"] = REALESRGAN_AVAILABLE
554
  info["realesrgan_initialized"] = app_state["upscaler"] is not None
555
  info["current_model"] = app_state.get("current_model", "None")
556
+ info["realesrgan_error"] = REALESRGAN_ERROR
557
 
558
  # Check if models exist
559
  models_status = {}
 
578
  info["storage_outputs"] = f"{output_size / (1024**2):.1f}MB"
579
  info["upload_files_count"] = len(upload_files)
580
  info["output_files_count"] = len(output_files)
581
+ except Exception as e:
582
+ info["storage_uploads"] = "Error"
583
+ info["storage_outputs"] = "Error"
584
+ info["upload_files_count"] = 0
585
+ info["output_files_count"] = 0
586
+
587
+ return jsonify({"success": True, "data": info})
588
+ except Exception as e:
589
+ return jsonify({"success": False, "error": str(e)})
590
+
591
+ @app.route('/api/upload', methods=['POST'])
592
+ def api_upload():
593
+ """Upload and process file for 4K upscaling"""
594
+ try:
595
+ if 'file' not in request.files:
596
+ return jsonify({"success": False, "error": "No file provided"})
597
+
598
+ file = request.files['file']
599
+ if file.filename == '':
600
+ return jsonify({"success": False, "error": "No file selected"})
601
+
602
+ if file and allowed_file(file.filename):
603
+ file_id = str(uuid.uuid4())
604
+ filename = secure_filename(file.filename)
605
+ file_ext = filename.rsplit('.', 1)[1].lower()
606
+
607
+ input_filename = f"{file_id}_input.{file_ext}"
608
+ input_path = os.path.join(UPLOAD_FOLDER, input_filename)
609
+ file.save(input_path)
610
+
611
+ output_filename = f"{file_id}_4k.{file_ext}"
612
+ output_path = os.path.join(OUTPUT_FOLDER, output_filename)
613
+
614
+ if file_ext in ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tiff', 'webp']:
615
+ upscale_image_4k(input_path, output_path)
616
+ media_type = "image"
617
+ elif file_ext in ['mp4', 'avi', 'mov', 'mkv']:
618
+ upscale_video_4k(input_path, output_path)
619
+ media_type = "video"
620
+
621
+ log_message(f"📤 File uploaded: {filename}")
622
+ log_message(f"🎯 Starting 4K upscaling process...")
623
+
624
+ return jsonify({
625
+ "success": True,
626
+ "file_id": file_id,
627
+ "filename": filename,
628
+ "output_filename": output_filename,
629
+ "media_type": media_type,
630
+ "message": "Upload successful, processing started"
631
+ })
632
+ else:
633
+ return jsonify({"success": False, "error": "File type not allowed"})
634
+ except Exception as e:
635
+ return jsonify({"success": False, "error": str(e)})
636
+
637
+ @app.route('/api/processing-status')
638
+ def api_processing_status():
639
+ """Get processing status"""
640
+ return jsonify({
641
+ "success": True,
642
+ "processing": app_state["processing_active"],
643
+ "processed_files": app_state["processed_files"]
644
+ })
645
+
646
+ @app.route('/api/download/<filename>')
647
+ def api_download(filename):
648
+ """Download processed file"""
649
+ try:
650
+ file_path = os.path.join(OUTPUT_FOLDER, filename)
651
+ if os.path.exists(file_path):
652
+ mimetype = get_file_mimetype(filename)
653
+ return send_file(
654
+ file_path,
655
+ as_attachment=True,
656
+ download_name=f"4k_upscaled_{filename}",
657
+ mimetype=mimetype
658
+ )
659
+ else:
660
+ return jsonify({"error": "File not found"}), 404
661
+ except Exception as e:
662
+ return jsonify({"error": str(e)}), 500
663
+
664
+ @app.route('/api/preview/<filename>')
665
+ def api_preview(filename):
666
+ """Preview processed file"""
667
+ try:
668
+ file_path = os.path.join(OUTPUT_FOLDER, filename)
669
+ if os.path.exists(file_path):
670
+ mimetype = get_file_mimetype(filename)
671
+ return send_file(file_path, mimetype=mimetype)
672
+ else:
673
+ return jsonify({"error": "File not found"}), 404
674
+ except Exception as e:
675
+ return jsonify({"error": str(e)}), 500
676
+
677
+ @app.route('/api/logs')
678
+ def api_logs():
679
+ """Get application logs"""
680
+ return jsonify({
681
+ "success": True,
682
+ "logs": app_state["logs"]
683
+ })
684
+
685
+ @app.route('/api/clear-logs', methods=['POST'])
686
+ def api_clear_logs():
687
+ """Clear application logs"""
688
+ app_state["logs"] = []
689
+ log_message("🧹 Logs cleared")
690
+ return jsonify({"success": True, "message": "Logs cleared"})
691
+
692
+ @app.route('/api/optimize-gpu', methods=['POST'])
693
+ def api_optimize_gpu():
694
+ """Optimize GPU for processing"""
695
+ try:
696
+ success = optimize_gpu()
697
+ return jsonify({"success": success})
698
+ except Exception as e:
699
+ return jsonify({"success": False, "error": str(e)})
700
+
701
+ @app.route('/api/init-realesrgan', methods=['POST'])
702
+ def api_init_realesrgan():
703
+ """Initialize Real-ESRGAN manually"""
704
+ try:
705
+ if not REALESRGAN_AVAILABLE:
706
+ return jsonify({
707
+ "success": False,
708
+ "error": f"Real-ESRGAN not available: {REALESRGAN_ERROR}"
709
+ })
710
+
711
+ success = force_init_realesrgan()
712
+ if success:
713
+ return jsonify({"success": True, "message": "Real-ESRGAN initialized successfully"})
714
+ else:
715
+ return jsonify({"success": False, "error": "Failed to initialize Real-ESRGAN"})
716
+ except Exception as e:
717
+ return jsonify({"success": False, "error": str(e)})
718
+
719
+ @app.route('/api/clear-cache', methods=['POST'])
720
+ def api_clear_cache():
721
+ """Clear cache and processed files"""
722
+ try:
723
+ if torch.cuda.is_available():
724
+ torch.cuda.empty_cache()
725
+
726
+ app_state["processed_files"] = []
727
+ log_message("🧹 Cache and history cleared")
728
+
729
+ return jsonify({"success": True, "message": "Cache cleared"})
730
+ except Exception as e:
731
+ return jsonify({"success": False, "error": str(e)})
732
+
733
+ @app.route('/api/test-realesrgan', methods=['POST'])
734
+ def api_test_realesrgan():
735
+ """Test Real-ESRGAN installation"""
736
+ try:
737
+ if not REALESRGAN_AVAILABLE:
738
+ return jsonify({
739
+ "success": False,
740
+ "error": f"Real-ESRGAN not available: {REALESRGAN_ERROR}",
741
+ "details": {
742
+ "import_error": REALESRGAN_ERROR,
743
+ "numpy_available": True,
744
+ "torch_available": True,
745
+ "opencv_available": True
746
+ }
747
+ })
748
+
749
+ # Test imports
750
+ try:
751
+ from realesrgan import RealESRGANer
752
+ from basicsr.archs.rrdbnet_arch import RRDBNet
753
+ import_success = True
754
+ import_error = None
755
+ except Exception as e:
756
+ import_success = False
757
+ import_error = str(e)
758
+
759
+ return jsonify({
760
+ "success": import_success,
761
+ "error": import_error,
762
+ "details": {
763
+ "realesrgan_available": REALESRGAN_AVAILABLE,
764
+ "import_error": import_error,
765
+ "current_model": app_state.get("current_model"),
766
+ "upscaler_initialized": app_state["upscaler"] is not None
767
+ }
768
+ })
769
+ except Exception as e:
770
+ return jsonify({"success": False, "error": str(e)})
771
+
772
+ if __name__ == '__main__':
773
+ # Initialize system
774
+ log_message("🚀 4K Upscaler starting...")
775
+
776
+ try:
777
+ # Optimize GPU if available
778
+ if optimize_gpu():
779
+ log_message("✅ GPU optimization completed")
780
+ else:
781
+ log_message("⚠️ Using CPU mode")
782
+
783
+ log_message("✅ 4K Upscaler ready")
784
+ log_message("📤 Upload images or videos to upscale to 4K resolution")
785
+
786
+ if REALESRGAN_AVAILABLE:
787
+ log_message("🧠 Real-ESRGAN neural upscaling available")
788
+ else:
789
+ log_message("⚠️ Real-ESRGAN not available, using enhanced bicubic fallback")
790
+
791
+ except Exception as e:
792
+ log_message(f"❌ Initialization error: {str(e)}")
793
+ log_message("⚠️ Starting in fallback mode...")
794
+
795
+ # Run application
796
+ try:
797
+ app.run(host='0.0.0.0', port=7860, debug=False, threaded=True)
798
+ except Exception as e:
799
+ log_message(f"❌ Server startup error: {str(e)}")
800
+ print(f"Critical error: {str(e)}")