omnivoice-server-api 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omnivoice_server_api-0.0.1/LICENSE +21 -0
- omnivoice_server_api-0.0.1/PKG-INFO +183 -0
- omnivoice_server_api-0.0.1/README.md +157 -0
- omnivoice_server_api-0.0.1/pyproject.toml +42 -0
- omnivoice_server_api-0.0.1/setup.cfg +4 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/__init__.py +8 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/config.py +24 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/data_models/__init__.py +6 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/data_models/enums.py +36 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/data_models/script.py +48 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/exceptions.py +59 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/models/__init__.py +5 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/models/omnivoice_client.py +667 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/utils/__init__.py +3 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/utils/regex.py +12 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api/utils/typing.py +11 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api.egg-info/PKG-INFO +183 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api.egg-info/SOURCES.txt +19 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api.egg-info/dependency_links.txt +1 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api.egg-info/requires.txt +4 -0
- omnivoice_server_api-0.0.1/src/omnivoice_server_api.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jerry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: omnivoice-server-api
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A Python async SDK that wraps the OmniVoice TTS server API into a clean, type-safe interface.
|
|
5
|
+
Author-email: Jerry <wujr24@m.fudan.edu.cn>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Jerry-Wu-GitHub/omnivoice-server-api
|
|
8
|
+
Project-URL: Repository, https://github.com/Jerry-Wu-GitHub/omnivoice-server-api.git
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: aiofiles
|
|
22
|
+
Requires-Dist: httpx
|
|
23
|
+
Requires-Dist: python-dotenv
|
|
24
|
+
Requires-Dist: yarl
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# OmniVoice Server API Python SDK
|
|
28
|
+
|
|
29
|
+
[](LICENSE)
|
|
30
|
+
[](https://www.python.org/downloads/)
|
|
31
|
+
|
|
32
|
+
一个**异步**、**类型安全**的 Python SDK,用于调用 [omnivoice-server](https://github.com/Howard-Hou/OmniVoice) 的 OpenAI 兼容 TTS HTTP 服务。
|
|
33
|
+
|
|
34
|
+
它提供了直观的接口,覆盖语音合成、声音克隆、多角色脚本合成、声音配置管理与模型查询等功能,让您能以 Pythonic 的方式生成语音。
|
|
35
|
+
|
|
36
|
+
## ✨ 特性
|
|
37
|
+
|
|
38
|
+
- 🚀 **全异步** – 基于 `httpx.AsyncClient`,支持高并发请求。
|
|
39
|
+
- 📦 **类型安全** – 提供 `AudioFormat`、`ScriptOutputFormat`、`ScriptSegment` 等数据模型,配合 IDE 自动补全。
|
|
40
|
+
- 🎙️ **语音合成** – 支持普通合成(`create_speech`)、一次发音克隆(`create_speech_clone`)与多角色脚本合成(`create_script_audio`)。
|
|
41
|
+
- 🔑 **灵活认证** – 通过 `headers` 或自定义 `http_client` 注入 `Authorization` 头。
|
|
42
|
+
- 🛠️ **开箱即用** – 支持 `.env` 配置,简洁的异步上下文管理。
|
|
43
|
+
|
|
44
|
+
## 📦 安装
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install omnivoice-server-api
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
或直接从源码安装:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
git clone https://github.com/Jerry-Wu-GitHub/omnivoice-server-api.git
|
|
54
|
+
cd omnivoice-server-api
|
|
55
|
+
pip install -e .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## 🚀 快速开始
|
|
59
|
+
|
|
60
|
+
### 1. 配置服务地址
|
|
61
|
+
|
|
62
|
+
默认使用 ModelScope 推理地址。若需要自定义,可在项目根目录创建 `.env` 文件:
|
|
63
|
+
|
|
64
|
+
```env
|
|
65
|
+
OMNIVOICE_BASE_URL=https://studio-jerrywumodelscope-omnivoice-server.api-inference.modelscope.net
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 2. 基础用法
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
import asyncio
|
|
72
|
+
from omnivoice_server_api import OmniVoiceClient
|
|
73
|
+
|
|
74
|
+
async def main():
|
|
75
|
+
async with OmniVoiceClient() as client:
|
|
76
|
+
# 合成语音
|
|
77
|
+
audio = await client.create_speech(
|
|
78
|
+
"你好,欢迎使用 OmniVoice 语音合成服务。",
|
|
79
|
+
voice="auto",
|
|
80
|
+
response_format="mp3",
|
|
81
|
+
)
|
|
82
|
+
with open("output.mp3", "wb") as f:
|
|
83
|
+
f.write(audio)
|
|
84
|
+
|
|
85
|
+
# 列出可用声音
|
|
86
|
+
voices = await client.list_voices()
|
|
87
|
+
print(voices)
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
asyncio.run(main())
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### 3. 认证(如服务需要)
|
|
94
|
+
|
|
95
|
+
通过 `headers` 注入 `Authorization` 头:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from omnivoice_server_api import OmniVoiceClient
|
|
99
|
+
|
|
100
|
+
client = OmniVoiceClient(headers={"Authorization": "Bearer <your_token>"})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## 📖 API 概览
|
|
104
|
+
|
|
105
|
+
SDK 的所有功能通过 `OmniVoiceClient` 提供:
|
|
106
|
+
|
|
107
|
+
| 方法 | 说明 | 对应接口 |
|
|
108
|
+
| ----------------------- | -------------------------- | ----------------------------------- |
|
|
109
|
+
| `create_speech()` | 文本合成语音 | `POST /v1/audio/speech` |
|
|
110
|
+
| `create_speech_clone()` | 一次发音克隆 | `POST /v1/audio/speech/clone` |
|
|
111
|
+
| `create_script_audio()` | 多角色脚本合成 | `POST /v1/audio/script` |
|
|
112
|
+
| `list_voices()` | 列出可用声音 | `GET /v1/voices` |
|
|
113
|
+
| `create_profile()` | 保存声音克隆配置 | `POST /v1/voices/profiles` |
|
|
114
|
+
| `get_profile()` | 获取声音克隆配置 | `GET /v1/voices/profiles/{id}` |
|
|
115
|
+
| `update_profile()` | 更新声音克隆配置 | `PATCH /v1/voices/profiles/{id}` |
|
|
116
|
+
| `delete_profile()` | 删除声音克隆配置 | `DELETE /v1/voices/profiles/{id}` |
|
|
117
|
+
| `list_models()` | 列出模型 | `GET /v1/models` |
|
|
118
|
+
| `get_model()` | 获取模型 | `GET /v1/models/{id}` |
|
|
119
|
+
| `health()` | 就绪检查 | `GET /health` |
|
|
120
|
+
| `metrics()` | 请求指标与内存使用 | `GET /metrics` |
|
|
121
|
+
|
|
122
|
+
### 详细示例:一次发音克隆
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
async def clone_example(client):
|
|
126
|
+
audio = await client.create_speech_clone(
|
|
127
|
+
"这是使用克隆音色合成的语音。",
|
|
128
|
+
ref_audio="reference.wav", # 支持路径 / bytes / 文件对象
|
|
129
|
+
ref_text="这是参考音频对应的文本。",
|
|
130
|
+
response_format="wav",
|
|
131
|
+
)
|
|
132
|
+
with open("cloned.wav", "wb") as f:
|
|
133
|
+
f.write(audio)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 详细示例:多角色脚本合成
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from omnivoice_server_api import OmniVoiceClient, ScriptSegment, ScriptOutputFormat
|
|
140
|
+
|
|
141
|
+
async def script_example(client):
|
|
142
|
+
script = [
|
|
143
|
+
ScriptSegment(speaker="主持人", text="欢迎来到今天的节目。"),
|
|
144
|
+
ScriptSegment(speaker="嘉宾", text="大家好,很高兴来到这里。"),
|
|
145
|
+
]
|
|
146
|
+
audio = await client.create_script_audio(
|
|
147
|
+
script,
|
|
148
|
+
output_format=ScriptOutputFormat.SINGLE_TRACK,
|
|
149
|
+
pause_between_speakers=0.8,
|
|
150
|
+
)
|
|
151
|
+
with open("script.wav", "wb") as f:
|
|
152
|
+
f.write(audio)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 详细示例:声音克隆配置管理
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
async def profile_example(client):
|
|
159
|
+
# 保存配置
|
|
160
|
+
await client.create_profile("my_voice", ref_audio="reference.wav")
|
|
161
|
+
|
|
162
|
+
# 查询配置
|
|
163
|
+
profile = await client.get_profile("my_voice")
|
|
164
|
+
print(profile)
|
|
165
|
+
|
|
166
|
+
# 更新配置
|
|
167
|
+
await client.update_profile("my_voice", ref_text="新的参考文本")
|
|
168
|
+
|
|
169
|
+
# 删除配置
|
|
170
|
+
await client.delete_profile("my_voice")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 🧪 运行测试
|
|
174
|
+
|
|
175
|
+
项目包含测试用例,位于 `tests/` 目录,需要能访问服务端。运行:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
python tests/main.py
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## 📄 许可证
|
|
182
|
+
|
|
183
|
+
本项目使用 [MIT](LICENSE) 许可证。
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# OmniVoice Server API Python SDK
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
|
|
6
|
+
一个**异步**、**类型安全**的 Python SDK,用于调用 [omnivoice-server](https://github.com/Howard-Hou/OmniVoice) 的 OpenAI 兼容 TTS HTTP 服务。
|
|
7
|
+
|
|
8
|
+
它提供了直观的接口,覆盖语音合成、声音克隆、多角色脚本合成、声音配置管理与模型查询等功能,让您能以 Pythonic 的方式生成语音。
|
|
9
|
+
|
|
10
|
+
## ✨ 特性
|
|
11
|
+
|
|
12
|
+
- 🚀 **全异步** – 基于 `httpx.AsyncClient`,支持高并发请求。
|
|
13
|
+
- 📦 **类型安全** – 提供 `AudioFormat`、`ScriptOutputFormat`、`ScriptSegment` 等数据模型,配合 IDE 自动补全。
|
|
14
|
+
- 🎙️ **语音合成** – 支持普通合成(`create_speech`)、一次发音克隆(`create_speech_clone`)与多角色脚本合成(`create_script_audio`)。
|
|
15
|
+
- 🔑 **灵活认证** – 通过 `headers` 或自定义 `http_client` 注入 `Authorization` 头。
|
|
16
|
+
- 🛠️ **开箱即用** – 支持 `.env` 配置,简洁的异步上下文管理。
|
|
17
|
+
|
|
18
|
+
## 📦 安装
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install omnivoice-server-api
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
或直接从源码安装:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git clone https://github.com/Jerry-Wu-GitHub/omnivoice-server-api.git
|
|
28
|
+
cd omnivoice-server-api
|
|
29
|
+
pip install -e .
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## 🚀 快速开始
|
|
33
|
+
|
|
34
|
+
### 1. 配置服务地址
|
|
35
|
+
|
|
36
|
+
默认使用 ModelScope 推理地址。若需要自定义,可在项目根目录创建 `.env` 文件:
|
|
37
|
+
|
|
38
|
+
```env
|
|
39
|
+
OMNIVOICE_BASE_URL=https://studio-jerrywumodelscope-omnivoice-server.api-inference.modelscope.net
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 2. 基础用法
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
import asyncio
|
|
46
|
+
from omnivoice_server_api import OmniVoiceClient
|
|
47
|
+
|
|
48
|
+
async def main():
|
|
49
|
+
async with OmniVoiceClient() as client:
|
|
50
|
+
# 合成语音
|
|
51
|
+
audio = await client.create_speech(
|
|
52
|
+
"你好,欢迎使用 OmniVoice 语音合成服务。",
|
|
53
|
+
voice="auto",
|
|
54
|
+
response_format="mp3",
|
|
55
|
+
)
|
|
56
|
+
with open("output.mp3", "wb") as f:
|
|
57
|
+
f.write(audio)
|
|
58
|
+
|
|
59
|
+
# 列出可用声音
|
|
60
|
+
voices = await client.list_voices()
|
|
61
|
+
print(voices)
|
|
62
|
+
|
|
63
|
+
if __name__ == "__main__":
|
|
64
|
+
asyncio.run(main())
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 3. 认证(如服务需要)
|
|
68
|
+
|
|
69
|
+
通过 `headers` 注入 `Authorization` 头:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from omnivoice_server_api import OmniVoiceClient
|
|
73
|
+
|
|
74
|
+
client = OmniVoiceClient(headers={"Authorization": "Bearer <your_token>"})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## 📖 API 概览
|
|
78
|
+
|
|
79
|
+
SDK 的所有功能通过 `OmniVoiceClient` 提供:
|
|
80
|
+
|
|
81
|
+
| 方法 | 说明 | 对应接口 |
|
|
82
|
+
| ----------------------- | -------------------------- | ----------------------------------- |
|
|
83
|
+
| `create_speech()` | 文本合成语音 | `POST /v1/audio/speech` |
|
|
84
|
+
| `create_speech_clone()` | 一次发音克隆 | `POST /v1/audio/speech/clone` |
|
|
85
|
+
| `create_script_audio()` | 多角色脚本合成 | `POST /v1/audio/script` |
|
|
86
|
+
| `list_voices()` | 列出可用声音 | `GET /v1/voices` |
|
|
87
|
+
| `create_profile()` | 保存声音克隆配置 | `POST /v1/voices/profiles` |
|
|
88
|
+
| `get_profile()` | 获取声音克隆配置 | `GET /v1/voices/profiles/{id}` |
|
|
89
|
+
| `update_profile()` | 更新声音克隆配置 | `PATCH /v1/voices/profiles/{id}` |
|
|
90
|
+
| `delete_profile()` | 删除声音克隆配置 | `DELETE /v1/voices/profiles/{id}` |
|
|
91
|
+
| `list_models()` | 列出模型 | `GET /v1/models` |
|
|
92
|
+
| `get_model()` | 获取模型 | `GET /v1/models/{id}` |
|
|
93
|
+
| `health()` | 就绪检查 | `GET /health` |
|
|
94
|
+
| `metrics()` | 请求指标与内存使用 | `GET /metrics` |
|
|
95
|
+
|
|
96
|
+
### 详细示例:一次发音克隆
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
async def clone_example(client):
|
|
100
|
+
audio = await client.create_speech_clone(
|
|
101
|
+
"这是使用克隆音色合成的语音。",
|
|
102
|
+
ref_audio="reference.wav", # 支持路径 / bytes / 文件对象
|
|
103
|
+
ref_text="这是参考音频对应的文本。",
|
|
104
|
+
response_format="wav",
|
|
105
|
+
)
|
|
106
|
+
with open("cloned.wav", "wb") as f:
|
|
107
|
+
f.write(audio)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 详细示例:多角色脚本合成
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from omnivoice_server_api import OmniVoiceClient, ScriptSegment, ScriptOutputFormat
|
|
114
|
+
|
|
115
|
+
async def script_example(client):
|
|
116
|
+
script = [
|
|
117
|
+
ScriptSegment(speaker="主持人", text="欢迎来到今天的节目。"),
|
|
118
|
+
ScriptSegment(speaker="嘉宾", text="大家好,很高兴来到这里。"),
|
|
119
|
+
]
|
|
120
|
+
audio = await client.create_script_audio(
|
|
121
|
+
script,
|
|
122
|
+
output_format=ScriptOutputFormat.SINGLE_TRACK,
|
|
123
|
+
pause_between_speakers=0.8,
|
|
124
|
+
)
|
|
125
|
+
with open("script.wav", "wb") as f:
|
|
126
|
+
f.write(audio)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 详细示例:声音克隆配置管理
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
async def profile_example(client):
|
|
133
|
+
# 保存配置
|
|
134
|
+
await client.create_profile("my_voice", ref_audio="reference.wav")
|
|
135
|
+
|
|
136
|
+
# 查询配置
|
|
137
|
+
profile = await client.get_profile("my_voice")
|
|
138
|
+
print(profile)
|
|
139
|
+
|
|
140
|
+
# 更新配置
|
|
141
|
+
await client.update_profile("my_voice", ref_text="新的参考文本")
|
|
142
|
+
|
|
143
|
+
# 删除配置
|
|
144
|
+
await client.delete_profile("my_voice")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 🧪 运行测试
|
|
148
|
+
|
|
149
|
+
项目包含测试用例,位于 `tests/` 目录,需要能访问服务端。运行:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
python tests/main.py
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## 📄 许可证
|
|
156
|
+
|
|
157
|
+
本项目使用 [MIT](LICENSE) 许可证。
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "omnivoice-server-api" # 包名,保持与项目仓库名一致
|
|
7
|
+
version = "0.0.1" # 当前版本
|
|
8
|
+
description = "A Python async SDK that wraps the OmniVoice TTS server API into a clean, type-safe interface." # 简短描述
|
|
9
|
+
readme = "README.md" # 自述文件,PyPI 会将其渲染为项目首页
|
|
10
|
+
authors = [{name = "Jerry", email = "wujr24@m.fudan.edu.cn"}] # 作者信息
|
|
11
|
+
license = {text = "MIT"} # 指定许可证,与 LICENSE 文件一致
|
|
12
|
+
classifiers = [ # 帮助用户在 PyPI 上找到你的项目
|
|
13
|
+
# 开发状态
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
|
|
16
|
+
# 目标受众
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Intended Audience :: Science/Research",
|
|
19
|
+
|
|
20
|
+
# 许可证
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
|
|
23
|
+
# 操作系统
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
|
|
26
|
+
# 编程语言 & Python 版本
|
|
27
|
+
"Programming Language :: Python :: 3",
|
|
28
|
+
"Programming Language :: Python :: 3.11",
|
|
29
|
+
"Programming Language :: Python :: 3.12",
|
|
30
|
+
"Programming Language :: Python :: 3.13",
|
|
31
|
+
]
|
|
32
|
+
requires-python = ">=3.11"
|
|
33
|
+
dependencies = [ # 项目的运行时依赖,从 requirements.txt 移植
|
|
34
|
+
"aiofiles",
|
|
35
|
+
"httpx",
|
|
36
|
+
"python-dotenv",
|
|
37
|
+
"yarl",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls] # 可选,但推荐,指向你的项目主页或仓库
|
|
41
|
+
Homepage = "https://github.com/Jerry-Wu-GitHub/omnivoice-server-api"
|
|
42
|
+
Repository = "https://github.com/Jerry-Wu-GitHub/omnivoice-server-api.git"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
配置
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
from dotenv import load_dotenv
|
|
8
|
+
from yarl import URL
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# 加载 .env 文件
|
|
12
|
+
load_dotenv()
|
|
13
|
+
|
|
14
|
+
# 基础域名
|
|
15
|
+
OMNIVOICE_BASE_URL: URL = URL(os.getenv(
|
|
16
|
+
"OMNIVOICE_BASE_URL",
|
|
17
|
+
"https://studio-jerrywumodelscope-omnivoice-server.api-inference.modelscope.net"
|
|
18
|
+
))
|
|
19
|
+
|
|
20
|
+
# API 的相对路径(挂在 base_url 之后,例如 /v1 下的接口)
|
|
21
|
+
OMNIVOICE_API_PATH: str = os.getenv(
|
|
22
|
+
"OMNIVOICE_API_PATH",
|
|
23
|
+
"v1"
|
|
24
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
枚举类型。
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import StrEnum
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AudioFormat(StrEnum):
|
|
9
|
+
"""
|
|
10
|
+
合成音频的编码格式。
|
|
11
|
+
"""
|
|
12
|
+
MP3 = "mp3"
|
|
13
|
+
OPUS = "opus"
|
|
14
|
+
AAC = "aac"
|
|
15
|
+
FLAC = "flac"
|
|
16
|
+
WAV = "wav"
|
|
17
|
+
PCM = "pcm"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ScriptOutputFormat(StrEnum):
|
|
21
|
+
"""
|
|
22
|
+
多角色脚本音频的输出格式。
|
|
23
|
+
"""
|
|
24
|
+
# 单轨音频,返回带元数据头的二进制音频
|
|
25
|
+
SINGLE_TRACK = "single_track"
|
|
26
|
+
|
|
27
|
+
# 多轨,返回包含每个说话人音轨与时间戳的 JSON
|
|
28
|
+
MULTI_TRACK = "multi_track"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ScriptOnError(StrEnum):
|
|
32
|
+
"""
|
|
33
|
+
多角色脚本合成时遇到错误的处理方式。
|
|
34
|
+
"""
|
|
35
|
+
ABORT = "abort"
|
|
36
|
+
SKIP = "skip"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
多角色脚本数据模型。
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
from ..utils.regex import SPEAKER_ID_PATTERN
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class ScriptSegment:
|
|
15
|
+
"""
|
|
16
|
+
多角色脚本中的单条台词。
|
|
17
|
+
|
|
18
|
+
Attributes:
|
|
19
|
+
speaker: 说话人 ID,须为 1~64 位字母、数字、下划线或横线。
|
|
20
|
+
text: 台词文本。
|
|
21
|
+
voice: 该台词使用的声音;缺省时回退到脚本的 default_voice。
|
|
22
|
+
speed: 该台词的语速(0.25~4);缺省时回退到脚本的 speed。
|
|
23
|
+
|
|
24
|
+
Raises:
|
|
25
|
+
ValueError: 如果 speaker 不符合 ID 规范。
|
|
26
|
+
"""
|
|
27
|
+
speaker: str
|
|
28
|
+
text: str
|
|
29
|
+
voice: Optional[str] = None
|
|
30
|
+
speed: Optional[float] = None
|
|
31
|
+
|
|
32
|
+
def __post_init__(self):
|
|
33
|
+
if not SPEAKER_ID_PATTERN.fullmatch(self.speaker):
|
|
34
|
+
raise ValueError(
|
|
35
|
+
f"Invalid speaker ID '{self.speaker}': "
|
|
36
|
+
"must be 1-64 alphanumeric/underscore/hyphen characters"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
def to_dict(self) -> dict:
|
|
40
|
+
"""
|
|
41
|
+
转为可 JSON 序列化的字典,并忽略值为 None 的字段。
|
|
42
|
+
"""
|
|
43
|
+
result = {"speaker": self.speaker, "text": self.text}
|
|
44
|
+
if self.voice is not None:
|
|
45
|
+
result["voice"] = self.voice
|
|
46
|
+
if self.speed is not None:
|
|
47
|
+
result["speed"] = self.speed
|
|
48
|
+
return result
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
异常类
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, ClassVar, Dict, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BusinessException(Exception):
|
|
9
|
+
"""
|
|
10
|
+
业务异常基类,所有业务错误都继承自这里。
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
code: 错误代码
|
|
14
|
+
message: 错误消息
|
|
15
|
+
details: 附加详情(可选)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# 默认消息
|
|
19
|
+
DEFAULT_MESSAGE: ClassVar[str] = "Business Error"
|
|
20
|
+
|
|
21
|
+
# 默认错误代码
|
|
22
|
+
DEFAULT_CODE: ClassVar[str] = "ERROR"
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
message: Optional[str] = None,
|
|
27
|
+
*,
|
|
28
|
+
code: Optional[str] = None,
|
|
29
|
+
details: Optional[Dict[str, Any]] = None
|
|
30
|
+
):
|
|
31
|
+
self.message : str = self.DEFAULT_MESSAGE if (message is None) else message
|
|
32
|
+
self.code : str = self.DEFAULT_CODE if (code is None) else code
|
|
33
|
+
self.details : Dict[str, Any] = details or {}
|
|
34
|
+
|
|
35
|
+
super().__init__(self.message)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class UpstreamException(BusinessException):
|
|
39
|
+
"""
|
|
40
|
+
上游服务端异常。
|
|
41
|
+
"""
|
|
42
|
+
DEFAULT_MESSAGE: ClassVar[str] = "UpstreamException"
|
|
43
|
+
DEFAULT_CODE: ClassVar[str] = "UPSTREAM EXCEPTION"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ParseException(UpstreamException):
|
|
47
|
+
"""
|
|
48
|
+
解析上游的响应失败。
|
|
49
|
+
"""
|
|
50
|
+
DEFAULT_MESSAGE: ClassVar[str] = "ParseException"
|
|
51
|
+
DEFAULT_CODE: ClassVar[str] = "PARSE EXCEPTION"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class OmniVoiceException(BusinessException):
|
|
55
|
+
"""
|
|
56
|
+
omnivoice-server 业务错误。
|
|
57
|
+
"""
|
|
58
|
+
DEFAULT_MESSAGE: ClassVar[str] = "OmniVoiceError"
|
|
59
|
+
DEFAULT_CODE: ClassVar[str] = "OMNIVOICE ERROR"
|