fixed a bug
This commit is contained in:
@@ -2,6 +2,8 @@ import hashlib
|
||||
import hmac
|
||||
import logging
|
||||
import mimetypes
|
||||
import shutil
|
||||
import subprocess
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Any, BinaryIO, Dict, List, Optional
|
||||
@@ -388,6 +390,7 @@ def create_app(
|
||||
video_hash: str = Form(...),
|
||||
title: str = Form(default="我的口语配音"),
|
||||
segments: str = Form(...),
|
||||
scores: str = Form(default="[]"),
|
||||
files: List[UploadFile] = File(...),
|
||||
) -> Dict[str, Any]:
|
||||
try:
|
||||
@@ -398,6 +401,17 @@ def create_app(
|
||||
raise HTTPException(status_code=400, detail="At least one dubbing segment is required.")
|
||||
if len(segment_items) != len(files):
|
||||
raise HTTPException(status_code=400, detail="Segment count does not match audio file count.")
|
||||
try:
|
||||
score_items = json.loads(scores)
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise HTTPException(status_code=400, detail="scores must be valid JSON.") from exc
|
||||
if not isinstance(score_items, list):
|
||||
raise HTTPException(status_code=400, detail="scores must be a JSON array.")
|
||||
scores_by_index = {
|
||||
int(item["sentence_index"]): item
|
||||
for item in score_items
|
||||
if isinstance(item, dict) and "sentence_index" in item
|
||||
}
|
||||
document = find_document(video_hash.lower())
|
||||
if document is None:
|
||||
raise HTTPException(status_code=404, detail="Video or sentence boundaries were not found.")
|
||||
@@ -418,7 +432,9 @@ def create_app(
|
||||
audio_name = f"{uuid.uuid4().hex}{suffix}"
|
||||
audio_path = service_settings.dub_shares_dir / audio_name
|
||||
await run_in_threadpool(_persist_upload, upload.file, audio_path, 50 * 1024 * 1024)
|
||||
await run_in_threadpool(_trim_leading_silence, audio_path)
|
||||
saved_files.append(audio_path)
|
||||
score = scores_by_index.get(sentence_index, {})
|
||||
prepared_segments.append({
|
||||
"sentence_index": sentence_index,
|
||||
"start_ms": boundary.start_ms,
|
||||
@@ -426,6 +442,8 @@ def create_app(
|
||||
"text": boundary.text,
|
||||
"audio_filename": audio_name,
|
||||
"audio_size_bytes": audio_path.stat().st_size,
|
||||
"overall_score": float(score.get("overall_score", 0)),
|
||||
"recognized_text": str(score.get("recognized_text") or ""),
|
||||
})
|
||||
share = video_repository.create_dub_share(
|
||||
video_hash=video_hash.lower(),
|
||||
@@ -458,12 +476,15 @@ def create_app(
|
||||
"video_hash": share["video_hash"],
|
||||
"title": share["title"],
|
||||
"created_at": share["created_at"],
|
||||
"video_hash": share["video_hash"],
|
||||
"segments": [
|
||||
{
|
||||
"index": row["sentence_index"],
|
||||
"start_ms": row["start_ms"],
|
||||
"end_ms": row["end_ms"],
|
||||
"text": row["text"],
|
||||
"overall_score": row["overall_score"],
|
||||
"recognized_text": row["recognized_text"],
|
||||
"audio_url": f"/api/v1/dub-shares/{share_id}/audio/{row['audio_filename']}",
|
||||
}
|
||||
for row in share["segments"]
|
||||
@@ -519,6 +540,34 @@ def _persist_upload(source: BinaryIO, destination: Path, max_bytes: int) -> tupl
|
||||
return digest.hexdigest(), size
|
||||
|
||||
|
||||
def _trim_leading_silence(audio_path: Path) -> None:
|
||||
ffmpeg = shutil.which("ffmpeg")
|
||||
if ffmpeg is None:
|
||||
return
|
||||
trimmed_path = audio_path.with_name(f"{audio_path.stem}-trimmed{audio_path.suffix}")
|
||||
command = [
|
||||
ffmpeg,
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"error",
|
||||
"-y",
|
||||
"-i",
|
||||
str(audio_path),
|
||||
"-af",
|
||||
"silenceremove=start_periods=1:start_threshold=-45dB:start_silence=0.08",
|
||||
"-c:a",
|
||||
"aac",
|
||||
str(trimmed_path),
|
||||
]
|
||||
try:
|
||||
subprocess.run(command, check=True)
|
||||
if trimmed_path.stat().st_size == 0:
|
||||
raise RuntimeError("Trimmed audio is empty.")
|
||||
trimmed_path.replace(audio_path)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
trimmed_path.unlink(missing_ok=True)
|
||||
|
||||
|
||||
async def _persist_request_stream(
|
||||
request: Request,
|
||||
destination: Path,
|
||||
|
||||
Reference in New Issue
Block a user