xiaogpt 1.50__tar.gz → 1.60__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.
@@ -1,3 +1,24 @@
1
+ Metadata-Version: 2.1
2
+ Name: xiaogpt
3
+ Version: 1.60
4
+ Summary: Play ChatGPT or other LLM with xiaomi AI speaker
5
+ Author-Email: yihong0618 <zouzou0208@gmail.com>
6
+ License: MIT
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python :: 3
10
+ Project-URL: Homepage, https://github.com/yihong0618/xiaogpt
11
+ Requires-Python: >=3.7.1
12
+ Requires-Dist: miservice_fork
13
+ Requires-Dist: openai
14
+ Requires-Dist: aiohttp
15
+ Requires-Dist: rich
16
+ Requires-Dist: zhipuai
17
+ Requires-Dist: bardapi
18
+ Requires-Dist: edge-tts>=6.1.3
19
+ Requires-Dist: EdgeGPT==0.1.26
20
+ Description-Content-Type: text/markdown
21
+
1
22
  # xiaogpt
2
23
 
3
24
  [![PyPI](https://img.shields.io/pypi/v/xiaogpt?style=flat-square)](https://pypi.org/project/xiaogpt)
@@ -17,6 +38,7 @@ Play ChatGPT with Xiaomi AI Speaker
17
38
  - GPT3
18
39
  - ChatGPT
19
40
  - New Bing
41
+ - [ChatGLM](http://open.bigmodel.cn/)
20
42
 
21
43
  ## Windows 获取小米音响DID
22
44
 
@@ -91,6 +113,11 @@ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --stream
91
113
  # 如果你想使用 gpt3 ai
92
114
  export OPENAI_API_KEY=${your_api_key}
93
115
  python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_gpt3
116
+
117
+ # 如果你想使用 ChatGLM api
118
+ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_glm --glm_key ${glm_key}
119
+ # 如果你想使用 google 的 bard
120
+ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_bard --bard_token ${bard_token}
94
121
  ```
95
122
 
96
123
  ## config.json
@@ -122,6 +149,8 @@ python3 xiaogpt.py
122
149
  ```
123
150
 
124
151
  具体参数作用请参考 [Open AI API 文档](https://platform.openai.com/docs/api-reference/chat/create)。
152
+ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
153
+ Bard-API [参考](https://github.com/dsdanielpark/Bard-API)
125
154
  ## 配置项说明
126
155
 
127
156
  | 参数 | 说明 | 默认值 |
@@ -130,6 +159,8 @@ python3 xiaogpt.py
130
159
  | account | 小爱账户 | |
131
160
  | password | 小爱账户密码 | |
132
161
  | openai_key | openai的apikey | |
162
+ | glm_key | chatglm 的 apikey | |
163
+ | bard_token | bard 的 token 参考 [Bard-API](https://github.com/dsdanielpark/Bard-API) | |
133
164
  | cookie | 小爱账户cookie (如果用上面密码登录可以不填) | |
134
165
  | mi_did | 设备did | |
135
166
  | use_command | 使用 MI command 与小爱交互 | `false` |
@@ -1,22 +1,3 @@
1
- Metadata-Version: 2.1
2
- Name: xiaogpt
3
- Version: 1.50
4
- Summary: Play ChatGPT with xiaomi AI speaker
5
- Author-Email: yihong0618 <zouzou0208@gmail.com>
6
- License: MIT
7
- Classifier: License :: OSI Approved :: MIT License
8
- Classifier: Operating System :: OS Independent
9
- Classifier: Programming Language :: Python :: 3
10
- Project-URL: Homepage, https://github.com/yihong0618/xiaogpt
11
- Requires-Python: >=3.7.1
12
- Requires-Dist: miservice_fork
13
- Requires-Dist: openai
14
- Requires-Dist: aiohttp
15
- Requires-Dist: rich
16
- Requires-Dist: edge-tts>=6.1.3
17
- Requires-Dist: EdgeGPT==0.1.26
18
- Description-Content-Type: text/markdown
19
-
20
1
  # xiaogpt
21
2
 
22
3
  [![PyPI](https://img.shields.io/pypi/v/xiaogpt?style=flat-square)](https://pypi.org/project/xiaogpt)
@@ -36,6 +17,7 @@ Play ChatGPT with Xiaomi AI Speaker
36
17
  - GPT3
37
18
  - ChatGPT
38
19
  - New Bing
20
+ - [ChatGLM](http://open.bigmodel.cn/)
39
21
 
40
22
  ## Windows 获取小米音响DID
41
23
 
@@ -110,6 +92,11 @@ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --stream
110
92
  # 如果你想使用 gpt3 ai
111
93
  export OPENAI_API_KEY=${your_api_key}
112
94
  python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_gpt3
95
+
96
+ # 如果你想使用 ChatGLM api
97
+ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_glm --glm_key ${glm_key}
98
+ # 如果你想使用 google 的 bard
99
+ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_bard --bard_token ${bard_token}
113
100
  ```
114
101
 
115
102
  ## config.json
@@ -141,6 +128,8 @@ python3 xiaogpt.py
141
128
  ```
142
129
 
143
130
  具体参数作用请参考 [Open AI API 文档](https://platform.openai.com/docs/api-reference/chat/create)。
131
+ ChatGLM [文档](http://open.bigmodel.cn/doc/api#chatglm_130b)
132
+ Bard-API [参考](https://github.com/dsdanielpark/Bard-API)
144
133
  ## 配置项说明
145
134
 
146
135
  | 参数 | 说明 | 默认值 |
@@ -149,6 +138,8 @@ python3 xiaogpt.py
149
138
  | account | 小爱账户 | |
150
139
  | password | 小爱账户密码 | |
151
140
  | openai_key | openai的apikey | |
141
+ | glm_key | chatglm 的 apikey | |
142
+ | bard_token | bard 的 token 参考 [Bard-API](https://github.com/dsdanielpark/Bard-API) | |
152
143
  | cookie | 小爱账户cookie (如果用上面密码登录可以不填) | |
153
144
  | mi_did | 设备did | |
154
145
  | use_command | 使用 MI command 与小爱交互 | `false` |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "xiaogpt"
3
- description = "Play ChatGPT with xiaomi AI speaker"
3
+ description = "Play ChatGPT or other LLM with xiaomi AI speaker"
4
4
  readme = "README.md"
5
5
  authors = [
6
6
  { name = "yihong0618", email = "zouzou0208@gmail.com" },
@@ -16,11 +16,13 @@ dependencies = [
16
16
  "openai",
17
17
  "aiohttp",
18
18
  "rich",
19
+ "zhipuai",
20
+ "bardapi",
19
21
  "edge-tts>=6.1.3",
20
22
  "EdgeGPT==0.1.26",
21
23
  ]
22
24
  dynamic = []
23
- version = "1.50"
25
+ version = "1.60"
24
26
 
25
27
  [project.license]
26
28
  text = "MIT"
@@ -4,12 +4,16 @@ from xiaogpt.bot.base_bot import BaseBot
4
4
  from xiaogpt.bot.chatgptapi_bot import ChatGPTBot
5
5
  from xiaogpt.bot.gpt3_bot import GPT3Bot
6
6
  from xiaogpt.bot.newbing_bot import NewBingBot
7
+ from xiaogpt.bot.glm_bot import GLMBot
8
+ from xiaogpt.bot.bard_bot import BardBot
7
9
  from xiaogpt.config import Config
8
10
 
9
11
  BOTS: dict[str, type[BaseBot]] = {
10
12
  "gpt3": GPT3Bot,
11
13
  "newbing": NewBingBot,
12
14
  "chatgptapi": ChatGPTBot,
15
+ "glm": GLMBot,
16
+ "bard": BardBot,
13
17
  }
14
18
 
15
19
 
@@ -20,4 +24,4 @@ def get_bot(config: Config) -> BaseBot:
20
24
  raise ValueError(f"Unsupported bot {config.bot}, must be one of {list(BOTS)}")
21
25
 
22
26
 
23
- __all__ = ["GPT3Bot", "ChatGPTBot", "NewBingBot", "get_bot"]
27
+ __all__ = ["GPT3Bot", "ChatGPTBot", "NewBingBot", "GLMBot", "BardBot", "get_bot"]
@@ -0,0 +1,32 @@
1
+ """ChatGLM bot"""
2
+ from __future__ import annotations
3
+ from typing import Any
4
+
5
+ from bardapi import BardAsync
6
+ from rich import print
7
+
8
+ from xiaogpt.bot.base_bot import BaseBot
9
+
10
+
11
+ class BardBot(BaseBot):
12
+ def __init__(
13
+ self,
14
+ bard_token: str,
15
+ ) -> None:
16
+ self._bot = BardAsync(token=bard_token)
17
+ self.history = []
18
+
19
+ @classmethod
20
+ def from_config(cls, config):
21
+ return cls(bard_token=config.bard_token)
22
+
23
+ async def ask(self, query, **options):
24
+ try:
25
+ r = await self._bot.get_answer(query)
26
+ except Exception as e:
27
+ print(str(e))
28
+ print(r["content"])
29
+ return r["content"]
30
+
31
+ def ask_stream(self, query: str, **options: Any):
32
+ raise Exception("Bard do not support stream")
@@ -48,7 +48,11 @@ class ChatGPTBot(BaseBot):
48
48
  ms.append({"role": "assistant", "content": h[1]})
49
49
  ms.append({"role": "user", "content": f"{query}"})
50
50
  kwargs = {**self.default_options, **options}
51
- completion = await openai.ChatCompletion.acreate(messages=ms, **kwargs)
51
+ try:
52
+ completion = await openai.ChatCompletion.acreate(messages=ms, **kwargs)
53
+ except Exception as e:
54
+ print(str(e))
55
+ return ""
52
56
  message = (
53
57
  completion["choices"][0]
54
58
  .get("message")
@@ -72,9 +76,13 @@ class ChatGPTBot(BaseBot):
72
76
  kwargs = {"model": "gpt-3.5-turbo", **options}
73
77
  if openai.api_type == "azure":
74
78
  kwargs["deployment_id"] = self.deployment_id
75
- completion = await openai.ChatCompletion.acreate(
76
- messages=ms, stream=True, **kwargs
77
- )
79
+ try:
80
+ completion = await openai.ChatCompletion.acreate(
81
+ messages=ms, stream=True, **kwargs
82
+ )
83
+ except Exception as e:
84
+ print(str(e))
85
+ return
78
86
 
79
87
  async def text_gen():
80
88
  async for event in completion:
@@ -0,0 +1,50 @@
1
+ """ChatGLM bot"""
2
+ from __future__ import annotations
3
+ from typing import Any, AsyncGenerator
4
+
5
+ import zhipuai
6
+ from rich import print
7
+
8
+ from xiaogpt.bot.base_bot import BaseBot
9
+
10
+
11
+ class GLMBot(BaseBot):
12
+ default_options = {"model": "chatglm_130b"}
13
+
14
+ def __init__(
15
+ self,
16
+ glm_key: str,
17
+ ) -> None:
18
+ self.history = []
19
+ zhipuai.api_key = glm_key
20
+
21
+ @classmethod
22
+ def from_config(cls, config):
23
+ return cls(glm_key=config.glm_key)
24
+
25
+ def ask(self, query, **options):
26
+ ms = []
27
+ for h in self.history:
28
+ ms.append({"role": "user", "content": h[0]})
29
+ ms.append({"role": "assistant", "content": h[1]})
30
+ kwargs = {**self.default_options, **options}
31
+ kwargs["prompt"] = ms
32
+ ms.append({"role": "user", "content": f"{query}"})
33
+ try:
34
+ r = zhipuai.model_api.sse_invoke(**kwargs)
35
+ except Exception as e:
36
+ print(str(e))
37
+ return
38
+ message = ""
39
+ for i in r.events():
40
+ message += str(i.data)
41
+
42
+ self.history.append([f"{query}", message])
43
+ # only keep 5 history
44
+ first_history = self.history.pop(0)
45
+ self.history = [first_history] + self.history[-5:]
46
+ print(message)
47
+ return message
48
+
49
+ def ask_stream(self, query: str, **options: Any):
50
+ raise Exception("GLM do not support stream")
@@ -29,7 +29,11 @@ class GPT3Bot(BaseBot):
29
29
  "top_p": 1,
30
30
  **options,
31
31
  }
32
- completion = await openai.Completion.acreate(**data)
32
+ try:
33
+ completion = await openai.Completion.acreate(**data)
34
+ except Exception as e:
35
+ print(str(e))
36
+ return ""
33
37
  print(completion["choices"][0]["text"])
34
38
  return completion["choices"][0]["text"]
35
39
 
@@ -43,12 +47,17 @@ class GPT3Bot(BaseBot):
43
47
  "stream": True,
44
48
  **options,
45
49
  }
46
- completion = await openai.Completion.acreate(**data)
50
+ try:
51
+ completion = await openai.Completion.acreate(**data)
52
+ except Exception as e:
53
+ print(str(e))
54
+ return
47
55
 
48
56
  async def text_gen():
49
57
  async for event in completion:
50
- print(event["text"], end="")
51
- yield event["text"]
58
+ text = event["choices"][0]["text"]
59
+ print(text, end="")
60
+ yield text
52
61
 
53
62
  try:
54
63
  async for sentence in split_sentences(text_gen()):
@@ -40,13 +40,20 @@ class NewBingBot(BaseBot):
40
40
  async def ask(self, query, **options):
41
41
  kwargs = {"conversation_style": ConversationStyle.balanced, **options}
42
42
  completion = await self._bot.ask(prompt=query, **kwargs)
43
- text = self.clean_text(completion["item"]["messages"][1]["text"])
43
+ try:
44
+ text = self.clean_text(completion["item"]["messages"][1]["text"])
45
+ except Exception as e:
46
+ print(str(e))
47
+ return
44
48
  print(text)
45
49
  return text
46
50
 
47
51
  async def ask_stream(self, query, **options):
48
52
  kwargs = {"conversation_style": ConversationStyle.balanced, **options}
49
- completion = self._bot.ask_stream(prompt=query, **kwargs)
53
+ try:
54
+ completion = self._bot.ask_stream(prompt=query, **kwargs)
55
+ except Exception as e:
56
+ return
50
57
 
51
58
  async def text_gen():
52
59
  current = ""
@@ -27,6 +27,16 @@ def main():
27
27
  dest="openai_key",
28
28
  help="openai api key",
29
29
  )
30
+ parser.add_argument(
31
+ "--glm_key",
32
+ dest="glm_key",
33
+ help="chatglm api key",
34
+ )
35
+ parser.add_argument(
36
+ "--bard_token",
37
+ dest="bard_token",
38
+ help="google bard token see https://github.com/dsdanielpark/Bard-API",
39
+ )
30
40
  parser.add_argument(
31
41
  "--proxy",
32
42
  dest="proxy",
@@ -94,13 +104,30 @@ def main():
94
104
  const="newbing",
95
105
  help="if use newbing",
96
106
  )
107
+ group.add_argument(
108
+ "--use_glm",
109
+ dest="bot",
110
+ action="store_const",
111
+ const="glm",
112
+ help="if use chatglm",
113
+ )
114
+ group.add_argument(
115
+ "--use_bard",
116
+ dest="bot",
117
+ action="store_const",
118
+ const="bard",
119
+ help="if use bard",
120
+ )
97
121
  parser.add_argument(
98
122
  "--bing_cookie_path",
99
123
  dest="bing_cookie_path",
100
124
  help="new bing cookies path if use new bing",
101
125
  )
102
126
  group.add_argument(
103
- "--bot", dest="bot", help="bot type", choices=["gpt3", "chatgptapi", "newbing"]
127
+ "--bot",
128
+ dest="bot",
129
+ help="bot type",
130
+ choices=["gpt3", "chatgptapi", "newbing", "glm", "bard"],
104
131
  )
105
132
  parser.add_argument(
106
133
  "--config",
@@ -129,6 +156,8 @@ def main():
129
156
  )
130
157
 
131
158
  options = parser.parse_args()
159
+ if options.bot in ["glm", "bard"] and options.stream:
160
+ raise Exception("For now ChatGLM do not support stream")
132
161
  config = Config.from_options(options)
133
162
 
134
163
  miboy = MiGPT(config)
@@ -60,6 +60,8 @@ class Config:
60
60
  account: str = os.getenv("MI_USER", "")
61
61
  password: str = os.getenv("MI_PASS", "")
62
62
  openai_key: str = os.getenv("OPENAI_API_KEY", "")
63
+ glm_key: str = os.getenv("CHATGLM_KEY", "")
64
+ bard_token: str = os.getenv("BARD_TOKEN", "")
63
65
  proxy: str | None = None
64
66
  mi_did: str = os.getenv("MI_DID", "")
65
67
  keyword: Iterable[str] = KEY_WORD
@@ -138,5 +140,9 @@ class Config:
138
140
  key, value = "bot", "gpt3"
139
141
  elif key == "use_newbing":
140
142
  key, value = "bot", "newbing"
143
+ elif key == "use_glm":
144
+ key, value = "bot", "glm"
145
+ elif key == "use_bard":
146
+ key, value = "bot", "bard"
141
147
  result[key] = value
142
148
  return result
@@ -356,7 +356,10 @@ class MiGPT:
356
356
  if not self.config.stream:
357
357
  async with ClientSession(trust_env=True) as session:
358
358
  openai.aiosession.set(session)
359
- answer = await self.chatbot.ask(query, **self.config.gpt_options)
359
+ if self.config.bot == "glm":
360
+ answer = self._chatbot.ask(query, **self.config.gpt_options)
361
+ else:
362
+ answer = await self.chatbot.ask(query, **self.config.gpt_options)
360
363
  message = self._normalize(answer) if answer else ""
361
364
  yield message
362
365
  return
@@ -418,6 +421,7 @@ class MiGPT:
418
421
  )
419
422
 
420
423
  async def run_forever(self):
424
+ ask_name = self.config.bot.upper()
421
425
  async with ClientSession() as session:
422
426
  await self.init_all_data(session)
423
427
  task = asyncio.create_task(self.poll_latest_ask())
@@ -467,7 +471,7 @@ class MiGPT:
467
471
  else:
468
472
  # waiting for xiaoai speaker done
469
473
  await asyncio.sleep(8)
470
- await self.do_tts("正在问GPT请耐心等待")
474
+ await self.do_tts(f"正在问{ask_name}请耐心等待")
471
475
  try:
472
476
  print(
473
477
  "以下是小爱的回答: ",
@@ -475,7 +479,7 @@ class MiGPT:
475
479
  )
476
480
  except IndexError:
477
481
  print("小爱没回")
478
- print("以下是GPT的回答: ", end="")
482
+ print(f"以下是 {ask_name} 的回答: ", end="")
479
483
  try:
480
484
  if not self.config.enable_edge_tts:
481
485
  async for message in self.ask_gpt(query):
@@ -489,7 +493,7 @@ class MiGPT:
489
493
  await self.edge_tts(self.ask_gpt(query), tts_lang)
490
494
  print("回答完毕")
491
495
  except Exception as e:
492
- print(f"GPT回答出错 {str(e)}")
496
+ print(f"{ask_name} 回答出错 {str(e)}")
493
497
  if self.in_conversation:
494
498
  print(f"继续对话, 或用`{self.config.end_conversation}`结束对话")
495
499
  await self.wakeup_xiaoai()
File without changes
File without changes
File without changes
File without changes
File without changes