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 sqlalchemy.orm import Session
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from .step4_persona_routes import _extract_user_id
|
|
||||||
from middleware.auth_middleware import get_current_user
|
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 base64
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
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())]
|
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]}")
|
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)
|
step4_entry = next((r for r in CORE_ROUTER_REGISTRY if r.get("name") == "step4_assets"), None)
|
||||||
if step4_entry:
|
if step4_entry:
|
||||||
try:
|
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 = router_manager._load_router_from_registry(step4_entry)
|
||||||
router_manager.include_router_safely(router, step4_entry["name"], step4_entry.get("include_kwargs"))
|
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:
|
except Exception as e:
|
||||||
logger.error(f"[PODCAST-ONLY] Failed to mount step4_assets: {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
|
# Prioritize YouTube paths
|
||||||
pass # Already first in list
|
pass # Already first in list
|
||||||
elif "/api/podcast/" in media_url_or_path:
|
elif "/api/podcast/" in media_url_or_path:
|
||||||
# Prioritize Podcast paths
|
# Prioritize Podcast paths: use centralized podcast media resolution
|
||||||
search_paths = [
|
try:
|
||||||
PODCAST_AVATARS_DIR / filename,
|
# Import the centralized function that checks tenant workspace first
|
||||||
PODCAST_IMAGES_DIR / filename,
|
from api.podcast.constants import get_podcast_media_read_dirs
|
||||||
YOUTUBE_AVATARS_DIR / filename,
|
podcast_dirs = get_podcast_media_read_dirs("image")
|
||||||
YOUTUBE_IMAGES_DIR / filename
|
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
|
# Iterate and find first existing file
|
||||||
for path in search_paths:
|
for path in search_paths:
|
||||||
|
|||||||
Reference in New Issue
Block a user