ladybug11 commited on
Commit
f081221
·
1 Parent(s): fa31f3c
Files changed (2) hide show
  1. app.py +55 -92
  2. modal_video_processing.py +4 -4
app.py CHANGED
@@ -603,107 +603,70 @@ def mcp_agent_pipeline(niche, style, num_variations=1):
603
 
604
  # STEP 4: Create multiple video variations
605
  status_log.append(f"🎬 **MCP TOOL: create_quote_video_tool (x{len(video_results)})**")
606
- status_log.append(f" ⏳ Creating {len(video_results)} video variations...")
607
 
608
  output_dir = "/tmp/quote_videos"
609
- gallery_dir = "/data/gallery_videos" # HF persistent storage
610
  os.makedirs(output_dir, exist_ok=True)
611
  os.makedirs(gallery_dir, exist_ok=True)
612
 
613
- created_videos = []
614
  import time
615
  timestamp = int(time.time())
616
 
617
- # Use batch processing if Modal configured and multiple videos
618
- modal_endpoint = os.getenv("MODAL_ENDPOINT_URL")
619
- if modal_endpoint and len(video_results) > 1:
620
- try:
621
- # Use batch endpoint for parallel processing
622
- batch_endpoint = modal_endpoint.replace("process-video-endpoint", "process-batch-endpoint")
623
-
624
- status_log.append(f" 🚀 Using Modal batch processing (parallel)...")
625
-
626
- videos_payload = []
627
- for video_result in video_results:
628
- videos_payload.append({
629
- "video_url": video_result["video_url"],
630
- "quote_text": quote,
631
- "audio_b64": None
632
- })
633
-
634
- import requests
635
- import base64
636
-
637
- response = requests.post(
638
- batch_endpoint,
639
- json={"videos": videos_payload},
640
- timeout=180
641
- )
642
-
643
- if response.status_code == 200:
644
- result = response.json()
645
- if result.get("success"):
646
- # Save all videos
647
- for i, video_data in enumerate(result["videos"]):
648
- output_filename = f"quote_video_v{i+1}_{timestamp}.mp4"
649
- output_path = os.path.join(output_dir, output_filename)
650
-
651
- video_bytes = base64.b64decode(video_data["video"])
652
- with open(output_path, 'wb') as f:
653
- f.write(video_bytes)
654
-
655
- created_videos.append(output_path)
656
- status_log.append(f" ✅ Variation {i+1} created!")
657
-
658
- # Copy to gallery
659
- import shutil
660
- gallery_filename = f"gallery_{timestamp}_v{i+1}.mp4"
661
- gallery_path = os.path.join(gallery_dir, gallery_filename)
662
- try:
663
- shutil.copy2(output_path, gallery_path)
664
- except:
665
- pass
666
-
667
- status_log.append(f" ⚡ Batch processing complete! All {len(created_videos)} videos done in parallel")
668
- else:
669
- status_log.append(f" ⚠️ Batch failed, falling back to sequential...")
670
- raise Exception("Batch failed")
671
- else:
672
- status_log.append(f" ⚠️ Batch endpoint error, falling back to sequential...")
673
- raise Exception("Batch endpoint error")
674
-
675
- except Exception as e:
676
- # Fall back to sequential processing
677
- status_log.append(f" ⚠️ Batch processing failed: {e}")
678
- status_log.append(f" 🔄 Falling back to sequential processing...")
679
- created_videos = [] # Reset
680
-
681
- # Sequential processing (fallback or single video)
682
- if len(created_videos) == 0:
683
- for i, video_result in enumerate(video_results):
684
- output_filename = f"quote_video_v{i+1}_{timestamp}.mp4"
685
- output_path = os.path.join(output_dir, output_filename)
686
-
687
- creation_result = create_quote_video_tool(
688
- video_result["video_url"],
689
- quote,
690
- output_path,
691
- None # No audio
692
- )
693
 
