saq1b commited on
Commit
3ead8be
·
verified ·
1 Parent(s): f584e07

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +66 -48
main.py CHANGED
@@ -1,14 +1,14 @@
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.staticfiles import StaticFiles
3
  from pydantic import BaseModel, HttpUrl
4
- from typing import List, Optional
5
  import os
6
  import asyncio
7
  import uuid
 
8
  import re
 
9
  import shutil
10
- # Install these packages using pip if needed
11
- import aiohttp
12
  import aiofiles
13
 
14
  # Create FastAPI app
@@ -23,7 +23,7 @@ class SlideshowRequest(BaseModel):
23
  image_urls: List[HttpUrl]
24
  audio_url: HttpUrl
25
  duration: int
26
- zoom: Optional[bool] = False # Optional zoom parameter with default value of False
27
 
28
  def extract_google_drive_id(url):
29
  """Extract file ID from a Google Drive URL"""
@@ -60,44 +60,65 @@ async def create_slideshow(image_paths, audio_path, output_path, duration, zoom=
60
  # Create temporary file list for ffmpeg concat
61
  concat_file = "temp_concat.txt"
62
 
63
- async with aiofiles.open(concat_file, "w") as f:
64
- for img in image_paths:
65
- await f.write(f"file '{img}'\n")
66
- await f.write(f"duration {duration}\n")
 
 
 
 
 
 
67
 
68
- # Add the last image again without duration (required by ffmpeg)
69
- if image_paths:
70
- await f.write(f"file '{image_paths[-1]}'\n")
71
-
72
- # Run ffmpeg command to create slideshow with audio
73
- total_duration = len(image_paths) * duration
74
-
75
- cmd = [
76
- "ffmpeg",
77
- "-f", "concat",
78
- "-safe", "0",
79
- "-i", concat_file,
80
- "-i", audio_path,
81
- ]
82
-
83
- # Add zoom effect if requested
84
- if zoom:
85
- # Create a single zooming filter for all images instead of individual filters
86
- zoom_filter = (
87
- f"[0:v]scale=1920:1080,zoompan=z='min(1.1,1+(on/{duration*25}/8))':"
88
- f"d={duration*25}:s=1920x1080:fps=25[outv]"
89
- )
90
- cmd.extend(["-filter_complex", zoom_filter, "-map", "[outv]", "-map", "1:a"])
91
-
92
- cmd.extend([
93
- "-c:v", "libx264",
94
- "-pix_fmt", "yuv420p",
95
- "-c:a", "aac",
96
- "-shortest",
97
- "-y",
98
- "-t", str(total_duration),
99
- output_path
100
- ])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
 
102
  try:
103
  process = await asyncio.create_subprocess_exec(
@@ -112,16 +133,13 @@ async def create_slideshow(image_paths, audio_path, output_path, duration, zoom=
112
 
113
  if process.returncode != 0:
114
  print(f"FFmpeg error: {stderr.decode()}")
115
- _, stderr = await process.communicate()
116
-
117
- if os.path.exists(concat_file):
118
- os.remove(concat_file)
119
  if os.path.exists(concat_file):
120
  os.remove(concat_file)
121
  return False
122
- except Exception as e:
123
- print(f"Error creating slideshow: {str(e)}")
124
- return False
125
 
126
  @app.post("/make_slideshow")
127
  async def make_slideshow(request: SlideshowRequest):
 
1
  from fastapi import FastAPI, HTTPException
2
  from fastapi.staticfiles import StaticFiles
3
  from pydantic import BaseModel, HttpUrl
4
+ from typing import List
5
  import os
6
  import asyncio
7
  import uuid
8
+ import aiohttp
9
  import re
10
+ from urllib.parse import urlparse
11
  import shutil
 
 
12
  import aiofiles
13
 
14
  # Create FastAPI app
 
23
  image_urls: List[HttpUrl]
24
  audio_url: HttpUrl
25
  duration: int
26
+ zoom: bool = False
27
 
28
  def extract_google_drive_id(url):
29
  """Extract file ID from a Google Drive URL"""
 
60
  # Create temporary file list for ffmpeg concat
61
  concat_file = "temp_concat.txt"
62
 
63
+ if not zoom:
64
+ # Original implementation without zoom effect
65
+ async with aiofiles.open(concat_file, "w") as f:
66
+ for img in image_paths:
67
+ await f.write(f"file '{img}'\n")
68
+ await f.write(f"duration {duration}\n")
69
+
70
+ # Add the last image again without duration (required by ffmpeg)
71
+ if image_paths:
72
+ await f.write(f"file '{image_paths[-1]}'\n")
73
 
74
+ # Run ffmpeg command to create slideshow with audio
75
+ total_duration = len(image_paths) * duration
76
+ cmd = [
77
+ "ffmpeg",
78
+ "-f", "concat",
79
+ "-safe", "0",
80
+ "-i", concat_file,
81
+ "-i", audio_path,
82
+ "-c:v", "libx264",
83
+ "-pix_fmt", "yuv420p",
84
+ "-c:a", "aac",
85
+ "-shortest",
86
+ "-y",
87
+ "-t", str(total_duration),
88
+ output_path
89
+ ]
90
+ else:
91
+ # With zoom effect - use complex filtergraph instead of concat
92
+ total_duration = len(image_paths) * duration
93
+ filter_complex = ""
94
+ inputs = []
95
+
96
+ # Add each image with zoompan effect
97
+ for i, img in enumerate(image_paths):
98
+ inputs.extend(["-loop", "1", "-t", str(duration), "-i", img])
99
+ # Apply zoom effect: start at 100% size and zoom to 110% over the duration
100
+ filter_complex += f"[{i}:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1,zoompan=z='min(zoom+0.0015,1.1)':d={duration*25}:s=1920x1080[v{i}];"
101
+
102
+ # Concatenate all video segments
103
+ for i in range(len(image_paths)):
104
+ filter_complex += f"[v{i}]"
105
+ filter_complex += f"concat=n={len(image_paths)}:v=1:a=0[outv]"
106
+
107
+ cmd = [
108
+ "ffmpeg",
109
+ *inputs,
110
+ "-i", audio_path,
111
+ "-filter_complex", filter_complex,
112
+ "-map", "[outv]",
113
+ "-map", f"{len(image_paths)}:a",
114
+ "-c:v", "libx264",
115
+ "-pix_fmt", "yuv420p",
116
+ "-c:a", "aac",
117
+ "-shortest",
118
+ "-y",
119
+ "-t", str(total_duration),
120
+ output_path
121
+ ]
122
 
123
  try:
124
  process = await asyncio.create_subprocess_exec(
 
133
 
134
  if process.returncode != 0:
135
  print(f"FFmpeg error: {stderr.decode()}")
136
+ return False
137
+ return True
138
+ except Exception as e:
139
+ print(f"FFmpeg error: {str(e)}")
140
  if os.path.exists(concat_file):
141
  os.remove(concat_file)
142
  return False
 
 
 
143
 
144
  @app.post("/make_slideshow")
145
  async def make_slideshow(request: SlideshowRequest):