# boardshadow **Repository Path**: x7h66/boardshadow ## Basic Information - **Project Name**: boardshadow - **Description**: 多学科板书AI视频生成工具 - **Primary Language**: Python - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-05-19 - **Last Updated**: 2026-05-20 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # BoardShadow 多学科板书 AI 视频生成工具 本项目已调整为纯 Python 后端技术栈:FastAPI + MySQL + 本地/线上大模型 + HyperFrames帧生成 + Pillow 板书帧渲染 + FFmpeg 视频合成。视频生成引擎已合并到 `backend/app/engine.py`,后端不再依赖其他语言服务。 ## 目录 - `backend/`:FastAPI 后端、MySQL 数据访问、鉴权、任务编排、视频生成引擎 - `backend/app/engine.py`:本地离线生成引擎,负责脚本、板书帧、音轨和 MP4 - `backend/schema.sql`:MySQL 建表与种子数据 - `web/`:Vue3 + Vite Web 前端 - `miniapp/`:uni-app 微信小程序端 - `storage/`:生成任务产物目录 - 78997b7d0c3cbf4b01350a947c358f9e - 303cf3ff8024289c9eda69c83e9bf01b - 3b537f5bf2c89f84ba2202fedc4adc80 ## 本地依赖 - Python 3.10+ - MySQL 8 - FFmpeg,并加入 `PATH` - Node.js 18+,用于 Web 和小程序端 - 可选:本地 Ollama,默认地址 `http://127.0.0.1:11434` - 可选:OpenAI 兼容 API,可接线上模型,也可接 LM Studio / vLLM / xinference 等本地离线服务 - 可选:开源 TTS,后端已内置 xiaozhi provider 运行子集与 OmniVoice 声音克隆推理包 未启动大模型或未配置开源 TTS 时,系统会使用内置学科模板和静音占位音轨,仍可生成 MP4。 ## 一键本地启动 首次部署可直接执行: ```bash cd /boardshadow ./scripts/deploy.sh ``` 如果只想启动已安装好的环境,可直接执行 `./scripts/start-stack.sh`。 如果要停止本地服务,可执行 `./scripts/stop-stack.sh`。 查看状态可执行 `./scripts/status.sh`,备份可执行 `./scripts/backup.sh`,恢复可执行 `./scripts/restore.sh /path/to/backup-dir`。 启动后访问 `http://127.0.0.1:5173`。 部署验收可执行: ```bash python3 scripts/smoke-test.py --base-url http://127.0.0.1:5173 python3 scripts/smoke-test.py --base-url http://127.0.0.1:5173 --video-fps 60 ``` 如果 Vite 自动换了端口,把 `--base-url` 改成实际 PC 前端地址,例如 `http://127.0.0.1:5177`。 默认登录: - 账号:`teacher` - 密码:`boardshadow123` - 角色:`admin` 生产部署可在 `.env.local` 中通过 `BOARDSHADOW_DEFAULT_ADMIN_USERNAME`、`BOARDSHADOW_DEFAULT_ADMIN_PASSWORD`、`BOARDSHADOW_DEFAULT_ADMIN_DISPLAY_NAME` 覆盖默认管理员。后端启动初始化数据库时会同步该账号;如需强制每次启动重置默认管理员密码,可设置 `BOARDSHADOW_RESET_DEFAULT_ADMIN_PASSWORD=1`。 ## 安装后端依赖 ```bash cd /boardshadow/backend pip3 install -r requirements.txt ``` ## 数据库 方式一,使用 Docker: ```bash cd /solo/boardshadow docker compose up -d mysql ``` 方式二,使用本机 MySQL: ```bash mysql -h127.0.0.1 -uroot -p12345678 < backend/schema.sql ``` 默认账号: - 用户名:`teacher` - 密码:`boardshadow123` - 角色:`admin` 如果已设置 `BOARDSHADOW_DEFAULT_ADMIN_*` 环境变量,以环境变量为准。默认情况下不会在每次启动时重写该账号密码,除非显式开启 `BOARDSHADOW_RESET_DEFAULT_ADMIN_PASSWORD=1`。 ## 启动后端 ```bash cd /boardshadow ./scripts/start-backend.sh ``` 等价命令: ```bash cd /boardshadow/backend python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8088 --reload ``` 常用环境变量: ```bash export MYSQL_HOST=127.0.0.1 export MYSQL_PORT=3306 export MYSQL_DATABASE=boardshadow export MYSQL_USERNAME=root export MYSQL_PASSWORD=12345678 export OLLAMA_BASE_URL=http://127.0.0.1:11434 export BOARDSHADOW_STORAGE_DIR=/boardshadow/storage export BOARDSHADOW_CORS_ORIGIN_REGEX='https?://(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?' ``` 也可以复制 `.env.local.example` 为 `.env.local`,`scripts/start-backend.sh` 和 `scripts/start-stack.sh` 会自动读取。 `scripts/deploy.sh` 会自动安装 Python / Web / 小程序依赖并启动服务,适合全新机器。 ## 运维脚本 - `./scripts/doctor.sh`:检查本机依赖、Ollama/TTS、端口和存储目录 - `./scripts/status.sh`:查看本地或容器运行状态和健康检查 - `python3 scripts/smoke-test.py --base-url http://127.0.0.1:5173 --video-fps 30|60`:跑登录、模板加载、视频生成、下载接口、TTS重复句和实际 MP4 帧率验收 - `./scripts/backup.sh`:备份数据库和 `storage/tasks`、`storage/logs` - `./scripts/restore.sh /path/to/backup-dir`:恢复数据库;追加 `--storage` 可恢复任务产物和日志 ## 容器化部署 如果机器上已安装 Docker,可以直接: ```bash cd /boardshadow ./scripts/deploy-docker.sh ``` 浏览器访问 `http://127.0.0.1:5173`。 如果希望 Ollama 也由 Docker 一起启动并自动拉取默认模型: ```bash ./scripts/deploy-docker-ai.sh ``` 等价地,也可以通过统一入口启用 AI 容器: ```bash BOARDSHADOW_DEPLOY_WITH_AI=1 ./scripts/deploy.sh ``` 停止容器: ```bash ./scripts/stop-stack.sh ``` 容器版会同时启动 MySQL、Python 后端和 Web 静态站点,适合正式部署。 状态查看、备份和恢复脚本同样适用于容器版。 如果要让容器内后端连接宿主机上的 Ollama 或开源 TTS,请在 `.env.local` 里设置对应的容器可访问地址和命令,不要直接复用只在宿主机有效的路径。 如果使用 `deploy-docker-ai.sh`,后端会改连 compose 内的 `ollama` 服务。 ## 大模型与开源 TTS 更完整的本地 AI 安装说明见 [docs/local-ai-setup.md](docs/local-ai-setup.md)。 默认使用本地 Ollama,安装并拉取默认模型: ```bash cd /boardshadow ./scripts/install-local-ai.sh ``` 也可以在 Web 管理面板或 `.env.local` 里切换大模型来源: ```bash # 默认本地 Ollama BOARDSHADOW_LLM_PROVIDER=ollama OLLAMA_BASE_URL=http://127.0.0.1:11434 # OpenAI 兼容 API,可用于线上模型或本地 LM Studio/vLLM/xinference BOARDSHADOW_LLM_PROVIDER=api BOARDSHADOW_LLM_API_BASE_URL=https://api.example.com/v1 BOARDSHADOW_LLM_API_KEY=sk-... BOARDSHADOW_LLM_API_MODEL=qwen-plus BOARDSHADOW_LLM_API_TIMEOUT=45 # 不调用大模型,仅用内置小学模板兜底 BOARDSHADOW_LLM_PROVIDER=template ``` xiaozhi TTS 命令可用模板接入: ```bash ./scripts/setup-xiaozhi-tts.sh "/path/to/tts --text {text} --out {output} --speed {speed} --mode {mode}" ``` Web 和小程序生成配置默认使用 `xiaozhi TTS`,也可切换到 `OmniVoice 克隆`。TTS 运行代码已内置到后端:xiaozhi 默认目录为 `./backend/vendor/xiaozhi-server`,OmniVoice 默认目录为 `./backend/vendor/omnivoice`,模型配置为 `OMNIVOICE_MODEL=k2-fsa/OmniVoice`。 生成页还提供小学课堂参数: - `年级层次`:小学低年级 / 中年级 / 高年级,影响用词难度和讲解深度。 - `教学方式`:引导互动 / 例题练习 / 故事导入,影响脚本组织方式。 - `视频节奏`:默认舒缓,控制板书逐行出现的速度。 - `视频帧率`:支持 30 FPS 和 60 FPS,默认 30 FPS。 - `语音语速`:传给开源 TTS,并影响音频合成速度。 ## 启动 Web ```bash cd /boardshadow/web npm install npm run dev ``` Vite 会把 `/api` 代理到 `http://127.0.0.1:8088`。 ## 启动小程序 ```bash cd /boardshadow/miniapp npm install npm run dev:mp-weixin ``` 小程序登录页可填写后端地址。微信开发者工具里调本机后端时,通常需要关闭域名校验;真机调试需把地址改成同局域网可访问 IP。 生产构建可执行 `npm run build:mp-weixin`,产物位于 `miniapp/dist/build/mp-weixin`。 ## 生成引擎单独验证 ```bash cd /boardshadow ./scripts/run-engine-demo.sh ``` 输出文件位于 `storage/tasks/demo/boardshadow.mp4`。 ## API 摘要 - `POST /api/auth/login`:登录,返回本地 token,兼容 `satoken` 请求头 - `POST /api/auth/register`:注册普通教师账号,注册成功后直接返回登录 token - `GET /api/auth/me`:当前用户 - `POST /api/auth/password`:登录用户修改自己的密码 - `GET /api/catalog/subjects`:学科列表 - `GET /api/catalog/templates?subject=math`:模板列表 - `POST /api/catalog/templates`:新增当前用户自定义模板 - `PUT /api/catalog/templates/{code}`:编辑模板,普通教师仅可维护自己创建的模板 - `DELETE /api/catalog/templates/{code}`:软删除模板,普通教师仅可删除自己创建的模板 - `GET /api/voice-profiles`:查看当前用户录入的声音样本 - `POST /api/voice-profiles?name=王老师&referenceText=...`:上传原始音频样本,用于 OmniVoice 克隆 - `DELETE /api/voice-profiles/{id}`:删除当前用户的声音样本 - `GET /api/admin/config`:管理员查看模型、TTS、FFmpeg 等运行配置 - `PUT /api/admin/config`:管理员更新运行配置 - `GET /api/admin/migrations`:管理员查看数据库迁移版本 - `GET /api/admin/dashboard`:管理员查看任务、用户、学科和存储看板 - `GET /api/admin/users?page=1&pageSize=20&q=teacher`:管理员分页检索账号 - `POST /api/admin/users`:管理员创建教师或管理员账号 - `PUT /api/admin/users/{id}`:管理员修改显示名称、角色和启用状态 - `POST /api/admin/users/{id}/password`:管理员重置账号密码 - `GET /api/admin/audit-logs?page=1&pageSize=30&q=USER`:管理员查看审计日志 - `GET /api/admin/audit-logs/export`:管理员导出审计日志 CSV,最多 5000 行 - `GET /api/admin/videos?page=1&pageSize=30&q=teacher`:管理员全局检索所有用户任务 - `GET /api/admin/videos/export`:管理员导出全局任务 CSV,最多 5000 行 - `GET /api/admin/storage`:管理员查看存储目录、产物体积和任务状态分布 - `POST /api/admin/storage/cleanup`:管理员按任务状态和保留天数预演或执行产物清理 - `POST /api/admin/scheduler/pause`:管理员暂停任务队列接收新执行 - `POST /api/admin/scheduler/resume`:管理员恢复任务队列并重新入队未完成任务 - `GET /api/admin/logs/tail?lines=200`:管理员查看系统日志尾部 - `GET /api/admin/logs/download`:管理员下载当前系统日志文件 - `GET /api/admin/videos/{taskNo}`:管理员查看任意用户任务详情 - `GET /api/admin/videos/{taskNo}/events`:管理员查看任意用户任务事件 - `GET /api/admin/videos/{taskNo}/stream`:管理员预览任意用户 MP4 - `GET /api/admin/videos/{taskNo}/download`:管理员下载任意用户 MP4 - `GET /api/admin/videos/{taskNo}/subtitles`:管理员下载任意用户字幕 - `GET /api/admin/videos/{taskNo}/assets`:管理员下载任意用户素材包 - `POST /api/admin/videos/{taskNo}/cancel`:管理员取消任意用户任务 - `POST /api/admin/videos/{taskNo}/retry`:管理员重试任意用户终态任务 - `POST /api/admin/videos/{taskNo}/mark-failed`:管理员将卡住任务强制标记失败 - `DELETE /api/admin/videos/{taskNo}`:管理员删除任意用户终态任务记录 - `POST /api/videos/generate`:创建生成任务,支持 `Idempotency-Key`,受每日额度和活跃任务上限控制 - `POST /api/videos/batch-generate`:批量创建生成任务,数量上限由 `task.max_batch_size` 配置控制,支持 `Idempotency-Key` - `GET /api/videos?page=1&pageSize=30&q=关键词&subject=math&status=COMPLETED`:分页检索历史记录 - `GET /api/videos/quota`:当前用户今日额度、活跃任务和剩余额度 - `GET /api/videos/{taskNo}`:查询任务状态 - `GET /api/videos/{taskNo}/events`:查询任务审计事件 - `GET /api/videos/{taskNo}/stream`:预览 MP4 - `GET /api/videos/{taskNo}/download`:下载 MP4 - `GET /api/videos/{taskNo}/subtitles`:下载 SRT 字幕 - `GET /api/videos/{taskNo}/assets`:下载二次剪辑素材包 ZIP - `POST /api/videos/{taskNo}/cancel`:取消排队或运行中任务 - `POST /api/videos/{taskNo}/retry`:重新生成 - `DELETE /api/videos/{taskNo}`:删除历史记录 - `GET /api/system/diagnostics`:检查 FFmpeg、Ollama、TTS、存储目录和任务调度器状态 ## 当前实现边界 - 鉴权使用 Python 本地 HMAC token,但请求头仍使用 `satoken` 这个兼容名称,前端无需改接口;管理接口使用 `admin` 角色保护。 - Web 和小程序登录页均展示默认账号密码,并支持注册普通教师账号;默认管理员账号默认是 `teacher / boardshadow123`,生产部署可用 `BOARDSHADOW_DEFAULT_ADMIN_*` 覆盖。 - 管理员可以在 Web 管理面板创建教师/管理员、启停账号、修改角色和重置密码;后端会阻止删除最后一个启用管理员权限。 - 登录用户可在 Web 顶部自助修改密码,密码修改会进入审计日志。 - Web 生成区会展示当前用户今日任务额度和活跃任务上限,生成后自动刷新。 - Web 模板管理支持新增、编辑和删除当前选中模板;系统模板有独立标识,普通教师不能改写内置模板或其他用户模板。 - 管理员操作会写入 `boardshadow_audit_log`,用于追踪配置修改、用户创建、角色调整和密码重置。 - Web 管理面板包含运行运维区,可查看全局任务、存储用量,暂停/恢复调度器,并对失败/取消/完成任务产物做清理预演或执行。 - Web 管理面板支持导出全局任务 CSV、导出审计 CSV、查看系统日志尾部和下载当前日志文件。 - 管理员可在全局任务列表接管任务,执行查看、预览、下载、查看事件、取消、重试、强制失败和删除,所有写操作进入审计日志。 - 运行配置保存在 MySQL 的 `boardshadow_app_config`,Web 管理面板可修改模型、Ollama、TTS、FFmpeg、批量任务上限、每日任务额度和活跃任务上限,生成任务会读取最新配置。 - 建表脚本和启动自检会维护 `boardshadow_schema_migration`、`boardshadow_app_config`、`boardshadow_idempotency_key`、`boardshadow_audit_log` 等生产运行表,并记录模板归属、系统模板标记和软删除状态。 - HyperFrames 以 `backend/app/engine.py` 内的 Pillow 渲染器实现,已按学科绘制不同板书符号和排版。 - 自定义模板的 `promptScaffold` 会进入本地 Ollama 提示词;Ollama 不可用时也会作为兜底脚本的板书骨架。 - 支持横版 `16:9` 与竖版 `9:16`,竖版用于短视频平台。 - TTS 已切换为开源接口;每个任务默认使用 xiaozhi,也可选择 OmniVoice。xiaozhi 使用 `XIAOZHI_TTS_CMD` / xiaozhi provider;OmniVoice 需要先录入并选择声音;未配置时生成同步静音 WAV。 - 视频默认面向小学课堂优化:板书逐行出现、节奏偏舒缓、无横线遮挡、无重点标记,脚本按课堂目标、一起观察、老师讲解、跟我练习、课堂小结组织,并可按小学低/中/高年级与教学方式调整。 - 每次生成会输出 `boardshadow.mp4`、`cover.png`、`subtitles.srt`、`script.json` 和 `manifest.json`,并可导出包含帧图与音频片段的 `boardshadow_assets.zip`,方便二次剪辑。 - 视频任务异步执行,Web 和小程序通过轮询状态更新预览;任务支持排队取消、运行中取消标记、失败/完成/取消后重试与删除。 - Web 支持批量模式,按空行分隔多个题目或知识点后批量创建任务。 - Web 历史记录支持服务端分页、关键词、学科和状态筛选。 - Web 支持新增自定义模板,保存后可直接用于当前学科生成;模板创建、更新和删除会写入审计日志。 - 后端使用进程级任务调度器执行生成任务,支持并发控制、服务启动后恢复未完成任务、任务事件审计和滚动日志文件。 ## 生产化运行参数 ```bash export BOARDSHADOW_TASK_WORKERS=2 export BOARDSHADOW_RECOVER_TASKS=1 export BOARDSHADOW_LOG_DIR=/boardshadow/storage/logs ``` 日志文件: ```text storage/logs/boardshadow.log ```