xiaogpt 2.42__tar.gz → 2.50__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.
Files changed (29) hide show
  1. {xiaogpt-2.42 → xiaogpt-2.50}/PKG-INFO +27 -29
  2. {xiaogpt-2.42 → xiaogpt-2.50}/README.md +15 -27
  3. {xiaogpt-2.42 → xiaogpt-2.50}/pyproject.toml +12 -2
  4. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/config.py +10 -0
  5. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/__init__.py +2 -1
  6. xiaogpt-2.50/xiaogpt/tts/volc.py +130 -0
  7. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/xiaogpt.py +6 -3
  8. {xiaogpt-2.42 → xiaogpt-2.50}/LICENSE +0 -0
  9. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/__init__.py +0 -0
  10. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/__main__.py +0 -0
  11. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/__init__.py +0 -0
  12. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/base_bot.py +0 -0
  13. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/chatgptapi_bot.py +0 -0
  14. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/gemini_bot.py +0 -0
  15. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/glm_bot.py +0 -0
  16. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/langchain_bot.py +0 -0
  17. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/newbing_bot.py +0 -0
  18. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/bot/qwen_bot.py +0 -0
  19. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/cli.py +0 -0
  20. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/langchain/callbacks.py +0 -0
  21. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/langchain/chain.py +0 -0
  22. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/langchain/examples/email/mail_box.py +0 -0
  23. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/langchain/examples/email/mail_summary_tools.py +0 -0
  24. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/azure.py +0 -0
  25. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/base.py +0 -0
  26. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/edge.py +0 -0
  27. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/mi.py +0 -0
  28. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/tts/openai.py +0 -0
  29. {xiaogpt-2.42 → xiaogpt-2.50}/xiaogpt/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xiaogpt
3
- Version: 2.42
3
+ Version: 2.50
4
4
  Summary: Play ChatGPT or other LLM with xiaomi AI speaker
5
5
  Author-Email: yihong0618 <zouzou0208@gmail.com>
6
6
  License: MIT
@@ -24,6 +24,8 @@ Requires-Dist: google-generativeai
24
24
  Requires-Dist: numexpr>=2.8.6
25
25
  Requires-Dist: dashscope>=1.10.0
26
26
  Requires-Dist: azure-cognitiveservices-speech>=1.37.0
27
+ Requires-Dist: multidict>=6.0.5
28
+ Requires-Dist: volcengine>=1.0.136
27
29
  Requires-Dist: aiohttp==3.9.4; extra == "locked"
28
30
  Requires-Dist: aiosignal==1.3.1; extra == "locked"
29
31
  Requires-Dist: annotated-types==0.6.0; extra == "locked"
@@ -39,11 +41,13 @@ Requires-Dist: charset-normalizer==3.3.2; extra == "locked"
39
41
  Requires-Dist: colorama==0.4.6; platform_system == "Windows" and extra == "locked"
40
42
  Requires-Dist: dashscope==1.10.0; extra == "locked"
41
43
  Requires-Dist: dataclasses-json==0.6.3; extra == "locked"
44
+ Requires-Dist: decorator==5.1.1; extra == "locked"
42
45
  Requires-Dist: distro==1.9.0; extra == "locked"
43
46
  Requires-Dist: edge-tts==6.1.10; extra == "locked"
44
47
  Requires-Dist: edgegpt==0.1.26; extra == "locked"
45
48
  Requires-Dist: exceptiongroup==1.2.0; python_version < "3.11" and extra == "locked"
46
49
  Requires-Dist: frozenlist==1.4.1; extra == "locked"
50
+ Requires-Dist: google==3.0.0; extra == "locked"
47
51
  Requires-Dist: google-ai-generativelanguage==0.6.1; extra == "locked"
48
52
  Requires-Dist: google-api-core==2.15.0; extra == "locked"
49
53
  Requires-Dist: google-api-core[grpc]==2.15.0; extra == "locked"
@@ -73,7 +77,7 @@ Requires-Dist: markdown-it-py==3.0.0; extra == "locked"
73
77
  Requires-Dist: marshmallow==3.20.1; extra == "locked"
74
78
  Requires-Dist: mdurl==0.1.2; extra == "locked"
75
79
  Requires-Dist: miservice-fork==2.4.3; extra == "locked"
76
- Requires-Dist: multidict==6.0.4; extra == "locked"
80
+ Requires-Dist: multidict==6.0.5; extra == "locked"
77
81
  Requires-Dist: mutagen==1.47.0; extra == "locked"
