xiaogpt 2.41__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 (30) hide show
  1. {xiaogpt-2.41 → xiaogpt-2.50}/PKG-INFO +116 -33
  2. {xiaogpt-2.41 → xiaogpt-2.50}/README.md +15 -27
  3. xiaogpt-2.50/pyproject.toml +165 -0
  4. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/config.py +10 -0
  5. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/__init__.py +2 -1
  6. xiaogpt-2.50/xiaogpt/tts/volc.py +130 -0
  7. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/xiaogpt.py +6 -3
  8. xiaogpt-2.41/pyproject.toml +0 -65
  9. {xiaogpt-2.41 → xiaogpt-2.50}/LICENSE +0 -0
  10. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/__init__.py +0 -0
  11. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/__main__.py +0 -0
  12. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/__init__.py +0 -0
  13. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/base_bot.py +0 -0
  14. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/chatgptapi_bot.py +0 -0
  15. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/gemini_bot.py +0 -0
  16. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/glm_bot.py +0 -0
  17. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/langchain_bot.py +0 -0
  18. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/newbing_bot.py +0 -0
  19. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/bot/qwen_bot.py +0 -0
  20. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/cli.py +0 -0
  21. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/langchain/callbacks.py +0 -0
  22. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/langchain/chain.py +0 -0
  23. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/langchain/examples/email/mail_box.py +0 -0
  24. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/langchain/examples/email/mail_summary_tools.py +0 -0
  25. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/azure.py +0 -0
  26. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/base.py +0 -0
  27. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/edge.py +0 -0
  28. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/mi.py +0 -0
  29. {xiaogpt-2.41 → xiaogpt-2.50}/xiaogpt/tts/openai.py +0 -0
  30. {xiaogpt-2.41 → 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.41
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
@@ -13,8 +13,8 @@ Requires-Dist: miservice_fork
13
13
  Requires-Dist: openai>=1
14
14
  Requires-Dist: aiohttp
15
15
  Requires-Dist: rich
16
- Requires-Dist: zhipuai==2.0.1
17
- Requires-Dist: httpx==0.24.1
16
+ Requires-Dist: zhipuai>=2.0.1
17
+ Requires-Dist: httpx[socks]
18
18
  Requires-Dist: edge-tts>=6.1.3
19
19
  Requires-Dist: EdgeGPT==0.1.26
20
20
  Requires-Dist: langchain>=0.0.343
@@ -22,10 +22,105 @@ Requires-Dist: beautifulsoup4>=4.12.0
22
22
  Requires-Dist: google-search-results>=2.4.2
23
23
  Requires-Dist: google-generativeai
24
24
  Requires-Dist: numexpr>=2.8.6
25
- Requires-Dist: dashscope==1.10.0
26
- Requires-Dist: httpcore==0.15.0
27
- Requires-Dist: idna==3.7
25
+ Requires-Dist: dashscope>=1.10.0
28
26
  Requires-Dist: azure-cognitiveservices-speech>=1.37.0
27
+ Requires-Dist: multidict>=6.0.5
28
+ Requires-Dist: volcengine>=1.0.136
29
+ Requires-Dist: aiohttp==3.9.4; extra == "locked"
30
+ Requires-Dist: aiosignal==1.3.1; extra == "locked"
31
+ Requires-Dist: annotated-types==0.6.0; extra == "locked"
32
+ Requires-Dist: anyio==3.7.1; extra == "locked"
33
+ Requires-Dist: async-timeout==4.0.3; python_version < "3.11" and extra == "locked"
34
+ Requires-Dist: attrs==23.2.0; extra == "locked"
35
+ Requires-Dist: azure-cognitiveservices-speech==1.37.0; extra == "locked"
36
+ Requires-Dist: beautifulsoup4==4.12.3; extra == "locked"
37
+ Requires-Dist: bingimagecreator==0.5.0; extra == "locked"
38
+ Requires-Dist: cachetools==5.3.2; extra == "locked"
39
+ Requires-Dist: certifi==2024.2.2; extra == "locked"
40
+ Requires-Dist: charset-normalizer==3.3.2; extra == "locked"
41
+ Requires-Dist: colorama==0.4.6; platform_system == "Windows" and extra == "locked"
42
+ Requires-Dist: dashscope==1.10.0; extra == "locked"
43
+ Requires-Dist: dataclasses-json==0.6.3; extra == "locked"
44
+ Requires-Dist: decorator==5.1.1; extra == "locked"
45
+ Requires-Dist: distro==1.9.0; extra == "locked"
46
+ Requires-Dist: edge-tts==6.1.10; extra == "locked"
47
+ Requires-Dist: edgegpt==0.1.26; extra == "locked"
48
+ Requires-Dist: exceptiongroup==1.2.0; python_version < "3.11" and extra == "locked"
49
+ Requires-Dist: frozenlist==1.4.1; extra == "locked"
50
+ Requires-Dist: google==3.0.0; extra == "locked"
51
+ Requires-Dist: google-ai-generativelanguage==0.6.1; extra == "locked"
52
+ Requires-Dist: google-api-core==2.15.0; extra == "locked"
53
+ Requires-Dist: google-api-core[grpc]==2.15.0; extra == "locked"
54
+ Requires-Dist: google-api-python-client==2.125.0; extra == "locked"
55
+ Requires-Dist: google-auth==2.26.1; extra == "locked"
56
+ Requires-Dist: google-auth-httplib2==0.2.0; extra == "locked"
57
+ Requires-Dist: google-generativeai==0.5.0; extra == "locked"
58
+ Requires-Dist: google-search-results==2.4.2; extra == "locked"
59
+ Requires-Dist: googleapis-common-protos==1.62.0; extra == "locked"
60
+ Requires-Dist: greenlet==3.0.3; (platform_machine == "win32" or platform_machine == "WIN32" or platform_machine == "AMD64" or platform_machine == "amd64" or platform_machine == "x86_64" or platform_machine == "ppc64le" or platform_machine == "aarch64") and extra == "locked"
61
+ Requires-Dist: grpcio==1.60.0; extra == "locked"
62
+ Requires-Dist: grpcio-status==1.60.0; extra == "locked"
63
+ Requires-Dist: h11==0.14.0; extra == "locked"
64
+ Requires-Dist: httpcore==1.0.5; extra == "locked"
65
+ Requires-Dist: httplib2==0.22.0; extra == "locked"
66
+ Requires-Dist: httpx==0.27.0; extra == "locked"
67
+ Requires-Dist: httpx[socks]==0.27.0; extra == "locked"
68
+ Requires-Dist: idna==3.7; extra == "locked"
69
+ Requires-Dist: jsonpatch==1.33; extra == "locked"
70
+ Requires-Dist: jsonpointer==2.4; extra == "locked"
71
+ Requires-Dist: langchain==0.1.16; extra == "locked"
72
+ Requires-Dist: langchain-community==0.0.32; extra == "locked"
73
+ Requires-Dist: langchain-core==0.1.42; extra == "locked"
74
+ Requires-Dist: langchain-text-splitters==0.0.1; extra == "locked"
75
+ Requires-Dist: langsmith==0.1.45; extra == "locked"
76
+ Requires-Dist: markdown-it-py==3.0.0; extra == "locked"
77
+ Requires-Dist: marshmallow==3.20.1; extra == "locked"
78
+ Requires-Dist: mdurl==0.1.2; extra == "locked"
79
+ Requires-Dist: miservice-fork==2.4.3; extra == "locked"
80
+ Requires-Dist: multidict==6.0.5; extra == "locked"
81
+ Requires-Dist: mutagen==1.47.0; extra == "locked"
82
+ Requires-Dist: mypy-extensions==1.0.0; extra == "locked"
83
+ Requires-Dist: numexpr==2.10.0; extra == "locked"
84
+ Requires-Dist: numpy==1.26.3; extra == "locked"
85
+ Requires-Dist: openai==1.17.1; extra == "locked"
86
+ Requires-Dist: orjson==3.10.0; extra == "locked"
87
+ Requires-Dist: packaging==23.2; extra == "locked"
88
+ Requires-Dist: prompt-toolkit==3.0.43; extra == "locked"
89
+ Requires-Dist: proto-plus==1.23.0; extra == "locked"
90
+ Requires-Dist: protobuf==4.25.1; extra == "locked"
91
+ Requires-Dist: py==1.11.0; extra == "locked"
92
+ Requires-Dist: pyasn1==0.5.1; extra == "locked"
93
+ Requires-Dist: pyasn1-modules==0.3.0; extra == "locked"
94
+ Requires-Dist: pycryptodome==3.9.9; extra == "locked"
95
+ Requires-Dist: pydantic==2.5.3; extra == "locked"
96
+ Requires-Dist: pydantic-core==2.14.6; extra == "locked"
97
+ Requires-Dist: pygments==2.17.2; extra == "locked"
98
+ Requires-Dist: pyjwt==2.8.0; extra == "locked"
99
+ Requires-Dist: pyparsing==3.1.2; python_version > "3.0" and extra == "locked"
100
+ Requires-Dist: pytz==2020.5; extra == "locked"
101
+ Requires-Dist: pyyaml==6.0.1; extra == "locked"
102
+ Requires-Dist: regex==2023.12.25; extra == "locked"
103
+ Requires-Dist: requests==2.31.0; extra == "locked"
104
+ Requires-Dist: retry==0.9.2; extra == "locked"
105
+ Requires-Dist: rich==13.7.1; extra == "locked"
106
+ Requires-Dist: rsa==4.9; extra == "locked"
107
+ Requires-Dist: six==1.16.0; extra == "locked"
108
+ Requires-Dist: sniffio==1.3.0; extra == "locked"
109
+ Requires-Dist: socksio==1.0.0; extra == "locked"
110
+ Requires-Dist: soupsieve==2.5; extra == "locked"
111
+ Requires-Dist: sqlalchemy==2.0.25; extra == "locked"
112
+ Requires-Dist: tenacity==8.2.3; extra == "locked"
113
+ Requires-Dist: tqdm==4.66.1; extra == "locked"
114
+ Requires-Dist: typing-extensions==4.9.0; extra == "locked"
115
+ Requires-Dist: typing-inspect==0.9.0; extra == "locked"
116
+ Requires-Dist: uritemplate==4.1.1; extra == "locked"
117
+ Requires-Dist: urllib3==2.1.0; extra == "locked"
118
+ Requires-Dist: volcengine==1.0.136; extra == "locked"
119
+ Requires-Dist: wcwidth==0.2.13; extra == "locked"
120
+ Requires-Dist: websockets==12.0; extra == "locked"
121
+ Requires-Dist: yarl==1.9.4; extra == "locked"
122
+ Requires-Dist: zhipuai==2.0.1; extra == "locked"
123
+ Provides-Extra: locked
29
124
  Description-Content-Type: text/markdown
30
125
 
31
126
  # xiaogpt
@@ -49,32 +144,15 @@ Play ChatGPT and other LLM with Xiaomi AI Speaker
49
144
  - [通义千问](https://help.aliyun.com/zh/dashscope/developer-reference/api-details)
50
145
 
51
146
  ## 获取小米音响DID
52
- ### Windows(使用 set 设置环境变量)
53
- ```cmd
54
- pip install miservice_fork
55
- set MI_USER=xxxx
56
- set MI_PASS=xxx
57
- micli list 得到did
58
- set MI_DID=xxxx
59
- ```
60
-
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赋值时,可能需要双引号来包括值。
61
155
  - 如果获取did报错时,请更换一下无线网络,有很大概率解决问题。
62
-
63
- ### Linux(使用 export 设置环境变量)
64
- ```sh
65
- # 1、安装模块
66
- pip install miservice_fork
67
-
68
- # 2、设置环境用户参数
69
- export MI_USER=xxxx
70
- export MI_PASS=xxx
71
-
72
- # 3、使用micli list 得到did
73
- micli list
74
-
75
- # 4、根据did设置环境DID参数
76
- export MI_DID=xxxx
77
- ```
78
156
 
79
157
  ## 一点原理
80
158
 
@@ -89,7 +167,7 @@ export MI_DID=xxxx
89
167
 
90
168
  ## 使用
91
169
 
92
- - `pip install -U --force-reinstall xiaogpt`
170
+ - `pip install -U --force-reinstall xiaogpt[locked]`
93
171
  - 参考我 fork 的 [MiService](https://github.com/yihong0618/MiService) 项目 README 并在本地 terminal 跑 `micli list` 拿到你音响的 DID 成功 **别忘了设置 export MI_DID=xxx** 这个 MI_DID 用
94
172
  - run `xiaogpt --hardware ${your_hardware} --use_chatgpt_api` hardware 你看小爱屁股上有型号,输入进来,如果在屁股上找不到或者型号不对,可以用 `micli mina` 找到型号
95
173
  - 跑起来之后就可以问小爱同学问题了,“帮我"开头的问题,会发送一份给 ChatGPT 然后小爱同学用 tts 回答
@@ -209,7 +287,7 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
209
287
  | mute_xiaoai | 快速停掉小爱自己的回答 | `true` | |
210
288
  | verbose | 是否打印详细日志 | `false` | |
211
289
  | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
212
- | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure` |
290
+ | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure`、`volc` |
213
291
  | tts_voice | TTS 的嗓音 | `zh-CN-XiaoxiaoNeural`(edge), `alloy`(openai), `zh-CN-XiaoxiaoMultilingualNeural`(azure) | |
214
292
  | prompt | 自定义prompt | `请用100字以内回答` | |
215
293
  | keyword | 自定义请求词列表 | `["请"]` | |
@@ -225,6 +303,11 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
225
303
  | api_base | 如果需要替换默认的api,或者使用Azure OpenAI 服务 | 例如:`https://abc-def.openai.azure.com/` | |
226
304
  | azure_tts_speech_key | Azure TTS key | null | |
227
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
+
228
311
 
229
312
  [这里]: https://github.com/acheong08/EdgeGPT#getting-authentication-required
230
313
 
@@ -19,32 +19,15 @@ 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
-
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
31
 
49
32
  ## 一点原理
50
33
 
@@ -59,7 +42,7 @@ export MI_DID=xxxx
59
42
 
60
43
  ## 使用
61
44
 
62
- - `pip install -U --force-reinstall xiaogpt`
45
+ - `pip install -U --force-reinstall xiaogpt[locked]`
63
46
  - 参考我 fork 的 [MiService](https://github.com/yihong0618/MiService) 项目 README 并在本地 terminal 跑 `micli list` 拿到你音响的 DID 成功 **别忘了设置 export MI_DID=xxx** 这个 MI_DID 用
64
47
  - run `xiaogpt --hardware ${your_hardware} --use_chatgpt_api` hardware 你看小爱屁股上有型号,输入进来,如果在屁股上找不到或者型号不对,可以用 `micli mina` 找到型号
65
48
  - 跑起来之后就可以问小爱同学问题了,“帮我"开头的问题,会发送一份给 ChatGPT 然后小爱同学用 tts 回答
@@ -179,7 +162,7 @@ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
179
162
  | mute_xiaoai | 快速停掉小爱自己的回答 | `true` | |
180
163
  | verbose | 是否打印详细日志 | `false` | |
181
164
  | bot | 使用的 bot 类型,目前支持 chatgptapi,newbing, qwen, gemini | `chatgptapi` | |
182
- | tts | 使用的 TTS 类型 | `mi` | `edge`、 `openai`、`azure` |
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
 
@@ -0,0 +1,165 @@
1
+ [project]
2
+ name = "xiaogpt"
3
+ description = "Play ChatGPT or other LLM with xiaomi AI speaker"
4
+ readme = "README.md"
5
+ authors = [
6
+ { name = "yihong0618", email = "zouzou0208@gmail.com" },
7
+ ]
8
+ classifiers = [
9
+ "License :: OSI Approved :: MIT License",
10
+ "Operating System :: OS Independent",
11
+ "Programming Language :: Python :: 3",
12
+ ]
13
+ requires-python = ">=3.9"
14
+ dependencies = [
15
+ "miservice_fork",
16
+ "openai>=1",
17
+ "aiohttp",
18
+ "rich",
19
+ "zhipuai>=2.0.1",
20
+ "httpx[socks]",
21
+ "edge-tts>=6.1.3",
22
+ "EdgeGPT==0.1.26",
23
+ "langchain>=0.0.343",
24
+ "beautifulsoup4>=4.12.0",
25
+ "google-search-results>=2.4.2",
26
+ "google-generativeai",
27
+ "numexpr>=2.8.6",
28
+ "dashscope>=1.10.0",
29
+ "azure-cognitiveservices-speech>=1.37.0",
30
+ "multidict>=6.0.5",
31
+ "volcengine>=1.0.136",
32
+ ]
33
+ dynamic = []
34
+ version = "2.50"
35
+
36
+ [project.license]
37
+ text = "MIT"
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/yihong0618/xiaogpt"
41
+
42
+ [project.scripts]
43
+ xiaogpt = "xiaogpt.cli:main"
44
+
45
+ [project.optional-dependencies]
46
+ locked = [
47
+ "aiohttp==3.9.4",
48
+ "aiosignal==1.3.1",
49
+ "annotated-types==0.6.0",
50
+ "anyio==3.7.1",
51
+ "async-timeout==4.0.3 ; python_version < \"3.11\"",
52
+ "attrs==23.2.0",
53
+ "azure-cognitiveservices-speech==1.37.0",
54
+ "beautifulsoup4==4.12.3",
55
+ "bingimagecreator==0.5.0",
56
+ "cachetools==5.3.2",
57
+ "certifi==2024.2.2",
58
+ "charset-normalizer==3.3.2",
59
+ "colorama==0.4.6 ; platform_system == \"Windows\"",
60
+ "dashscope==1.10.0",
61
+ "dataclasses-json==0.6.3",
62
+ "decorator==5.1.1",
63
+ "distro==1.9.0",
64
+ "edge-tts==6.1.10",
65
+ "edgegpt==0.1.26",
66
+ "exceptiongroup==1.2.0 ; python_version < \"3.11\"",
67
+ "frozenlist==1.4.1",
68
+ "google==3.0.0",
69
+ "google-ai-generativelanguage==0.6.1",
70
+ "google-api-core==2.15.0",
71
+ "google-api-core[grpc]==2.15.0",
72
+ "google-api-python-client==2.125.0",
73
+ "google-auth==2.26.1",
74
+ "google-auth-httplib2==0.2.0",
75
+ "google-generativeai==0.5.0",
76
+ "google-search-results==2.4.2",
77
+ "googleapis-common-protos==1.62.0",
78
+ "greenlet==3.0.3 ; platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\"",
79
+ "grpcio==1.60.0",
80
+ "grpcio-status==1.60.0",
81
+ "h11==0.14.0",
82
+ "httpcore==1.0.5",
83
+ "httplib2==0.22.0",
84
+ "httpx==0.27.0",
85
+ "httpx[socks]==0.27.0",
86
+ "idna==3.7",
87
+ "jsonpatch==1.33",
88
+ "jsonpointer==2.4",
89
+ "langchain==0.1.16",
90
+ "langchain-community==0.0.32",
91
+ "langchain-core==0.1.42",
92
+ "langchain-text-splitters==0.0.1",
93
+ "langsmith==0.1.45",
94
+ "markdown-it-py==3.0.0",
95
+ "marshmallow==3.20.1",
96
+ "mdurl==0.1.2",
97
+ "miservice-fork==2.4.3",
98
+ "multidict==6.0.5",
99
+ "mutagen==1.47.0",
100
+ "mypy-extensions==1.0.0",
101
+ "numexpr==2.10.0",
102
+ "numpy==1.26.3",
103
+ "openai==1.17.1",
104
+ "orjson==3.10.0",
105
+ "packaging==23.2",
106
+ "prompt-toolkit==3.0.43",
107
+ "proto-plus==1.23.0",
108
+ "protobuf==4.25.1",
109
+ "py==1.11.0",
110
+ "pyasn1==0.5.1",
111
+ "pyasn1-modules==0.3.0",
112
+ "pycryptodome==3.9.9",
113
+ "pydantic==2.5.3",
114
+ "pydantic-core==2.14.6",
115
+ "pygments==2.17.2",
116
+ "pyjwt==2.8.0",
117
+ "pyparsing==3.1.2 ; python_version > \"3.0\"",
118
+ "pytz==2020.5",
119
+ "pyyaml==6.0.1",
120
+ "regex==2023.12.25",
121
+ "requests==2.31.0",
122
+ "retry==0.9.2",
123
+ "rich==13.7.1",
124
+ "rsa==4.9",
125
+ "six==1.16.0",
126
+ "sniffio==1.3.0",
127
+ "socksio==1.0.0",
128
+ "soupsieve==2.5",
129
+ "sqlalchemy==2.0.25",
130
+ "tenacity==8.2.3",
131
+ "tqdm==4.66.1",
132
+ "typing-extensions==4.9.0",
133
+ "typing-inspect==0.9.0",
134
+ "uritemplate==4.1.1",
135
+ "urllib3==2.1.0",
136
+ "volcengine==1.0.136",
137
+ "wcwidth==0.2.13",
138
+ "websockets==12.0",
139
+ "yarl==1.9.4",
140
+ "zhipuai==2.0.1",
141
+ ]
142
+
143
+ [tool.pdm]
144
+ plugins = [
145
+ "pdm-autoexport",
146
+ ]
147
+ autoexport = [
148
+ { filename = "requirements.txt", without-hashes = true },
149
+ ]
150
+
151
+ [tool.pdm.version]
152
+ source = "scm"
153
+
154
+ [tool.pdm.build]
155
+ includes = [
156
+ "xiaogpt/",
157
+ ]
158
+ locked = true
159
+
160
+ [build-system]
161
+ requires = [
162
+ "pdm-backend>=2.0.0",
163
+ "pdm-build-locked",
164
+ ]
165
+ build-backend = "pdm.backend"
@@ -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("开始对话")
@@ -1,65 +0,0 @@
1
- [project]
2
- name = "xiaogpt"
3
- description = "Play ChatGPT or other LLM with xiaomi AI speaker"
4
- readme = "README.md"
5
- authors = [
6
- { name = "yihong0618", email = "zouzou0208@gmail.com" },
7
- ]
8
- classifiers = [
9
- "License :: OSI Approved :: MIT License",
10
- "Operating System :: OS Independent",
11
- "Programming Language :: Python :: 3",
12
- ]
13
- requires-python = ">=3.9"
14
- dependencies = [
15
- "miservice_fork",
16
- "openai>=1",
17
- "aiohttp",
18
- "rich",
19
- "zhipuai==2.0.1",
20
- "httpx==0.24.1",
21
- "edge-tts>=6.1.3",
22
- "EdgeGPT==0.1.26",
23
- "langchain>=0.0.343",
24
- "beautifulsoup4>=4.12.0",
25
- "google-search-results>=2.4.2",
26
- "google-generativeai",
27
- "numexpr>=2.8.6",
28
- "dashscope==1.10.0",
29
- "httpcore==0.15.0",
30
- "idna==3.7",
31
- "azure-cognitiveservices-speech>=1.37.0",
32
- ]
33
- dynamic = []
34
- version = "2.41"
35
-
36
- [project.license]
37
- text = "MIT"
38
-
39
- [project.urls]
40
- Homepage = "https://github.com/yihong0618/xiaogpt"
41
-
42
- [project.scripts]
43
- xiaogpt = "xiaogpt.cli:main"
44
-
45
- [tool.pdm]
46
- plugins = [
47
- "pdm-autoexport",
48
- ]
49
- autoexport = [
50
- { filename = "requirements.txt", without-hashes = true },
51
- ]
52
-
53
- [tool.pdm.version]
54
- source = "scm"
55
-
56
- [tool.pdm.build]
57
- includes = [
58
- "xiaogpt/",
59
- ]
60
-
61
- [build-system]
62
- requires = [
63
- "pdm-backend>=2.0.0",
64
- ]
65
- build-backend = "pdm.backend"
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