ladybug11 commited on
Commit
fb7805c
Β·
1 Parent(s): 1475643
__pycache__/modal_video_processing.cpython-311.pyc CHANGED
Binary files a/__pycache__/modal_video_processing.cpython-311.pyc and b/__pycache__/modal_video_processing.cpython-311.pyc differ
 
modal_video_processing.py CHANGED
@@ -20,10 +20,11 @@ image = modal.Image.debian_slim(python_version="3.11").pip_install(
20
 
21
  @app.function(
22
  image=image,
23
- cpu=2, # Reduced to 2 CPUs for faster cold start
24
- memory=2048, # Reduced to 2GB
25
- timeout=180, # 3 minute timeout
26
- concurrency_limit=10, # Allow multiple concurrent requests
 
27
  )
28
  def process_quote_video(video_url: str, quote_text: str, audio_url: str = None) -> bytes:
29
  """
@@ -43,31 +44,42 @@ def process_quote_video(video_url: str, quote_text: str, audio_url: str = None)
43
  from moviepy.editor import VideoFileClip, ImageClip, CompositeVideoClip, AudioFileClip
44
  from PIL import Image, ImageDraw, ImageFont
45
  import numpy as np
 
46
 
 
47
  print(f"🎬 Starting video processing on Modal...")
48
- print(f" Video: {video_url[:50]}...")
49
- print(f" Quote length: {len(quote_text)} chars")
50
 
51
- # Download video
52
  print("πŸ“₯ Downloading video...")
 
53
  response = requests.get(video_url, stream=True, timeout=30)
54
  response.raise_for_status()
55
 
56
  temp_video = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
57
  with open(temp_video.name, 'wb') as f:
58
- for chunk in response.iter_content(chunk_size=8192):
59
  f.write(chunk)
60
 
61
- print("βœ… Video downloaded")
62
 
63
  # Load video
64
  print("πŸŽ₯ Loading video...")
 
65
  video = VideoFileClip(temp_video.name)
 
 
 
 
 
 
66
  w, h = video.size
67
- print(f" Dimensions: {w}x{h}")
 
68
 
69
  # Create text overlay using PIL
70
  print("✍️ Creating text overlay...")
 
 
71
  def make_text_frame(t):
72
  img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
73
  draw = ImageDraw.Draw(img)
@@ -126,50 +138,37 @@ def process_quote_video(video_url: str, quote_text: str, audio_url: str = None)
126
  return np.array(img)
127
 
128
  text_clip = ImageClip(make_text_frame(0), duration=video.duration)
129
- print("βœ… Text overlay created")
130
 
131
  # Composite
132
  print("🎨 Compositing video...")
 
133
  final_video = CompositeVideoClip([video, text_clip])
 
134
 
135
- # Add audio if provided
136
  if audio_url:
137
- print("🎀 Adding voice narration...")
138
- try:
139
- audio_response = requests.get(audio_url, timeout=30)
140
- audio_response.raise_for_status()
141
-
142
- temp_audio = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3')
143
- with open(temp_audio.name, 'wb') as f:
144
- f.write(audio_response.content)
145
-
146
- audio_clip = AudioFileClip(temp_audio.name)
147
- audio_duration = min(audio_clip.duration, final_video.duration)
148
- audio_clip = audio_clip.subclip(0, audio_duration)
149
- final_video = final_video.set_audio(audio_clip)
150
- print("βœ… Audio added")
151
-
152
- os.unlink(temp_audio.name)
153
- except Exception as e:
154
- print(f"⚠️ Audio failed: {e}")
155
 
156
- # Export
157
  print("πŸ“¦ Exporting video...")
 
158
  output_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
159
 
160
  final_video.write_videofile(
161
  output_file.name,
162
  codec='libx264',
163
  audio_codec='aac',
164
- fps=15, # Reduced from 24 for faster encoding
165
  preset='ultrafast',
166
- threads=4,
167
  verbose=False,
168
  logger=None,
169
- bitrate="1000k" # Lower bitrate for faster encoding
 
170
  )
171
 
172
- print("βœ… Video exported")
173
 
174
  # Read video bytes
175
  with open(output_file.name, 'rb') as f:
@@ -181,7 +180,9 @@ def process_quote_video(video_url: str, quote_text: str, audio_url: str = None)
181
  os.unlink(temp_video.name)
182
  os.unlink(output_file.name)
183
 
184
- print(f"πŸŽ‰ Processing complete! Video size: {len(video_bytes) / 1024 / 1024:.2f}MB")
 
 
185
 
186
  return video_bytes
187
 
@@ -226,4 +227,4 @@ if __name__ == "__main__":
226
  quote_text="Test quote for local testing",
227
  audio_url=None
228
  )
229
- print(f"Got video: {len(result)} bytes")
 
20
 
21
  @app.function(
22
  image=image,
23
+ cpu=2,
24
+ memory=2048,
25
+ timeout=180,
26
+ keep_warm=1, # Keep 1 container warm to eliminate cold starts!
27
+ container_idle_timeout=300, # Keep alive for 5 minutes
28
  )
29
  def process_quote_video(video_url: str, quote_text: str, audio_url: str = None) -> bytes:
30
  """
 
44
  from moviepy.editor import VideoFileClip, ImageClip, CompositeVideoClip, AudioFileClip
45
  from PIL import Image, ImageDraw, ImageFont
46
  import numpy as np
47
+ import time
48
 
49
+ start_time = time.time()
50
  print(f"🎬 Starting video processing on Modal...")
 
 
51
 
52
+ # Download video with streaming
53
  print("πŸ“₯ Downloading video...")
54
+ download_start = time.time()
55
  response = requests.get(video_url, stream=True, timeout=30)
56
  response.raise_for_status()
57
 
58
  temp_video = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
59
  with open(temp_video.name, 'wb') as f:
60
+ for chunk in response.iter_content(chunk_size=1024*1024): # 1MB chunks
61
  f.write(chunk)
62
 
63
+ print(f"βœ… Video downloaded in {time.time() - download_start:.1f}s")
64
 
65
  # Load video
66
  print("πŸŽ₯ Loading video...")
67
+ load_start = time.time()
68
  video = VideoFileClip(temp_video.name)
69
+
70
+ # Limit video duration to 10 seconds max for faster processing
71
+ # Instagram quote videos are typically short anyway
72
+ if video.duration > 10:
73
+ video = video.subclip(0, 10)
74
+
75
  w, h = video.size
76
+ print(f" Dimensions: {w}x{h}, Duration: {video.duration:.1f}s")
77
+ print(f"βœ… Video loaded in {time.time() - load_start:.1f}s")
78
 
79
  # Create text overlay using PIL
80
  print("✍️ Creating text overlay...")
81
+ overlay_start = time.time()
82
+
83
  def make_text_frame(t):
84
  img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
85
  draw = ImageDraw.Draw(img)
 
138
  return np.array(img)
139
 
140
  text_clip = ImageClip(make_text_frame(0), duration=video.duration)
141
+ print(f"βœ… Text overlay created in {time.time() - overlay_start:.1f}s")
142
 
143
  # Composite
144
  print("🎨 Compositing video...")
145
+ composite_start = time.time()
146
  final_video = CompositeVideoClip([video, text_clip])
147
+ print(f"βœ… Composited in {time.time() - composite_start:.1f}s")
148
 
149
+ # Skip audio for speed
150
  if audio_url:
151
+ print("⚠️ Skipping audio for speed optimization")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
+ # Export with FASTEST possible settings
154
  print("πŸ“¦ Exporting video...")
155
+ export_start = time.time()
156
  output_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4')
157
 
158
  final_video.write_videofile(
159
  output_file.name,
160
  codec='libx264',
161
  audio_codec='aac',
162
+ fps=10, # Even lower - 10fps is fine for quote videos
163
  preset='ultrafast',
164
+ threads=2,
165
  verbose=False,
166
  logger=None,
167
+ bitrate="400k", # Lower bitrate
168
+ ffmpeg_params=['-crf', '30', '-g', '30'] # Even lower quality, larger GOP
169
  )
170
 
171
+ print(f"βœ… Video exported in {time.time() - export_start:.1f}s")
172
 
173
  # Read video bytes
174
  with open(output_file.name, 'rb') as f:
 
180
  os.unlink(temp_video.name)
181
  os.unlink(output_file.name)
182
 
183
+ total_time = time.time() - start_time
184
+ print(f"πŸŽ‰ TOTAL PROCESSING TIME: {total_time:.1f}s")
185
+ print(f" Video size: {len(video_bytes) / 1024 / 1024:.2f}MB")
186
 
187
  return video_bytes
188
 
 
227
  quote_text="Test quote for local testing",
228
  audio_url=None
229
  )
230
+ print(f"Got video: {len(result)} bytes")