tester343 commited on
Commit
b5ffd51
·
verified ·
1 Parent(s): f2379ad

Update app_enhanced.py

Browse files
Files changed (1) hide show
  1. app_enhanced.py +54 -24
app_enhanced.py CHANGED
@@ -5,9 +5,16 @@ import uuid
5
  import shutil
6
  import json
7
  import traceback
 
8
  from concurrent.futures import ThreadPoolExecutor
9
  from flask import Flask, render_template, request, jsonify, send_from_directory, send_file
10
 
 
 
 
 
 
 
11
  # --- 1. CORE DEPENDENCY CHECKS ---
12
  try:
13
  import cv2
@@ -16,15 +23,12 @@ try:
16
  import srt
17
  except ImportError as e:
18
  print(f"❌ CRITICAL ERROR: Missing python library. {e}")
19
- # Define dummies to allow app to start (will fail gracefully later)
20
  cv2 = None
21
  np = None
22
  Image = None
23
  srt = None
24
 
25
  # --- 2. BACKEND MODULE IMPORTS (WITH ROBUST FALLBACKS) ---
26
- # This section ensures the app loads even if specific backend files are missing.
27
-
28
  def dummy_black_bar_crop(): return 0, 0, None, None
29
 
30
  try:
@@ -51,7 +55,6 @@ try:
51
  from backend.class_def import bubble, panel, Page
52
  print("✅ Core class definitions loaded.")
53
  except Exception:
54
- # Fallback definitions if backend/class_def.py is missing
55
  def bubble(dialog="", bubble_offset_x=50, bubble_offset_y=20, lip_x=-1, lip_y=-1, emotion='normal'):
