GPT-SoVITS-WebUI
A Powerful Few-shot Voice Conversion and Text-to-Speech WebUI.
@@ -31,17 +31,37 @@ A Powerful Few-shot Voice Conversion and Text-to-Speech WebUI.
本工作区新增了一个用于 MVP 调用的中间层接口和测试前端:
+| 页面 | 地址 | 说明 |
+|------|------|------|
+| 测试前端 | http://127.0.0.1:9881/test/ | 带波形裁剪、视频转音频的测试 UI |
+| Swagger UI | http://127.0.0.1:9881/docs | 交互式 API 文档 |
+| ReDoc | http://127.0.0.1:9881/redoc | 可读式 API 文档 |
+
+文档:
+
- 快速启动:[docs/simple_api_quickstart.md](./docs/simple_api_quickstart.md)
- 完整教程:[docs/simple_api.md](./docs/simple_api.md)
-- 后端入口:simple_api.py
-- 测试前端:启动后访问 http://127.0.0.1:9881/test/
+
+核心功能:
+
+- `/api/tts` — 上传参考音频/视频 + 文字,直接返回生成的音频
+- 前端支持视频上传,自动提取音频
+- 前端波形裁剪工具,可选择 3-10 秒片段
+- 5 种情绪预设(neutral/happy/calm/sad/angry)
+- 7 个契约测试,无需 GPU 即可运行
启动命令:
-`powershell
+```
cd D:\tts\GPT-SoVITS
.\go-simple-api.ps1
-`
+```
+
+运行测试:
+
+```
+python -m unittest tests.test_simple_api_contract -v
+```
---
diff --git a/docs/simple_api.md b/docs/simple_api.md
index bcdedaf6..f9e5cc09 100644
--- a/docs/simple_api.md
+++ b/docs/simple_api.md
@@ -1,116 +1,128 @@
-# GPT-SoVITS 简化接口教程
+# GPT-SoVITS 简化接口文档
-本项目原本已经有 `api_v2.py`,但调用时需要传很多 GPT-SoVITS 参数。新增的 `simple_api.py` 是一个中间层,目标是让前端或业务方用更简单的方式调用。
+本项目新增 `simple_api.py` 作为中间层,封装 GPT-SoVITS 推理引擎,提供更简洁的调用方式。
-当前 MVP 推荐使用:
+## 快速开始
-```http
-POST /api/tts
+```bash
+# 安装依赖
+python -m pip install -r requirements.txt
+
+# 启动
+python simple_api.py -c simple_api.yaml
+
+# 访问
+Swagger UI: http://127.0.0.1:9881/docs
+ReDoc: http://127.0.0.1:9881/redoc
+测试前端: http://127.0.0.1:9881/test/
+```
+
+## 接口总览
+
+| 方法 | 路径 | 说明 | 标签 |
+|------|------|------|------|
+| GET | `/health` | 健康检查(含 GPU 信息) | System |
+| GET | `/voices` | 列出 voice profiles | System |
+| **POST** | **`/api/tts`** | **核心 TTS 接口(MVP)** | **MVP** |
+| GET | `/speak` | voice profile TTS (GET) | Profile |
+| POST | `/speak` | voice profile TTS (POST) | Profile |
+| POST | `/v1/tts` | OpenAI 兼容格式 TTS | Profile |
+| POST | `/speak/base64` | 返回 Base64 音频 | Profile |
+| POST | `/admin/reload-config` | 热加载配置 | Admin |
+| POST | `/admin/weights` | 切换模型权重 | Admin |
+
+---
+
+## 1. POST /api/tts — 核心 TTS 接口
+
+**推荐使用此接口**。上传参考音频和文字,直接返回生成的音频。
+
+### 请求格式
+
+```
Content-Type: multipart/form-data
```
-适合你的流程:
+### 字段说明
-1. 前端从视频中提取音频(或直接上传已裁剪的 3-10 秒音频)。
-2. 用户人工裁剪主参考音频到 3-10 秒。
-3. 前端把主参考音频、要生成的文字、可选辅助音频提交给后端。
-4. 后端调用 GPT-SoVITS 生成音频并返回。
+| 字段 | 类型 | 必填 | 默认值 | 说明 |
+|------|------|------|--------|------|
+| `text` | string | **是** | — | 需要生成的文字 |
+| `ref_audio` | file | **是** | — | 主参考音频,3-10 秒(支持 wav/flac/ogg/mp3/m4a/aac) |
+| `aux_ref_audio` | file[] | 否 | — | 辅助参考音频,可上传多个 |
+| `prompt_text` | string | 否 | `""` | 主参考音频对应文字(v2 可留空;v3/v4 必填) |
+| `text_lang` | string | 否 | `zh` | 生成文字语言:zh/en/ja/ko/yue/auto |
+| `prompt_lang` | string | 否 | `zh` | 参考音频语言:zh/en/ja/ko/yue/auto |
+| `format` | string | 否 | `wav` | 返回格式:wav/ogg/aac/raw |
+| `emotion` | string | 否 | `neutral` | 情绪预设:neutral/happy/calm/sad/angry |
+| `speed` | float | 否 | — | 语速(0.5-2.0),覆盖情绪预设中的语速 |
+| `seed` | int | 否 | `-1` | 随机种子,-1 为随机 |
-## 1. 安装依赖
+### 情绪预设参数映射
-在 GPT-SoVITS 使用的 Python 环境里运行:
+| 情绪 | temperature | top_p | top_k | speed_factor | repetition_penalty |
+|------|-------------|-------|-------|--------------|-------------------|
+| neutral | — | — | — | — | — |
+| happy | 1.1 | 0.95 | — | — | — |
+| calm | 0.8 | 0.85 | — | 0.92 | — |
+| sad | 0.75 | 0.85 | — | 0.9 | — |
+| angry | 1.2 | — | 20 | — | 1.25 |
+
+> 显式传入 `speed` 会覆盖情绪预设中的 `speed_factor`。
+
+### curl 示例
+
+**基础调用:**
+
+```powershell
+curl.exe -X POST http://127.0.0.1:9881/api/tts `
+ -F "text=你好,欢迎使用这个声音。" `
+ -F "ref_audio=@D:\audio\ref.wav" `
+ --output output.wav
+```
+
+**带辅助参考音频和情绪:**
+
+```powershell
+curl.exe -X POST http://127.0.0.1:9881/api/tts `
+ -F "text=你好,欢迎使用这个声音。" `
+ -F "ref_audio=@D:\audio\ref.wav" `
+ -F "aux_ref_audio=@D:\audio\aux1.wav" `
+ -F "emotion=happy" `
+ -F "speed=1.1" `
+ --output output.wav
+```
+
+**Linux/macOS:**
```bash
-python -m pip install -r requirements.txt
+curl -X POST http://127.0.0.1:9881/api/tts \
+ -F "text=你好,欢迎使用这个声音。" \
+ -F "ref_audio=@/path/to/ref.wav" \
+ -F "emotion=calm" \
+ --output output.wav
```
-本中间层额外需要:
+### 返回
-- `python-multipart`:用于接收前端上传的音频文件。
-- `soundfile`:用于读取音频信息和校验参考音频时长。
+- 成功:音频二进制流(Content-Type: `audio/wav` 等)
+- 失败:JSON 错误信息
-这两个依赖已经写入 `requirements.txt`。
-
-## 2. 检查配置
-
-配置文件:
-
-```text
-simple_api.yaml
+```json
+{"message": "tts failed", "exception": "..."}
```
-常用配置:
+### 常见错误
-```yaml
-server:
- host: 127.0.0.1
- port: 9881
- tts_config: GPT_SoVITS/configs/tts_infer.yaml
+| HTTP 状态码 | 原因 |
+|------------|------|
+| 400 | text 为空 / ref_audio 缺失 / 音频时长不在 3-10 秒 / 不支持的 format / v3/v4 时 prompt_text 为空 |
+| 404 | voice profile 不存在(仅 /speak 接口) |
+| 503 | TTS pipeline 未就绪(模型未加载) |
-upload:
- dir: runtime/uploads
- min_ref_seconds: 3
- max_ref_seconds: 10
- max_upload_mb: 80
-```
+---
-说明:
-
-- `server.host`:后端监听地址。
-- `server.port`:后端端口。
-- `server.tts_config`:GPT-SoVITS 推理配置文件。
-- `upload.dir`:临时上传目录。
-- `upload.min_ref_seconds`:主参考音频最短秒数。
-- `upload.max_ref_seconds`:主参考音频最长秒数。
-- `upload.max_upload_mb`:单个上传音频最大体积。
-
-当前默认后端地址:
-
-```text
-http://127.0.0.1:9881
-```
-
-## 3. 启动后端
-
-进入项目目录:
-
-```powershell
-cd D:\tts\GPT-SoVITS
-```
-
-方式一:
-
-```powershell
-python simple_api.py -c simple_api.yaml
-```
-
-方式二,Windows PowerShell:
-
-```powershell
-.\go-simple-api.ps1
-```
-
-方式三,Windows 批处理:
-
-```bat
-go-simple-api.bat
-```
-
-启动成功后,后端会监听:
-
-```text
-http://127.0.0.1:9881
-```
-
-## 4. 健康检查
-
-后端启动后,可以访问:
-
-```text
-http://127.0.0.1:9881/health
-```
-
-或者命令行测试:
+## 2. GET /health — 健康检查
```bash
curl http://127.0.0.1:9881/health
@@ -123,198 +135,268 @@ curl http://127.0.0.1:9881/health
"status": "ok",
"tts_config": "GPT_SoVITS/configs/tts_infer.yaml",
"version": "v2",
- "languages": ["auto", "auto_yue", "en", "zh"]
+ "languages": ["auto", "en", "zh"],
+ "pid": 12345,
+ "memory_mb": 2048.5,
+ "gpu": {
+ "name": "NVIDIA GeForce RTX 3080",
+ "memory_used_mb": 4096.2,
+ "memory_total_mb": 10240.0
+ }
}
```
-## 5. 打开测试前端
+---
-后端启动后,推荐直接打开:
-
-```text
-http://127.0.0.1:9881/test/
-```
-
-这个页面已经挂载在后端服务里,不需要额外启动前端服务。
-
-也可以直接打开本地文件:
-
-```text
-test_frontend/index.html
-```
-
-Windows 下也可以运行:
-
-```powershell
-.\open-test-frontend.ps1
-```
-
-测试前端里有一个“后端接口地址”输入框。
-
-默认值:
-
-```text
-http://127.0.0.1:9881/api/tts
-```
-
-如果你修改了 `server.host` 或 `server.port`,记得同步修改页面里的接口地址。
-
-## 6. MVP 接口
-
-接口地址:
-
-```http
-POST /api/tts
-```
-
-请求类型:
-
-```http
-multipart/form-data
-```
-
-字段说明:
-
-```text
-text 必填。需要生成的文字。
-ref_audio 必填。主参考音频(支持上传视频,前端会自动提取音频),要求 3-10 秒。
-aux_ref_audio 可选。辅助参考音频,可以上传多个。
-prompt_text 可选。主参考音频对应文字,可以留空。
-text_lang 可选。生成文字语言,默认 zh。
-prompt_lang 可选。参考音频语言,默认 zh。即使 prompt_text 为空,也需要传给 GPT-SoVITS 内部。
-format 可选。返回格式,默认 wav。
-emotion 可选。情绪 preset:neutral、happy、calm、sad、angry。
-speed 可选。语速,对应 GPT-SoVITS 的 speed_factor。
-seed 可选。随机种子,默认 -1。
-```
-
-## 7. curl 调用示例
-
-PowerShell 示例:
-
-```powershell
-curl.exe -X POST http://127.0.0.1:9881/api/tts `
- -F "text=你好,欢迎使用这个声音。" `
- -F "ref_audio=@D:\audio\ref.wav" `
- -F "prompt_text=" `
- -F "text_lang=zh" `
- -F "prompt_lang=zh" `
- -F "emotion=neutral" `
- --output output.wav
-```
-
-如果有辅助参考音频:
-
-```powershell
-curl.exe -X POST http://127.0.0.1:9881/api/tts `
- -F "text=你好,欢迎使用这个声音。" `
- -F "ref_audio=@D:\audio\ref.wav" `
- -F "aux_ref_audio=@D:\audio\aux1.wav" `
- -F "aux_ref_audio=@D:\audio\aux2.wav" `
- -F "prompt_text=" `
- -F "text_lang=zh" `
- -F "prompt_lang=zh" `
- --output output.wav
-```
-
-## 8. 重要规则
-
-- 主参考音频必须是 3-10 秒。
-- `aux_ref_audio` 是可选项。
-- `prompt_text` 可以为空,但当前主要针对 GPT-SoVITS v2。
-- 如果切到 GPT-SoVITS v3/v4,空 `prompt_text` 会被中间层直接返回 400。
-- 生成文字固定使用 `cut5`,也就是按照标点符号切句。
-- `emotion` 目前是轻量 preset,本质是映射到采样和语速参数;更稳定的情绪控制仍然依赖带情绪的参考音频。
-
-## 9. 测试前端使用步骤
-
-1. 启动后端。
-2. 打开 `http://127.0.0.1:9881/test/`。
-3. 检查“后端接口地址”是否为:
-
-```text
-http://127.0.0.1:9881/api/tts
-```
-
-4. 填写“需要生成的文字”。
-5. 上传主参考音频。
-6. 可选上传辅助参考音频。
-7. 可选填写参考音频文字。
-8. 选择语言、情绪、语速。
-9. 点击“生成音频”。
-10. 页面右侧会显示返回结果,可以在线播放和下载。
-
-## 10. 其他接口
-
-除了 MVP 上传接口,还保留了 profile 调用接口:
-
-```http
-GET /voices
-GET /speak?text=hello&voice=default
-POST /speak
-POST /speak/base64
-POST /v1/tts
-POST /admin/reload-config
-POST /admin/weights
-```
-
-这些接口适合后续做固定音色 profile,不是当前 MVP 的主流程。
-
-## 11. Base64 返回示例
+## 3. GET /voices — 列出 voice profiles
```bash
-curl -X POST http://127.0.0.1:9881/speak/base64 ^
- -H "Content-Type: application/json" ^
- -d "{\"text\":\"hello\",\"voice\":\"default\"}"
+curl http://127.0.0.1:9881/voices
```
-返回格式:
+返回示例:
+
+```json
+{
+ "default_voice": "default",
+ "voices": [
+ {
+ "name": "default",
+ "description": "Replace this profile with your reference voice.",
+ "text_lang": "zh",
+ "prompt_lang": "zh",
+ "ref_audio_path": "reference.wav",
+ "ready": true
+ }
+ ]
+}
+```
+
+---
+
+## 4. POST /speak — voice profile TTS
+
+基于 `simple_api.yaml` 中配置的 voice profile 调用 TTS。
+
+### 请求体(JSON)
+
+```json
+{
+ "text": "hello world",
+ "voice": "default",
+ "text_lang": "zh",
+ "format": "wav",
+ "speed": 1.0
+}
+```
+
+| 字段 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `text` | string | **是** | 需要生成的文字 |
+| `voice` | string | 否 | voice profile 名称,不传则使用 default |
+| `text_lang` | string | 否 | 生成文字语言 |
+| `format` | string | 否 | 返回格式 |
+| `stream` | bool | 否 | 是否流式返回 |
+| `speed` | float | 否 | 语速 |
+
+### curl 示例
+
+```bash
+curl -X POST http://127.0.0.1:9881/speak \
+ -H "Content-Type: application/json" \
+ -d '{"text":"你好世界","voice":"default"}' \
+ --output output.wav
+```
+
+---
+
+## 5. GET /speak — voice profile TTS (GET)
+
+与 POST /speak 相同,但通过 URL 参数传递。
+
+```
+GET /speak?text=hello&voice=default&format=wav
+```
+
+---
+
+## 6. POST /speak/base64 — 返回 Base64 音频
+
+返回 Base64 编码的音频,适合 Web 前端直接使用。
+
+```bash
+curl -X POST http://127.0.0.1:9881/speak/base64 \
+ -H "Content-Type: application/json" \
+ -d '{"text":"hello","voice":"default"}'
+```
+
+返回:
```json
{
"media_type": "audio/wav",
- "audio_base64": "..."
+ "audio_base64": "UklGRi..."
}
```
-## 12. 添加固定音色 profile
+---
-如果后续要做固定音色,可以编辑 `simple_api.yaml`:
+## 7. POST /v1/tts — OpenAI 兼容格式
-```yaml
-voices:
- default:
- ref_audio_path: reference.wav
- prompt_text: exact transcript
- prompt_lang: zh
- text_lang: zh
+请求格式与 POST /speak 相同,路径兼容 OpenAI TTS API 风格。
- narrator:
- ref_audio_path: voices/narrator.wav
- prompt_text: exact transcript of narrator.wav
- prompt_lang: zh
- text_lang: zh
-```
+---
-编辑后调用:
+## 8. POST /admin/reload-config — 热加载配置
+
+重新加载 `simple_api.yaml`,无需重启服务。
```bash
curl -X POST http://127.0.0.1:9881/admin/reload-config
```
-## 13. 契约测试
+返回:`{"message": "success", "default_voice": "default"}`
-这个测试使用 mock,不会加载 GPT-SoVITS 模型:
+---
+
+## 9. POST /admin/weights — 切换模型权重
+
+运行时切换 GPT-SoVITS 模型权重文件。
```bash
-python -m unittest tests.test_simple_api_contract
+curl -X POST http://127.0.0.1:9881/admin/weights \
+ -H "Content-Type: application/json" \
+ -d '{"gpt_weights_path":"path/to/gpt.pt","sovits_weights_path":"path/to/sovits.pt"}'
```
-用于确认:
+---
-- `/api/tts` 路由存在。
-- 上传接口能构造正确参数。
-- 主参考音频 3-10 秒校验正常。
-- 空 `prompt_text` 在 v2 可用。
-- v3/v4 空 `prompt_text` 会返回 400。
-- 临时上传目录会被清理。
+## 配置文件
+
+`simple_api.yaml`:
+
+```yaml
+server:
+ host: 127.0.0.1
+ port: 9881
+ tts_config: GPT_SoVITS/configs/tts_infer.yaml
+
+cors_allow_origins:
+ - "*"
+
+upload:
+ dir: runtime/uploads
+ min_ref_seconds: 3
+ max_ref_seconds: 10
+ max_upload_mb: 80
+
+defaults:
+ text_lang: zh
+ prompt_lang: zh
+ media_type: wav
+ text_split_method: cut5
+ batch_size: 1
+ speed_factor: 1.0
+ seed: -1
+
+emotion_presets:
+ neutral: {}
+ happy:
+ temperature: 1.1
+ top_p: 0.95
+ calm:
+ temperature: 0.8
+ top_p: 0.85
+ speed_factor: 0.92
+ sad:
+ temperature: 0.75
+ top_p: 0.85
+ speed_factor: 0.9
+ angry:
+ temperature: 1.2
+ top_k: 20
+ repetition_penalty: 1.25
+
+voices:
+ default:
+ description: Replace this profile with your reference voice.
+ ref_audio_path: reference.wav
+ prompt_text: Replace this with the exact text spoken in reference.wav.
+ prompt_lang: zh
+ text_lang: zh
+```
+
+### 配置说明
+
+| 配置项 | 说明 |
+|--------|------|
+| `server.host` | 监听地址 |
+| `server.port` | 监听端口 |
+| `server.tts_config` | GPT-SoVITS 推理配置文件路径 |
+| `upload.dir` | 临时上传目录 |
+| `upload.min_ref_seconds` | 主参考音频最短秒数 |
+| `upload.max_ref_seconds` | 主参考音频最长秒数 |
+| `upload.max_upload_mb` | 单个上传文件最大体积 (MB) |
+| `defaults.*` | 所有接口的默认参数 |
+| `emotion_presets.*` | 情绪预设参数映射 |
+| `voices.*` | 固定音色 profile |
+
+---
+
+## 添加自定义音色
+
+编辑 `simple_api.yaml`,在 `voices` 下添加:
+
+```yaml
+voices:
+ narrator:
+ description: "男声旁白"
+ ref_audio_path: voices/narrator.wav
+ prompt_text: "旁白参考音频的逐字稿"
+ prompt_lang: zh
+ text_lang: zh
+```
+
+然后热加载:
+
+```bash
+curl -X POST http://127.0.0.1:9881/admin/reload-config
+```
+
+---
+
+## 测试
+
+### 契约测试(无需 GPU)
+
+```bash
+python -m unittest tests.test_simple_api_contract -v
+```
+
+覆盖:
+
+- `/api/tts` 路由注册
+- 上传接口参数构造
+- 主参考音频 3-10 秒校验
+- v2 空 prompt_text 允许 / v3/v4 空 prompt_text 拒绝
+- 临时上传目录清理
+- 情绪预设应用与 speed 覆盖
+
+### 前端测试
+
+1. 启动后端
+2. 访问 `http://127.0.0.1:9881/test/`
+3. 上传音频或视频(视频会自动提取音频)
+4. 使用波形裁剪工具选择 3-10 秒片段
+5. 填写文字,选择情绪和语速
+6. 点击生成
+
+---
+
+## 启动脚本
+
+| 脚本 | 平台 | 说明 |
+|------|------|------|
+| `go-simple-api.ps1` | Windows PowerShell | 自动检测 runtime\python.exe |
+| `go-simple-api.bat` | Windows CMD | 同上 |
+| `open-test-frontend.ps1` | Windows PowerShell | 直接打开测试前端 HTML |
diff --git a/docs/simple_api_quickstart.md b/docs/simple_api_quickstart.md
index 2f07eb65..b3865fa9 100644
--- a/docs/simple_api_quickstart.md
+++ b/docs/simple_api_quickstart.md
@@ -4,7 +4,7 @@
## 一句话流程
-启动后端,打开测试页,上传 3-10 秒参考音频或视频(视频会自动提取音频),填写生成文字,点击生成。
+启动后端,打开测试页,上传 3-10 秒参考音频或视频(视频自动提取音频),填写生成文字,点击生成。
## 1. 启动后端
@@ -26,19 +26,13 @@ go-simple-api.bat
http://127.0.0.1:9881
```
-## 2. 打开测试前端
+## 2. 打开页面
-后端启动后访问:
-
-```text
-http://127.0.0.1:9881/test/
-```
-
-测试页面里的默认接口地址是:
-
-```text
-http://127.0.0.1:9881/api/tts
-```
+| 页面 | 地址 | 说明 |
+|------|------|------|
+| 测试前端 | http://127.0.0.1:9881/test/ | 带波形裁剪的测试 UI |
+| Swagger UI | http://127.0.0.1:9881/docs | 交互式 API 文档 |
+| ReDoc | http://127.0.0.1:9881/redoc | 可读式 API 文档 |
## 3. 调用接口
@@ -53,7 +47,7 @@ Content-Type: multipart/form-data
```text
text 要生成的文字
-ref_audio 3-10 秒主参考音频(支持视频,前端自动提取音频)
+ref_audio 3-10 秒主参考音频(或视频,前端自动提取)
```
常用可选字段:
@@ -83,6 +77,8 @@ curl.exe -X POST http://127.0.0.1:9881/api/tts `
## 5. 注意事项
- 主参考音频必须是 3-10 秒。
+- 前端支持上传视频文件,会自动提取音频。
+- 前端提供波形裁剪工具,可直接选择 3-10 秒片段。
- `prompt_text` 在当前 v2 配置下可以为空。
- 如果切换到 v3/v4,空 `prompt_text` 会返回 400。
- 生成文字固定按标点符号切句。
diff --git a/simple_api.py b/simple_api.py
index 91180548..eb8d635b 100644
--- a/simple_api.py
+++ b/simple_api.py
@@ -151,8 +151,26 @@ infer_lock = threading.Lock()
APP = FastAPI(
title="GPT-SoVITS Simple API",
- description="Profile-based API layer that hides GPT-SoVITS request details.",
- version="1.0.0",
+ description=(
+ "简化接口层,封装 GPT-SoVITS 推理引擎。\n\n"
+ "## 核心流程\n"
+ "1. 上传 3-10 秒参考音频(或视频,前端自动提取音频)\n"
+ "2. 填写需要生成的文字\n"
+ "3. 调用 `/api/tts` 获取生成的音频\n\n"
+ "## 其他接口\n"
+ "- `/speak` — 基于 voice profile 的调用方式\n"
+ "- `/v1/tts` — OpenAI 兼容格式\n"
+ "- `/admin/*` — 管理接口(热加载配置、切换模型)"
+ ),
+ version="1.1.0",
+ docs_url="/docs",
+ redoc_url="/redoc",
+ openapi_tags=[
+ {"name": "MVP", "description": "核心 TTS 接口,上传参考音频直接生成"},
+ {"name": "Profile", "description": "基于 voice profile 的调用方式"},
+ {"name": "Admin", "description": "管理接口:热加载配置、切换模型权重"},
+ {"name": "System", "description": "健康检查与信息查询"},
+ ],
)
APP.add_middleware(
CORSMiddleware,
@@ -584,33 +602,51 @@ def startup() -> None:
tts_pipeline = TTS(tts_config)
-@APP.get("/")
+@APP.get("/", tags=["System"])
def index() -> Dict[str, Any]:
return {
"name": "GPT-SoVITS Simple API",
- "endpoints": [
- "/health",
- "/voices",
- "/api/tts",
- "/speak",
- "/speak/base64",
- "/admin/weights",
- "/admin/reload-config",
- ],
+ "version": "1.1.0",
+ "docs": "/docs",
+ "endpoints": {
+ "system": ["/health", "/voices"],
+ "mvp": ["/api/tts"],
+ "profile": ["/speak", "/speak/base64", "/v1/tts"],
+ "admin": ["/admin/reload-config", "/admin/weights"],
+ },
}
-@APP.get("/health")
+@APP.get("/health", tags=["System"], summary="健康检查")
def health() -> Dict[str, Any]:
- return {
+ import os
+
+ result: Dict[str, Any] = {
"status": "ok" if tts_pipeline is not None else "starting",
"tts_config": tts_config_path,
"version": getattr(tts_config, "version", None),
"languages": getattr(tts_config, "languages", []),
+ "pid": os.getpid(),
}
+ try:
+ import psutil
+ result["memory_mb"] = round(psutil.Process(os.getpid()).memory_info().rss / 1024 / 1024, 1)
+ except Exception:
+ pass
+ try:
+ import torch
+ if torch.cuda.is_available():
+ result["gpu"] = {
+ "name": torch.cuda.get_device_name(0),
+ "memory_used_mb": round(torch.cuda.memory_allocated(0) / 1024 / 1024, 1),
+ "memory_total_mb": round(torch.cuda.get_device_properties(0).total_mem / 1024 / 1024, 1),
+ }
+ except Exception:
+ pass
+ return result
-@APP.get("/voices")
+@APP.get("/voices", tags=["System"], summary="列出可用 voice profiles")
def list_voices() -> Dict[str, Any]:
voices = simple_config.get("voices", {}) or {}
return {
@@ -619,7 +655,17 @@ def list_voices() -> Dict[str, Any]:
}
-@APP.post("/api/tts")
+@APP.post(
+ "/api/tts",
+ tags=["MVP"],
+ summary="核心 TTS 接口",
+ description=(
+ "上传参考音频和需要生成的文字,返回生成的音频。\n\n"
+ "**主参考音频要求**:3-10 秒,支持 wav/flac/ogg/mp3/m4a/aac 格式。\n\n"
+ "**文字切句**:固定使用 `cut5`(按标点符号切句)。\n\n"
+ "**情绪预设**:neutral / happy / calm / sad / angry,本质是映射到采样和语速参数。"
+ ),
+)
async def mvp_tts(
text: str = Form(...),
ref_audio: UploadFile = File(...),
@@ -666,7 +712,7 @@ async def mvp_tts(
shutil.rmtree(request_dir, ignore_errors=True)
-@APP.get("/speak")
+@APP.get("/speak", tags=["Profile"], summary="GET 方式调用 voice profile TTS")
def speak_get(
text: str,
voice: Optional[str] = None,
@@ -686,17 +732,17 @@ def speak_get(
return synthesize_response({k: v for k, v in payload.items() if v is not None})
-@APP.post("/speak")
+@APP.post("/speak", tags=["Profile"], summary="POST 方式调用 voice profile TTS")
def speak_post(request: SpeakRequest) -> Response:
return synthesize_response(request_to_dict(request))
-@APP.post("/v1/tts")
+@APP.post("/v1/tts", tags=["Profile"], summary="OpenAI 兼容格式 TTS")
def openai_style_tts(request: SpeakRequest) -> Response:
return synthesize_response(request_to_dict(request))
-@APP.post("/speak/base64")
+@APP.post("/speak/base64", tags=["Profile"], summary="返回 Base64 编码的音频")
def speak_base64(request: SpeakRequest) -> Dict[str, Any]:
audio_bytes, media_type = synthesize_once(request_to_dict(request))
return {
@@ -705,14 +751,14 @@ def speak_base64(request: SpeakRequest) -> Dict[str, Any]:
}
-@APP.post("/admin/reload-config")
+@APP.post("/admin/reload-config", tags=["Admin"], summary="热加载 simple_api.yaml 配置")
def reload_config() -> Dict[str, Any]:
global simple_config
simple_config = load_yaml_config(args.config)
return {"message": "success", "default_voice": get_default_voice_name()}
-@APP.post("/admin/weights")
+@APP.post("/admin/weights", tags=["Admin"], summary="运行时切换 GPT-SoVITS 模型权重")
def set_weights(request: WeightsRequest) -> Dict[str, Any]:
if tts_pipeline is None:
raise HTTPException(status_code=503, detail="TTS pipeline is not ready")
diff --git a/test_frontend/index.html b/test_frontend/index.html
index c7e1b5ba..ed441135 100644
--- a/test_frontend/index.html
+++ b/test_frontend/index.html
@@ -282,6 +282,81 @@
color: var(--bad);
}
+ .waveform-wrap {
+ display: none;
+ margin-top: 14px;
+ border: 1px solid var(--line);
+ border-radius: 8px;
+ background: #fbfcfb;
+ padding: 12px;
+ }
+
+ .waveform-wrap.visible {
+ display: block;
+ }
+
+ .waveform-wrap h3 {
+ margin: 0 0 8px;
+ font-size: 13px;
+ font-weight: 650;
+ color: var(--ink);
+ }
+
+ #waveform {
+ border-radius: 4px;
+ overflow: hidden;
+ background: #e9efeb;
+ min-height: 50px;
+ }
+
+ .trim-controls {
+ display: none;
+ align-items: center;
+ gap: 12px;
+ margin-top: 10px;
+ flex-wrap: wrap;
+ }
+
+ .trim-controls.visible {
+ display: flex;
+ }
+
+ .trim-controls label {
+ margin-bottom: 0;
+ font-size: 12px;
+ }
+
+ .trim-controls input[type="number"] {
+ width: 80px;
+ padding: 6px 8px;
+ font-size: 13px;
+ text-align: center;
+ }
+
+ .trim-time-group {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ }
+
+ .trim-time-group span {
+ color: var(--muted);
+ font-size: 12px;
+ }
+
+ .trim-separator {
+ color: var(--muted);
+ font-size: 13px;
+ padding: 0 2px;
+ }
+
+ .btn-export-trim {
+ margin-left: auto;
+ font-size: 12px;
+ min-height: 32px;
+ padding: 0 12px;
+ }
+
@media (max-width: 860px) {
header,
.workspace,
@@ -304,7 +379,7 @@