78
82
  Requires-Dist: mypy-extensions==1.0.0; extra == "locked"
79
83
  Requires-Dist: numexpr==2.10.0; extra == "locked"
@@ -84,18 +88,23 @@ Requires-Dist: packaging==23.2; extra == "locked"
84
88
  Requires-Dist: prompt-toolkit==3.0.43; extra == "locked"
85
89
  Requires-Dist: proto-plus==1.23.0; extra == "locked"
86
90
  Requires-Dist: protobuf==4.25.1; extra == "locked"
91
+ Requires-Dist: py==1.11.0; extra == "locked"
87
92
  Requires-Dist: pyasn1==0.5.1; extra == "locked"
88
93
  Requires-Dist: pyasn1-modules==0.3.0; extra == "locked"
94
+ Requires-Dist: pycryptodome==3.9.9; extra == "locked"
89
95
  Requires-Dist: pydantic==2.5.3; extra == "locked"
90
96
  Requires-Dist: pydantic-core==2.14.6; extra == "locked"
91
97
  Requires-Dist: pygments==2.17.2; extra == "locked"
92
98
  Requires-Dist: pyjwt==2.8.0; extra == "locked"
93
99
  Requires-Dist: pyparsing==3.1.2; python_version > "3.0" and extra == "locked"
100
+ Requires-Dist: pytz==2020.5; extra == "locked"
94
101
  Requires-Dist: pyyaml==6.0.1; extra == "locked"
95
102
  Requires-Dist: regex==2023.12.25; extra == "locked"
96
103
  Requires-Dist: requests==2.31.0; extra == "locked"
104
+ Requires-Dist: retry==0.9.2; extra == "locked"
97
105
  Requires-Dist: rich==13.7.1; extra == "locked"
98
106
  Requires-Dist: rsa==4.9; extra == "locked"
107
+ Requires-Dist: six==1.16.0; extra == "locked"
99
108
  Requires-Dist: sniffio==1.3.0; extra == "locked"
100
109
  Requires-Dist: socksio==1.0.0; extra == "locked"
101
110
  Requires-Dist: soupsieve==2.5; extra == "locked"
@@ -106,6 +115,7 @@ Requires-Dist: typing-extensions==4.9.0; extra == "locked"
106
115
  Requires-Dist: typing-inspect==0.9.0; extra == "locked"
107
116
  Requires-Dist: uritemplate==4.1.1; extra == "locked"
108
117
  Requires-Dist: urllib3==2.1.0; extra == "locked"
118
+ Requires-Dist: volcengine==1.0.136; extra == "locked"
109
119
  Requires-Dist: wcwidth==0.2.13; extra == "locked"
110
120
  Requires-Dist: websockets==12.0; extra == "locked"
111
121
  Requires-Dist: yarl==1.9.4; extra == "locked"