56
  return {
57
  'dialog': dialog, 'bubble_offset_x': bubble_offset_x, 'bubble_offset_y': bubble_offset_y,
@@ -65,9 +68,9 @@ try:
65
  from backend.ai_enhanced_core import image_processor, comic_styler, face_detector, layout_optimizer
66
  from backend.ai_bubble_placement import ai_bubble_placer
67
  from backend.subtitles.subs_real import get_real_subtitles
 
68
  print("✅ Core utility modules loaded.")
69
  except Exception:
70
- # Dummies for AI modules
71
  def get_real_subtitles(v): pass
72
  class DummyDetector:
73
  def detect_faces(self, p): return []
@@ -82,7 +85,7 @@ except Exception:
82
  app = Flask(__name__)
83
  BASE_USER_DIR = "userdata"
84
 
85
- # --- HTML INTERFACE (Upload + Editor + JS) ---
86
  INDEX_HTML = '''
87
  <!DOCTYPE html>
88
  <html lang="en">
@@ -90,10 +93,7 @@ INDEX_HTML = '''
90
  <meta charset="UTF-8">
91
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
92
  <title>Movie to Comic Generator</title>
93
- <!-- Export Library that supports CSS Masks/Gradients -->
94
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html-to-image/1.11.11/html-to-image.min.js"></script>
95
- <link rel="preconnect" href="https://fonts.googleapis.com">
96
- <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
97
  <link href="https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@700&family=Lato&display=swap" rel="stylesheet">
98
  <style>
99
  /* GLOBAL STYLES */
@@ -570,8 +570,9 @@ INDEX_HTML = '''
570
  updateImageTransform(img);
571
  }
572
 
 
573
  function replacePanelImage() {
574
- if(!currentlySelectedPanel) return alert("Select panel");
575
  const img = currentlySelectedPanel.querySelector('img');
576
  const inp = document.getElementById('image-uploader');
577
  inp.onchange = async (e) => {
@@ -649,18 +650,23 @@ class EnhancedComicGenerator:
649
  json.dump({'message': message, 'progress': progress}, f)
650
  except: pass
651
 
652
- def cleanup_generated(self):
653
- if os.path.exists(self.frames_dir): shutil.rmtree(self.frames_dir)
654
- if os.path.exists(self.output_dir): shutil.rmtree(self.output_dir)
655
- os.makedirs(self.frames_dir, exist_ok=True)
656
- os.makedirs(self.output_dir, exist_ok=True)
657
- srt = os.path.join(self.user_dir, 'subs.srt')
658
- if os.path.exists(srt): os.remove(srt)
 
 
 
 
 
 
659
 
660
  def generate_comic(self):
661
  try:
662
  if cv2 is None: raise Exception("OpenCV missing on server.")
663
- self.cleanup_generated()
664
 
665
  self.update_status("Processing Video...", 5)
666
  cap = cv2.VideoCapture(self.video_path)
@@ -676,7 +682,7 @@ class EnhancedComicGenerator:
676
  get_real_subtitles(self.video_path)
677
  if os.path.exists('test1.srt'): shutil.move('test1.srt', user_srt)
678
  except:
679
- with open(user_srt, 'w') as f: f.write("1\n00:00:00,000 --> 00:00:05,000\nStart\n")
680
 
681
  # 2. Keyframes
682
  self.update_status("Generating Panels...", 40)
@@ -686,7 +692,7 @@ class EnhancedComicGenerator:
686
  frame_files = []
687
  bubbles = []
688
 
689
- limit_subs = subs[:12] # Limit to 12 panels for demo speed
690
 
691
  for i, sub in enumerate(limit_subs):
692
  mid = (sub.start.total_seconds() + sub.end.total_seconds()) / 2
@@ -696,7 +702,6 @@ class EnhancedComicGenerator:
696
  fname = f"frame_{i}.png"
697
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
698
  frame_files.append(fname)
699
- # Map file to time for regeneration
700
  self.frame_metadata[fname] = mid
701
 
702
  bubbles.append(bubble(
@@ -706,13 +711,13 @@ class EnhancedComicGenerator:
706
  ))
707
  cap.release()
708
 
709
- # Save metadata for features like "Next Frame"
710
  with open(os.path.join(self.frames_dir, 'frame_metadata.json'), 'w') as f:
711
  json.dump(self.frame_metadata, f)
712
 
713
  # 3. Enhance
714
  self.update_status("Enhancing...", 70)
715
- # (Call enhancers here if needed)
 
716
 
717
  # 4. Assemble
718
  self.update_status("Finalizing...", 90)
@@ -758,6 +763,8 @@ class EnhancedComicGenerator:
758
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
759
  meta[fname] = new_time
760
  with open(meta_path,'w') as f: json.dump(meta, f)
 
 
761
  return {"success":True}
762
  return {"success":False, "message":"End of video"}
763
  except Exception as e: return {"success":False, "message":str(e)}
@@ -770,15 +777,34 @@ class EnhancedComicGenerator:
770
  cap.release()
771
  if ret:
772
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
773
- # Update meta
774
  meta_path = os.path.join(self.frames_dir, 'frame_metadata.json')
775
  if os.path.exists(meta_path):
776
  with open(meta_path,'r') as f: meta = json.load(f)
777
  meta[fname] = float(ts)
778
  with open(meta_path,'w') as f: json.dump(meta, f)
 
 
779
  return {"success":True}
780
  return {"success":False, "message":"Invalid time"}
781
  except Exception as e: return {"success":False, "message":str(e)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
782
 
783
  # --- ROUTES ---
784
  @app.route('/')
@@ -790,6 +816,10 @@ def upload():
790
  if not sid: return "Missing SID", 400
791
  f = request.files['file']
792
  gen = EnhancedComicGenerator(sid)
 
 
 
 
793
  f.save(gen.video_path)
794
  gen.update_status("Starting...", 5)
795
  threading.Thread(target=gen.generate_comic).start()
 
5
  import shutil
6
  import json
7
  import traceback
8
+ import logging
9
  from concurrent.futures import ThreadPoolExecutor
10
  from flask import Flask, render_template, request, jsonify, send_from_directory, send_file
11
 
12
+ # --- 0. SUPPRESS HUGGING FACE WARNINGS ---
13
+ import warnings
14
+ warnings.filterwarnings("ignore", category=UserWarning)
15
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
16
+ logging.getLogger("transformers").setLevel(logging.ERROR)
17
+
18
  # --- 1. CORE DEPENDENCY CHECKS ---
19
  try:
20
  import cv2
 
23
  import srt
24
  except ImportError as e:
25
  print(f"❌ CRITICAL ERROR: Missing python library. {e}")
 
26
  cv2 = None
27
  np = None
28
  Image = None
29
  srt = None
30
 
31
  # --- 2. BACKEND MODULE IMPORTS (WITH ROBUST FALLBACKS) ---
 
 
32
  def dummy_black_bar_crop(): return 0, 0, None, None
33
 
34
  try:
 
55
  from backend.class_def import bubble, panel, Page
56
  print("✅ Core class definitions loaded.")
57
  except Exception:
 
58
  def bubble(dialog="", bubble_offset_x=50, bubble_offset_y=20, lip_x=-1, lip_y=-1, emotion='normal'):
59
  return {
60
  'dialog': dialog, 'bubble_offset_x': bubble_offset_x, 'bubble_offset_y': bubble_offset_y,
 
68
  from backend.ai_enhanced_core import image_processor, comic_styler, face_detector, layout_optimizer
69
  from backend.ai_bubble_placement import ai_bubble_placer
70
  from backend.subtitles.subs_real import get_real_subtitles
71
+ from backend.keyframes.keyframes_simple import generate_keyframes_simple
72
  print("✅ Core utility modules loaded.")
73
  except Exception:
 
74
  def get_real_subtitles(v): pass
75
  class DummyDetector:
76
  def detect_faces(self, p): return []
 
85
  app = Flask(__name__)
86
  BASE_USER_DIR = "userdata"
87
 
88
+ # --- HTML INTERFACE ---
89
  INDEX_HTML = '''
90
  <!DOCTYPE html>
91
  <html lang="en">
 
93
  <meta charset="UTF-8">
94
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
95
  <title>Movie to Comic Generator</title>
 
96
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html-to-image/1.11.11/html-to-image.min.js"></script>
 
 
97
  <link href="https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@700&family=Lato&display=swap" rel="stylesheet">
98
  <style>
99
  /* GLOBAL STYLES */
 
570
  updateImageTransform(img);
571
  }
