xiaogpt 1.80__tar.gz → 1.81__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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xiaogpt
3
- Version: 1.80
3
+ Version: 1.81
4
4
  Summary: Play ChatGPT or other LLM with xiaomi AI speaker
5
5
  Author-Email: yihong0618 <zouzou0208@gmail.com>
6
6
  License: MIT
@@ -29,7 +29,7 @@ dependencies = [
29
29
  "numexpr==2.8.6",
30
30
  ]
31
31
  dynamic = []
32
- version = "1.80"
32
+ version = "1.81"
33
33
 
34
34
  [project.license]
35
35
  text = "MIT"
@@ -1,14 +1,15 @@
1
1
  """ChatGLM bot"""
2
2
  from __future__ import annotations
3
+
3
4
  from typing import Any
4
5
 
5
6
  from bardapi import BardAsync
6
7
  from rich import print
7
8
 
8
- from xiaogpt.bot.base_bot import BaseBot
9
+ from xiaogpt.bot.base_bot import BaseBot, ChatHistoryMixin
9
10
 
10
11
 
11
- class BardBot(BaseBot):
12
+ class BardBot(ChatHistoryMixin, BaseBot):
12
13
  def __init__(
13
14
  self,
14
15
  bard_token: str,
@@ -0,0 +1,56 @@
1
+ from __future__ import annotations
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any, AsyncGenerator, TypeVar
5
+
6
+ from xiaogpt.config import Config
7
+
8
+ T = TypeVar("T", bound="BaseBot")
9
+
10
+
11
+ class BaseBot(ABC):
12
+ @abstractmethod
13
+ async def ask(self, query: str, **options: Any) -> str:
14
+ pass
15
+
16
+ @abstractmethod
17
+ async def ask_stream(self, query: str, **options: Any) -> AsyncGenerator[str, None]:
18
+ pass
19
+
20
+ @classmethod
21
+ @abstractmethod
22
+ def from_config(cls: type[T], config: Config) -> T:
23
+ pass
24
+
25
+ @abstractmethod
26
+ def has_history(self) -> bool:
27
+ pass
28
+
29
+ @abstractmethod
30
+ def change_prompt(self, new_prompt: str) -> None:
31
+ pass
32
+
33
+
34
+ class ChatHistoryMixin:
35
+ history: list[tuple[str, str]]
36
+
37
+ def has_history(self) -> bool:
38
+ return bool(self.history)
39
+
40
+ def change_prompt(self, new_prompt: str) -> None:
41
+ if self.history:
42
+ print(self.history)
43
+ self.history[0][0] = new_prompt
44
+
45
+ def get_messages(self) -> list[dict]:
46
+ ms = []
47
+ for h in self.history:
48
+ ms.append({"role": "user", "content": h[0]})
49
+ ms.append({"role": "assistant", "content": h[1]})
50
+ return ms
51
+
52
+ def add_message(self, query: str, message: str) -> None:
53
+ self.history.append([f"{query}", message])
54
+ # only keep 5 history
55
+ first_history = self.history.pop(0)
56
+ self.history = [first_history] + self.history[-5:]
@@ -3,11 +3,11 @@ from __future__ import annotations
3
3
  import openai
4
4
  from rich import print
5
5
 
6
- from xiaogpt.bot.base_bot import BaseBot
6
+ from xiaogpt.bot.base_bot import BaseBot, ChatHistoryMixin
7
7
  from xiaogpt.utils import split_sentences
8
8
 
9
9
 
10
- class ChatGPTBot(BaseBot):
10
+ class ChatGPTBot(ChatHistoryMixin, BaseBot):
11
11
  default_options = {"model": "gpt-3.5-turbo-0613"}
12
12
 
13
13
  def __init__(
@@ -42,10 +42,7 @@ class ChatGPTBot(BaseBot):
42
42
  )
43
43
 
44
44
  async def ask(self, query, **options):
45
- ms = []
46
- for h in self.history:
47
- ms.append({"role": "user", "content": h[0]})
48
- ms.append({"role": "assistant", "content": h[1]})
45
+ ms = self.get_messages()
49
46
  ms.append({"role": "user", "content": f"{query}"})
50
47
  kwargs = {**self.default_options, **options}
51
48
  try:
@@ -60,18 +57,12 @@ class ChatGPTBot(BaseBot):
60
57
  .encode("utf8")
61
58
  .decode()
62
59
  )
63
- self.history.append([f"{query}", message])
64
- # only keep 5 history
65
- first_history = self.history.pop(0)
66
- self.history = [first_history] + self.history[-5:]
60
+ self.add_message(query, message)
67
61
  print(message)
68
62
  return message
69
63
 
70
64
  async def ask_stream(self, query, **options):
