Fix: Avatar/media path resolution and voice clone dependencies
- Remove nltk dependency from step4_assets by inlining _extract_user_id - Add graceful error handling for step4_assets in podcast-only mode - Fix media_utils.py to use tenant-aware get_podcast_media_read_dirs() - Resolves avatar image 404 during scene image generation
This commit is contained in:
@@ -9,8 +9,21 @@ from fastapi.responses import FileResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from pydantic import BaseModel
|
||||
from loguru import logger
|
||||
from .step4_persona_routes import _extract_user_id
|
||||
from middleware.auth_middleware import get_current_user
|
||||
|
||||
|
||||
def _extract_user_id(user: Dict[str, Any]) -> str:
|
||||
"""Extract a stable user ID from Clerk-authenticated user payloads.
|
||||
Prefers 'clerk_user_id' or 'id', falls back to 'user_id', else 'unknown'.
|
||||
"""
|
||||
if not isinstance(user, dict):
|
||||
return 'unknown'
|
||||
return (
|
||||
user.get('clerk_user_id')
|
||||
or user.get('id')
|
||||
or user.get('user_id')
|
||||
or 'unknown'
|
||||
)
|
||||
import base64
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
@@ -426,13 +426,15 @@ if PODCAST_ONLY_DEMO_MODE:
|
||||
podcast_routers = [r for r in CORE_ROUTER_REGISTRY if "podcast" in r.get("features", set())]
|
||||
logger.info(f"[PODCAST-ONLY] Found {len(podcast_routers)} podcast routers: {[r['name'] for r in podcast_routers]}")
|
||||
|
||||
# Force include step4_assets for voice cloning
|
||||
# Try to include step4_assets for voice cloning (may fail if nltk not installed)
|
||||
step4_entry = next((r for r in CORE_ROUTER_REGISTRY if r.get("name") == "step4_assets"), None)
|
||||
if step4_entry:
|
||||
try:
|
||||
logger.info(f"[PODCAST-ONLY] Forcing load of step4_assets for voice cloning")
|
||||
logger.info(f"[PODCAST-ONLY] Attempting to load step4_assets for voice cloning")
|
||||
router = router_manager._load_router_from_registry(step4_entry)
|
||||
router_manager.include_router_safely(router, step4_entry["name"], step4_entry.get("include_kwargs"))
|
||||
except ImportError as e:
|
||||
logger.warning(f"[PODCAST-ONLY] Skipping step4_assets (missing optional dependency): {e}")
|
||||
except Exception as e:
|
||||
logger.error(f"[PODCAST-ONLY] Failed to mount step4_assets: {e}")
|
||||
|
||||
|
||||
@@ -97,13 +97,22 @@ def resolve_media_path(media_url_or_path: str) -> Optional[Path]:
|
||||
# Prioritize YouTube paths
|
||||
pass # Already first in list
|
||||
elif "/api/podcast/" in media_url_or_path:
|
||||
# Prioritize Podcast paths
|
||||
search_paths = [
|
||||
PODCAST_AVATARS_DIR / filename,
|
||||
PODCAST_IMAGES_DIR / filename,
|
||||
YOUTUBE_AVATARS_DIR / filename,
|
||||
YOUTUBE_IMAGES_DIR / filename
|
||||
]
|
||||
# Prioritize Podcast paths: use centralized podcast media resolution
|
||||
try:
|
||||
# Import the centralized function that checks tenant workspace first
|
||||
from api.podcast.constants import get_podcast_media_read_dirs
|
||||
podcast_dirs = get_podcast_media_read_dirs("image")
|
||||
search_paths = []
|
||||
for pod_dir in podcast_dirs:
|
||||
# Add both avatar and image subdirectories
|
||||
search_paths.append(pod_dir / "avatars" / filename)
|
||||
search_paths.append(pod_dir / filename)
|
||||
except ImportError:
|
||||
# Fallback if podcast constants not available
|
||||
search_paths = [
|
||||
PODCAST_AVATARS_DIR / filename,
|
||||
PODCAST_IMAGES_DIR / filename,
|
||||
]
|
||||
|
||||
# Iterate and find first existing file
|
||||
for path in search_paths:
|
||||
|
||||
Reference in New Issue
Block a user