233 lines
9.7 KiB
Python
233 lines
9.7 KiB
Python
import time
|
||
from prompt_toolkit import prompt
|
||
from openai import OpenAI
|
||
from get_tianqi import get_tianqi_data
|
||
from cha_xianglaing import search1
|
||
from weixin import weix
|
||
import json
|
||
|
||
tool_list = [
|
||
{"name":"tainqi","description":"查询天气"},
|
||
{"name":"sousuo","description":"网页搜索"},
|
||
{"name":"export_video","description":"导出视频片段"},
|
||
]
|
||
|
||
toole_details = {
|
||
"tianqi":{
|
||
"type":"function",
|
||
"function":{
|
||
"name":"tianqi",
|
||
"description":"查询天气状况(温度、湿度、风力、天气....)时使用此tool",
|
||
"strict": True,
|
||
"parameters": {
|
||
"type":"object",
|
||
"properties":{
|
||
"city":{"type": "string", "description": "要获取天气的城市名称"}
|
||
},
|
||
"required": ["city"],
|
||
"additionalProperties": False
|
||
}
|
||
}
|
||
},
|
||
}
|
||
|
||
def get_tools_details():
|
||
# 获取工具详情
|
||
pass
|
||
|
||
|
||
class send_message:
|
||
def __init__(self, system_content: str ,tool_choice="auto"):
|
||
self.ai_return = []
|
||
self.tool_choice1 = tool_choice
|
||
self.messages_1 = [
|
||
{"role": "system", "content": system_content},
|
||
]
|
||
def test_openai(self):
|
||
# print("111",self.messages_1)
|
||
client = OpenAI(api_key="tp-cj0x379me5rqk198qnnt4n1spcdbx986jjr163gu2iiw1s7w",
|
||
base_url="https://token-plan-cn.xiaomimimo.com/v1")
|
||
response = client.chat.completions.create(
|
||
model="mimo-v2.5-pro",
|
||
messages=self.messages_1,
|
||
top_p=0.5,
|
||
tools=[
|
||
{"type": "function",
|
||
"function": {
|
||
"name": "get_tianqi",
|
||
"description": "获取天气信息。当你需要回答任何与天气、气温、冷暖有关的问题时调用此工具;判断用户是否是询问温度而不是出现冷热就调用此工具,例如用户说:你这个笑话好冷,则无需调用。**必须**使用此工具来获取实时、真实的天气数据。",
|
||
"parameters": {
|
||
"type": "object",
|
||
"properties": {
|
||
"city": {"type": "string", "description": "城市名称"}
|
||
},
|
||
"required": ["city"],
|
||
"additionalProperties": False
|
||
}
|
||
}
|
||
},{"type": "function",
|
||
"function": {
|
||
"name": "get_donghua_images",
|
||
"description": "用户需要查询具体动画场景时调用此工具。例如:用户说这个场景不错帮我找下,调用此工具;",
|
||
"parameters": {
|
||
"type": "object",
|
||
"properties": {
|
||
"donghua": {"type": "string", "description": "动画场景描述,必须为英文;例如:Tom is tired"},
|
||
"xiangsidu": {"type": "integer", "description": "图片与场景的相似度要求,例如:'给我相似度大于50%的图片 则传值0.5'"},
|
||
"tupianshuliang": {"type": "integer", "description": "返回图片数量,例如:'给我返回10张图片 则传值10'"},
|
||
},
|
||
"required": ["donghua"],
|
||
"additionalProperties": False
|
||
}}
|
||
},
|
||
{"type": "function",
|
||
"function": {
|
||
"name": "export_video",
|
||
"description": "当用户确认某张图片并要求导出视频时调用此工具。例如:'这张图不错,给我前后30秒的视频'、'导出这个场景后面5分钟'、'我要整个视频'、'帮我截取这个片段'",
|
||
"parameters": {
|
||
"type": "object",
|
||
"properties": {
|
||
"image_name": {
|
||
"type": "string",
|
||
"description": "用户确认的图片文件名,例如 '001 Puss Gets the Boot [1940]_05m23s_456.jpg'"
|
||
},
|
||
"mode": {
|
||
"type": "string",
|
||
"enum": ["around", "after", "before", "total"],
|
||
"description": "导出模式:around=前后各N秒,after=后N秒,before=前N秒,total=整个视频"
|
||
},
|
||
"seconds": {
|
||
"type": "integer",
|
||
"description": "秒数,total模式下可省略,默认300秒。例如用户说'前后30秒'则传30,'前后5分钟'则传300",
|
||
"default": 300
|
||
}
|
||
},
|
||
"required": ["image_name", "mode","seconds"],
|
||
"additionalProperties": False
|
||
}}
|
||
}
|
||
],
|
||
tool_choice=self.tool_choice1,
|
||
)
|
||
return response.choices[0].message
|
||
|
||
|
||
def test_json_format(json_string):
|
||
try:
|
||
return json.loads(json_string)
|
||
except json.JSONDecodeError:
|
||
return False
|
||
def get_tianqi(ai_json):
|
||
print(f"正在获取{ai_json['city']}的天气信息...")
|
||
return f"{get_tianqi_data(ai_json['city'])}"
|
||
# m = send_message('')
|
||
|
||
|
||
|
||
cont = 1
|
||
# m = send_message('你是一个个人助手,会适当使用工具')
|
||
class get_ai_message:
|
||
def __init__(self):
|
||
self.system_content = open("猫和老鼠分镜.md", "r", encoding="utf-8").read()
|
||
self.m = send_message(self.system_content)
|
||
self.wx = weix()
|
||
|
||
async def _handle_donghua(self, args):
|
||
"""处理动画图片搜索工具"""
|
||
donghua = args["donghua"]
|
||
xiangsidu = args.get("xiangsidu", 0)
|
||
tupianshuliang = args.get("tupianshuliang", 5)
|
||
re_donghua_image = search1(query_text=donghua, top_k=tupianshuliang)
|
||
result_str = ""
|
||
for result in re_donghua_image:
|
||
if result.score < xiangsidu:
|
||
continue
|
||
result_str += f"相似度:{result.score},图片路径:{result.payload}\n"
|
||
print(result)
|
||
await self.wx.send_images(result.payload["image_path"])
|
||
return result_str if result_str else "未找到符合条件的图片"
|
||
|
||
async def _handle_export_video(self, args):
|
||
"""处理视频导出工具"""
|
||
from video_cutter import export_video_clip
|
||
export_result = export_video_clip(
|
||
image_name=args["image_name"],
|
||
mode=args["mode"],
|
||
seconds=args.get("seconds", 300)
|
||
)
|
||
if export_result["success"]:
|
||
await self.wx.send_video(export_result["video_path"])
|
||
return (
|
||
f"✅ 视频已导出并发送!\n"
|
||
f"⏱️ 时间范围:{export_result['start_time']} -> {export_result['end_time']}\n"
|
||
f"🎬 时长:{export_result['duration']}"
|
||
)
|
||
else:
|
||
return f"❌ 视频导出失败:{export_result['error']}"
|
||
|
||
async def sen_mess(self, s_input_text):
|
||
# 拼接用户消息
|
||
self.m.messages_1.append({"role": "user", "content": s_input_text})
|
||
|
||
while True:
|
||
out_text = self.m.test_openai()
|
||
|
||
if out_text.tool_calls:
|
||
# 将 assistant 的 tool_calls 消息整体追加到 messages(转为 dict)
|
||
self.m.messages_1.append({
|
||
"role": "assistant",
|
||
"content": out_text.content,
|
||
"tool_calls": [
|
||
{
|
||
"id": tc.id,
|
||
"type": "function",
|
||
"function": {
|
||
"name": tc.function.name,
|
||
"arguments": tc.function.arguments
|
||
}
|
||
}
|
||
for tc in out_text.tool_calls
|
||
]
|
||
})
|
||
|
||
for tool_call in out_text.tool_calls:
|
||
args = test_json_format(tool_call.function.arguments)
|
||
tool_name = tool_call.function.name
|
||
print("M调用了工具:", tool_name)
|
||
|
||
tool_result = ""
|
||
if tool_name == "get_tianqi":
|
||
tool_result = get_tianqi(args)
|
||
elif tool_name == "get_donghua_images":
|
||
tool_result = await self._handle_donghua(args)
|
||
elif tool_name == "export_video":
|
||
tool_result = await self._handle_export_video(args)
|
||
|
||
# 工具结果以 tool role 追加到 messages
|
||
self.m.messages_1.append({
|
||
"role": "tool",
|
||
"tool_call_id": tool_call.id,
|
||
"content": tool_result
|
||
})
|
||
print(f"工具 {tool_name} 返回: {tool_result[:100]}...")
|
||
|
||
# 循环继续,让 LLM 看到工具结果后继续推理
|
||
|
||
elif out_text.content:
|
||
# 没有工具调用,发送最终文本给用户
|
||
self.m.messages_1.append({"role": "assistant", "content": out_text.content})
|
||
await self.wx.send_text(out_text.content)
|
||
print(f"小爱:{out_text.content}")
|
||
return out_text.content
|
||
|
||
gm = get_ai_message()
|
||
bot = gm.wx.bot
|
||
@bot.on_message
|
||
async def echo_handler(msg):
|
||
print(f"收到来自 {msg.user_id} 的消息: {msg.text}")
|
||
await gm.sen_mess(msg.text)
|
||
# await bot.reply(msg, f"你说了: {msg.text}")
|
||
bot.run()
|
||
|
||
|