feat: voice clone audio generation + podcast workspace architecture
- Voice clone integration: When user selects voice clone in Write phase, backend uses their uploaded voice sample + scene script text to generate audio via qwen3/minimax/cosyvoice voice clone APIs - Multi-tenant workspace storage: All podcast assets (audio, video, images, charts) now use workspace-specific directories per user - Chart preview improvements: Card-based B-Roll charts UI with thumbnails, takeaway text, and action buttons; public endpoint for image serving - Voice clone caching: In-memory LRU cache for voice samples (avoids re-downloading per scene); frontend caches voice clone metadata - Thread pool for voice clone: Audio generation uses ThreadPoolExecutor to avoid blocking the FastAPI event loop - Auto-detect voice clone IDs (vc_*, MY_VOICE_CLONE) to route correctly - DB fallback for voice sample URL: Fetches from ContentAsset if not passed - Fixed API URL resolution for chart previews - Fixed GlassyCard DOM warnings for motion props - Fixed ScriptGenerationProgressView syntax error - Fixed usePodcastWorkflow scriptData reference
This commit is contained in:
@@ -86,8 +86,8 @@ class PodcastService:
|
||||
) -> Optional[PodcastProject]:
|
||||
"""Update project fields."""
|
||||
from loguru import logger
|
||||
logger.warning(f"[PodcastService] update_project: user_id={user_id}, project_id={project_id}")
|
||||
logger.warning(f"[PodcastService] update_project: updates={updates}")
|
||||
updated_fields = list(updates.keys()) if isinstance(updates, dict) else []
|
||||
logger.warning(f"[PodcastService] update_project: user_id={user_id}, project_id={project_id}, fields={updated_fields}")
|
||||
|
||||
project = self.get_project(user_id, project_id)
|
||||
if not project:
|
||||
|
||||
Reference in New Issue
Block a user