# fay-player **Repository Path**: xszyou/fay-player ## Basic Information - **Project Name**: fay-player - **Description**: 这是一个支持本地与网络课程包的在线播放器,可以与 Fay 数字人服务联动,实现 AI 驱动的互动式课程体验。AI时代视频是给ai看的,内容比效果重要! 播放器可选连接 Fay,实现数字人驱动、问答及导出视频;不连接 Fay 也可本地播放(降级模式)。 - **Primary Language**: JavaScript - **License**: GPL-3.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2026-03-04 - **Last Updated**: 2026-03-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Fay数字人视频播放器 在线地址:https://player.fay-agent.com/ ![播放界面](course.png) ![制作界面](editui.png) ## 1. 项目介绍 这是一个支持本地与网络课程包的在线播放器,可以与 Fay 数字人服务联动,实现 AI 驱动的互动式课程体验。AI时代视频是给ai看的,内容比效果重要! 播放器可选连接 Fay,实现数字人驱动、语音与问答、导出视频;不连接 Fay 也可本地播放(降级模式)。 ## 2. 核心能力 - 无独立课程服务端,前端可直接加载课程包。 - 支持本地 Zip 导入、HTTP 链接导入、API 导入课程包。 - 支持自由添加/删除课程。 - 支持课程制作模式(本地编辑、导出课程包)。 - 支持视频导出(按播放效果合成)。 - 支持本地持久化: - 播放进度 - 题目回答 - 聊天记录 - 以上全部存入 `IndexedDB`。 - 支持 MCP 控制播放(Python MCP 服务已提供)。 ## 3. 运行前准备 - Node.js 18+(Windows 建议 LTS)。 - 首次运行先安装依赖: ```powershell npm install ``` ## 4. 启动方式 ### 4.1 浏览器模式(推荐) ```powershell npm run dev ``` 打开 `http://localhost:5173`。 ### 4.2 Electron 开发模式 ```powershell npm run dev:electron ``` ### 4.3 Electron 构建后运行 ```powershell npm run build:electron ``` ### 4.4 Windows 依赖安装常见问题 如 `npm install` 卡住或报错(如 `3221225786`): ```powershell Remove-Item -Recurse -Force .\node_modules, .\package-lock.json -ErrorAction SilentlyContinue npm cache clean --force npm install ``` 网络不稳定可临时设置 Electron 镜像: ```powershell $env:ELECTRON_MIRROR = "https://npmmirror.com/mirrors/electron/" npm install ``` 单独重装 Electron: ```powershell npm rebuild electron ``` ### 4.5 URL 参数 打开播放器时可通过 URL 参数控制加载行为。 #### `?course=` 指定启动后默认显示哪门课(按 `manifest.json` 中的 `id` 字段匹配)。 ``` http://localhost:5173/?course=python-basics ``` - 切换课程时 URL 自动更新,可直接复制分享。 - 若 `course_id` 在本地库中不存在,回退到第一门课。 #### `?load=` 启动时从指定 URL 拉取课程 ZIP 并自动导入、选中。 ``` http://localhost:5173/?load=https://example.com/my-course.zip ``` - 支持 HTTP/HTTPS,需服务端允许 CORS。 - 本次加载**不写入 localStorage**,刷新时重新拉取。 - 拉取失败时静默忽略,继续显示本地已有课程。 #### `?embed=` 以嵌入模式启动播放器,隐藏顶部控制栏、侧边栏、聊天面板等 UI 外壳,仅显示核心播放区域。适用于嵌入 iframe 场景。 ``` http://localhost:5173/?embed=1 ``` 可接受的值:`1`、`true`、`yes`、`on`(不区分大小写)。 #### 参数组合 | URL | 行为 | |-----|------| | `?load=` | 拉取 ZIP,自动选中其中的课程 | | `?load=&course=` | 拉取 ZIP,但显示 `course` 指定的课 | | `?course=` | 从本地库加载指定课程 | | `?embed=1` | 嵌入模式,隐藏 UI 外壳 | | 无参数 | 恢复上次打开的课程 | ## 5. 课程包格式规范(AI 友好) 课程包默认是 Zip,推荐结构: ```text python-basics-demo.zip ├── manifest.json ├── robot/ │ ├── Normal.jpg │ └── Speaking.jpg └── sections/ ├── 01-intro/ │ ├── script.txt │ ├── audio.mp3 │ ├── quiz.json │ └── assets/ │ ├── slide1.png │ └── demo.code.json └── 02-setup/ └── ... ``` `manifest.json` 示例: ```json { "id": "python-basics", "title": "Python 基础入门", "author": "张老师", "cover_icon_url": "sections/01-intro/assets/slide1.png", "avatar_assets": { "normal": "robot/Normal.jpg", "speaking": "robot/Speaking.jpg", "listening": "robot/Listening.gif", "thinking": "robot/Thinking.jpg", "angry": "robot/Angry.gif", "crying": "robot/Crying.gif", "gentle": "robot/Gentle.jpg" }, "sections": [ { "id": "s01", "title": "什么是 Python", "script": "sections/01-intro/script.txt", "audio": "sections/01-intro/audio.mp3", "assets": [ { "type": "slide", "src": "sections/01-intro/assets/slide1.png", "display_at": 0 }, { "type": "code", "src": "sections/01-intro/assets/demo.code.json", "display_at": 8 } ], "quiz": "sections/01-intro/quiz.json" } ] } ``` 说明: - `quiz.json` 推荐字段:`q`、`opts`、`ans`、`tip`,可选 `topic`。 - 章节允许没有题目。 - 代码资源字段也可写文案、步骤、伪代码等文本内容。 - 头像资源优先使用课程包内 `avatar_assets` 或 `robot/` 目录。 - 支持的头像状态(`avatar_assets` 键名):`normal`(待命)、`speaking`(讲解)、`listening`(聆听)、`thinking`(思考)、`angry`(生气)、`crying`(伤心)、`gentle`(温和)。课程包中可只提供部分状态,其余回退到播放器内置默认图。 - 课程制作模式目前支持上传 `normal` / `speaking` / `thinking` 三种头像;其余状态头像需在课程包内手动放置。 ## 6. Fay 对接说明 ### 6.1 透传接口(驱动讲解/语音) - 地址:`http://127.0.0.1:5000/transparent-pass` - 方法:`POST` - 参数: - `user`:可选,透传用户名 - `text`:必填,透传文本 - `audio`:可选,透传音频 URL(存在时可不做 text TTS) 请求示例: ```json { "user": "User", "text": "你好,请说?", "audio": "https://xxx.com/aaaa.wav" } ``` ### 6.2 数字人 WebSocket 接口 - 地址:`ws://127.0.0.1:10002` - Fay 作为服务端,播放器作为客户端。 播放器对接要点: - 接收 `Topic=human`、`Data.Key=audio` 的消息,使用 `HttpValue` 播放音频。 - 按 `CONV_MSG_NO` 做顺序播放,避免高频推送乱序。 - 可通过 `{"Output": false}` / `{"Output": true}` 切换数字人播放模式。 - UI 中“使用数字人播放”按钮会主动向 10002 推送 Output 开关。 ### 6.3 问答接口(Fay LLM) 兼容 GPT 地址: - `http://127.0.0.1:5000/api/send/v1/chat/completions` - `http://127.0.0.1:5000/v1/chat/completions` 推荐使用 `fay-streaming` 流式。 请求体示例: ```json { "model": "llm", "messages": [ { "role": "system", "content": "参考课程助教提示词设计文档" }, { "role": "User", "content": "用户问题" } ], "no_reply": false } ``` > 播放器默认模型为 `"llm"`;如需流式输出可改为 `"fay-streaming"`。 问答提示词设计参考:课程助教提示词设计文档。 ### 6.4 连接 Fay 与本地模式差异 - 连接 Fay 时: - 字幕使用 Fay 回传音频对应文本; - 不使用本地打字字幕逻辑。 - 未连接 Fay 时: - 仅播放课程包内音频; - 无提问能力; - 无 Fay 驱动数字人能力。 ## 7. 本地持久化(必须) 以下内容全部通过 `localStorage` 保存与恢复: - 播放进度:`fay.course.progress.v1` - 答题记录:`fay.quiz.results.v1` - 聊天记录:`fay.chat.messages.v1` - 问答历史:`fay.qa.history.v1` ## 8. 本地 API 与播放器网关 播放器内部暴露统一调用入口: ```js window.__fay_course_player_api.request(method, path, body) ``` 返回格式: ```json { "ok": true, "message": "...", "data": {}, "statusCode": 200 } ``` 常用接口能力: - 课程管理:导入、删除、列表、加载。 - 播放控制:播放、暂停、续播、跳章、定位。 - 状态读取:播放状态、章节进度、课程信息。 ## 9. MCP(Python)服务 项目提供两个独立的 MCP 服务,详细文档见 [`mcp_server/README.md`](mcp_server/README.md)。 | 服务 | 脚本 | 场景 | 依赖 | | --- | --- | --- | --- | | 播放器控制 | `fay_digital_human_video_player_mcp_server.py` | 远程控制播放器(播放、暂停、跳转等) | 需要播放器在线 | | 知识库检索 | `fay_player_knowledge_base_mcp_server.py` | 离线课程知识检索,适合接入 Fay 或第三方 agent | 不依赖播放器 | ### 9.1 播放器控制 MCP 通过本地桥接(默认 `http://127.0.0.1:18765`)调用播放器 API。 ```powershell python mcp_server/fay_digital_human_video_player_mcp_server.py ``` 常用工具:`playback_status`、`playback_play`、`playback_pause`、`playback_resume`、`playback_next_section`、`playback_prev_section`、`playback_goto_section`、`playback_seek_ratio`、`course_list`、`course_import_url`、`course_knowledge`、`course_remove_at`、`player_api_request`。 ### 9.2 知识库检索 MCP 直接读取本地 markdown / 课程 ZIP,内建轻量词法检索,按章节返回完整内容。 ```powershell python mcp_server/fay_player_knowledge_base_mcp_server.py --source ./fay-player-guide.zip ``` 常用工具:`kb_add_source`、`kb_list_sources`、`kb_get_catalog`、`kb_search`、`kb_get_section`、`kb_read_document`、`kb_reload`、`kb_remove_source`。 ## 10. 验收清单 1. 能本地导入并播放课程包。 2. 能通过 URL 导入课程包。 3. 能保存并恢复播放进度、答题记录、聊天记录。 4. 能连接 Fay 完成透传播放与问答。 5. 无本地音频章节在连接 Fay 时可通过回传音频播放。 6. MCP 工具可控制播放与跳转。 7. 课程制作模式可导出课程包并再次导入播放。 ## 11. 视频导出(ffmpeg.wasm) 播放器已将视频导出改为 `ffmpeg.wasm` 纯前端编码,不再依赖浏览器 `MediaRecorder`。 - 首次导出会加载 `ffmpeg-core.wasm`,初始化时间会明显更长。 - 导出格式固定为 `webm`(VP9 + Opus 编码)。 - 导出范围可选:**全部章节**或**当前章节**。 - 分辨率可选:`720p` 或 `1080p`。 - 帧率可选:12–60 fps(推荐 30 fps)。 - 导出音频策略: - `fay_first`(默认):优先收集 Fay 回传音频,超时/失败自动回退本地音频; - `local_only`:只使用课程包本地音频。 - 无可用音频时会自动导出静音段,不中断整次导出。 ### Fay 音频收集超时策略 - 首包超时:12 秒 - 尾包静默窗口:3 秒(收到 `IsEnd=1` 后等待静默封段) - 总超时:30 秒 任一超时会触发本地音频回退,不会直接中断导出。 ## 12. 本地存储升级(IndexedDB) 从当前版本开始,课程包存储策略已升级: - 课程包二进制:存入 `IndexedDB`(数据库 `fay.course.store.v1`,表 `packages`) - `localStorage`:仅保留轻量课程索引元数据(`type: "idb"` + `blob_key`) ### 12.1 自动迁移 启动时会自动扫描旧的 `type: "base64"` 课程记录并迁移到 `IndexedDB`: - 迁移成功:课程索引会改写为 `type: "idb"`,不再保留 `base64` 大字段 - 迁移失败:保留旧记录并继续启动,不阻塞主流程 ### 12.2 空间不足处理 当保存课程包遇到浏览器配额不足时,播放器会: 1. 给出已用空间/配额/建议清理量 2. 先弹窗征求确认 3. 用户确认后,按“同课程只保留最高版本 + 删除最旧包”策略清理 4. 自动重试保存一次 如果用户取消清理,当前保存会被取消,不会自动删除数据。 ### 12.3 IndexedDB 不可用时的降级模式 若浏览器不支持 IndexedDB(如某些隐私模式或受限环境),播放器会: - 仍然正常加载和播放课程包; - 给出提示:"当前环境不支持 IndexedDB,本次仅临时加载,刷新后不会保留"; - 不阻塞主流程,本次会话内可正常使用。 ## 13. Knowledge Base MCP 除现有的播放器控制 MCP 外,项目还提供了一个独立的离线知识库 MCP 服务。它特别适合作为 [Fay](https://gitee.com/xszyou/fay) 的外部 MCP 知识库被引入,让 Fay 在对话前先检索课程内容,再把结果注入上下文。 - 服务名称:`fay_player_knowledge_base_mcp_server` - 脚本路径:`mcp_server/fay_player_knowledge_base_mcp_server.py` - 支持输入:本地 markdown、导出的 markdown ZIP、原生课程 ZIP、目录批量加载 - 搜索方式:`kb_search` 可直接接收用户原句,内部做轻量词法检索,并按章节返回完整内容 ### 如何被 Fay 引入 根据 Fay 仓库自带的 MCP 知识库配置文档,推荐按“外部 `stdio` MCP 服务”方式接入: 1. 启动 Fay 后,打开 MCP 管理页:`http://127.0.0.1:5010/Page3` 2. 新增一个 MCP 服务,传输方式选择 `stdio` 3. 启动命令填 `python` 4. 启动参数填: ```text mcp_server/fay_player_knowledge_base_mcp_server.py --source ./fay-player-guide.zip ``` 5. 保存并连接服务 6. 在工具列表里给 `kb_search` 配置 Prestart 参数,让 Fay 在每轮对话前自动检索课程知识: ```json { "query": "{{question}}", "limit": 3, "include_quizzes": true } ``` 这样 Fay 的调用链就会变成: ```text 用户提问 -> Fay 预启动 kb_search -> 命中章节注入上下文 -> LLM 生成答案 ``` 这种方式的好处是: - 不需要先让 LLM 提炼关键词 - 只需 1 次主 LLM 请求 - 非常适合“一页 PPT = 一章”的短章节课程结构 启动示例: ```powershell python mcp_server/fay_player_knowledge_base_mcp_server.py --source ./fay-player-guide.zip ``` 或使用 npm 脚本: ```powershell npm run mcp:kb:python ``` 详细工具说明、返回结构和配置示例见:[`mcp_server/README.md`](mcp_server/README.md) ## 联系方式 ![微信联系方式](wechat.png)