71
- ms = []
72
- for h in self.history:
73
- ms.append({"role": "user", "content": h[0]})
74
- ms.append({"role": "assistant", "content": h[1]})
65
+ ms = self.get_messages()
75
66
  ms.append({"role": "user", "content": f"{query}"})
76
67
  kwargs = {"model": "gpt-3.5-turbo", **options}
77
68
  if openai.api_type == "azure":
@@ -99,6 +90,4 @@ class ChatGPTBot(BaseBot):
99
90
  yield sentence
100
91
  finally:
101
92
  print()
102
- self.history.append([f"{query}", message])
103
- first_history = self.history.pop(0)
104
- self.history = [first_history] + self.history[-5:]
93
+ self.add_message(query, message)
@@ -1,21 +1,18 @@
1
1
  """ChatGLM bot"""
2
2
  from __future__ import annotations
3
3
 
4
- from typing import Any, AsyncGenerator
4
+ from typing import Any
5
5
 
6
6
  import zhipuai
7
7
  from rich import print
8
8
 
9
- from xiaogpt.bot.base_bot import BaseBot
9
+ from xiaogpt.bot.base_bot import BaseBot, ChatHistoryMixin
10
10
 
11
11
 
12
- class GLMBot(BaseBot):
12
+ class GLMBot(ChatHistoryMixin, BaseBot):
13
13
  default_options = {"model": "chatglm_130b"}
14
14
 
15
- def __init__(
16
- self,
17
- glm_key: str,
18
- ) -> None:
15
+ def __init__(self, glm_key: str) -> None:
19
16
  self.history = []
20
17
  zhipuai.api_key = glm_key
21
18
 
@@ -24,10 +21,7 @@ class GLMBot(BaseBot):
24
21
  return cls(glm_key=config.glm_key)
25
22
 
26
23
  def ask(self, query, **options):
27
- ms = []
28
- for h in self.history:
29
- ms.append({"role": "user", "content": h[0]})
30
- ms.append({"role": "assistant", "content": h[1]})
24
+ ms = self.get_messages()
31
25
  kwargs = {**self.default_options, **options}
32
26
  kwargs["prompt"] = ms
33
27
  ms.append({"role": "user", "content": f"{query}"})
@@ -40,10 +34,7 @@ class GLMBot(BaseBot):
40
34
  for i in r.events():
41
35
  message += str(i.data)
42
36
 
43
- self.history.append([f"{query}", message])
44
- # only keep 5 history
45
- first_history = self.history.pop(0)
46
- self.history = [first_history] + self.history[-5:]
37
+ self.add_message(query, message)
47
38
  print(message)
48
39
  return message
49
40
 
@@ -1,11 +1,11 @@
1
1
  import openai
2
2
  from rich import print
3
3
 
4
- from xiaogpt.bot.base_bot import BaseBot
4
+ from xiaogpt.bot.base_bot import BaseBot, ChatHistoryMixin
5
5
  from xiaogpt.utils import split_sentences
6
6
 
7
7
 
8
- class GPT3Bot(BaseBot):
8
+ class GPT3Bot(ChatHistoryMixin, BaseBot):
9
9
  def __init__(self, openai_key, api_base=None, proxy=None):
10
10
  openai.api_key = openai_key
11
11
  if api_base:
@@ -3,6 +3,7 @@ from __future__ import annotations
3
3
  import asyncio
4
4
  import os
5
5
 
6
+ from langchain.memory import ConversationBufferWindowMemory
6
7
  from rich import print
7
8
 
8
9
  from xiaogpt.bot.base_bot import BaseBot
@@ -26,8 +27,14 @@ class LangChainBot(BaseBot):
26
27
  os.environ["OPENAI_API_BASE"] = api_base
27
28
  if proxy:
28
29
  os.environ["OPENAI_PROXY"] = proxy
29
- # Todo,Plan to implement within langchain
30
- self.history = []
30
+ self.memory = ConversationBufferWindowMemory(return_messages=True)
31
+
32
+ def has_history(self) -> bool:
33
+ return len(self.memory.chat_memory.messages) > 0
34
+
35
+ def change_prompt(self, new_prompt: str) -> None:
36
+ self.memory.clear()
37
+ self.memory.chat_memory.add_user_message(new_prompt)
31
38
 
32
39
  @classmethod
33
40
  def from_config(cls, config):
@@ -39,14 +46,11 @@ class LangChainBot(BaseBot):
39
46
  )
40
47
 
41
48
  async def ask(self, query, **options):
42
- # Todo,Currently only supports stream
43
- raise Exception(
44
- "The bot does not support it. Please use 'ask_stream, add: --stream'"
45
- )
49
+ return await agent_search(query, self.memory)
46
50
 
47
51
  async def ask_stream(self, query, **options):
48
52
  callback = AsyncIteratorCallbackHandler()
