Spaces:
Sleeping
Sleeping
Update server.py
Browse files
server.py
CHANGED
|
@@ -172,54 +172,78 @@ async def generate_video(
|
|
| 172 |
files: List[UploadFile] = File(...)
|
| 173 |
):
|
| 174 |
"""
|
| 175 |
-
Full pipeline: Upload
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
|
| 177 |
Form parameters:
|
| 178 |
-
- manifest: JSON string with title
|
| 179 |
-
- files: Uploaded image files
|
| 180 |
|
| 181 |
-
Returns: MP4 video file
|
| 182 |
"""
|
| 183 |
try:
|
| 184 |
-
# Parse manifest
|
| 185 |
manifest_data = json.loads(manifest)
|
| 186 |
manifest_req = ManifestRequest(**manifest_data)
|
| 187 |
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
|
| 193 |
-
#
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
SELECTED_DIR.mkdir(exist_ok=True)
|
| 197 |
-
|
| 198 |
-
# Save uploaded files directly to selected/ directory
|
| 199 |
-
for i, file in enumerate(files):
|
| 200 |
if file.filename:
|
| 201 |
-
#
|
| 202 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
with open(file_path, "wb") as f:
|
| 204 |
-
content = await file.read()
|
| 205 |
f.write(content)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
|
|
|
| 213 |
|
| 214 |
-
# Compose video with
|
| 215 |
compose_result = await _compose(manifest_req)
|
| 216 |
if compose_result["status"] != "success":
|
| 217 |
raise Exception(compose_result.get("message", "Composition failed"))
|
| 218 |
|
| 219 |
-
# Return the MP4 file
|
| 220 |
output_file = Path(compose_result["output_path"])
|
| 221 |
if not output_file.exists():
|
| 222 |
-
raise Exception("Output file not
|
| 223 |
|
| 224 |
return FileResponse(
|
| 225 |
path=output_file,
|
|
|
|
| 172 |
files: List[UploadFile] = File(...)
|
| 173 |
):
|
| 174 |
"""
|
| 175 |
+
Full pipeline: Upload candidates + manifest → select best → compose → return MP4.
|
| 176 |
+
|
| 177 |
+
Workflow:
|
| 178 |
+
1. Accepts multiple image files organized by scene (scene_0/img1.jpg, scene_0/img2.jpg, etc.)
|
| 179 |
+
2. Saves to candidates/ folder
|
| 180 |
+
3. Calls scene selector to pick best from each
|
| 181 |
+
4. Composes video
|
| 182 |
+
5. Returns MP4 file
|
| 183 |
|
| 184 |
Form parameters:
|
| 185 |
+
- manifest: JSON string with {"title": str, "scenes": [{"label": str, "image_query": str}]}
|
| 186 |
+
- files: Uploaded image files (can be multiple per scene, sent as scene_N/filename)
|
| 187 |
|
| 188 |
+
Returns: MP4 video file (video/mp4)
|
| 189 |
"""
|
| 190 |
try:
|
| 191 |
+
# Step 1: Parse manifest
|
| 192 |
manifest_data = json.loads(manifest)
|
| 193 |
manifest_req = ManifestRequest(**manifest_data)
|
| 194 |
|
| 195 |
+
# Step 2: Clean and prepare candidates directory
|
| 196 |
+
if CANDIDATES_DIR.exists():
|
| 197 |
+
shutil.rmtree(CANDIDATES_DIR)
|
| 198 |
+
CANDIDATES_DIR.mkdir(exist_ok=True)
|
| 199 |
|
| 200 |
+
# Step 3: Save uploaded files to candidates/ organized by scene
|
| 201 |
+
files_saved = {}
|
| 202 |
+
for file in files:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
if file.filename:
|
| 204 |
+
# Parse filename to extract scene index
|
| 205 |
+
# Format: "scene_0/image1.jpg" or just "image1.jpg"
|
| 206 |
+
parts = file.filename.split("/")
|
| 207 |
+
if len(parts) == 2:
|
| 208 |
+
scene_folder = parts[0] # "scene_0"
|
| 209 |
+
filename = parts[1] # "image1.jpg"
|
| 210 |
+
else:
|
| 211 |
+
# Fallback: use filename directly
|
| 212 |
+
scene_folder = "scene_0"
|
| 213 |
+
filename = file.filename
|
| 214 |
+
|
| 215 |
+
# Create scene folder if needed
|
| 216 |
+
scene_path = CANDIDATES_DIR / scene_folder
|
| 217 |
+
scene_path.mkdir(parents=True, exist_ok=True)
|
| 218 |
+
|
| 219 |
+
# Save file
|
| 220 |
+
file_path = scene_path / filename
|
| 221 |
+
content = await file.read()
|
| 222 |
with open(file_path, "wb") as f:
|
|
|
|
| 223 |
f.write(content)
|
| 224 |
+
|
| 225 |
+
# Track saved files
|
| 226 |
+
if scene_folder not in files_saved:
|
| 227 |
+
files_saved[scene_folder] = 0
|
| 228 |
+
files_saved[scene_folder] += 1
|
| 229 |
|
| 230 |
+
if len(files_saved) == 0:
|
| 231 |
+
raise Exception("No files were saved")
|
| 232 |
+
|
| 233 |
+
# Step 4: Call scene selector to pick best from each candidate folder
|
| 234 |
+
select_result = await _select_scenes(manifest_req, CANDIDATES_DIR)
|
| 235 |
+
if select_result["status"] != "success":
|
| 236 |
+
raise Exception(select_result.get("message", "Scene selection failed"))
|
| 237 |
|
| 238 |
+
# Step 5: Compose video with selected images and manifest
|
| 239 |
compose_result = await _compose(manifest_req)
|
| 240 |
if compose_result["status"] != "success":
|
| 241 |
raise Exception(compose_result.get("message", "Composition failed"))
|
| 242 |
|
| 243 |
+
# Step 6: Return the MP4 file
|
| 244 |
output_file = Path(compose_result["output_path"])
|
| 245 |
if not output_file.exists():
|
| 246 |
+
raise Exception("Output video file not found")
|
| 247 |
|
| 248 |
return FileResponse(
|
| 249 |
path=output_file,
|