xiaogpt 2.42__py3-none-any.whl → 2.50__py3-none-any.whl

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.
xiaogpt/config.py CHANGED
@@ -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:
xiaogpt/tts/__init__.py CHANGED
@@ -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"]
xiaogpt/tts/volc.py ADDED
@@ -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))
xiaogpt/xiaogpt.py CHANGED
@@ -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,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
 
@@ -1,7 +1,7 @@
1
- xiaogpt-2.42.dist-info/METADATA,sha256=NEpOOqe2DKXkqji4SemjYNvNo7dTQ3tcP6O8InlT_hI,28865
2
- xiaogpt-2.42.dist-info/WHEEL,sha256=gZRWN_1fGFDwBnXrZ9N3dgvbKlKgo5AUcDIMajlGpKM,90
3
- xiaogpt-2.42.dist-info/entry_points.txt,sha256=zLFzA72qQ_eWBepdA2YU5vdXFqORH8wXhv2Ox1vnYP8,46
4
- xiaogpt-2.42.dist-info/licenses/LICENSE,sha256=XdClh516MvlnOf9749JZHCxSB7y6_fyXcWmLDz6IkZY,1063
1
+ xiaogpt-2.50.dist-info/METADATA,sha256=vRIqumlE_-ZX5cRlvJMOAOA2ap3DJe81s98p6ctH9SY,30311
2
+ xiaogpt-2.50.dist-info/WHEEL,sha256=7sv5iXvIiTVJSnAxCz2tGBm9DHsb2vPSzeYeT7pvGUY,90
3
+ xiaogpt-2.50.dist-info/entry_points.txt,sha256=zLFzA72qQ_eWBepdA2YU5vdXFqORH8wXhv2Ox1vnYP8,46
4
+ xiaogpt-2.50.dist-info/licenses/LICENSE,sha256=XdClh516MvlnOf9749JZHCxSB7y6_fyXcWmLDz6IkZY,1063
5
5
  xiaogpt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  xiaogpt/__main__.py,sha256=MSmt_5Xg84uHqzTN38JwgseJK8rsJn_11A8WD99VtEo,61
7
7
  xiaogpt/bot/__init__.py,sha256=7K9v6j6xDkuvIrJwjby0Ec_1ywd4Si0Ww9S_R8M3LeU,919
@@ -13,17 +13,18 @@ xiaogpt/bot/langchain_bot.py,sha256=4Uz5iOYzA2ongCklS-9zBse2fw-7kEE_9wITH7wdVCc,
13
13
  xiaogpt/bot/newbing_bot.py,sha256=afUmw6tyMXbgGZvfQQWaA5h0-e0V0isFolW-WGhd0Vs,2289
14
14
  xiaogpt/bot/qwen_bot.py,sha256=325lMa4Z38rRh47HDa3J4XjvSs4SWOqMVhrMWzkGNo4,3657
15
15
  xiaogpt/cli.py,sha256=GnRj-AawthaZ5oE2jUzp_ML64afsSBnGXFvbnaqgJHE,4738
16
- xiaogpt/config.py,sha256=bhaOdmAr18qe9mv2CtL64aJxtf_-_g_-dDI0C7pLdpE,6301
16
+ xiaogpt/config.py,sha256=4ZAhefT9ROKpYw6i_QK4C1dcm2o2rjoROO5WqxJk3ww,6726
17
17
  xiaogpt/langchain/callbacks.py,sha256=yR9AXQt9OHVYBWC47Q1I_BUT4Xg9iM44vnW2vv0BLpE,2616
18
18
  xiaogpt/langchain/chain.py,sha256=z0cqRlL0ElWnf31ByxZBN7AKOT-svXQDt5_NDft_nYc,1495
19
19
  xiaogpt/langchain/examples/email/mail_box.py,sha256=xauqrjE4-G4XPQnokUPE-MZgAaHQ_VrUDLlbfYTdCoo,6372
20
20
  xiaogpt/langchain/examples/email/mail_summary_tools.py,sha256=6cWvBJUaA7iaywcHdbUoww8WiCtaNw3TmwyxyF4DY7E,1561
21
- xiaogpt/tts/__init__.py,sha256=SZ0FVKbKVbuV7xfRtpwUt5cmqyNQaFa7LyGRYsmdDNE,220
21
+ xiaogpt/tts/__init__.py,sha256=N-mg521hRDByAPXts1Dl8EQVLEYQI7D2iWDIQ7ILLNE,279
22
22
  xiaogpt/tts/azure.py,sha256=JuE1wirQQAsYnnHmlc3sziuVXQUU0yGeGt5cHgiY388,3979
23
23
  xiaogpt/tts/base.py,sha256=a7J5cpcDNefr7deXJQWwDKw9XPFm6EQQL9O-GLe23hM,4660
24
24
  xiaogpt/tts/edge.py,sha256=yMFGxRTi086XS1d_mbMzQ365bvG4KgAz8ZptaoDAfGU,1172
25
25
  xiaogpt/tts/mi.py,sha256=9HkgGWByAs7k8sTpRdVlgJnnmjc44RNAccJa6tGDlXk,1096
26
26
  xiaogpt/tts/openai.py,sha256=_Qk12zYY-UuXLKvQVe3PqIvCmoRW9OcVCqQRoGCXvNc,1533
27
+ xiaogpt/tts/volc.py,sha256=fLN7Z5HXx9TCkhGKWyTXasUcXn_fSlTNjVccvQunLUM,3984
27
28
  xiaogpt/utils.py,sha256=B7NCH7g19hcwHDXsnBJPTU6UcWnXoEntKWm-pgcet2I,2072
28
- xiaogpt/xiaogpt.py,sha256=YyDTm5DaO_US7cJOg-nPcjdQ_Xug0-tT3yQWg9APpBs,15337
29
- xiaogpt-2.42.dist-info/RECORD,,
29
+ xiaogpt/xiaogpt.py,sha256=dF_G26axLD9htLbFfHLMTLf2gaIdvAHkU88-s4RSmOs,15513
30
+ xiaogpt-2.50.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: pdm-backend (2.2.0)
2
+ Generator: pdm-backend (2.2.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any