Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support LangChain #344

Merged
merged 11 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Play ChatGPT and other LLM with Xiaomi AI Speaker
- 如果你遇到了墙需要用 Cloudflare Workers 替换 api_base 请使用 `--api_base ${url}` 来替换。 **请注意,此处你输入的api应该是'`https://xxxx/v1`'的字样,域名需要用引号包裹**
- 可以跟小爱说 `开始持续对话` 自动进入持续对话状态,`结束持续对话` 结束持续对话状态。
- 可以使用 `--enable_edge_tts` 来获取更好的 tts 能力
- 可以使用 `--use_langchain` 替代 `--use_chatgpt_api` 来调用 LangChain(默认 chatgpt)服务,实现上网检索、数学运算..

e.g.

Expand All @@ -76,6 +77,10 @@ export OPENAI_API_KEY=${your_api_key}
xiaogpt --hardware LX06 --mute_xiaoai --use_gpt3
# 如果你想用 edge-tts
xiaogpt --hardware LX06 --cookie ${cookie} --use_chatgpt_api --enable_edge_tts
# 如果你想使用 LangChain + SerpApi 实现上网检索或其他本地服务(目前仅支持 stream 模式)
export OPENAI_API_KEY=${your_api_key}
export SERPAPI_API_KEY=${your_serpapi_key}
xiaogpt --hardware Lx06 --use_langchain --mute_xiaoai --stream --openai_key ${your_api_key} --serpapi_api_key ${your_serpapi_key}
```
使用 git clone 运行

Expand All @@ -93,11 +98,14 @@ python3 xiaogpt.py --hardware LX06 --mute_xiaoai --stream
# 如果你想使用 gpt3 ai
export OPENAI_API_KEY=${your_api_key}
python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_gpt3

# 如果你想使用 ChatGLM api
python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_glm --glm_key ${glm_key}
# 如果你想使用 google 的 bard
python3 xiaogpt.py --hardware LX06 --mute_xiaoai --use_bard --bard_token ${bard_token}
# 如果你想使用 LangChain+SerpApi 实现上网检索或其他本地服务(目前仅支持 stream 模式)
export OPENAI_API_KEY=${your_api_key}
export SERPAPI_API_KEY=${your_serpapi_key}
python3 xiaogpt.py --hardware Lx06 --use_langchain --mute_xiaoai --stream --openai_key ${your_api_key} --serpapi_api_key ${your_serpapi_key}
```

## config.json
Expand Down Expand Up @@ -139,6 +147,7 @@ Bard-API [参考](https://github.com/dsdanielpark/Bard-API)
| account | 小爱账户 | |
| password | 小爱账户密码 | |
| openai_key | openai的apikey | |
| serpapi_api_key | serpapi的key 参考 [SerpAPI](https://serpapi.com/) | |
| glm_key | chatglm 的 apikey | |
| bard_token | bard 的 token 参考 [Bard-API](https://github.com/dsdanielpark/Bard-API) | |
| cookie | 小爱账户cookie (如果用上面密码登录可以不填) | |
Expand Down
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ dependencies = [
"bardapi",
"edge-tts>=6.1.3",
"EdgeGPT==0.1.26",
"langchain==0.0.301",
"datetime==5.2",
"bs4==0.0.1",
"chardet==5.1.0",
"typing==3.7.4.3",
"google-search-results==2.4.2",
"numexpr==2.8.6"
]
license = {text = "MIT"}
dynamic = ["version"]
Expand Down
8 changes: 8 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,11 @@ wcwidth==0.2.6
websockets==11.0
yarl==1.8.2
zhipuai==1.0.7
langchain==0.0.301
datetime==5.2
bs4==0.0.1
chardet==5.1.0
typing==3.7.4.3
google-search-results==2.4.2
numexpr==2.8.6

1 change: 1 addition & 0 deletions xiao_config.json.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"openai_key": "",
"glm_key": "",
"bard_token": "",
"serpapi_api_key": "",
"cookie": "",
"mi_did": "",
"use_command": false,
Expand Down
12 changes: 11 additions & 1 deletion xiaogpt/bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from xiaogpt.bot.newbing_bot import NewBingBot
from xiaogpt.bot.glm_bot import GLMBot
from xiaogpt.bot.bard_bot import BardBot
from xiaogpt.bot.langchain_bot import LangChainBot
from xiaogpt.config import Config

BOTS: dict[str, type[BaseBot]] = {
Expand All @@ -14,6 +15,7 @@
"chatgptapi": ChatGPTBot,
"glm": GLMBot,
"bard": BardBot,
"langchain": LangChainBot,
}


Expand All @@ -24,4 +26,12 @@ def get_bot(config: Config) -> BaseBot:
raise ValueError(f"Unsupported bot {config.bot}, must be one of {list(BOTS)}")


__all__ = ["GPT3Bot", "ChatGPTBot", "NewBingBot", "GLMBot", "BardBot", "get_bot"]
__all__ = [
"GPT3Bot",
"ChatGPTBot",
"NewBingBot",
"GLMBot",
"BardBot",
"get_bot",
"LangChainBot",
]
48 changes: 48 additions & 0 deletions xiaogpt/bot/langchain_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from __future__ import annotations

import openai
from rich import print

from xiaogpt.bot.base_bot import BaseBot
from xiaogpt.utils import split_sentences

from xiaogpt.langchain.chain import agent_search
from xiaogpt.langchain.stream_call_back import streaming_call_queue

import os


class LangChainBot(BaseBot):
def __init__(
self,
openai_key: str,
serpapi_api_key: str,
) -> None:
# Set environment indicators
os.environ["OPENAI_API_KEY"] = openai_key
os.environ["SERPAPI_API_KEY"] = serpapi_api_key
# todo,Plan to implement within langchain
self.history = []

@classmethod
def from_config(cls, config):
return cls(openai_key=config.openai_key, serpapi_api_key=config.serpapi_api_key)

async def ask(self, query, **options):
# todo,Currently only supports stream
raise Exception(
"The bot does not support it. Please use 'ask_stream,add: --stream'"
)

async def ask_stream(self, query, **options):
agent_search(query)
try:
while True:
if not streaming_call_queue.empty():
token = streaming_call_queue.get()
print(token, end="")
yield token
else:
break
except Exception as e:
print("An error occurred:", str(e))
14 changes: 13 additions & 1 deletion xiaogpt/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ def main():
dest="bard_token",
help="google bard token see https://github.com/dsdanielpark/Bard-API",
)
parser.add_argument(
"--serpapi_api_key",
dest="serpapi_api_key",
help="serp api key see https://serpapi.com/",
)
parser.add_argument(
"--proxy",
dest="proxy",
Expand Down Expand Up @@ -97,6 +102,13 @@ def main():
const="chatgptapi",
help="if use openai chatgpt api",
)
group.add_argument(
"--use_langchain",
dest="bot",
action="store_const",
const="langchain",
help="if use langchain",
)
group.add_argument(
"--use_newbing",
dest="bot",
Expand Down Expand Up @@ -127,7 +139,7 @@ def main():
"--bot",
dest="bot",
help="bot type",
choices=["gpt3", "chatgptapi", "newbing", "glm", "bard"],
choices=["gpt3", "chatgptapi", "newbing", "glm", "bard", "langchain"],
)
parser.add_argument(
"--config",
Expand Down
5 changes: 4 additions & 1 deletion xiaogpt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,14 @@ class Config:
openai_key: str = os.getenv("OPENAI_API_KEY", "")
glm_key: str = os.getenv("CHATGLM_KEY", "")
bard_token: str = os.getenv("BARD_TOKEN", "")
serpapi_api_key: str = os.getenv("SERPAPI_API_KEY", "")
proxy: str | None = None
mi_did: str = os.getenv("MI_DID", "")
keyword: Iterable[str] = KEY_WORD
change_prompt_keyword: Iterable[str] = CHANGE_PROMPT_KEY_WORD
prompt: str = PROMPT
mute_xiaoai: bool = False
bot: str = "chatgpt"
bot: str = "chatgptapi"
cookie: str = ""
api_base: str | None = None
deployment_id: str | None = None
Expand Down Expand Up @@ -147,5 +148,7 @@ def read_from_file(cls, config_path: str) -> dict:
key, value = "bot", "glm"
elif key == "use_bard":
key, value = "bot", "bard"
elif key == "use_langchain":
key, value = "bot", "langchain"
result[key] = value
return result
38 changes: 38 additions & 0 deletions xiaogpt/langchain/chain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.tools import BaseTool
from langchain.llms import OpenAI
from langchain.chains import LLMMathChain
from langchain.utilities import SerpAPIWrapper
from langchain.chat_models import ChatOpenAI
from langchain.memory import ChatMessageHistory
from xiaogpt.langchain.stream_call_back import StreamCallbackHandler
from langchain.agents.agent_toolkits import ZapierToolkit
from langchain.utilities.zapier import ZapierNLAWrapper
from langchain.memory import ConversationBufferMemory


def agent_search(query):
llm = ChatOpenAI(
streaming=True,
temperature=0,
model="gpt-3.5-turbo-0613",
callbacks=[StreamCallbackHandler()],
)

# Initialization: search chain, mathematical calculation chain
search = SerpAPIWrapper()
llm_math_chain = LLMMathChain.from_llm(llm=llm, verbose=False)

# Tool list: search, mathematical calculations
tools = [
Tool(name="Search", func=search.run, description="如果你不知道或不确定答案,可以使用这个搜索引擎检索答案"),
Tool(name="Calculator", func=llm_math_chain.run, description="在需要回答数学问题时非常有用"),
]

agent = initialize_agent(
tools, llm, agent=AgentType.OPENAI_FUNCTIONS, verbose=False
)

# query eg:'杭州亚运会中国队获得了多少枚金牌?' // '计算3的2次方'
agent.run(query)
Loading