@@ -134,33 +144,16 @@ Play ChatGPT and other LLM with Xiaomi AI Speaker
134
144
  - [通义千问](https://help.aliyun.com/zh/dashscope/developer-reference/api-details)
135
145
 
136
146
  ## 获取小米音响DID
137
- ### Windows(使用 set 设置环境变量)
138
- ```cmd
139
- pip install miservice_fork
140
- set MI_USER=xxxx
141
- set MI_PASS=xxx
142
- micli list 得到did
143
- set MI_DID=xxxx
144
- ```
145
-
147
+ 系统和Shell|Linux *sh|Windows CMD用户|Windows PowerShell用户
148
+ -|-|-|-
149
+ 1、安装包|`pip install miservice_fork`|`pip install miservice_fork`|`pip install miservice_fork`
150
+ 2、设置变量|`export MI_USER=xxx` <br> `export MI_PASS=xxx`|`set MI_USER=xxx`<br>`set MI_PASS=xxx`|`$env:MI_USER="xxx"` <br> `$env:MI_PASS="xxx"`
151
+ 3、取得MI_DID|`micli list` |`micli list` |`micli list`
152
+ 4、设置MI_DID|`export MI_DID=xxx`| `set MI_DID=xxx`| `$env:MI_DID="xxx"`
153
+
154
+ - 注意不同shell 对环境变量的处理是不同的,尤其是powershell赋值时,可能需要双引号来包括值。
146
155
  - 如果获取did报错时,请更换一下无线网络,有很大概率解决问题。
147
156
 
148
- ### Linux(使用 export 设置环境变量)
149
- ```sh
150
- # 1、安装模块
151
- pip install miservice_fork
152
-
153
- # 2、设置环境用户参数
154
- export MI_USER=xxxx
155
- export MI_PASS=xxx
156
-
157
- # 3、使用micli list 得到did
158
- micli list
159
-
160
- # 4、根据did设置环境DID参数
161
- export MI_DID=xxxx
162
- ```
163
-
164
157
  ## 一点原理
165
158
 
166
159
  [不用 root 使用小爱同学和 ChatGPT 交互折腾记](https://github.com/yihong0618/gitblog/issues/258)
@@ -293,8 +286,8 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
293
286
  | use_command | 使用 MI command 与小爱交互 | `false` | |
294
287
  | mute_xiaoai | 快速停掉小爱自己的回答 | `true` | |
295
288
  | verbose | 是否打印详细日志 | `false` | |
296
- | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
297
- | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure` |
289
+ | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
290
+ | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure`、`volc` |
298
291
  | tts_voice | TTS 的嗓音 | `zh-CN-XiaoxiaoNeural`(edge), `alloy`(openai), `zh-CN-XiaoxiaoMultilingualNeural`(azure) | |
299
292
  | prompt | 自定义prompt | `请用100字以内回答` | |
300
293
  | keyword | 自定义请求词列表 | `["请"]` | |
@@ -310,6 +303,11 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
310
303
  | api_base | 如果需要替换默认的api,或者使用Azure OpenAI 服务 | 例如:`https://abc-def.openai.azure.com/` | |
311
304
  | azure_tts_speech_key | Azure TTS key | null | |
312
305
  | azure_tts_service_region | Azure TTS 服务地区 | `eastasia` | [Regions - Speech service - Azure AI services](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/regions) |
306
+ | volc_accesskey | 火山引擎accesskey [参考](https://console.volcengine.com/iam/keymanage/) | | |
307
+ | volc_secretkey | 火山引擎secretkey [参考](https://console.volcengine.com/iam/keymanage/) | | |
308
+ | volc_tts_app | 火山引擎 TTS app 服务 [参考]( https://console.volcengine.com/sami/) | | |
309
+ | volc_tts_speaker | 火山引擎 TTS speaker [参考]( https://www.volcengine.com/docs/6489/93478) | `zh_female_qingxin` | |
310
+
313
311
 
314
312
  [这里]: https://github.com/acheong08/EdgeGPT#getting-authentication-required
315
313
 
@@ -19,33 +19,16 @@ Play ChatGPT and other LLM with Xiaomi AI Speaker
19
19
  - [通义千问](https://help.aliyun.com/zh/dashscope/developer-reference/api-details)
20
20
 
21
21
  ## 获取小米音响DID
22
- ### Windows(使用 set 设置环境变量)
23
- ```cmd
24
- pip install miservice_fork
25
- set MI_USER=xxxx
26
- set MI_PASS=xxx
27
- micli list 得到did
28
- set MI_DID=xxxx
29
- ```
30
-
22
+ 系统和Shell|Linux *sh|Windows CMD用户|Windows PowerShell用户
23
+ -|-|-|-
24
+ 1、安装包|`pip install miservice_fork`|`pip install miservice_fork`|`pip install miservice_fork`
25
+ 2、设置变量|`export MI_USER=xxx` <br> `export MI_PASS=xxx`|`set MI_USER=xxx`<br>`set MI_PASS=xxx`|`$env:MI_USER="xxx"` <br> `$env:MI_PASS="xxx"`
26
+ 3、取得MI_DID|`micli list` |`micli list` |`micli list`
27
+ 4、设置MI_DID|`export MI_DID=xxx`| `set MI_DID=xxx`| `$env:MI_DID="xxx"`
28
+
29
+ - 注意不同shell 对环境变量的处理是不同的,尤其是powershell赋值时,可能需要双引号来包括值。
31
30
  - 如果获取did报错时,请更换一下无线网络,有很大概率解决问题。
32
31
 
33
- ### Linux(使用 export 设置环境变量)
34
- ```sh
35
- # 1、安装模块
36
- pip install miservice_fork
37
-
38
- # 2、设置环境用户参数
39
- export MI_USER=xxxx
40
- export MI_PASS=xxx
41
-
42
- # 3、使用micli list 得到did
43
- micli list
44
-
45
- # 4、根据did设置环境DID参数
46
- export MI_DID=xxxx
47
- ```
48
-
49
32
  ## 一点原理
50
33
 
51
34
  [不用 root 使用小爱同学和 ChatGPT 交互折腾记](https://github.com/yihong0618/gitblog/issues/258)
@@ -178,8 +161,8 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
178
161
  | use_command | 使用 MI command 与小爱交互 | `false` | |
179
162
  | mute_xiaoai | 快速停掉小爱自己的回答 | `true` | |
180
163
  | verbose | 是否打印详细日志 | `false` | |
181
- | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
182
- | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure` |
164
+ | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
165
+ | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure`、`volc` |
183
166
  | tts_voice | TTS 的嗓音 | `zh-CN-XiaoxiaoNeural`(edge), `alloy`(openai), `zh-CN-XiaoxiaoMultilingualNeural`(azure) | |
184
167
  | prompt | 自定义prompt | `请用100字以内回答` | |
185
168
  | keyword | 自定义请求词列表 | `["请"]` | |
@@ -195,6 +178,11 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
195
178
  | api_base | 如果需要替换默认的api,或者使用Azure OpenAI 服务 | 例如:`https://abc-def.openai.azure.com/` | |
196
179
  | azure_tts_speech_key | Azure TTS key | null | |
197
180
  | azure_tts_service_region | Azure TTS 服务地区 | `eastasia` | [Regions - Speech service - Azure AI services](https://learn.microsoft.com/en-us/azure/ai-services/speech-service/regions) |
181
+ | volc_accesskey | 火山引擎accesskey [参考](https://console.volcengine.com/iam/keymanage/) | | |
182
+ | volc_secretkey | 火山引擎secretkey [参考](https://console.volcengine.com/iam/keymanage/) | | |
183
+ | volc_tts_app | 火山引擎 TTS app 服务 [参考]( https://console.volcengine.com/sami/) | | |
184
+ | volc_tts_speaker | 火山引擎 TTS speaker [参考]( https://www.volcengine.com/docs/6489/93478) | `zh_female_qingxin` | |
185
+
198
186
 
199
187
  [这里]: https://github.com/acheong08/EdgeGPT#getting-authentication-required
200
188
 
@@ -27,9 +27,11 @@ dependencies = [
27
27
  "numexpr>=2.8.6",
28
28
  "dashscope>=1.10.0",
29
29
  "azure-cognitiveservices-speech>=1.37.0",
30
+ "multidict>=6.0.5",
31
+ "volcengine>=1.0.136",
30
32
  ]
31
33
  dynamic = []
32
- version = "2.42"
34
+ version = "2.50"
33
35
 
34
36
  [project.license]
35
37
  text = "MIT"
@@ -57,11 +59,13 @@ locked = [
57
59
  "colorama==0.4.6 ; platform_system == \"Windows\"",
58
60
  "dashscope==1.10.0",
59
61
  "dataclasses-json==0.6.3",
62
+ "decorator==5.1.1",
60
63
  "distro==1.9.0",
61
64
  "edge-tts==6.1.10",
62
65
  "edgegpt==0.1.26",
63
66
  "exceptiongroup==1.2.0 ; python_version < \"3.11\"",
64
67
  "frozenlist==1.4.1",
68
+ "google==3.0.0",
65
69
  "google-ai-generativelanguage==0.6.1",
66
70
  "google-api-core==2.15.0",
67
71
  "google-api-core[grpc]==2.15.0",
@@ -91,7 +95,7 @@ locked = [
91
95
  "marshmallow==3.20.1",
92
96
  "mdurl==0.1.2",
93
97
  "miservice-fork==2.4.3",
94
- "multidict==6.0.4",
98
+ "multidict==6.0.5",
95
99
  "mutagen==1.47.0",
96
100
  "mypy-extensions==1.0.0",
97
101
  "numexpr==2.10.0",
@@ -102,18 +106,23 @@ locked = [
102
106
  "prompt-toolkit==3.0.43",
103
107
  "proto-plus==1.23.0",
104
108
  "protobuf==4.25.1",
109
+ "py==1.11.0",
105
110
  "pyasn1==0.5.1",
106
111
  "pyasn1-modules==0.3.0",
112
+ "pycryptodome==3.9.9",
107
113
  "pydantic==2.5.3",
108
114
  "pydantic-core==2.14.6",
109
115
  "pygments==2.17.2",
110
116
  "pyjwt==2.8.0",
111
117
  "pyparsing==3.1.2 ; python_version > \"3.0\"",
118
+ "pytz==2020.5",
112
119
  "pyyaml==6.0.1",
113
120
  "regex==2023.12.25",
114
121
  "requests==2.31.0",
122
+ "retry==0.9.2",
115
123
  "rich==13.7.1",
116
124
  "rsa==4.9",
125
+ "six==1.16.0",
117
126
  "sniffio==1.3.0",
118
127
  "socksio==1.0.0",
119
128
  "soupsieve==2.5",
@@ -124,6 +133,7 @@ locked = [
124
133
  "typing-inspect==0.9.0",
125
134
  "uritemplate==4.1.1",
126
135
  "urllib3==2.1.0",
136
+ "volcengine==1.0.136",
127
137
  "wcwidth==0.2.13",
128
138
  "websockets==12.0",
129
139
  "yarl==1.9.4",
@@ -87,6 +87,16 @@ class Config:
87
87
  bing_cookies: dict | None = None
88
88
  azure_tts_speech_key: str | None = None
89
89
  azure_tts_service_region: str = "eastasia"
90
+ volc_accesskey: str = os.getenv(
91
+ "VOLC_ACCESSKEY", ""
92
+ ) # https://console.volcengine.com/iam/keymanage/
93
+ volc_secretkey: str = os.getenv("VOLC_SECRETKEY", "")
94
+ volc_tts_app: str = os.getenv(
95
+ "VOLC_TTS_APP", ""
96
+ ) # https://console.volcengine.com/sami
97
+ volc_tts_speaker: str = os.getenv(
98
+ "VOLC_TTS_SPEAPER", "zh_female_qingxin"
99
+ ) # https://www.volcengine.com/docs/6489/93478
90
100
 
91
101
  def __post_init__(self) -> None:
92
102
  if self.proxy:
@@ -1,6 +1,7 @@
1
1
  from xiaogpt.tts.base import TTS as TTS
2
2
  from xiaogpt.tts.edge import EdgeTTS as EdgeTTS
3
3
  from xiaogpt.tts.mi import MiTTS as MiTTS
4
+ from xiaogpt.tts.volc import VolcTTS as VolcTTS
4
5
  from xiaogpt.tts.azure import AzureTTS
5
6
 
6
- __all__ = ["TTS", "EdgeTTS", "MiTTS", "AzureTTS"]
7
+ __all__ = ["TTS", "EdgeTTS", "MiTTS", "AzureTTS", "VolcTTS"]
@@ -0,0 +1,130 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+ import tempfile
5
+ from pathlib import Path
6
+ from typing import Optional
7
+ import json
8
+ import os
9
+ import time
10
+ import base64
11
+ import threading
12
+ import httpx
13
+
14
+ from volcengine.ApiInfo import ApiInfo
15
+ from volcengine.Credentials import Credentials
16
+ from volcengine.ServiceInfo import ServiceInfo
17
+ from volcengine.base.Service import Service
18
+
19
+
20
+ from xiaogpt.tts.base import AudioFileTTS
21
+ from xiaogpt.utils import calculate_tts_elapse
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class VolcTTS(AudioFileTTS):
27
+ def __init__(self, mina_service, device_id, config):
28
+ super().__init__(mina_service, device_id, config)
29
+ self.token = get_token(config)
30
+ self.client = httpx.Client()
31
+ logger.info("Initializing VolcTTS {self.token}")
32
+
33
+ async def make_audio_file(self, query: str, text: str) -> tuple[Path, float]:
34
+ tts_payload = json.dumps(
35
+ {
36
+ "text": text,
37
+ "speaker": self.config.volc_tts_speaker,
38
+ "audio_config": {
39
+ "format": "mp3",
40
+ "sample_rate": 24000,
41
+ "speech_rate": 0,
42
+ },
43
+ }
44
+ )
45
+
46
+ req = {
47
+ "appkey": self.config.volc_tts_app,
48
+ "token": self.token,
49
+ "namespace": "TTS",
50
+ "payload": tts_payload,
51
+ }
52
+
53
+ resp = self.client.post("https://sami.bytedance.com/api/v1/invoke", json=req)
54
+ try:
55
+ sami_resp = resp.json()
56
+ logger.info(f"volc sami_resp {resp.status_code}")
57
+ if resp.status_code != 200:
58
+ print(sami_resp)
59
+ except:
60
+ logger.error(f"Failed to get tts from volcengine with voice=zh {text}")
61
+
62
+ if sami_resp["status_code"] == 20000000 and len(sami_resp["data"]) > 0:
63
+ audio_data = base64.b64decode(sami_resp["data"])
64
+ with tempfile.NamedTemporaryFile(
65
+ suffix=".mp3", mode="wb", delete=False, dir=self.dirname.name
66
+ ) as f:
67
+ f.write(audio_data)
68
+
69
+ return Path(f.name), calculate_tts_elapse(text)
70
+
71
+
72
+ ## fetch token and save it to file
73
+ ## it's aimed to reduce the request to volcengine
74
+ ## it'll throw error if token is requested too frequently (more than 1 times per minute)
75
+ def get_token(config):
76
+ token_file = Path.home() / ".volc.token"
77
+ if not Path.exists(token_file):
78
+ token = request_token_data(config)
79
+ else:
80
+ with open(token_file, "r") as f:
81
+ token = json.load(f)
82
+ if token["expires_at"] < time.time():
83
+ token = request_token_data(config)
84
+
85
+ if not Path.exists(token_file):
86
+ with open(token_file, "w") as f:
87
+ json.dump(token, f)
88
+ return token["token"]
89
+
90
+
91
+ def request_token_data(config):
92
+ sami_service = SAMIService()
93
+ sami_service.set_ak(config.volc_accesskey)
94
+ sami_service.set_sk(config.volc_secretkey)
95
+
96
+ req = {
97
+ "appkey": config.volc_tts_app,
98
+ "token_version": "volc-auth-v1",
99
+ "expiration": 24 * 3600,
100
+ }
101
+ token = sami_service.common_json_handler("GetToken", req)
102
+ logger.info(f"Got token from volcengine {token}")
103
+ return token
104
+
105
+
106
+ class SAMIService(Service):
107
+ def __init__(self):
108
+ self.service_info = ServiceInfo(
109
+ "open.volcengineapi.com",
110
+ {},
111
+ Credentials("", "", "sami", "cn-north-1"),
112
+ 10,
113
+ 10,
114
+ )
115
+ self.api_info = {
116
+ "GetToken": ApiInfo(
117
+ "POST", "/", {"Action": "GetToken", "Version": "2021-07-27"}, {}, {}
118
+ ),
119
+ }
120
+ super(SAMIService, self).__init__(self.service_info, self.api_info)
121
+
122
+ def common_json_handler(self, api, body):
123
+ params = dict()
124
+ try:
125
+ body = json.dumps(body)
126
+ res = self.json(api, params, body)
127
+ res_json = json.loads(res)
128
+ return res_json
129
+ except Exception as e:
130
+ raise Exception(str(e))
@@ -23,7 +23,7 @@ from xiaogpt.config import (
23
23
  WAKEUP_KEYWORD,
24
24
  Config,
25
25
  )
26
- from xiaogpt.tts import TTS, EdgeTTS, MiTTS, AzureTTS
26
+ from xiaogpt.tts import TTS, EdgeTTS, MiTTS, AzureTTS, VolcTTS
27
27
  from xiaogpt.tts.openai import OpenAITTS
28
28
  from xiaogpt.utils import (
29
29
  parse_cookie_string,
@@ -62,7 +62,9 @@ class MiGPT:
62
62
  )
63
63
  new_record = await self.get_latest_ask_from_xiaoai(session)
64
64
  start = time.perf_counter()
65
- self.log.debug("Polling_event, timestamp: %s", self.last_timestamp)
65
+ self.log.debug(
66
+ "Polling_event, timestamp: %s %s", self.last_timestamp, new_record
67
+ )
66
68
  await self.polling_event.wait()
67
69
  if (
68
70
  self.config.mute_xiaoai
@@ -262,6 +264,8 @@ class MiGPT:
262
264
  return AzureTTS(self.mina_service, self.device_id, self.config)
263
265
  elif self.config.tts == "openai":
264
266
  return OpenAITTS(self.mina_service, self.device_id, self.config)
267
+ elif self.config.tts == "volc":
268
+ return VolcTTS(self.mina_service, self.device_id, self.config)
265
269
  else:
266
270
  return MiTTS(self.mina_service, self.device_id, self.config)
267
271
 
@@ -355,7 +359,6 @@ class MiGPT:
355
359
  new_record = await self.last_record.get()
356
360
  self.polling_event.clear() # stop polling when processing the question
357
361
  query = new_record.get("query", "").strip()
358
-
359
362
  if query == self.config.start_conversation:
360
363
  if not self.in_conversation:
361
364
  print("开始对话")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes