auto-save 2026-05-14 10:45 (+1, ~5)
This commit is contained in:
47
api/main.py
47
api/main.py
@@ -561,7 +561,36 @@ async def lifespan(_: FastAPI):
|
||||
for p in JOBS_DIR.iterdir():
|
||||
if p.is_dir() and (p / "state.json").exists():
|
||||
try:
|
||||
JOBS[p.name] = Job.model_validate_json((p / "state.json").read_text())
|
||||
job = Job.model_validate_json((p / "state.json").read_text())
|
||||
source_exists = (p / "source.mp4").exists()
|
||||
if job.status in {"created", "downloading"}:
|
||||
if source_exists:
|
||||
update(job, status="downloaded", progress=25, message="服务重启 · 视频已恢复,可重新解析")
|
||||
else:
|
||||
update(job, status="failed", message="服务重启 · 下载任务已中断,请重新提交")
|
||||
elif job.status == "splitting":
|
||||
update(
|
||||
job,
|
||||
status="frames_extracted" if job.frames else "downloaded",
|
||||
progress=70 if job.frames else 25,
|
||||
message="服务重启 · 上次抽帧已中断,可重新抽帧",
|
||||
)
|
||||
elif job.status == "transcribing":
|
||||
audio_script = job.audio_script
|
||||
if audio_script.status == "rewriting":
|
||||
audio_script = audio_script.model_copy(update={
|
||||
"status": "failed",
|
||||
"error": "服务重启 · 上次音频改写/配音已中断,可重新处理",
|
||||
"created_at": audio_script.created_at or time.time(),
|
||||
})
|
||||
update(
|
||||
job,
|
||||
status="frames_extracted",
|
||||
progress=70,
|
||||
audio_script=audio_script,
|
||||
message="服务重启 · 上次音频处理已中断,可重新处理",
|
||||
)
|
||||
JOBS[p.name] = job
|
||||
except Exception:
|
||||
pass
|
||||
yield
|
||||
@@ -1122,7 +1151,7 @@ def ffprobe_meta(mp4: Path) -> dict:
|
||||
return json.loads(out)
|
||||
|
||||
|
||||
async def pipeline_download(job_id: str) -> None:
|
||||
def pipeline_download(job_id: str) -> None:
|
||||
"""阶段 1:仅下载(或上传跳过),落 source.mp4,停在 downloaded 等用户点解析。"""
|
||||
job = JOBS[job_id]
|
||||
d = job_dir(job_id)
|
||||
@@ -1159,7 +1188,7 @@ async def pipeline_download(job_id: str) -> None:
|
||||
update(job, status="failed", error=str(e), message="下载失败")
|
||||
|
||||
|
||||
async def pipeline_analyze(
|
||||
def pipeline_analyze(
|
||||
job_id: str,
|
||||
frame_count: int = KEYFRAME_COUNT,
|
||||
target: FrameExtractTarget = "transparent_human",
|
||||
@@ -1311,7 +1340,7 @@ async def pipeline_analyze(
|
||||
update(job, status="failed", error=str(e), message="解析失败")
|
||||
|
||||
|
||||
async def analyze_queue_worker() -> None:
|
||||
def analyze_queue_worker() -> None:
|
||||
global ANALYZE_WORKER_RUNNING
|
||||
ANALYZE_WORKER_RUNNING = True
|
||||
try:
|
||||
@@ -1319,7 +1348,7 @@ async def analyze_queue_worker() -> None:
|
||||
job_id, frames, target, mode, quality = ANALYZE_QUEUE.pop(0)
|
||||
if job_id not in JOBS:
|
||||
continue
|
||||
await pipeline_analyze(job_id, frames, target, mode, quality)
|
||||
pipeline_analyze(job_id, frames, target, mode, quality)
|
||||
if ANALYZE_QUEUE:
|
||||
for pos, (queued_job_id, *_rest) in enumerate(ANALYZE_QUEUE, start=1):
|
||||
queued_job = JOBS.get(queued_job_id)
|
||||
@@ -1984,6 +2013,14 @@ def get_video(job_id: str):
|
||||
return FileResponse(p, media_type="video/mp4")
|
||||
|
||||
|
||||
@app.get("/jobs/{job_id}/audio.wav")
|
||||
def get_source_audio(job_id: str):
|
||||
p = job_dir(job_id) / "audio.wav"
|
||||
if not p.exists():
|
||||
raise HTTPException(404, "audio not found")
|
||||
return FileResponse(p, media_type="audio/wav")
|
||||
|
||||
|
||||
@app.get("/jobs/{job_id}/audio-script.mp3")
|
||||
def get_audio_script(job_id: str):
|
||||
p = job_dir(job_id) / "audio_script.mp3"
|
||||
|
||||
Reference in New Issue
Block a user