| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899 |
- import logging
- from pathlib import Path
- from fastapi import APIRouter, HTTPException
- import os
- import uuid
- import shutil
- from fastapi import UploadFile, File
- from starlette.concurrency import run_in_threadpool
- import service.ai_task as ai_task
- import service.pyav as pyav
- from setting import UPLOAD_DIR, OUTPUT_DIR
- logger = logging.getLogger(__name__)
- # 创建路由对象,可以统一设置前缀 (prefix) 和 标签 (tags)
- router = APIRouter(
- prefix="/api1/audio",
- tags=["audio"]
- )
- @router.post("/asr")
- async def upload_audio(file: UploadFile = File(...)):
- # 1. 统一生成一次 task_id,确保前后一致
- task_id = str(uuid.uuid4())[:8]
- ext = file.filename.split('.')[-1]
- save_path = os.path.join(UPLOAD_DIR, f"{task_id}.{ext}")
- # 2. 解决 IO 阻塞方案 A: 使用 run_in_threadpool (推荐)
- # 这样会将同步的写入操作丢进单独的线程,不阻塞主事件循环
- def save_file():
- with open(save_path, "wb") as buffer:
- shutil.copyfileobj(file.file, buffer)
- await run_in_threadpool(save_file)
- # 3. 构造路径并存入队列
- srt_path = os.path.join(OUTPUT_DIR, f"{task_id}.srt")
- video_path = os.path.join(OUTPUT_DIR, f"{task_id}.mp4")
- # 传递已经确定好的 task_id
- await ai_task.put_task(task_id, save_path, srt_path, video_path)
- return {
- "status": "queued",
- "task_id": task_id,
- "message": "文件已上传并加入 GPU 处理队列",
- "srt_preview_path": f"{OUTPUT_DIR}/{task_id}.srt"
- }
- @router.get("/tasks")
- async def get_queue_status():
- return {"queue_size": ai_task.get_tasks()}
- @router.get("/result/{task_id}")
- async def get_asr_result(task_id: str):
- file_name = check_file_prefix(UPLOAD_DIR, task_id)
- if not file_name:
- raise HTTPException(status_code=404, detail="音频文件不存在")
- audio_path = f"{UPLOAD_DIR}/{file_name}"
- txt_path = f"{OUTPUT_DIR}/{task_id}.txt"
- if not os.path.exists(txt_path):
- raise HTTPException(status_code=404, detail="音频文本文件不存在")
- srt_path = f"{OUTPUT_DIR}/{task_id}.srt"
- if not os.path.exists(srt_path):
- raise HTTPException(status_code=404, detail="字幕文件不存在")
- video_path = f"{OUTPUT_DIR}/{task_id}.mp4"
- if not os.path.exists(video_path):
- raise HTTPException(status_code=404, detail="视频文件不存在")
- with open(txt_path, "r", encoding="utf-8") as f:
- text = f.read()
- info = pyav.get_media_info(audio_path)
- srt = pyav.parse_srt_to_list(srt_path)
- return {
- "task_id": task_id,
- "duration": info['duration'],
- "text": text,
- "srt": srt,
- "audio_url": f"/api1/file/audio/{file_name}",
- "video_url": f"/api1/file/video/{task_id}.mp4"
- }
- def check_file_prefix(directory, prefix):
- # 1. 转化为 Path 对象
- path = Path(directory)
- # 2. 匹配所有以 prefix 开头的文件
- # 如果要匹配特定后缀,可以使用 f"{prefix}*.jpg"
- matched_files = list(path.glob(f"{prefix}*"))
- count = len(matched_files)
- if count == 1:
- file_path = matched_files[0]
- return file_path.name
- else:
- return None
|