From e48b8d8a2dd6b98040432c17d4bc86b5cb91e6ca Mon Sep 17 00:00:00 2001 From: xszyou Date: Mon, 18 Dec 2023 16:52:53 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC4=E6=AC=A1=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1、优化prompt; 2、解决日程删除错误; 3、iotm demo tool整体更新。 --- README.md | 10 ++- README_EN.md | 65 ++++++++++++++++++ WebSocket.md | 1 + agent/agent_service.py | 24 +++---- agent/fay_agent.py | 19 +++++- agent/tools/CheckSensor.py | 121 +++++++++++++++------------------ agent/tools/DeleteTimer.py | 34 ++++----- agent/tools/GetSwitchLog.py | 27 ++++++++ agent/tools/IotmService.py | 47 +++++++++++++ agent/tools/MyTimer.py | 4 +- agent/tools/QueryTimerDB.py | 2 +- agent/tools/Say.py | 2 +- agent/tools/Switch.py | 35 ++++++++-- agent/tools/Weather.py | 34 +++++++-- agent/tools/getOnRunLinkage.py | 26 +++++++ requirements.txt | 4 +- 16 files changed, 341 insertions(+), 114 deletions(-) create mode 100644 README_EN.md create mode 100644 agent/tools/GetSwitchLog.py create mode 100644 agent/tools/IotmService.py create mode 100644 agent/tools/getOnRunLinkage.py diff --git a/README.md b/README.md index 2b612ac..d582b68 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,14 @@
Fay

Fay数字人 AI Agent版

