RuntimeError: 无法从正在运行的事件循环中调用asyncio.run()。有人知道该怎么做吗?

我一直在开发一个Discord机器人,它可以像character.ai角色一样对话。我主要使用了一个非官方的characterai API (https://github.com/kramcat/CharacterAI) 和discord.py库。代码如下:

import tracemalloctracemalloc.start()import asyncioimport discordfrom discord.ext import commandsimport characteraicharacter_ai_token = "character ai token here"intents = discord.Intents.all()client = characterai.pyCAI(character_ai_token)bot = commands.Bot(command_prefix='!', intents=intents)@bot.eventasync def on_ready():    print(f'Bot is ready. Logged in as {bot.user.name}')target_channel_id = "channel_id_here"@bot.eventasync def on_message(message):    data = await client.chat.send_message('CHAR', message, wait=True)    if message.author == bot.user:        return    if message.channel.id != target_channel_id:        return    if message.content.startswith(bot.command_prefix):        await bot.process_commands(message)        return    response = await data['replies'][0]['text']    await message.channel.send(response)async def start_bot():    await bot.start("bot token")async def main():    await asyncio.create_task(start_bot())asyncio.run(main())

我尝试使用了asyncio.create_task()、asyncio.get_event_loop()、loop.create_task()。我还尝试在不将start_bot函数放入main()的情况下使用asyncio.run()。

Traceback (most recent call last):  File "C:\Users\hp\Desktop\projects\discoBotchai\main.py", line 43, in <module>    asyncio.run(main())  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.3056.0_x64__qbz5n2kfra8p0\lib\asyncio\runners.py", line 33, in run    raise RuntimeError(RuntimeError: asyncio.run() cannot be called from a running event loopsys:1: RuntimeWarning: coroutine 'main' was never awaitedObject allocated at (most recent call last):  File "C:\Users\hp\Desktop\projects\discoBotchai\main.py", lineno 43Process finished with exit code 1

回答:

我看到你试图使用await bot.start('...')start_bot函数中启动你的Discord机器人。此外,我注意到你在on_message函数中使用client变量来以”character.ai角色”的身份回应。我发现了一些与启动你的Discord机器人无关的问题。让我们先看看这些问题,然后再看看如何解决它们。

一般问题

  • 启动你的bot目前是多余的。
  • 你应该使用监听器来处理on_message,而不是@bot.event。这样做可以避免在处理命令时遇到问题,并且不需要在消息监听器中手动处理命令。
  • 你的目标频道ID是一个字符串,Discord.py使用整数作为频道ID。
  • 在调用client.chat.send_message时,你将discord.Message对象传递给了message参数。这会导致问题,你需要传递消息的清理内容,如果有的话。
  • 你为你的客户端创建了一个pyCAI实例,而不是pyAsyncCAI实例。pyCAI不是异步的,你需要使用异步客户端实例。
  • 在从你的client获取响应时,你等待了data。这会在运行时导致问题。

启动机器人

让我们看看你当前用于启动机器人的代码块,然后详细说明如何修复它以使其运行。

async def start_bot():    await bot.start("bot token")async def main():    await asyncio.create_task(start_bot())asyncio.run(main())

在你当前的示例中,你的main()函数被调用,它会生成一个任务来运行start_bot函数。然后这个函数调用await bot.start('bot token')。不幸的是,你当前的实现忽略了启动你的异步characterAI客户端,如Github上所示。为了实现这一点,我们需要调整你的main函数以启动机器人和客户端。

async def wrapped_start_bot():    async with bot:        await bot.start('bot token')async def main():    tasks = [        asyncio.create_task(wrapped_start_bot()),        asyncio.create_task(client.start(headless=True)    ]    await asyncio.wait(tasks)

在我们调整后的版本中,我们创建了两个任务:一个启动机器人,另一个启动我们的异步character AI客户端。之后,我们使用asyncio.wait,它会暂停main协程,直到所有任务完成,或者在我们的例子中,直到机器人的生命周期结束。很好,让我们将所有这些更改整合在一起。

最终修订

import asyncioimport characteraiimport discordfrom discord.ext import commandsimport tracemalloctracemalloc.start()character_ai_token = "character ai token here"intents = discord.Intents.all()client = characterai.pyAsyncCAI(character_ai_token)bot = commands.Bot(command_prefix='!', intents=intents)@bot.eventasync def on_ready():    print(f'Bot is ready. Logged in as {bot.user.name}')# 将目标频道ID设置为整数:target_channel_id: int = 000000001# 使用bot.listen()而不是@bot.event,以免担心手动处理命令。@bot.listen('on_message')async def on_message(message: discord.Message):    if not message.content:        # 这条消息没有内容!        return    if message.author.bot:        # 这条消息是由机器人发送的!        return    if message.channel.id != target_channel_id:        # 这不在正确的频道中!        return     # 但我们怎么知道这不是一个命令呢?让我们确保这不是一个有效的命令!    context = await bot.get_context(message)    if context.valid:        # 这是一个有效的命令,这意味着我们的机器人不应该对此做出回应!        return     # 我们知道以下所有项目:    # - 这条消息有内容。    # - 这条消息不是由机器人发送的。    # - 这条消息在正确的频道中。    # - 这条消息不是机器人命令。    data = await client.chat.send_message('CHAR', message.clean_content, wait=True)    response = data['replies'][0]['text']    await message.reply(response, mention_author=False)async def wrapped_start_bot():    async with bot:        await bot.start('bot token')async def main():    tasks = [        asyncio.create_task(wrapped_start_bot()),        asyncio.create_task(client.start(headless=True)    ]    await asyncio.wait(tasks)

很好。我们已经修正了启动botclient的问题,并修复了你当前实现中的一些其他一般问题!

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注