49
- task = asyncio.create_task(agent_search(query, callback))
53
+ task = asyncio.create_task(agent_search(query, self.memory, callback))
50
54
  try:
51
55
  async for message in split_sentences(callback.aiter()):
52
56
  yield message
@@ -4,13 +4,13 @@ import re
4
4
 
5
5
  from EdgeGPT import Chatbot, ConversationStyle
6
6
 
7
- from xiaogpt.bot.base_bot import BaseBot
7
+ from xiaogpt.bot.base_bot import BaseBot, ChatHistoryMixin
8
8
  from xiaogpt.utils import split_sentences
9
9
 
10
10
  _reference_link_re = re.compile(r"\[\d+\]: .+?\n+")
11
11
 
12
12
 
13
- class NewBingBot(BaseBot):
13
+ class NewBingBot(ChatHistoryMixin, BaseBot):
14
14
  def __init__(
15
15
  self,
16
16
  bing_cookie_path: str = "",
@@ -52,7 +52,7 @@ class NewBingBot(BaseBot):
52
52
  kwargs = {"conversation_style": ConversationStyle.balanced, **options}
53
53
  try:
54
54
  completion = self._bot.ask_stream(prompt=query, **kwargs)
55
- except Exception as e:
55
+ except Exception:
56
56
  return
57
57
 
58
58
  async def text_gen():
@@ -33,7 +33,7 @@ class AsyncIteratorCallbackHandler(AsyncCallbackHandler):
33
33
 
34
34
  async def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
35
35
  if token is not None and token != "":
36
- print(token, end="")
36
+ print(token, end="", flush=True)
37
37
  self.queue.put_nowait(token)
38
38
 
39
39
  async def on_chain_end(
@@ -1,11 +1,16 @@
1
+ from __future__ import annotations
2
+
1
3
  from langchain.agents import AgentType, Tool, initialize_agent
2
4
  from langchain.callbacks.base import BaseCallbackHandler
3
5
  from langchain.chains import LLMMathChain
4
6
  from langchain.chat_models import ChatOpenAI
7
+ from langchain.schema.memory import BaseMemory
5
8
  from langchain.utilities import SerpAPIWrapper
6
9
 
7
10
 
8
- async def agent_search(query: str, callback: BaseCallbackHandler) -> None:
11
+ async def agent_search(
12
+ query: str, memeory: BaseMemory, callback: BaseCallbackHandler | None = None
13
+ ) -> str:
9
14
  llm = ChatOpenAI(
10
15
  streaming=True,
11
16
  temperature=0,
@@ -23,8 +28,8 @@ async def agent_search(query: str, callback: BaseCallbackHandler) -> None:
23
28
  ]
24
29
 
25
30
  agent = initialize_agent(
26
- tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=False
31
+ tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=False, memory=memeory
27
32
  )
28
-
33
+ callbacks = [callback] if callback else None
29
34
  # query eg:'杭州亚运会中国队获得了多少枚金牌?' // '计算3的2次方'
30
- await agent.arun(query, callbacks=[callback])
35
+ return await agent.arun(query, callbacks=callbacks)
@@ -231,9 +231,7 @@ class MiGPT:
231
231
  new_prompt = "以下都" + new_prompt
232
232
  print(f"Prompt from {self.config.prompt} change to {new_prompt}")
233
233
  self.config.prompt = new_prompt
234
- if self.chatbot.history:
235
- print(self.chatbot.history)
236
- self.chatbot.history[0][0] = new_prompt
234
+ self.chatbot.change_prompt(new_prompt)
237
235
 
238
236
  async def get_latest_ask_from_xiaoai(self, session: ClientSession) -> dict | None:
239
237
  retries = 3
@@ -489,7 +487,7 @@ class MiGPT:
489
487
 
490
488
  print("-" * 20)
491
489
  print("问题:" + query + "?")
492
- if not self.chatbot.history:
490
+ if not self.chatbot.has_history():
493
491
  query = f"{query},{self.config.prompt}"
494
492
  if self.config.mute_xiaoai:
495
493
  await self.stop_if_xiaoai_is_playing()
@@ -1,25 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from abc import ABC, abstractmethod
4
- from typing import Any, AsyncGenerator, TypeVar
5
-
6
- from xiaogpt.config import Config
7
-
8
- T = TypeVar("T", bound="BaseBot")
9
-
10
-
11
- class BaseBot(ABC):
12
- history: list
13
-
14
- @abstractmethod
15
- async def ask(self, query: str, **options: Any) -> str:
16
- pass
17
-
18
- @abstractmethod
19
- async def ask_stream(self, query: str, **options: Any) -> AsyncGenerator[str, None]:
20
- pass
21
-
22
- @classmethod
23
- @abstractmethod
24
- def from_config(cls: type[T], config: Config) -> T:
25
- pass
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes