Files
LLM-infa/api/route/convert_from_mp3.py
2026-02-18 16:37:45 +05:00

89 lines
3.0 KiB
Python

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from fastapi.responses import FileResponse
import os
from pathlib import Path
import uuid
from typing import List
import asyncio
# moviepy is imported lazily inside the conversion function to avoid
# failing module import at application startup when the package is missing.
router = APIRouter(prefix="/convert", tags=["convert"])
@router.get("/list-audio", response_model=List[str])
async def list_audio_files():
base_dir = Path(__file__).resolve().parent.parent.parent / "data" / "audio"
if not base_dir.exists():
return []
files = [f.name for f in base_dir.iterdir() if f.is_file()]
return files
class DownloadAudioRequest(BaseModel):
filename: str
@router.post("/download-audio")
async def download_audio_file(data: DownloadAudioRequest):
base_dir = Path(__file__).resolve().parent.parent.parent / "data" / "audio"
src = (base_dir / data.filename).resolve()
try:
src.relative_to(base_dir.parent)
except Exception:
raise HTTPException(status_code=400, detail="Invalid filename")
if not src.exists():
raise HTTPException(status_code=404, detail="File not found")
return FileResponse(str(src), filename=src.name, media_type="audio/mpeg")
# New: convert a video file (located in ./data) to mp3 using bundled imageio-ffmpeg
class VideoToMp3Request(BaseModel):
filename: str
def _run_moviepy(src: Path, dest: Path):
from moviepy import VideoFileClip
clip = VideoFileClip(str(src))
try:
if clip.audio is None:
raise RuntimeError("Source file has no audio stream")
clip.audio.write_audiofile(str(dest), codec="libmp3lame", bitrate="192k")
finally:
clip.close()
@router.post("/video-to-mp3")
async def video_to_mp3(req: VideoToMp3Request):
# ensure MoviePy is available before doing work, return clear 503 if not
try:
import moviepy # noqa: F401
except Exception:
raise HTTPException(status_code=503, detail="moviepy is not installed in the runtime. Rebuild image or install moviepy/imageio-ffmpeg")
data_dir = Path(__file__).resolve().parent.parent.parent / "data"
src = (data_dir / req.filename).resolve()
try:
src.relative_to(data_dir)
except Exception:
raise HTTPException(status_code=400, detail="Invalid filename")
if not src.exists() or not src.is_file():
raise HTTPException(status_code=404, detail="Source file not found")
out_dir = data_dir / "audio"
out_dir.mkdir(parents=True, exist_ok=True)
dest = out_dir / f"{src.stem}.mp3"
try:
# run blocking MoviePy conversion in threadpool to avoid blocking event loop
await asyncio.get_running_loop().run_in_executor(None, _run_moviepy, src, dest)
except Exception as e:
raise HTTPException(status_code=500, detail=f"conversion failed: {e}")
return FileResponse(str(dest), filename=dest.name, media_type="audio/mpeg")
# Note: this endpoint uses the bundled ffmpeg provided by `imageio-ffmpeg`.