import configparser
import random
import sys
import time
import uuid
from langchain_core.messages import SystemMessage,HumanMessage,ToolMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import StateGraph,START,END
from langgraph.graph.message import add_messages
from typing import Annotated
from typing import TypedDict
#对话结束标志
conversation_over = False
@tool
def exit_conversation():
'''
用户不想聊天、结束聊天时调用
输入参数:
无
返回:
结束成功返回True,否则返回False
'''
global conversation_over
conversation_over = True
return True
tools = {
'exit_conversation':exit_conversation
}
class State(TypedDict):
messages: Annotated[list,add_messages]
class ChatBot:
def __init__(self,base_url,api_key,model,temperature,name,behavior):
self.config = {
'configurable':{
'thread_id':uuid.uuid4().hex,
'user_id':uuid.uuid4().hex
}
}
llm = (ChatOpenAI(
model = model,
temperature = temperature,
api_key = api_key,
base_url = base_url
).bind_tools(tools = list(tools.values())))
chat = 'chat'
builder = StateGraph(state_schema = State)
builder.add_node(node = chat,action = lambda state:{'messages':[llm.invoke(state['messages'])]})
builder.add_edge(start_key = START,end_key = chat)
builder.add_edge(start_key = chat,end_key = END)
self.graph = builder.compile(checkpointer = MemorySaver())
if (behavior):
for event in self.graph.stream(input = {'messages':[SystemMessage(content = behavior)]},config = self.config):
for value in event.values():
pass
self.name = name
def conversation(self,nick):
while (not conversation_over):
ask = input(nick + ':')
if (not ask):
continue
for event in self.graph.stream(input = {'messages':[HumanMessage(content = ask)]},config = self.config):
for value in event.values():
if (value['messages'][-1].tool_calls):
self.call_tools(value['messages'][-1].tool_calls)
else:
print(self.name,':',value['messages'][-1].content)
def call_tools(self,tool_calls):
messages = []
for call in tool_calls:
messages.append(ToolMessage(content = tools[call['name']].invoke(call['args']),tool_call_id = call['id']))
time.sleep(5)
for event in self.graph.stream(input = {'messages': messages}, config = self.config):
for value in event.values():
if (value['messages'][-1].tool_calls):
self.call_tools(value['messages'][-1].tool_calls)
else:
print(self.name,':',value['messages'][-1].content)
if ('__main__' == __name__):
print('加载机器人配置...',end = '')
load = True
config = configparser.ConfigParser()
config.read(filenames = 'chatbot.ini',encoding = 'utf-8')
base_url = config.get(section = 'chat_bot',option = 'base_url')
if (not base_url):
print('机器人地址为空',end = '')
load = False
api_key = config.get(section = 'chat_bot',option = 'api_key')
if (not api_key):
print('机器人密码为空',end = '')
load = False
model = config.get(section = 'chat_bot',option = 'model')
if (not model):
print('机器人模型为空',end = '')
load = False
temperature = config.get(section = 'chat_bot',option = 'temperature')
if (not temperature):
print('机器人温度为空',end = '')
load = False
if (not load):
print('...失败...')
sys.exit(10)
names = ['捧着风的少女','暖南倾绿','百锂汐','三悲未暖']
print('...成功...')
nick = input('请告诉我你的昵称:')
behavior = input('很高兴见到你,' + nick + '!请告诉我你喜欢的机器人特色:')
print('好的,马上安排...',end='')
name = names[random.randint(a = 0,b = len(names) - 1)]
bot = ChatBot(base_url = base_url,api_key = api_key,model = model,
temperature = temperature,name = name,behavior = behavior)
print('...机器人 ',name,' 陪你聊天...^^')
bot.conversation(nick = nick)