Files
vrsub/src/wov_app/main.py
T
cat-shark 711867e79f feat: 文件夹批量处理引擎(后端)
- BatchWorker 单线程轮询 batch_jobs 表,处理 source=batch 的运行,
  与主调度器互不抢占(next_queued_run 排除 batch 来源)
- 直接读取用户所选文件夹下的视频逐个执行流水线,不上传到工作目录;
  中间态与产物落在视频旁同名文件夹,batch.done.json 完成标记去重
- 支持暂停/继续、失败容错(单视频失败不阻塞后续)、删除任务只清库
- 孤儿清理跳过 source=batch 运行,防止误删用户视频文件夹
- workflow_runs 新增 source 列(upload/batch),旧库自动迁移
2026-08-23 16:25:09 +08:00

95 lines
3.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""FastAPI 应用入口。
负责组装数据库、进程内节点注册表、调度器与静态前端,并在应用生命周期内
管理后台线程的启动与清理。单体版所有节点在同一进程内直接调用。
"""
from __future__ import annotations
# 先加载 .env(含 LLM API Key 等本地配置),再导入读取环境变量的 config。
from dotenv import load_dotenv
load_dotenv()
import os # noqa: E402
from contextlib import asynccontextmanager # noqa: E402
from datetime import datetime, timezone # noqa: E402
from pathlib import Path # noqa: E402
from fastapi import FastAPI # noqa: E402
from fastapi.middleware.cors import CORSMiddleware # noqa: E402
from fastapi.staticfiles import StaticFiles # noqa: E402
from wov_app import registry
from wov_app.batch import BatchWorker
from wov_app.config import BATCH_ENABLED, DB_PATH, STORAGE_DIR, WORKSPACE_ROOT
from wov_app.db import Database
from wov_app.maintenance import OrphanCleaner
from wov_app.routers import apps, batch, workflows
from wov_app.scheduler import WorkflowScheduler
from wov_app.seed import seed_default_workflows
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期:启动时初始化数据、注册节点和后台服务,退出时回收资源。"""
# 确保数据与存储目录存在,避免首次启动写文件失败。
db = Database(DB_PATH)
STORAGE_DIR.mkdir(parents=True, exist_ok=True)
# 静态注册全部内置节点到进程内注册表(内存态,不落库)。
registry.register_all()
# 默认创建演示工作流,可关闭便于测试。
if os.getenv("WOV_AUTO_SEED", "1") == "1":
seed_default_workflows(db)
# 重启恢复:上次进程被杀时遗留的 RUNNING 任务恢复为 QUEUED
# 调度器会从产物表断点续跑(不重复已完成节点);PAUSED 保持等待显式 resume。
db.recover_interrupted_runs(datetime.now(timezone.utc).isoformat())
scheduler = WorkflowScheduler(db, STORAGE_DIR)
# 调度器默认开启,处理排队中的任务;测试可关闭后手动执行。
if os.getenv("WOV_SCHEDULER_ENABLED", "1") == "1":
scheduler.start()
cleaner = OrphanCleaner(db, STORAGE_DIR)
# 孤儿数据清理默认开启,定时清除死数据;测试可关闭。
if os.getenv("WOV_CLEANUP_ENABLED", "1") == "1":
cleaner.start()
# 批量处理引擎:处理用户所选文件夹的批量任务(source=batch 的运行),
# 与主调度器互不抢占;默认开启,测试可关闭。
batch_worker = BatchWorker(db)
if os.getenv("WOV_BATCH_ENABLED", "1") == "1":
batch_worker.start()
# 共享对象挂到 app.state,路由通过 Depends 延迟获取。
app.state.db = db
app.state.scheduler = scheduler
app.state.cleaner = cleaner
app.state.batch = batch_worker
yield
# 退出时先停批量引擎、调度器与清理器,避免残留后台线程。
batch_worker.stop()
cleaner.stop()
scheduler.stop()
app = FastAPI(title="VRSub API(单体版)", version="0.1.0", lifespan=lifespan)
# MVP 阶段不做鉴权,允许跨域便于本地调试与静态页面访问。
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(workflows.router)
app.include_router(apps.router)
app.include_router(batch.router)
@app.get("/health")
def health() -> dict:
"""进程存活探针,供部署环境与前端检测后端可用性。"""
return {"status": "ok", "service": "wov-api", "mode": "monolith"}
# 静态前端目录位于仓库根下的 web,由 FastAPI 直接挂载。
FRONTEND_DIR = WORKSPACE_ROOT / "web"
app.mount("/", StaticFiles(directory=FRONTEND_DIR, html=True), name="frontend")