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 8 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)服务,实现上网检索、数学运算..
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

来调用 LangChain(默认 chatgpt)服务,实现上网检索、数学运算..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,已调整


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模式)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

目前仅支持stream模式 -> 目前仅支持 stream 模式

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,已调整

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
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ dependencies = [
"bardapi",
"edge-tts>=6.1.3",
"EdgeGPT==0.1.26",
"langchain",
"datetime",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lock the langchain version since it changes a lot

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,已调整

"bs4",
"chardet",
"typing"
]
license = {text = "MIT"}
dynamic = ["version"]
Expand Down
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,8 @@ wcwidth==0.2.6
websockets==11.0
yarl==1.8.2
zhipuai==1.0.7
langchain==0.0.314
datetime==5.2
bs4==0.0.1
chardet==5.1.0
typing==3.7.4.3
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",
]
47 changes: 47 additions & 0 deletions xiaogpt/bot/langchain_bot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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'.")

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:
# 处理异常的代码
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drop the comment

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok,已调整

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
3 changes: 3 additions & 0 deletions xiaogpt/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ 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
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
45 changes: 45 additions & 0 deletions xiaogpt/langchain/chain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.tools import BaseTool
from langchain.llms import OpenAI
from langchain import LLMMathChain, 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 xiaogpt.langchain.mail_box import Mailbox
from xiaogpt.langchain.mail_summary_tools import MailSummaryTool
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, custom summary email chain
search = SerpAPIWrapper()
llm_math_chain = LLMMathChain(llm=llm, verbose=False)
mail_summary = MailSummaryTool()

# Tool list: search, mathematical calculations, custom summary emails
tools = [
Tool(name="Search", func=search.run, description="如果你不知道或不确定答案,可以使用这个搜索引擎检索答案"),
Tool(name="Calculator", func=llm_math_chain.run, description="在需要回答数学问题时非常有用"),
Tool(
name="MailSummary",
func=mail_summary.run,
description="这是一个工具,订阅每天收到的邮件,总结并发送到我邮箱",
),
]

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

# query eg:'杭州亚运会中国队获得了多少枚金牌?' // '计算3的2次方' // '帮我总结今天收到的邮件'
agent.run(query)
Loading