- “agent”即代理,它能够代替你完成决策规划并执行,这一切都依赖目前最强的大语言模型的ReAct能力。 + “agent”即代理,它能够代替你完成决策规划并执行,这一切都依赖目前最强的大语言模型的ReAct能力。不同于助理版的一问一答,agent版的Fay可以实现自动代理执行的同时,在它认为必要时候会触发数字人或者直接的声音输出。 -**12月迟来的报到,Fay数字人 AI Agent版(含智慧农业应用demo)第3版正式上传!** + + + + +**12月迟来的报到,Fay数字人 AI Agent版(含智慧农业箱的操作demo代码,如果你需要完整代码可以公众号留言申请获取)第4版正式上传!** 如果你需要是一个线上线下的销售员,请移步[`带货完整版`](https://github.com/TheRamU/Fay/tree/fay-sales-edition) @@ -53,6 +57,8 @@ python main.py + 启动数字人[xszyou/fay-ue5: 可对接fay数字人的ue5工程 (github.com)](https://github.com/xszyou/fay-ue5) + + ### **联系** **商务QQ: 467665317** diff --git a/README_EN.md b/README_EN.md new file mode 100644 index 0000000..5e33e37 --- /dev/null +++ b/README_EN.md @@ -0,0 +1,65 @@ +[`中文`](https://github.com/TheRamU/Fay/blob/main/README.md) + +
+
+ Fay +

Fay Digital Human AI Agent Version

+ An "agent" is a representative that can make decisions and execute plans for you, relying on the powerful ReAct capability of the most advanced large language models. +
+ + + + + +**Belated December announcement, the 4th edition of Fay Digital Human AI Agent Version (complete code for smart agriculture box can be requested via our public channel) is officially uploaded!** + +If you need an online and offline salesperson, please go to [`Complete Retail Version`](https://github.com/TheRamU/Fay/tree/fay-sales-edition) + +If you need a digital human assistant for human-computer interaction (and yes, you can command it to switch devices on and off), please go to [`Complete Assistant Version`](https://github.com/TheRamU/Fay/tree/fay-assistant-edition) + +***“Exceptional products deserve to be reimagined with digital humans”*** + +Highlights: Proactive execution of planned tasks without the need for question-and-answer interactions, automatic planning and use of the agent tool to complete tasks; use of OpenAI TTS; use of a vector database for permanent memory and memory retrieval; + +![](images/agent_demo.gif) + +​ (Above image: Testing ReAct capabilities) + +## **Installation Instructions** + +### **System Requirements** + +- Python 3.9, 3.10 +- Windows, macOS, Linux + +### **Installing Dependencies** + +```shell +pip install -r requirements.txt +``` + +### **Configuring Application Keys** + ++ Enter your GPT-4 key in `./system.conf` + +### **Launching the Controller** + +Start the Fay controller + +```shell +python main.py +``` + +### **Launching the Digital Human (Optional)** + ++ Launch the digital human[xszyou/fay-ue5: 可对接fay数字人的ue5工程 (github.com)](https://github.com/xszyou/fay-ue5) + + + +### **Contact** + +**Business QQ: 467665317** + +Join the discussion group by following the public account Fay Digital Human (please star this repository first) + + diff --git a/WebSocket.md b/WebSocket.md index a315fcb..b006adc 100644 --- a/WebSocket.md +++ b/WebSocket.md @@ -1,3 +1,4 @@ +#这是与数字人通讯的接口说明 ## 消息格式 通讯地址: [`ws://127.0.0.1:10002`](ws://127.0.0.1:10002) diff --git a/agent/agent_service.py b/agent/agent_service.py index 92d876e..3cdf053 100644 --- a/agent/agent_service.py +++ b/agent/agent_service.py @@ -51,7 +51,7 @@ def parse_repeat_rule(rule, task_time): # 执行任务 def execute_task(task_time, id, content): - content = content + content = "执行任务->现在" + content agent.run(content) del scheduled_tasks[id] # 如果不重复,执行后删除记录 @@ -96,19 +96,17 @@ def agent_start(): #初始计划 agent.run("""执行任务--> - 请为我一个个时间设置初始计划: - 1、在每天12:30到13:30安静不影响主人休息; - 2、每天12点提醒主人吃饭; - 3、在星期一到星期五13:30提醒主人开始工作; - 4、在星期一到星期五15:15提醒主人冲咖啡; - 5、在星期一、星期三的11:15提醒主人开会; - 6、在星期五17:30提醒主人开会; - 7、在星期一到星期五18:00提醒主人下班; + 你是一个智慧农业实验箱里的ai,你的责任是陪伴主人生活、工作,以及协助主人打理好农业种植箱里的农作物: + 1、在每天早上8点、中午12点、晚上10点检查农业种植箱的状态是否附合设定的预期执行,如果不符合请告知我调整。 + 2、每天12点“语音提醒主人吃饭”; + 3、在星期一到星期五13:30“语音提醒主人开始工作”; + 4、在星期一到星期五15:15“语音提醒主人冲咖啡”; + 5、在星期一、星期三的11:15“语音提醒主人开会”; + 6、在星期五17:30“语音提醒主人开会”; + 7、在星期一到星期五18:00“语音提醒主人下班”; 8、在每天21点陪主人聊聊天; - 9、在每天晚上10:30会跟据天气预报信息和前一天的运行情况,检查iotm系统当天的控制规则; - 10、在每天早上8点、中午12点、晚上10点检查农业种植箱的状态是否附合设定的预期执行, - 如果不符合请告知我调整。 - 另外:在任何意外的情况需要进一步指导请马联系我。 + 9、在每天晚上10:30会跟据第二天的天气预报信息和当天的运行情况,检查iotm系统当天的控制规则; + """) def agent_stop(): diff --git a/agent/fay_agent.py b/agent/fay_agent.py index 3fd8fa9..1585088 100644 --- a/agent/fay_agent.py +++ b/agent/fay_agent.py @@ -17,6 +17,8 @@ from agent.tools.Knowledge import Knowledge from agent.tools.Say import Say from agent.tools.QueryTimerDB import QueryTimerDB from agent.tools.DeleteTimer import DeleteTimer +from agent.tools.GetSwitchLog import GetSwitchLog +from agent.tools.getOnRunLinkage import getOnRunLinkage import utils.config_util as utils from core.content_db import Content_Db @@ -35,7 +37,7 @@ class FayAgentCore(): embedding_fn = OpenAIEmbeddings() #创建llm - llm = ChatOpenAI(verbose=True)#model="gpt-4-1106-preview" + llm = ChatOpenAI(model="gpt-4-1106-preview", verbose=True) #创建向量数据库 vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {}) @@ -60,6 +62,9 @@ class FayAgentCore(): say_tool = Say() query_timer_db_tool = QueryTimerDB() delete_timer_tool = DeleteTimer() + get_switch_log = GetSwitchLog() + get_on_run_linkage = getOnRunLinkage() + tools = [ Tool( name=my_timer.name, @@ -111,6 +116,16 @@ class FayAgentCore(): func=delete_timer_tool.run, description=delete_timer_tool.description ), + Tool( + name=get_switch_log.name, + func=get_switch_log.run, + description=get_switch_log.description + ), + Tool( + name=get_on_run_linkage.name, + func=get_on_run_linkage.run, + description=get_on_run_linkage.description + ), ] @@ -126,7 +141,7 @@ class FayAgentCore(): wsa_server.get_web_instance().add_cmd({"panelReply": {"type":"member","content":input_text.replace('主人语音说了:', '').replace('主人文字说了:', '')}}) result = None try: - result = self.agent.run(input_text.replace('执行任务-->', '')) + result = self.agent.run(input_text) except Exception as e: print(e) result = "执行完毕" if result is None or result == "N/A" else result diff --git a/agent/tools/CheckSensor.py b/agent/tools/CheckSensor.py index 1f04b03..395f354 100644 --- a/agent/tools/CheckSensor.py +++ b/agent/tools/CheckSensor.py @@ -3,11 +3,13 @@ from typing import Any import requests from langchain.tools import BaseTool - +import time +import agent.tools.IotmService as IotmService +from datetime import datetime class CheckSensor(BaseTool): name = "CheckSensor" - description = "此工具用于查询农业箱传感器数据及设备开关状态" + description = "此工具用于查询农业箱在线状态、传感器数据、设备开关状态" def __init__(self): super().__init__() @@ -18,73 +20,58 @@ class CheckSensor(BaseTool): def _run(self, para: str) -> str: - return """ - { - "result": True, - "ts": "2023-05-09 17:54:31.948", - "data": [ - "co2": - { - "ts": "2022-05-09 17:54:31.948", - "val": "1000ppm", - "desc":"箱内的二氧化碳含量" - }, - - "inside_temperature": - { - "ts": "2022-05-09 17:54:31.948", - "val": 28, - "desc":"箱内的温度" - }, - - "inside_humidity": - { - "ts": "2022-05-09 17:54:31.948", - "val": 80, - "desc":"箱内的湿度" - }, - - "outside_temperature": - { - "ts": "2022-05-09 17:54:31.948", - "val": 28, - "desc":"箱外的温度" - }, - - "outside_humidity": - { - "ts": "2022-05-09 17:54:31.948", - "val": 80, - "desc":"箱外的湿度" - }, - - "inside_illuminance": - { - "ts": "2022-05-09 17:54:31.948", - "val": "300lux" - "desc":"箱内的光照强度的值,当箱内光照强度太低时,生长灯会被打开,传感器位置是可以检测到生长灯的亮度的" - }, - - "inside_soil": - { - "ts": "2022-05-09 17:54:31.948", - "val": 70 - "desc":"箱内土壤的湿度,检测的数所有延迟,水在土壤里有个渗透的过程" - }, - - - - ], - "制冷":"off", - "加热":"off", - "通风":"off", - "加co2":"off", - "补光":"off", - "浇水":"off" - } -""" + #箱子信息 + building_infos = IotmService.get_building_unit() + is_online = building_infos.get('isonline', 0) + #传感器数据 + sensor_all_infos = IotmService.get_latest_list() + sensor_infos = sensor_all_infos['data'] + desc_list = { + 'temperature': '温度', + 'humidity': '湿度', + 'co2': '二氧化碳', + 'light': '箱内的光照强度的值,当箱内光照强度太低时,生长灯会被打开,传感器位置是可以检测到生长灯的亮度的', + 'air': '污染气体', + 'nh3': '氨气' + } + infos = [] + for sensor_type, sensor_data in sensor_infos.items(): + for data_point in sensor_data: + if sensor_type == 'temperature': + if data_point['port'] == 'MP14': + description = '箱外温度' + else: + description = '箱内温度' + elif sensor_type == 'humidity': + if data_point['port'] == 'MP14': + description = '箱外湿度' + elif data_point['port'] == 'S34': + description = '箱内土壤的湿度,检测的数所有延迟,水在土壤里有个渗透的过程' + else: + description = '箱内湿度' + else: + description = desc_list.get(sensor_type, 'Unknown') # Get description from desc_list, default to 'Unknown' + timestamp = data_point['ts'] + value = data_point['val'] + infos.append({'ts': timestamp, 'val': value, 'desc':description }) + #开关数据 + switch_all_infos = IotmService.get_switch_info() + switch_infos = {} + switch_dict = switch_all_infos[0] + #设备配置 + switch_infos['小风扇'] = 'on' if switch_dict.get('onoff1', '') == '1' else 'off' + switch_infos['电热风扇'] = 'on' if switch_dict.get('onoff2', '') == '1' else 'off' + switch_infos['制冷风扇'] = 'on' if switch_dict.get('onoff3', '') == '1' else 'off' + switch_infos['水开关'] = 'on' if switch_dict.get('onoff4', '') == '1' else 'off' + switch_infos['肥料开关'] = 'on' if switch_dict.get('onoff5', '') == '1' else 'off' + switch_infos['植物生长灯'] = 'on' if switch_dict.get('onoff6', '') == '1' else 'off' + switch_infos['二氧化碳'] = 'on' if switch_dict.get('onoff7', '') == '1' else 'off' + current_time = datetime.now() + current_time_str = current_time.strftime("%Y-%m-%d %H:%M:%S") + result = {'sensor_infos': infos, 'switch_infos': switch_infos, 'is_online': is_online, 'ts' : current_time_str} + return result if __name__ == "__main__": tool = CheckSensor() diff --git a/agent/tools/DeleteTimer.py b/agent/tools/DeleteTimer.py index 0ef19e1..531558c 100644 --- a/agent/tools/DeleteTimer.py +++ b/agent/tools/DeleteTimer.py @@ -1,36 +1,36 @@ -import abc import sqlite3 from typing import Any -import ast from langchain.tools import BaseTool from agent import agent_service -class DeleteTimer(BaseTool, abc.ABC): +class DeleteTimer(BaseTool): name = "DeleteTimer" - description = "用于删除某一个定时任务,接受任务id作为参数,如:('2')" + description = "用于删除某一个日程,接受任务id作为参数,如:2" def __init__(self): super().__init__() - async def _arun(self, *args: Any, **kwargs: Any) -> Any: - # 用例中没有用到 arun 不予具体实现 - pass - - def _run(self, para) -> str: - para = ast.literal_eval(para) + try: + id = int(para) + except ValueError: + return "输入的 ID 无效,必须是数字。" - del agent_service.scheduled_tasks[int(para[0])] - conn = sqlite3.connect('timer.db') - cursor = conn.cursor() - cursor.execute(f"DELETE FROM timer WHERE id = {id}") - conn.commit() - conn.close() + if id in agent_service.scheduled_tasks: + del agent_service.scheduled_tasks[id] - return f"{id}任务取消成功" + try: + with sqlite3.connect('timer.db') as conn: + cursor = conn.cursor() + cursor.execute("DELETE FROM timer WHERE id = ?", (id,)) + conn.commit() + except sqlite3.Error as e: + return f"数据库错误: {e}" + + return f"任务 {id} 取消成功。" if __name__ == "__main__": diff --git a/agent/tools/GetSwitchLog.py b/agent/tools/GetSwitchLog.py new file mode 100644 index 0000000..54ee251 --- /dev/null +++ b/agent/tools/GetSwitchLog.py @@ -0,0 +1,27 @@ +import os +from typing import Any + +from langchain.tools import BaseTool +import agent.tools.IotmService as IotmService + +class GetSwitchLog(BaseTool): + name = "GetSwitchLog" + description = "此工具用于查询农业箱的设备开关操作历史记录,设备序号:小风扇(1)、电热风扇(2)、制冷风扇(3)、肥料开关(4)、补光设备(5)、植物生长灯(6)、二氧化碳(7)" + + def __init__(self): + super().__init__() + + async def _arun(self, *args: Any, **kwargs: Any) -> Any: + # 用例中没有用到 arun 不予具体实现 + pass + + + def _run(self, para: str) -> str: + infos = IotmService.get_switch_log() + + return infos + +if __name__ == "__main__": + tool = GetSwitchLog() + info = tool.run("") + print(info) diff --git a/agent/tools/IotmService.py b/agent/tools/IotmService.py new file mode 100644 index 0000000..ff2d2d3 --- /dev/null +++ b/agent/tools/IotmService.py @@ -0,0 +1,47 @@ + +#获取传感器状态 +def get_latest_list(): + info =""" + {'result': True, 'code': 1, 'msg': '查询成功', 'data': {'co2': [{'ts': '2023-12-18 16:07:28.124', 'val': 8, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S36', 'sensorid': 297}], 'air': [{'ts': '2023-12-18 16:07:28.124', 'val': 15, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S37', 'sensorid': 298}], 'humidity': [{'ts': '2023-12-18 16:06:20.152', 'val': 49.7, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP14', 'sensorid': 302}, {'ts': '2023-12-18 16:06:57.861', 'val': 40.8, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP21', 'sensorid': 300}, {'ts': '2023-12-18 16:07:28.124', 'val': 99.41003, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S34', 'sensorid': 299}], 'light': [{'ts': '2023-12-18 16:07:28.124', 'val': 185, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'bh1', 'sensorid': 301}], 'nh3': [{'ts': '2023-12-18 16:07:28.124', 'val': 14, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'S37', 'sensorid': 303}], 'temperature': [{'ts': '2023-12-18 16:03:58.326', 'val': 18.6, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP14', 'sensorid': 304}, {'ts': '2023-12-18 16:07:28.124', 'val': 22.9, 'istext': False, 'content_des': '', 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'port': 'MP21', 'sensorid': 305}]}} + """ + return info + +#获取开关状态 +def get_switch_info(): + info = """ + [{'id': 16, 'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'onoff1': '1', 'onoff2': '0', 'onoff3': '0', 'onoff4': '0', 'onoff5': '0', 'onoff6': '1', 'onoff7': '1', 'onoff8': '0', 'onoff9': '0', 'onoff10': '0', 'onoff11': '0', 'onoff12': '0', 'onoff13': '0', 'onoff14': '0', 'onoff15': '0', 'onoff16': '0', 'updatetime': 1702886988874}] + """ + return info + +#设备开关操作 +def do_switch_operation(num,onoff): + return True + +#获取传感器基本信息 +def get_building_unit(): + info = """ + {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'lat': '0.0000000000000', 'lng': '0.0000000000000', 'sensor': [{'id': 297, 'title': '二氧化碳传感器', 'label': 'co2'}, {'id': 298, 'title': '空气质量传感器', 'label': 'air'}, {'id': 299, 'title': '土壤湿度传感器', 'label': 'humidity'}, {'id': 300, 'title': '温湿度传感器', 'label': 'humidity'}, {'id': 301, 'title': '光照传感器', 'label': 'light'}, {'id': 302, 'title': '温湿度传感器', 'label': 'humidity'}, {'id': 303, 'title': '氨气传感器', 'label': 'nh3'}, {'id': 304, 'title': '温湿度传感器', 'label': 'temperature'}, {'id': 305, 'title': '温湿度传感器', 'label': 'temperature'}], 'isonline': 1 + """ + return info + +#获取开关记录日志 +def get_switch_log(): + info = """ + [{'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 0, 'createTime': 1702732876735, 'timetText': '2023-12-16 21:21:16'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 1, 'createTime': 1702667478198, 'timetText': '2023-12-16 03:11:18'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 1, 'createTime': 1702664989048, 'timetText': '2023-12-16 02:29:49'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 0, 'createTime': 1702657012799, 'timetText': '2023-12-16 00:16:52'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 7, 'status': 1, 'createTime': 1702648220859, 'timetText': '2023-12-15 21:50:20'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 1, 'createTime': 1702646816090, 'timetText': '2023-12-15 21:26:56'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 0, 'createTime': 1702646531391, 'timetText': '2023-12-15 21:22:11'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 0, 'createTime': 1702646530372, 'timetText': '2023-12-15 21:22:10'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 3, 'status': 1, 'createTime': 1702645992974, 'timetText': '2023-12-15 21:13:12'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 1, 'createTime': 1702644950252, 'timetText': '2023-12-15 20:55:50'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 1, 'status': 0, 'createTime': 1702644949600, 'timetText': '2023-12-15 20:55:49'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702634257442, 'timetText': '2023-12-15 17:57:37'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702633183083, 'timetText': '2023-12-15 17:39:43'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702631382970, 'timetText': '2023-12-15 17:09:42'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702629480618, 'timetText': '2023-12-15 16:38:00'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702628371951, 'timetText': '2023-12-15 16:19:31'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702626695422, 'timetText': '2023-12-15 15:51:35'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702625360795, 'timetText': '2023-12-15 15:29:20'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 0, 'createTime': 1702624152081, 'timetText': '2023-12-15 15:09:12'}, {'did': 'bbb14d38-2814-11ed-b20a-e45f019833ac', 'number': 6, 'status': 1, 'createTime': 1702622351970, 'timetText': '2023-12-15 14:39:11'}] + """ + return info + +#获取联动规则 +def get_on_run_linkage(): + info = """ + {'result': True, 'code': 1, 'msg': '获取成功', 'data': [{'port': 'S34', 'sensorTitle': '土壤湿度传感器', 'label': 'humidity', 'minVal': 0, 'maxVal': 70, 'taskId': 'linkage_135', 'onoff': 1, 'switchNum': 4, 'keeptime': '0.25', 'delaytime': 30}, {'port': 'S36', 'sensorTitle': '二氧化碳传感器', 'label': 'co2', 'minVal': 0, 'maxVal': 8, 'taskId': 'linkage_138', 'onoff': 1, 'switchNum': 7, 'keeptime': '30.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 0, 'maxVal': 28, 'taskId': 'linkage_143', 'onoff': 1, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': +'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_144', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_145', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'bh1', 'sensorTitle': '光照传感器', 'label': 'light', 'minVal': 0, 'maxVal': 100, 'taskId': 'linkage_147', 'onoff': 1, 'switchNum': 6, 'keeptime': '30.00', 'delaytime': 50}]} +[{'port': 'S34', 'sensorTitle': '土壤湿度传感器', 'label': 'humidity', 'minVal': 0, 'maxVal': 70, 'taskId': 'linkage_135', 'onoff': 1, 'switchNum': 4, 'keeptime': '0.25', 'delaytime': 30}, {'port': 'S36', 'sensorTitle': '二氧化碳传感器', 'label': 'co2', 'minVal': 0, 'maxVal': 8, 'taskId': 'linkage_138', 'onoff': 1, 'switchNum': 7, 'keeptime': '30.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 0, 'maxVal': 28, 'taskId': 'linkage_143', 'onoff': +1, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30, 'maxVal': 999999, 'taskId': 'linkage_144', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'MP14', 'sensorTitle': '温湿度传感器', 'label': 'temperature', 'minVal': 30, +'maxVal': 999999, 'taskId': 'linkage_145', 'onoff': 0, 'switchNum': 1, 'keeptime': '0.00', 'delaytime': 0}, {'port': 'bh1', 'sensorTitle': '光照传感器', 'label': 'light', 'minVal': 0, 'maxVal': 100, 'taskId': 'linkage_147', 'onoff': 1, 'switchNum': 6, 'keeptime': '30.00', 'delaytime': 50}] + """ + return info + +if __name__ == "__main__": + str = get_on_run_linkage() + print(str) \ No newline at end of file diff --git a/agent/tools/MyTimer.py b/agent/tools/MyTimer.py index 130afa5..b9d61ff 100644 --- a/agent/tools/MyTimer.py +++ b/agent/tools/MyTimer.py @@ -9,7 +9,7 @@ from langchain.tools import BaseTool class MyTimer(BaseTool, abc.ABC): name = "MyTimer" - description = "用于设置定时任务,每次调用只可以设置一次定时任务.使用的时候需要接受3个参数,第1个参数是时间,第2个参数是循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环),第3个参数代表要执行的事项,如:('15:15', '0000001', '提醒主人叫咖啡')" + description = "用于设置日程,使用的时候需要接受3个参数,第1个参数是时间,第2个参数是循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环),第3个参数代表要执行的事项,如:('15:15', '0000001', '提醒主人叫咖啡')" def __init__(self): super().__init__() @@ -26,7 +26,7 @@ class MyTimer(BaseTool, abc.ABC): cursor.execute("INSERT INTO timer (time, repeat_rule, content) VALUES (?, ?, ?)", (para[0], para[1], para[2])) conn.commit() conn.close() - return "定时任务设置成功" + return "日程设置成功" if __name__ == "__main__": diff --git a/agent/tools/QueryTimerDB.py b/agent/tools/QueryTimerDB.py index 4600194..94a9336 100644 --- a/agent/tools/QueryTimerDB.py +++ b/agent/tools/QueryTimerDB.py @@ -9,7 +9,7 @@ from langchain.tools import BaseTool class QueryTimerDB(BaseTool, abc.ABC): name = "QueryTimerDB" - description = "用于查询所有定时任务,返回的数据里包含3个参数:时间、循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环)、执行的事项" + description = "用于查询所有日程,返回的数据里包含3个参数:时间、循环规则(如:'1000100'代表星期一和星期五循环,'0000000'代表不循环)、执行的事项" def __init__(self): super().__init__() diff --git a/agent/tools/Say.py b/agent/tools/Say.py index b624946..43f1aa9 100644 --- a/agent/tools/Say.py +++ b/agent/tools/Say.py @@ -9,7 +9,7 @@ from core.interact import Interact class Say(BaseTool): name = "Say" - description = """此工具用于语音输出内容,用于与主人沟通及提醒主人,使用时请传入说话内容作为参数,例如:“该下班了,请注意休息”""" + description = """此工具用于沟通及提醒,使用时请传入说话内容作为参数,例如:“该下班了,请注意休息”""" def __init__(self): super().__init__() diff --git a/agent/tools/Switch.py b/agent/tools/Switch.py index 4c91125..2e05741 100644 --- a/agent/tools/Switch.py +++ b/agent/tools/Switch.py @@ -1,13 +1,17 @@ import os +import ast from typing import Any import requests from langchain.tools import BaseTool - +import json +import sys +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) +import agent.tools.IotmService as IotmService class Switch(BaseTool): name = "Switch" - description = "此工具用于控制箱内制冷设备(A)、制热设备(B)、内外通风设备(C)、浇水设备(D)、补光设备(E)、二氧化碳设备(F)的开关状态,参数格式:('A':'on')" + description = '此工具用于控制小风扇、电热风扇、制冷风扇、水开关、肥料开关、植物生长灯、二氧化碳的开关,参数格式:("小风扇","on"),返回True为成功' def __init__(self): super().__init__() @@ -18,11 +22,34 @@ class Switch(BaseTool): def _run(self, para: str) -> str: - return para + try: + if not para: + return "参数不能为空" + para = ast.literal_eval(para) + if not para: + return "参数格式不正确" + switch = para[0] + switch_mapping = { + '小风扇': 1, + '电热风扇': 2, + '制冷风扇': 3, + '水开关': 4, + '肥料开关': 5, + '植物生长灯': 6, + '二氧化碳': 7 + } + if switch not in switch_mapping: + return "未知的设备类型,请检查 'switch' 字段值" + num = switch_mapping[switch] + onoff = para[1] + re = IotmService.do_switch_operation(num, onoff) + return re + except json.JSONDecodeError: + return '参数格式不正确,请使用正确的 JSON 格式表示方式,例如 {"switch": "小风扇", "onoff": "on"}' if __name__ == "__main__": tool = Switch() - info = tool.run("""{"name":"制热设备","switch":"on"}""") + info = tool.run('("小风扇","off")') print(info) diff --git a/agent/tools/Weather.py b/agent/tools/Weather.py index 4014665..9e6d4d9 100644 --- a/agent/tools/Weather.py +++ b/agent/tools/Weather.py @@ -3,11 +3,11 @@ from typing import Any import requests from langchain.tools import BaseTool - +from urllib.parse import quote class Weather(BaseTool): name = "weather" - description = "Use for searching weather at a specific location" + description = "此工具用于获取天气预报信息,需传入英文的城市名,参数格式:Guangzhou" def __init__(self): super().__init__() @@ -18,10 +18,36 @@ class Weather(BaseTool): def _run(self, para: str) -> str: - return "今天天气晴朗,风和日丽,气温25度,空气十分清新,心情美美哒" + try: + if not para: + return "参数不能为空" + encoded_city = quote(para) + + api_url = f"http://api.openweathermap.org/data/2.5/weather?q={encoded_city}&appid=272fcb70d2c4e6f5134c2dce7d091df6" + response = requests.get(api_url) + if response.status_code == 200: + weather_data = response.json() + # 提取天气信息 + temperature_kelvin = weather_data['main']['temp'] + temperature_celsius = temperature_kelvin - 273.15 + min_temperature_kelvin = weather_data['main']['temp_min'] + max_temperature_kelvin = weather_data['main']['temp_max'] + min_temperature_celsius = min_temperature_kelvin - 273.15 + max_temperature_celsius = max_temperature_kelvin - 273.15 + description = weather_data['weather'][0]['description'] + wind_speed = weather_data['wind']['speed'] + + # 构建天气描述 + weather_description = f"今天天气:{description},气温:{temperature_celsius:.2f}摄氏度,风速:{wind_speed} m/s。" + + return f"天气预报信息:{weather_description}" + else: + return f"无法获取天气预报信息,状态码:{response.status_code}" + except Exception as e: + return f"发生错误:{str(e)}" if __name__ == "__main__": weather_tool = Weather() - weather_info = weather_tool.run("成都") + weather_info = weather_tool.run("Guangzhou") print(weather_info) diff --git a/agent/tools/getOnRunLinkage.py b/agent/tools/getOnRunLinkage.py new file mode 100644 index 0000000..5a2d9ab --- /dev/null +++ b/agent/tools/getOnRunLinkage.py @@ -0,0 +1,26 @@ +import os +from typing import Any + +from langchain.tools import BaseTool +import agent.tools.IotmService as IotmService + +class getOnRunLinkage(BaseTool): + name = "getOnRunLinkage" + description = "此工具用于查询农业箱当前在运行的联动,设备序号:小风扇(1)、电热风扇(2)、制冷风扇(3)、肥料开关(4)、补光设备(5)、植物生长灯(6)、二氧化碳(7)" + + def __init__(self): + super().__init__() + + async def _arun(self, *args: Any, **kwargs: Any) -> Any: + # 用例中没有用到 arun 不予具体实现 + pass + + + def _run(self, para: str) -> str: + infos = IotmService.get_on_run_linkage() + return infos + +if __name__ == "__main__": + tool = getOnRunLinkage() + info = tool.run("") + print(info) diff --git a/requirements.txt b/requirements.txt index f944163..7764b9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -21,4 +21,6 @@ ultralytics~=8.0.2 pydub cemotion langchain -faiss-cpu \ No newline at end of file +faiss-cpu +openai +tiktoken \ No newline at end of file