Skip to main content

函数调用

此章节会略有难度,请耐心阅读。

plugins

在plugins新建一个weather.py,并完成对应天气查询函数

import httpx
async def weather_query(location):
async with httpx.AsyncClient() as client:
r=await client.get(f"https://api.lolimi.cn/API/weather/?city={location}")
data=r.json()
return data["data"]

run

在run下创建一个life_service文件夹,并在其中新建一个query_weather.py,实现天气查询的收发。

我们需要同时考虑【格式触发】和【函数调用】两种情况,那么我认为目前最好的处理方式是这样。

from developTools.event.events import GroupMessageEvent
from developTools.message.message_components import Record, Node, Text
from plugins.weather import weather_query
"""
func calling
"""
async def call_weather_query(bot,event,config,location):
r=await weather_query(location)
"""
在获取到天气查询的结果后,我们可以采取以下几种处理方式。
"""
#1.直接返回结果
#await bot.send(event, str(r)) #不算美观,但方便调试

#2.直接返回让调用它的模型判断(推荐),同样是ai总结,但这是更加明智的做法
return {"result": r}

"""
传统指令触发
"""
def main(bot,config):
global avatar
avatar=False
@bot.on(GroupMessageEvent)
async def sendLike(event: GroupMessageEvent):
if event.raw_message.startswith("查天气"):
location = event.raw_message.split("查天气")[1].strip()
r=await call_weather_query(bot,event,config,location)
await bot.send(event, r["result"]) #这里返回的是原始数据。

如你所见,我们将call_weather_query定义在了main函数外部。这是为了能够让它被func_map.py导入并调用。

这是一条Eridanus函数调用的基本规则:所有支持【函数调用】的函数,都必须接受(bot,event,config)作为前三个参数。

init

在你的query_weather.py文件旁边,新建一个__init__.py文件,写入以下内容:

#dynamic_imports使Eridanus的函数调用能够找到你定义的函数
dynamic_imports = {
"run.life_service.query_weather": [ #文件所在位置
"call_weather_query" #函数名
]
}

#function_declarations用来声明函数的具体用法,在实际使用时,会和其他init文件的function_declarations合并为一个function_declarations。
function_declarations=[
{
"name": "call_weather_query",
"description": "Get the current weather in a given location.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city and state, e.g. 上海"
}
},
"required": [
"location"
]
}
},
]

只要你自己写的模块有定义了main(bot,config),当主程序启动时,它就会自动被主程序载入并运行。

需要注意的是,目前我们不建议在包含函数调用函数的文件中使用aiReplyCore,你可以暂时将【函数调用】函数写在一个单独的py文件。后续我们将提供一些拓展函数用于处理函数调用返回结果。

非阻塞式函数调用

在25.2的更新中,aiReplyCore引入了锁机制,使得函数调用返回结果前,用户将无法再次发起对话,这对于一些耗时操作(如ai绘画)来说是非常不利的。

不过你可以用asyncio.create_task(run_tasks()) 创建一个新的异步任务,并在后台执行这个异步协程,这样就不会阻塞当前代码的执行。

from developTools.event.events import GroupMessageEvent
from developTools.message.message_components import Record, Node, Text
from plugins.weather import weather_query


async def call_weather_query(bot,event,config,location):
async def run_tasks():
r=await weather_query(location)
"""
在获取到天气查询的结果后,我们可以采取以下几种处理方式。
"""
#1.直接返回结果
await bot.send(event, str(r)) #不算美观,但方便调试,你可以解析一下再发送给用户

#2.后面我们会提供其他的处理方式
asyncio.create_task(run_tasks())
return {"result": "查询中..."}
def main(bot,config):
global avatar
avatar=False
@bot.on(GroupMessageEvent)
async def sendLike(event: GroupMessageEvent):
if event.raw_message.startswith("查天气"):
location = event.raw_message.split("查天气")[1].strip()
r=await call_weather_query(bot,event,config,location)
await bot.send(event, r["result"]) #这里返回的是原始数据。

从结果来看,在调用此函数后,bot会立即收到"查询中...",然后把“查询中”这一状态告知用户,而不会阻塞当前代码的执行,后台任务仍会继续执行直到完成。