572
 
573
+ // --- API Calls ---
574
  function replacePanelImage() {
575
+ if (!currentlySelectedPanel) return alert("Select panel");
576
  const img = currentlySelectedPanel.querySelector('img');
577
  const inp = document.getElementById('image-uploader');
578
  inp.onchange = async (e) => {
 
650
  json.dump({'message': message, 'progress': progress}, f)
651
  except: pass
652
 
653
+ # --- CLEANUP: Deletes OLD processing files on NEW upload ---
654
+ def cleanup_previous_run(self):
655
+ print(f"[{self.sid}] 🧹 Cleaning previous run...")
656
+ if os.path.exists(self.frames_dir):
657
+ for f in os.listdir(self.frames_dir):
658
+ try: os.remove(os.path.join(self.frames_dir, f))
659
+ except: pass
660
+ if os.path.exists(self.output_dir):
661
+ for f in os.listdir(self.output_dir):
662
+ try: os.remove(os.path.join(self.output_dir, f))
663
+ except: pass
664
+ srt_file = os.path.join(self.user_dir, 'subs.srt')
665
+ if os.path.exists(srt_file): os.remove(srt_file)
666
 
667
  def generate_comic(self):
668
  try:
669
  if cv2 is None: raise Exception("OpenCV missing on server.")
 
670
 
671
  self.update_status("Processing Video...", 5)
672
  cap = cv2.VideoCapture(self.video_path)
 
682
  get_real_subtitles(self.video_path)
683
  if os.path.exists('test1.srt'): shutil.move('test1.srt', user_srt)
684
  except:
685
+ with open(user_srt, 'w') as f: f.write("1\n00:00:00,000 --> 00:00:05,000\n...\n")
686
 
687
  # 2. Keyframes
688
  self.update_status("Generating Panels...", 40)
 
692
  frame_files = []
693
  bubbles = []
694
 
695
+ limit_subs = subs[:12] # Limit to 12 panels for demo
696
 
697
  for i, sub in enumerate(limit_subs):
698
  mid = (sub.start.total_seconds() + sub.end.total_seconds()) / 2
 
702
  fname = f"frame_{i}.png"
703
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
704
  frame_files.append(fname)
 
705
  self.frame_metadata[fname] = mid
706
 
707
  bubbles.append(bubble(
 
711
  ))
712
  cap.release()
713
 
 
714
  with open(os.path.join(self.frames_dir, 'frame_metadata.json'), 'w') as f:
715
  json.dump(self.frame_metadata, f)
716
 
717
  # 3. Enhance
718
  self.update_status("Enhancing...", 70)
719
+ self._enhance_all_images()
720
+ self._enhance_quality_colors()
721
 
722
  # 4. Assemble
723
  self.update_status("Finalizing...", 90)
 
763
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
764
  meta[fname] = new_time
765
  with open(meta_path,'w') as f: json.dump(meta, f)
766
+ self._enhance_all_images(single_image_path=os.path.join(self.frames_dir, fname))
767
+ self._enhance_quality_colors(single_image_path=os.path.join(self.frames_dir, fname))
768
  return {"success":True}
769
  return {"success":False, "message":"End of video"}
770
  except Exception as e: return {"success":False, "message":str(e)}
 
777
  cap.release()
778
  if ret:
779
  cv2.imwrite(os.path.join(self.frames_dir, fname), frame)
 
780
  meta_path = os.path.join(self.frames_dir, 'frame_metadata.json')
781
  if os.path.exists(meta_path):
782
  with open(meta_path,'r') as f: meta = json.load(f)
783
  meta[fname] = float(ts)
784
  with open(meta_path,'w') as f: json.dump(meta, f)
785
+ self._enhance_all_images(single_image_path=os.path.join(self.frames_dir, fname))
786
+ self._enhance_quality_colors(single_image_path=os.path.join(self.frames_dir, fname))
787
  return {"success":True}
788
  return {"success":False, "message":"Invalid time"}
789
  except Exception as e: return {"success":False, "message":str(e)}
790
+
791
+ def _enhance_all_images(self, single_image_path=None):
792
+ try:
793
+ enhancer = SimpleColorEnhancer()
794
+ if single_image_path: enhancer.enhance_single(single_image_path)
795
+ else:
796
+ paths = [os.path.join(self.frames_dir, f) for f in os.listdir(self.frames_dir) if f.endswith('.png')]
797
+ with ThreadPoolExecutor() as ex: list(ex.map(enhancer.enhance_single, paths))
798
+ except: pass
799
+
800
+ def _enhance_quality_colors(self, single_image_path=None):
801
+ try:
802
+ enhancer = QualityColorEnhancer()
803
+ if single_image_path: enhancer.enhance_single(single_image_path)
804
+ else:
805
+ paths = [os.path.join(self.frames_dir, f) for f in os.listdir(self.frames_dir) if f.endswith('.png')]
806
+ with ThreadPoolExecutor() as ex: list(ex.map(enhancer.enhance_single, paths))
807
+ except: pass
808
 
809
  # --- ROUTES ---
810
  @app.route('/')
 
816
  if not sid: return "Missing SID", 400
817
  f = request.files['file']
818
  gen = EnhancedComicGenerator(sid)
819
+
820
+ # CLEAN OLD FILES
821
+ gen.cleanup_previous_run()
822
+
823
  f.save(gen.video_path)
824
  gen.update_status("Starting...", 5)
825
  threading.Thread(target=gen.generate_comic).start()