694
- if creation_result["success"]:
695
- created_videos.append(creation_result["output_path"])
696
- status_log.append(f" ✅ Variation {i+1} created!")
697
-
698
- # Copy to gallery for public viewing
699
- import shutil
700
- gallery_filename = f"gallery_{timestamp}_v{i+1}.mp4"
701
- gallery_path = os.path.join(gallery_dir, gallery_filename)
702
- try:
703
- shutil.copy2(creation_result["output_path"], gallery_path)
704
- except:
705
- pass # Silently fail if can't copy to gallery
706
- else:
707
  error_msg = creation_result.get("message", "Unknown error")
708
  status_log.append(f" ⚠️ Variation {i+1} failed: {error_msg}")
709
 
 
603
 
604
  # STEP 4: Create multiple video variations
605
  status_log.append(f"🎬 **MCP TOOL: create_quote_video_tool (x{len(video_results)})**")
606
+ status_log.append(f" ⏳ Creating {len(video_results)} video variations in parallel...")
607
 
608
  output_dir = "/tmp/quote_videos"
609
+ gallery_dir = "/data/gallery_videos"
610
  os.makedirs(output_dir, exist_ok=True)
611
  os.makedirs(gallery_dir, exist_ok=True)
612
 
 
613
  import time
614
  timestamp = int(time.time())
615
 
616
+ # Use threading for parallel Modal calls
617
+ import threading
618
+ import queue
619
+
620
+ results_queue = queue.Queue()
621
+
622
+ def create_single_video(index, video_result):
623
+ output_filename = f"quote_video_v{index+1}_{timestamp}.mp4"
624
+ output_path = os.path.join(output_dir, output_filename)
625
+
626
+ creation_result = create_quote_video_tool(
627
+ video_result["video_url"],
628
+ quote,
629
+ output_path,
630
+ None
631
+ )
632
+
633
+ results_queue.put((index, creation_result, output_path))
634
+
635
+ # Start all threads
636
+ threads = []
637
+ for i, video_result in enumerate(video_results):
638
+ thread = threading.Thread(target=create_single_video, args=(i, video_result))
639
+ thread.start()
640
+ threads.append(thread)
641
+
642
+ # Wait for all to complete
643
+ for thread in threads:
644
+ thread.join()
645
+
646
+ # Collect results
647
+ created_videos = []
648
+ all_results = []
649
+ while not results_queue.empty():
650
+ all_results.append(results_queue.get())
651
+
652
+ # Sort by index
653
+ all_results.sort(key=lambda x: x[0])
654
+
655
+ # Process results
656
+ for index, creation_result, output_path in all_results:
657
+ if creation_result["success"]:
658
+ created_videos.append(output_path)
659
+ status_log.append(f" ✅ Variation {index+1} created!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
 
661
+ # Copy to gallery
662
+ import shutil
663
+ gallery_filename = f"gallery_{timestamp}_v{index+1}.mp4"
664
+ gallery_path = os.path.join(gallery_dir, gallery_filename)
665
+ try:
666
+ shutil.copy2(output_path, gallery_path)
667
+ except:
668
+ pass
669
+ else:
 
 
 
 
670
  error_msg = creation_result.get("message", "Unknown error")
671
  status_log.append(f" ⚠️ Variation {i+1} failed: {error_msg}")
672
 
modal_video_processing.py CHANGED
@@ -23,9 +23,9 @@ image = modal.Image.debian_slim(python_version="3.11").pip_install(
23
  cpu=2,
24
  memory=2048,
25
  timeout=180,
26
- keep_warm=1, # Keep 1 container warm
27
- container_idle_timeout=300,
28
- concurrency_limit=10, # Allow multiple videos in parallel
29
  )
30
  def process_quote_video(video_url: str, quote_text: str, audio_b64: str = None) -> bytes:
31
  """
@@ -215,4 +215,4 @@ def process_batch_endpoint(data: dict):
215
 
216
  except Exception as e:
217
  return {"error": str(e)}, 500
218
-
 
23
  cpu=2,
24
  memory=2048,
25
  timeout=180,
26
+ concurrency_limit=10, # Allow 10 videos at once
27
+ allow_concurrent_inputs=10, # Process multiple in parallel
28
+ container_idle_timeout=120,
29
  )
30
  def process_quote_video(video_url: str, quote_text: str, audio_b64: str = None) -> bytes:
31
  """
 
215
 
216
  except Exception as e:
217
  return {"error": str(e)}, 500
218
+