From d76bcc13662abb3d118dc896f8992035ea880006 Mon Sep 17 00:00:00 2001 From: Jad Date: Wed, 26 Mar 2025 01:32:43 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(plugin=5Ffunc):=20=E6=8B=86=E5=88=86ge?= =?UTF-8?q?t=5Ftime=E5=92=8Cget=5Flunar=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/handle/functionHandler.py | 1 + .../plugins_func/functions/get_time.py | 48 ++++++++++++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/main/xiaozhi-server/core/handle/functionHandler.py b/main/xiaozhi-server/core/handle/functionHandler.py index e8056517..2879ad6d 100644 --- a/main/xiaozhi-server/core/handle/functionHandler.py +++ b/main/xiaozhi-server/core/handle/functionHandler.py @@ -50,6 +50,7 @@ class FunctionHandler: self.function_registry.register_function("handle_exit_intent") self.function_registry.register_function("plugin_loader") self.function_registry.register_function("get_time") + self.function_registry.register_function("get_lunar") self.function_registry.register_function("raise_and_lower_the_volume") def register_config_functions(self): diff --git a/main/xiaozhi-server/plugins_func/functions/get_time.py b/main/xiaozhi-server/plugins_func/functions/get_time.py index c415e4a2..3eb7324c 100644 --- a/main/xiaozhi-server/plugins_func/functions/get_time.py +++ b/main/xiaozhi-server/plugins_func/functions/get_time.py @@ -6,26 +6,59 @@ get_time_function_desc = { "type": "function", "function": { "name": "get_time", - "description": "获取当前日期、时间和农历、黄历等信息", + "description": "获取今天日期或者当前时间信息", 'parameters': {'type': 'object', 'properties': {}, 'required': []} } } - - @register_function('get_time', get_time_function_desc, ToolType.WAIT) def get_time(): """ - 获取当前日期、时间和农历、黄历等信息 + 获取当前的日期时间信息 """ now = datetime.now() current_time = now.strftime("%H:%M:%S") current_date = now.strftime("%Y-%m-%d") current_weekday = now.strftime("%A") - response_text = f"根据以下信息,回应用户的时间查询请求,默认仅回应公历信息;如果用户询问阴历或农历日期,则回应农历日期;如果用户要求提供更多信息,则回应黄历信息\n" + response_text = f"当前日期: {current_date},当前时间: {current_time},星期: {current_weekday}" + + return ActionResponse(Action.REQLLM, response_text, None) + + +get_lunar_function_desc = { + "type": "function", + "function": { + "name": "get_lunar", + "description": ( + "用于获取今天的阴历/农历和黄历信息。" + "用户可以指定查询内容,如:阴历日期、天干地支、节气、生肖、星座、八字、宜忌等。" + "如果没有指定查询内容,则默认查询干支年和农历日期。" + ), + "parameters": { + "type": "object", + "properties": { + "query": { + "type": "string", + "description": "要查询的内容,例如阴历日期、天干地支、节日、节气、生肖、星座、八字、宜忌等" + } + }, + "required": [] + } + } +} +@register_function('get_lunar', get_lunar_function_desc, ToolType.WAIT) +def get_lunar(query): + """ + 用于获取当前的阴历/农历,和天干地支、节气、生肖、星座、八字、宜忌等黄历信息 + """ + now = datetime.now() + current_time = now.strftime("%H:%M:%S") + current_date = now.strftime("%Y-%m-%d") + current_weekday = now.strftime("%A") + response_text = f"根据以下信息回应用户的查询请求,并提供与{query}相关的信息:\n" lunar = cnlunar.Lunar(now, godType='8char') response_text += ( - f"当前日期: {current_date},当前时间: {current_time},星期: {current_weekday}\n" + f"当前公历日期: {current_date},当前时间: {current_time},星期: {current_weekday}\n" "农历信息:\n" "%s年%s%s\n" % (lunar.lunarYearCn, lunar.lunarMonthCn[:-1], lunar.lunarDayCn) + "干支: %s年 %s月 %s日\n" % (lunar.year8Char, lunar.month8Char, lunar.day8Char) + @@ -45,7 +78,8 @@ def get_time(): "吉神方位: %s\n" % ' '.join(lunar.get_luckyGodsDirection()) + "今日胎神: %s\n" % lunar.get_fetalGod() + "宜: %s\n" % '、'.join(lunar.goodThing[:10]) + - "忌: %s\n" % '、'.join(lunar.badThing[:10]) + "忌: %s\n" % '、'.join(lunar.badThing[:10]) + + "(默认返回干支年和农历日期;仅在要求查询宜忌信息时才返回本日宜忌)" ) return ActionResponse(Action.REQLLM, response_text, None) \ No newline at end of file From 3649a33afb7874b6646106bce625f7fed1e49bd3 Mon Sep 17 00:00:00 2001 From: Jad Date: Wed, 26 Mar 2025 03:56:39 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat(plugin=5Ffunc):=20=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E9=9F=B3=E9=87=8F=E6=8E=A7=E5=88=B6=E6=8F=92=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E4=BA=AE=E5=BA=A6=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持立创实战派等设备亮度调整 --- .../core/handle/functionHandler.py | 2 +- .../plugins_func/functions/handle_device.py | 105 ++++++++++++++++++ .../functions/raise_and_lower_the_volume.py | 64 ----------- 3 files changed, 106 insertions(+), 65 deletions(-) create mode 100644 main/xiaozhi-server/plugins_func/functions/handle_device.py delete mode 100644 main/xiaozhi-server/plugins_func/functions/raise_and_lower_the_volume.py diff --git a/main/xiaozhi-server/core/handle/functionHandler.py b/main/xiaozhi-server/core/handle/functionHandler.py index 2879ad6d..9cad9499 100644 --- a/main/xiaozhi-server/core/handle/functionHandler.py +++ b/main/xiaozhi-server/core/handle/functionHandler.py @@ -51,7 +51,7 @@ class FunctionHandler: self.function_registry.register_function("plugin_loader") self.function_registry.register_function("get_time") self.function_registry.register_function("get_lunar") - self.function_registry.register_function("raise_and_lower_the_volume") + self.function_registry.register_function("handle_device") def register_config_functions(self): """注册配置中的函数,可以不同客户端使用不同的配置""" diff --git a/main/xiaozhi-server/plugins_func/functions/handle_device.py b/main/xiaozhi-server/plugins_func/functions/handle_device.py new file mode 100644 index 00000000..d564562b --- /dev/null +++ b/main/xiaozhi-server/plugins_func/functions/handle_device.py @@ -0,0 +1,105 @@ +from config.logger import setup_logging +from plugins_func.register import register_function, ToolType, ActionResponse, Action +from core.handle.iotHandle import get_iot_status, send_iot_conn +import asyncio + +TAG = __name__ +logger = setup_logging() + +async def _get_device_status(conn, device_name, device_type, property_name): + """获取设备状态""" + status = await get_iot_status(conn, device_type, property_name) + if status is None: + raise Exception(f"你的设备不支持{device_name}控制") + return status + +async def _set_device_property(conn, device_name, device_type, method_name, property_name, new_value=None, action=None, step=10): + """设置设备属性""" + current_value = await _get_device_status(conn, device_name, device_type, property_name) + + if action == 'raise': + current_value += step + elif action == 'lower': + current_value -= step + elif action == 'set': + if new_value is None: + raise Exception(f"缺少{property_name}参数") + current_value = new_value + + # 限制属性范围在0到100之间 + current_value = max(0, min(100, current_value)) + + await send_iot_conn(conn, device_type, method_name, {property_name: current_value}) + return current_value + +def _handle_device_action(conn, func, success_message, error_message, *args, **kwargs): + """处理设备操作的通用函数""" + future = asyncio.run_coroutine_threadsafe(func(conn, *args, **kwargs), conn.loop) + try: + result = future.result() + logger.bind(tag=TAG).info(f"{success_message}: {result}") + response = f"{success_message}{result}" + return ActionResponse(action=Action.RESPONSE, result=result, response=response) + except Exception as e: + logger.bind(tag=TAG).error(f"{error_message}: {e}") + response = f"{error_message}: {e}" + return ActionResponse(action=Action.RESPONSE, result=None, response=response) + +# 设备控制 +handle_device_function_desc = { + "type": "function", + "function": { + "name": "handle_device", + "description": ( + "用户想要获取或者设置设备的音量/亮度大小,或者用户觉得声音/亮度过高或过低,或者用户想提高或降低音量/亮度。" + "比如用户说现在亮度多少,参数为:device_type:Backlight,action:get。" + "比如用户说设置音量为50,参数为:device_type:Speaker,action:set,value:50。" + "比如用户说亮度太高了,参数为:device_type:Backlight,action:lower。" + "比如用户说调大音量,参数为:device_type:Speaker,action:raise。" + ), + "parameters": { + "type": "object", + "properties": { + "device_type": { + "type": "string", + "description": "设备类型,可选值:Speaker(音量),Backlight(亮度)" + }, + "action": { + "type": "string", + "description": "动作名称,可选值:get(获取),set(设置),raise(提高),lower(降低)" + }, + "value": { + "type": "int", + "description": "值大小,可选值:0-100之间的整数" + } + }, + "required": ["device_type", "action"] + } + } +} + +@register_function('handle_device', handle_device_function_desc, ToolType.IOT_CTL) +def handle_device(conn, device_type: str, action: str, value: int = None): + if device_type == "Speaker": + method_name, property_name, device_name = "SetVolume", "volume", "音量" + elif device_type == "Backlight": + method_name, property_name, device_name = "SetBrightness", "brightness", "亮度" + else: + raise Exception(f"未识别的设备类型: {device_type}") + + if action not in ["get", "set", "raise", "lower"]: + raise Exception(f"未识别的动作名称: {action}") + + if action == "get": + # get + return _handle_device_action( + conn, _get_device_status, f"当前{device_name}", f"获取{device_name}失败", + device_name=device_name, device_type=device_type, property_name=property_name, + ) + else: + # set, raise, lower + return _handle_device_action( + conn, _set_device_property, f"{device_name}已调整到", f"{device_name}调整失败", + device_name=device_name, device_type=device_type, method_name=method_name, + property_name=property_name, new_value=value, action=action + ) diff --git a/main/xiaozhi-server/plugins_func/functions/raise_and_lower_the_volume.py b/main/xiaozhi-server/plugins_func/functions/raise_and_lower_the_volume.py deleted file mode 100644 index c77cb78b..00000000 --- a/main/xiaozhi-server/plugins_func/functions/raise_and_lower_the_volume.py +++ /dev/null @@ -1,64 +0,0 @@ -from config.logger import setup_logging -from plugins_func.register import register_function, ToolType, ActionResponse, Action -from core.handle.iotHandle import get_iot_status, send_iot_conn -import asyncio - -TAG = __name__ -logger = setup_logging() - -raise_and_lower_the_volume_function_desc = { - "type": "function", - "function": { - "name": "raise_and_lower_the_volume", - "description": "用户觉得声音过高或过低,或者用户想提高或降低音量。比如用户说太大声了,参数为:lower,比如用户说提高音量,参数为:raise", - "parameters": { - "type": "object", - "properties": { - "action": { - "type": "string", - "description": "动作名称,要么是raise,要么是lower" - } - }, - "required": ["action"] - } - } -} - - -@register_function('raise_and_lower_the_volume', raise_and_lower_the_volume_function_desc, ToolType.IOT_CTL) -def raise_and_lower_the_volume(conn, action: str): - """ - 获取当前设备音量 - """ - - future = asyncio.run_coroutine_threadsafe( - _raise_and_lower_the_volume(conn, action), - conn.loop - ) - - try: - new_volume = future.result() # 同步等待异步操作完成 - logger.bind(tag=TAG).info(f"音量操作完成: {new_volume}") - response = f"音量已调整到{new_volume}" - except Exception as e: - logger.bind(tag=TAG).error(f"音量操作失败: {e}") - response = f"音量调整失败: {e}" - - return ActionResponse(action=Action.RESPONSE, result="指令已接收", response=response) - - -async def _raise_and_lower_the_volume(conn, action): - volume = await get_iot_status(conn, "Speaker", "volume") - if volume is None: - raise Exception("你的设备不支持音量控制") - if action == 'raise': - volume += 10 - elif action == 'lower': - volume -= 10 - # 限制音量范围在0到100之间 - if volume < 0: - volume = 0 - elif volume > 100: - volume = 100 - await send_iot_conn(conn, "Speaker", "SetVolume", {"volume": volume}) - return volume