英文:
RuntimeError: asyncio.run() cannot be called from a running event loop. Anyone know what to do?
问题
以下是您要翻译的代码部分:
import tracemalloc
tracemalloc.start()
import asyncio
import discord
from discord.ext import commands
import characterai
character_ai_token = "character ai token here"
intents = discord.Intents.all()
client = characterai.pyCAI(character_ai_token)
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'Bot is ready. Logged in as {bot.user.name}')
target_channel_id = "channel_id_here"
@bot.event
async 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())
希望这有所帮助。如果您需要进一步的信息或翻译,请告诉我。
英文:
Been working on a Discord bot that talks as a character.ai character, I utilized mainly an unofficial characterai API (https://github.com/kramcat/CharacterAI) and the discord.py library.
Code below:
import tracemalloc
tracemalloc.start()
import asyncio
import discord
from discord.ext import commands
import characterai
character_ai_token = "character ai token here"
intents = discord.Intents.all()
client = characterai.pyCAI(character_ai_token)
bot = commands.Bot(command_prefix='!', intents=intents)
@bot.event
async def on_ready():
print(f'Bot is ready. Logged in as {bot.user.name}')
target_channel_id = "channel_id_here"
@bot.event
async 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())
I tried using asyncio.create_task(), asyncio.get_event_loop(), loop.create_task(). I tried using asyncio.run() without putting the start_bot function into main()
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 loop
sys:1: RuntimeWarning: coroutine 'main' was never awaited
Object allocated at (most recent call last):
File "C:\Users\hp\Desktop\projects\discoBotchai\main.py", lineno 43
Process finished with exit code 1
答案1
得分: 1
I see you are trying to start your given Discord bot using await bot.start('...')
in a start_bot
function. Additionally, I see that you use the client
variable in your on_message
function to respond as the "character.ai character". I see a couple of issues unrelated to starting your Discord bot. Let us look at these, then look at how we can solve them.
General Issues
- Starting your
bot
is currently redundant. - You should be using listeners for on_message instead of
@bot.event
. This is so you do not run into issues with processing commands and do not have to do it in your message listener. - Your target channel ID is a string, Discord.py uses integers for channel IDs.
- When calling
client.chat.send_message
, you are passing thediscord.Message
object into themessage
parameter. This will cause issues, you need to be passing the message's clean content, if it has it. - You created an instance of
pyCAI
for your client, not an instance ofpyAsyncCAI
.pyCAI
is not async, you need to be using the async client instance. - When retrieving the response from your
client
, you await thedata
. This will cause issues at runtime.
Getting the Bot Running
Let's take a look at your current block of code for starting your bot, then elaborate on how we can fix this to get you running.
async def start_bot():
await bot.start("bot token")
async def main():
await asyncio.create_task(start_bot())
asyncio.run(main())
In your current example, your main()
function gets called, which spawns a task that runs the start_bot
function. This function then calls await bot.start('bot token')
. Your current implementation, unfortunately, neglects to start your async characterAI client as shown on the Github. To achieve this, we need to adjust your main
function to launch both the bot and the client.
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)
In our adjusted version, we create two tasks: One that starts the bot, and another that starts our async character AI client. Afterward, we use asyncio.wait
which will suspend the main
coroutine until all tasks are done, or in our case, until the end of the bot's lifetime. Great, let's push all these changes together.
Finalized Revisions
import asyncio
import characterai
import discord
from discord.ext import commands
import tracemalloc
tracemalloc.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.event
async def on_ready():
print(f'Bot is ready. Logged in as {bot.user.name}')
# Set target channel ID to be an integer here:
target_channel_id: int = 000000001
# Utilizing bot.listen() instead of @bot.event as to
# not worry about manually processing commands.
@bot.listen('on_message')
async def on_message(message: discord.Message):
if not message.content:
# This message has no content!
return
if message.author.bot:
# This message has been sent by a bot!
return
if message.channel.id != target_channel_id:
# This is not in the correct channel!
return
# But how do we know this isn't a command? Let's ensure this isn't a valid command!
context = await bot.get_context(message)
if context.valid:
# This is a valid command, which means our bot should not respond to it!
return
# We know all the following items:
# - This message has content.
# - This message was not sent by a bot.
# - This message is in the correct channel.
# - This message is not a bot command.
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)
Great. We've corrected launching the bot
and client
as well as fixed some other general issues with your current implementation!
英文:
I see you are trying to start your given Discord bot using await bot.start('...')
in a start_bot
function. Additionally, I see that you use the client
variable in your on_message
function to respond as the "character.ai character". I see a couple of issues unrelated to starting your Discord bot. Let us look at these, then look at how we can solve them.
General Issues
- Starting your
bot
is currently redundant. - You should be using listeners for on_message instead of
@bot.event
. This is so you do not run into issues with processing commands and do not have to do it in your message listener. - Your target channel ID is a string, Discord.py uses integers for channel IDs.
- When calling
client.chat.send_message
, you are passing thediscord.Message
object into themessage
parameter. This will cause issues, you need to be passing the message's clean content, if it has it. - You created an instance of
pyCAI
for your client, not an instance ofpyAsyncCAI
.pyCAI
is not async, you need to be using the async client instance. - When retrieving the response from your
client
, you await thedata
. This will cause issues at runtime.
Getting the Bot Running
Let's take a look at your current block of code for starting your bot, then elaborate on how we can fix this to get you running.
async def start_bot():
await bot.start("bot token")
async def main():
await asyncio.create_task(start_bot())
asyncio.run(main())
In your current example, your main()
function gets called, which spawns a task that runs the start_bot
function. This function then calls await bot.start('bot token')
. Your current implementation, unfortunately, neglects to start your async characterAI client as shown on the Github. To achieve this, we need to adjust your main
function to launch both the bot and the client.
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)
In our adjusted version, we create two tasks: One that starts the bot, and another that starts our async character AI client. Afterward, we use asyncio.wait
which will suspend the main
coroutine until all tasks are done, or in our case, until the end of the bot's lifetime. Great, let's push all these changes together.
Finalized Revisions
import asyncio
import characterai
import discord
from discord.ext import commands
import tracemalloc
tracemalloc.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.event
async def on_ready():
print(f'Bot is ready. Logged in as {bot.user.name}')
# Set target channel ID to be an integer here:
target_channel_id: int = 000000001
# Utilizing bot.listen() instead of @bot.event as to
# not worry about manually processing commands.
@bot.listen('on_message')
async def on_message(message: discord.Message):
if not message.content:
# This message has no content!
return
if message.author.bot:
# This message has been sent by a bot!
return
if message.channel.id != target_channel_id:
# This is not in the correct channel!
return
# But how do we know this isn't a command? Let's ensure this isn't a valid command!
context = await bot.get_context(message)
if context.valid:
# This is a valid command, which means our bot should not respond to it!
return
# We know all the following items:
# - This message has content.
# - This message was not sent by a bot.
# - This message is in the correct channel.
# - This message is not a bot command.
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)
Great. We've corrected launching the bot
and client
as well as fixed some other general issues with your current implementation!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论