mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-27 01:23:55 +08:00
Merge pull request #528 from journey-ad/refactor-plugins
优化获取日期和音量亮度控制插件
This commit is contained in:
@@ -50,7 +50,8 @@ class FunctionHandler:
|
|||||||
self.function_registry.register_function("handle_exit_intent")
|
self.function_registry.register_function("handle_exit_intent")
|
||||||
self.function_registry.register_function("plugin_loader")
|
self.function_registry.register_function("plugin_loader")
|
||||||
self.function_registry.register_function("get_time")
|
self.function_registry.register_function("get_time")
|
||||||
self.function_registry.register_function("raise_and_lower_the_volume")
|
self.function_registry.register_function("get_lunar")
|
||||||
|
self.function_registry.register_function("handle_device")
|
||||||
|
|
||||||
def register_config_functions(self):
|
def register_config_functions(self):
|
||||||
"""注册配置中的函数,可以不同客户端使用不同的配置"""
|
"""注册配置中的函数,可以不同客户端使用不同的配置"""
|
||||||
|
|||||||
@@ -6,26 +6,59 @@ get_time_function_desc = {
|
|||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "get_time",
|
"name": "get_time",
|
||||||
"description": "获取当前日期、时间和农历、黄历等信息",
|
"description": "获取今天日期或者当前时间信息",
|
||||||
'parameters': {'type': 'object', 'properties': {}, 'required': []}
|
'parameters': {'type': 'object', 'properties': {}, 'required': []}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@register_function('get_time', get_time_function_desc, ToolType.WAIT)
|
@register_function('get_time', get_time_function_desc, ToolType.WAIT)
|
||||||
def get_time():
|
def get_time():
|
||||||
"""
|
"""
|
||||||
获取当前日期、时间和农历、黄历等信息
|
获取当前的日期时间信息
|
||||||
"""
|
"""
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
current_time = now.strftime("%H:%M:%S")
|
current_time = now.strftime("%H:%M:%S")
|
||||||
current_date = now.strftime("%Y-%m-%d")
|
current_date = now.strftime("%Y-%m-%d")
|
||||||
current_weekday = now.strftime("%A")
|
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')
|
lunar = cnlunar.Lunar(now, godType='8char')
|
||||||
response_text += (
|
response_text += (
|
||||||
f"当前日期: {current_date},当前时间: {current_time},星期: {current_weekday}\n"
|
f"当前公历日期: {current_date},当前时间: {current_time},星期: {current_weekday}\n"
|
||||||
"农历信息:\n"
|
"农历信息:\n"
|
||||||
"%s年%s%s\n" % (lunar.lunarYearCn, lunar.lunarMonthCn[:-1], lunar.lunarDayCn) +
|
"%s年%s%s\n" % (lunar.lunarYearCn, lunar.lunarMonthCn[:-1], lunar.lunarDayCn) +
|
||||||
"干支: %s年 %s月 %s日\n" % (lunar.year8Char, lunar.month8Char, lunar.day8Char) +
|
"干支: %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" % ' '.join(lunar.get_luckyGodsDirection()) +
|
||||||
"今日胎神: %s\n" % lunar.get_fetalGod() +
|
"今日胎神: %s\n" % lunar.get_fetalGod() +
|
||||||
"宜: %s\n" % '、'.join(lunar.goodThing[:10]) +
|
"宜: %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)
|
return ActionResponse(Action.REQLLM, response_text, None)
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user