Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
-
from fastapi import FastAPI, BackgroundTasks
|
| 2 |
-
from fastapi.responses import FileResponse
|
| 3 |
from pydantic import BaseModel
|
| 4 |
from typing import List
|
| 5 |
from pathlib import Path
|
|
@@ -32,7 +31,7 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
| 32 |
# Supabase client
|
| 33 |
# -----------------------------
|
| 34 |
SUPABASE_URL = "https://kvlxvhdgacktsgykyckm.supabase.co/"
|
| 35 |
-
SUPABASE_KEY = "
|
| 36 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 37 |
|
| 38 |
# -----------------------------
|
|
@@ -43,13 +42,11 @@ download_cache = {} # URL -> local path
|
|
| 43 |
# -----------------------------
|
| 44 |
# Helper to get cached file (downloads if missing)
|
| 45 |
# -----------------------------
|
| 46 |
-
async def get_cached_file(url: str, subfolder: str) -> str | None:
|
| 47 |
"""
|
| 48 |
Returns local cached path for URL.
|
| 49 |
Downloads and stores in subfolder if missing.
|
| 50 |
-
|
| 51 |
-
- Raise error for prosody or bg_music
|
| 52 |
-
- Skip (return None) for sfx
|
| 53 |
"""
|
| 54 |
if url in download_cache:
|
| 55 |
return download_cache[url]
|
|
@@ -76,11 +73,11 @@ async def get_cached_file(url: str, subfolder: str) -> str | None:
|
|
| 76 |
return local_path
|
| 77 |
|
| 78 |
except Exception as e:
|
| 79 |
-
if subfolder == "sfx":
|
| 80 |
-
print(f"Warning: Failed to download
|
| 81 |
return None
|
| 82 |
else:
|
| 83 |
-
# Raise error
|
| 84 |
raise RuntimeError(f"Failed to download {subfolder} file {url}: {e}") from e
|
| 85 |
|
| 86 |
# -----------------------------
|
|
@@ -97,9 +94,6 @@ def list_all_files(bucket_name: str):
|
|
| 97 |
files.append((f["name"], url))
|
| 98 |
return files
|
| 99 |
|
| 100 |
-
async def download_to_cache(url: str, subfolder: str):
|
| 101 |
-
await get_cached_file(url, subfolder)
|
| 102 |
-
|
| 103 |
async def preload_all_assets():
|
| 104 |
print("Starting Supabase asset preloading...")
|
| 105 |
tasks = []
|
|
@@ -113,7 +107,8 @@ async def preload_all_assets():
|
|
| 113 |
for bucket_name, subfolder in buckets.items():
|
| 114 |
files = list_all_files(bucket_name)
|
| 115 |
for _, url in files:
|
| 116 |
-
|
|
|
|
| 117 |
|
| 118 |
await asyncio.gather(*tasks)
|
| 119 |
print(f"Preloading completed. {len(download_cache)} files cached on disk.")
|
|
@@ -251,6 +246,9 @@ async def generate_story_audios(story: StoryCreationDTO, base_output: str):
|
|
| 251 |
chapter_dir.mkdir(exist_ok=True)
|
| 252 |
|
| 253 |
prosody_file_title = await get_cached_file(chapter.title.prosodyReference, "prosody")
|
|
|
|
|
|
|
|
|
|
| 254 |
title_save_path = chapter_dir / "title.wav"
|
| 255 |
tagged_text_title = generate_tagged_text(
|
| 256 |
chapter.title.sentence,
|
|
@@ -265,6 +263,9 @@ async def generate_story_audios(story: StoryCreationDTO, base_output: str):
|
|
| 265 |
|
| 266 |
for sentence in scene.sentences:
|
| 267 |
prosody_file = await get_cached_file(sentence.prosodyReference, "prosody")
|
|
|
|
|
|
|
|
|
|
| 268 |
sentence_save_path = scene_dir / f"{sentence.sentenceId}.wav"
|
| 269 |
tagged_text = generate_tagged_text(
|
| 270 |
sentence.sentence,
|
|
@@ -309,11 +310,14 @@ async def concat_story_audio(story: StoryCreationDTO, base_output: str, final_pa
|
|
| 309 |
|
| 310 |
if scene.location.path:
|
| 311 |
sfx_file = await get_cached_file(scene.location.path, "sfx")
|
| 312 |
-
|
| 313 |
-
|
|
|
|
| 314 |
|
| 315 |
if scene.bgMusic and scene.bgMusic.musicPath:
|
| 316 |
bg_file = await get_cached_file(scene.bgMusic.musicPath, "bg_music")
|
|
|
|
|
|
|
| 317 |
bg_file_wav = ensure_wav(bg_file)
|
| 318 |
bg_audio = AudioSegment.from_file(bg_file_wav)
|
| 319 |
bg_audio = bg_audio - (1 - scene.bgMusic.volume) * 30
|
|
|
|
| 1 |
+
from fastapi import FastAPI, BackgroundTasks
|
|
|
|
| 2 |
from pydantic import BaseModel
|
| 3 |
from typing import List
|
| 4 |
from pathlib import Path
|
|
|
|
| 31 |
# Supabase client
|
| 32 |
# -----------------------------
|
| 33 |
SUPABASE_URL = "https://kvlxvhdgacktsgykyckm.supabase.co/"
|
| 34 |
+
SUPABASE_KEY = "YOUR_SUPABASE_KEY_HERE"
|
| 35 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 36 |
|
| 37 |
# -----------------------------
|
|
|
|
| 42 |
# -----------------------------
|
| 43 |
# Helper to get cached file (downloads if missing)
|
| 44 |
# -----------------------------
|
| 45 |
+
async def get_cached_file(url: str, subfolder: str, skip_on_startup: bool = False) -> str | None:
|
| 46 |
"""
|
| 47 |
Returns local cached path for URL.
|
| 48 |
Downloads and stores in subfolder if missing.
|
| 49 |
+
skip_on_startup: if True, don't raise errors even for prosody/bg_music (used during startup).
|
|
|
|
|
|
|
| 50 |
"""
|
| 51 |
if url in download_cache:
|
| 52 |
return download_cache[url]
|
|
|
|
| 73 |
return local_path
|
| 74 |
|
| 75 |
except Exception as e:
|
| 76 |
+
if subfolder == "sfx" or skip_on_startup:
|
| 77 |
+
print(f"Warning: Failed to download {subfolder} file {url}, skipping: {e}")
|
| 78 |
return None
|
| 79 |
else:
|
| 80 |
+
# Raise error if essential and not in startup
|
| 81 |
raise RuntimeError(f"Failed to download {subfolder} file {url}: {e}") from e
|
| 82 |
|
| 83 |
# -----------------------------
|
|
|
|
| 94 |
files.append((f["name"], url))
|
| 95 |
return files
|
| 96 |
|
|
|
|
|
|
|
|
|
|
| 97 |
async def preload_all_assets():
|
| 98 |
print("Starting Supabase asset preloading...")
|
| 99 |
tasks = []
|
|
|
|
| 107 |
for bucket_name, subfolder in buckets.items():
|
| 108 |
files = list_all_files(bucket_name)
|
| 109 |
for _, url in files:
|
| 110 |
+
# skip_on_startup=True prevents crash at startup
|
| 111 |
+
tasks.append(get_cached_file(url, subfolder, skip_on_startup=True))
|
| 112 |
|
| 113 |
await asyncio.gather(*tasks)
|
| 114 |
print(f"Preloading completed. {len(download_cache)} files cached on disk.")
|
|
|
|
| 246 |
chapter_dir.mkdir(exist_ok=True)
|
| 247 |
|
| 248 |
prosody_file_title = await get_cached_file(chapter.title.prosodyReference, "prosody")
|
| 249 |
+
if prosody_file_title is None:
|
| 250 |
+
raise RuntimeError(f"Missing prosody file for chapter title: {chapter.title.prosodyReference}")
|
| 251 |
+
|
| 252 |
title_save_path = chapter_dir / "title.wav"
|
| 253 |
tagged_text_title = generate_tagged_text(
|
| 254 |
chapter.title.sentence,
|
|
|
|
| 263 |
|
| 264 |
for sentence in scene.sentences:
|
| 265 |
prosody_file = await get_cached_file(sentence.prosodyReference, "prosody")
|
| 266 |
+
if prosody_file is None:
|
| 267 |
+
raise RuntimeError(f"Missing prosody file for sentence: {sentence.sentenceId}")
|
| 268 |
+
|
| 269 |
sentence_save_path = scene_dir / f"{sentence.sentenceId}.wav"
|
| 270 |
tagged_text = generate_tagged_text(
|
| 271 |
sentence.sentence,
|
|
|
|
| 310 |
|
| 311 |
if scene.location.path:
|
| 312 |
sfx_file = await get_cached_file(scene.location.path, "sfx")
|
| 313 |
+
if sfx_file:
|
| 314 |
+
sfx_file_wav = ensure_wav(sfx_file)
|
| 315 |
+
scene_audio = scene_audio.overlay(AudioSegment.from_wav(sfx_file_wav))
|
| 316 |
|
| 317 |
if scene.bgMusic and scene.bgMusic.musicPath:
|
| 318 |
bg_file = await get_cached_file(scene.bgMusic.musicPath, "bg_music")
|
| 319 |
+
if bg_file is None:
|
| 320 |
+
raise RuntimeError(f"Missing background music file: {scene.bgMusic.musicPath}")
|
| 321 |
bg_file_wav = ensure_wav(bg_file)
|
| 322 |
bg_audio = AudioSegment.from_file(bg_file_wav)
|
| 323 |
bg_audio = bg_audio - (1 - scene.bgMusic.volume) * 30
|