好的,这是基于你提供的代码生成的详细 `README.md` 文档。 # 数字人生成服务 本项目提供一个后端服务,用于根据文本和样本媒体(视频、音频)生成数字人。它利用后台线程处理视频和音频处理等资源密集型操作,以实现异步任务处理。 ----- ## 系统架构 该服务基于 **Flask** Web 框架,并遵循 **RESTful API** 设计。主要组件包括: - **API 端点**: 用于文件上传、数字人生成、音频提取和任务状态查询的路由。 - **异步任务处理**: 像视频处理 (`api_extract_audio`) 和数字人生成 (`api_generate_digital_human`) 这样的繁重任务使用 **Python 的 `threading` 模块**在后台非阻塞地处理。这可以防止主 Flask 应用被阻塞,确保 API 保持响应。 - **任务管理**: 一个全局字典 (`TASKS`) 用于存储每个异步任务的状态、进度和结果,并通过一个唯一的 `task_id` 进行访问。 - **文件管理**: 服务使用 `FileManager` 类处理文件上传和存储,将文件组织到 `video` 和 `audio` 子目录中。 - **错误处理**: 自定义的 `APIException`、`404 Not Found` 和 `500 Internal Server Error` 错误处理器提供了统一且信息丰富的响应。 整体流程如下: 1. 客户端向生成端点(例如,`/api/digital_human/generate`)发送请求。 2. 服务器验证请求并创建一个带有唯一 `task_id` 的新任务。 3. 服务器生成一个新的后台线程来执行生成逻辑。 4. 服务器立即返回一个 `submitted` 状态和 `task_id` 给客户端。 5. 客户端随后可以轮询 `/api/task/status/` 端点,以检查进度并在任务完成时获取最终结果。 ----- ## 运行环境 要运行此服务,你需要设置一个包含所需库的 Python 环境。 ### 运行要求 - **Python 3.6+**: 代码使用了 f-string 和类型提示,这些都是现代 Python 的标准特性。 - **`moviepy`**: 用于视频和音频处理,特别是从视频文件中提取音频。 - **`Flask`**: 核心 Web 框架。 - **`Flask-CORS`**: 处理跨域资源共享,允许来自不同域的请求。 ### 安装 1. 克隆此仓库(或将提供的代码保存为 `app.py`)。 2. 使用 `pip` 安装所需的 Python 包: ```bash pip install Flask Flask-Cors moviepy ``` 3. 确保你的系统已安装 `moviepy` 的必要依赖项,例如 **FFmpeg**。`moviepy` 通常会自动处理,但在某些系统上你可能需要手动安装。 ----- ## 部署方法 ### 本地开发 1. 确保你已安装所有先决条件。 2. 直接从命令行运行应用程序: ```bash python app.py ``` 3. 服务将在 `http://0.0.0.0:5001` 上可用。 ### Docker 部署(推荐) 为了确保一个一致且隔离的环境,强烈推荐使用 Docker 进行部署。 1. **创建 `Dockerfile`**: ```dockerfile # 使用官方 Python 运行时作为父镜像 FROM python:3.9-slim # 设置容器中的工作目录 WORKDIR /app # 将当前目录内容复制到容器的 /app 目录中 COPY . . # 安装 requirements.txt 中指定的所需包 RUN pip install --no-cache-dir Flask Flask-Cors moviepy # 暴露应用程序运行的端口 EXPOSE 5001 # 定义环境变量 ENV FLASK_APP=app.py # 运行应用程序 CMD ["flask", "run", "--host=0.0.0.0", "--port=5001"] ``` 2. **创建 `requirements.txt` 文件**: ```txt Flask Flask-Cors moviepy ``` 这有助于 Docker 更有效地构建镜像。 3. **构建并运行 Docker 容器**: ```bash docker build -t digital-human-service . docker run -p 5001:5001 digital-human-service ``` `-p 5001:5001` 标志将主机上的 5001 端口映射到容器中的 5001 端口。 ----- ## API 文档 所有 API 端点都以 `/api` 为前缀。 ### 1\. 生成数字人 - **端点**: `POST /api/digital_human/generate` - **描述**: 启动一个后台任务,根据提供的文本、视频和音频生成数字人视频。 - **请求体**: ```json { "speech_text": "Hello, this is a test.", "sample_video": "my-video-file.mp4", "sample_voice": "my-voice-file.wav" } ``` - **成功响应**: ```json { "status": "submitted", "task_id": "a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890", "query_url": "/api/task/status/a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890" } ``` ### 2\. 从视频中提取音频 - **端点**: `POST /api/video/extract_audio` - **描述**: 启动一个后台任务,从视频文件中提取音轨。 - **请求体**: ```json { "video_path": "/path/to/my-video.mp4" } ``` - **成功响应**: ```json { "status": "submitted", "task_id": "f6e5d4c3-b2a1-0987-6543-210fedcba987", "query_url": "/api/task/status/f6e5d4c3-b2a1-0987-6543-210fedcba987" } ``` ### 3\. 查询任务状态 - **端点**: `GET /api/task/status/` - **描述**: 获取正在运行任务的当前状态。 - **成功响应(待处理/运行中)**: ```json { "status": "running", "progress": 50, "type": "digital_human", "params": { ... }, "result": null } ``` - **成功响应(已完成)**: ```json { "status": "completed", "progress": 100, "type": "digital_human", "params": { ... }, "result": { "uuid": "my-video-uuid", "download_url": "/download/generated/video/my-video-uuid?task_id=200" } } ``` ### 4\. 文件上传 - **端点**: `POST /api/upload/video` - **描述**: 上传视频文件。 - **表单数据**: `file`(视频文件)、`custom_name`(可选)。 - **端点**: `POST /api/upload/audio` - **描述**: 上传音频文件。 - **表单数据**: `file`(音频文件)、`custom_name`(可选)。 - **成功响应**: ```json { "success": true, "message": "视频上传成功", "file_info": { ... } } ``` ### 5\. 下载生成的视频 - **端点**: `GET /download/generated/video/` - **描述**: 提供之前生成的视频文件下载。 - **参数**: - `uuid`: 视频文件的唯一 ID。 - `task_id`(可选): 生成该视频的任务 ID。 ### 6\. 文件列表与查找 - **端点**: `GET /api/files/list` - **描述**: 列出指定目录中可用的文件。 - **查询参数**: - `directory`: 目录路径。 - `file_type`: `video`、`audio` 或 `all`(默认)。 - **端点**: `GET /api/files/find/` - **描述**: 按 UUID 查找生成的文件。