Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -286,6 +286,53 @@ class VideoGenerator:
|
|
286 |
self.temp_dir = tempfile.mkdtemp()
|
287 |
self.pixabay_api_key = os.getenv("PIXABAY_API_KEY")
|
288 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
def fetch_background_video(self, query: str) -> Optional[str]:
|
290 |
"""Fetch background video from Pixabay with error handling"""
|
291 |
try:
|
@@ -327,44 +374,46 @@ class VideoGenerator:
|
|
327 |
return None
|
328 |
|
329 |
def create_video(self, content: Dict[str, str], preferences: Dict, style: ContentStyle) -> Optional[str]:
|
330 |
-
"""Create video with
|
331 |
try:
|
332 |
-
# Basic video creation
|
333 |
self.update_progress(85, "Creating video...")
|
334 |
|
335 |
-
# Create
|
336 |
-
|
337 |
-
|
338 |
|
339 |
-
# Create
|
340 |
-
|
341 |
|
342 |
-
#
|
343 |
-
|
344 |
-
|
345 |
-
fontsize=40,
|
346 |
-
color='white',
|
347 |
-
size=(1000, None),
|
348 |
-
method='label'
|
349 |
-
).set_duration(15)
|
350 |
|
351 |
-
#
|
352 |
-
|
353 |
-
text_clips.append(main_text)
|
354 |
|
355 |
-
#
|
356 |
-
|
357 |
|
358 |
-
#
|
359 |
self.update_progress(95, "Saving video...")
|
360 |
-
output_path =
|
361 |
-
|
|
|
|
|
|
|
|
|
362 |
|
363 |
return output_path
|
364 |
|
365 |
except Exception as e:
|
366 |
st.error(f"Error creating video: {str(e)}")
|
367 |
return None
|
|
|
|
|
|
|
|
|
|
|
368 |
|
369 |
def main():
|
370 |
st.set_page_config(page_title="Professional Content Generator", layout="wide")
|
|
|
286 |
self.temp_dir = tempfile.mkdtemp()
|
287 |
self.pixabay_api_key = os.getenv("PIXABAY_API_KEY")
|
288 |
|
289 |
+
|
290 |
+
def create_text_image(self, text: str, size=(1080, 1920)) -> np.ndarray:
|
291 |
+
"""Create text overlay using PIL instead of MoviePy's TextClip"""
|
292 |
+
# Create image with PIL
|
293 |
+
image = Image.new('RGBA', size, (0, 0, 128, 255)) # Navy blue background
|
294 |
+
draw = ImageDraw.Draw(image)
|
295 |
+
|
296 |
+
# Use a basic font
|
297 |
+
try:
|
298 |
+
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 40)
|
299 |
+
except:
|
300 |
+
# Fallback to default font if custom font not available
|
301 |
+
font = ImageFont.load_default()
|
302 |
+
|
303 |
+
# Word wrap text
|
304 |
+
words = text.split()
|
305 |
+
lines = []
|
306 |
+
current_line = []
|
307 |
+
|
308 |
+
for word in words:
|
309 |
+
current_line.append(word)
|
310 |
+
w, _ = draw.textsize(' '.join(current_line), font=font)
|
311 |
+
if w > size[0] - 100: # Leave margins
|
312 |
+
if len(current_line) > 1:
|
313 |
+
current_line.pop()
|
314 |
+
lines.append(' '.join(current_line))
|
315 |
+
current_line = [word]
|
316 |
+
else:
|
317 |
+
lines.append(' '.join(current_line))
|
318 |
+
current_line = []
|
319 |
+
|
320 |
+
if current_line:
|
321 |
+
lines.append(' '.join(current_line))
|
322 |
+
|
323 |
+
# Calculate text position
|
324 |
+
y_position = size[1] // 2 - (len(lines) * 50) // 2 # Center text vertically
|
325 |
+
|
326 |
+
# Draw each line
|
327 |
+
for line in lines:
|
328 |
+
bbox = draw.textbbox((0, 0), line, font=font)
|
329 |
+
text_width = bbox[2] - bbox[0]
|
330 |
+
x_position = (size[0] - text_width) // 2 # Center text horizontally
|
331 |
+
draw.text((x_position, y_position), line, fill='white', font=font)
|
332 |
+
y_position += 50
|
333 |
+
|
334 |
+
return np.array(image)
|
335 |
+
|
336 |
def fetch_background_video(self, query: str) -> Optional[str]:
|
337 |
"""Fetch background video from Pixabay with error handling"""
|
338 |
try:
|
|
|
374 |
return None
|
375 |
|
376 |
def create_video(self, content: Dict[str, str], preferences: Dict, style: ContentStyle) -> Optional[str]:
|
377 |
+
"""Create video with PIL-based text rendering"""
|
378 |
try:
|
|
|
379 |
self.update_progress(85, "Creating video...")
|
380 |
|
381 |
+
# Create frames directory
|
382 |
+
frames_dir = os.path.join(self.temp_dir, "frames")
|
383 |
+
os.makedirs(frames_dir, exist_ok=True)
|
384 |
|
385 |
+
# Create main content frame
|
386 |
+
frame = self.create_text_image(content['main_content'][:200])
|
387 |
|
388 |
+
# Save frame as image
|
389 |
+
frame_path = os.path.join(frames_dir, "frame.png")
|
390 |
+
Image.fromarray(frame).save(frame_path)
|
|
|
|
|
|
|
|
|
|
|
391 |
|
392 |
+
# Create video from frame
|
393 |
+
output_path = os.path.join(self.temp_dir, f"output_{int(time.time())}.mp4")
|
|
|
394 |
|
395 |
+
# Create video clip from frame
|
396 |
+
clip = VideoFileClip(frame_path, duration=15)
|
397 |
|
398 |
+
# Write video file
|
399 |
self.update_progress(95, "Saving video...")
|
400 |
+
clip.write_videofile(output_path, fps=24, codec='libx264', audio=False)
|
401 |
+
|
402 |
+
# Cleanup
|
403 |
+
clip.close()
|
404 |
+
if os.path.exists(frame_path):
|
405 |
+
os.remove(frame_path)
|
406 |
|
407 |
return output_path
|
408 |
|
409 |
except Exception as e:
|
410 |
st.error(f"Error creating video: {str(e)}")
|
411 |
return None
|
412 |
+
finally:
|
413 |
+
# Cleanup frames directory
|
414 |
+
if os.path.exists(frames_dir):
|
415 |
+
import shutil
|
416 |
+
shutil.rmtree(frames_dir)
|
417 |
|
418 |
def main():
|
419 |
st.set_page_config(page_title="Professional Content Generator", layout="wide")
|