Pycord-Development / pycord

Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for Discord written in Python
https://docs.pycord.dev
MIT License
2.74k stars 463 forks source link

voice_client receiving voice errors / not working ? #2644

Open borick opened 3 days ago

borick commented 3 days ago

Summary

trying to use voice_client getting errors

Reproduction Steps

talk to bot using discord voice and it errors out for me i'm not sure why, i'm trying to get the voice to respond to voice automatically without having to start a command is this possible?

Minimal Reproducible Code

import asyncio
import discord
from discord.ext import commands
from dotenv import load_dotenv
from os import environ
from deepgram import DeepgramClient, PrerecordedOptions, FileSource
from PyCharacterAI import get_client
import tempfile
import logging
import numpy as np

logging.basicConfig(level=logging.DEBUG)

intents = discord.Intents.default()
intents.message_content = True
intents.guilds = True
intents.voice_states = True

bot = commands.Bot(command_prefix="!", intents=intents)
connections = {}
load_dotenv()

deepgram = DeepgramClient(environ.get("DEEPGRAM_API_TOKEN"))

character_ai_token = environ.get("CHARACTER_AI_TOKEN")

options = PrerecordedOptions(
    model="nova-2",
    smart_format=True,
    utterances=True,
    punctuate=True,
    diarize=True,
    detect_language=True,
)

class SilenceDetectingSink(discord.sinks.WaveSink):
    def __init__(self, threshold=-40, **kwargs):
        super().__init__(**kwargs)
        self.threshold = threshold
        self.is_silent = True

    async def process_audio(self, audio_data):
        if self.is_silent:
            if np.mean(audio_data) > self.threshold:
                self.is_silent = False
                self.start_recording()
        else:
            if np.mean(audio_data) < self.threshold:
                self.is_silent = True
                self.stop_recording()
                self.emit("silence_detected")
        await super().process_audio(audio_data)

@bot.event
async def on_ready():
    logging.info(f"Bot is ready and logged in as {bot.user}")

@bot.event
async def on_guild_join(guild):
    logging.info(f'Joined new guild: {guild.name} (id: {guild.id})')

@bot.event
async def on_command_error(ctx, error):
    if isinstance(error, commands.CommandNotFound):
        await ctx.send("Command not found. Please check the available commands.")
    else:
        await ctx.send(f"An error occurred: {str(error)}")
        logging.error(f"An error occurred: {str(error)}")

@bot.command()
async def join(ctx):
    if not ctx.author.voice:
        await ctx.send("⚠️ You aren't in a voice channel!")
        return

    channel = ctx.author.voice.channel
    try:
        vc = await channel.connect()
        connections.update({ctx.guild.id: vc})

        vc.start_recording(
            SilenceDetectingSink(threshold=-40),
            once_done,
            ctx.channel,
        )

        await ctx.send("🔊 Joined the voice channel. Monitoring conversation...")
        logging.info("Started recording")

    except Exception as e:
        await ctx.send(f"Error joining voice channel: {str(e)}")
        logging.error(f"Error joining voice channel: {str(e)}")

async def once_done(sink: discord.sinks, channel: discord.TextChannel, *args):
    logging.info("Recording completed")
    recorded_users = [f"<@{user_id}>" for user_id, audio in sink.audio_data.items()]
    words_list = []

    for user_id, audio in sink.audio_data.items():
        with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
            tmpfile.write(audio.file.read())
            tmpfile_path = tmpfile.name

        payload = FileSource(buffer=audio.file.read())
        response = await deepgram.listen.prerecorded.v("1").transcribe_file(payload, options)
        words = response["results"]["channels"][0]["alternatives"][0]["words"]
        words = [word.to_dict() for word in words]

        for word in words:
            if word["speaker"] != 0:
                user_id = word["speaker"]

            new_word = {
                "word": word["word"],
                "start": word["start"],
                "end": word["end"],
                "confidence": word["confidence"],
                "punctuated_word": word["punctuated_word"],
                "speaker": user_id,
                "speaker_confidence": word["speaker_confidence"],
            }
            words_list.append(new_word)

    words_list.sort(key=lambda x: x["start"])

    transcript = ""
    current_speaker = None

    for word in words_list:
        if "speaker" in word and word["speaker"] != current_speaker:
            transcript += f"\n\nSpeaker <@{word['speaker']}>: "
            current_speaker = word["speaker"]
        transcript += f"{word['punctuated_word']} "

    transcript is transcript.strip()
    await channel.send(f"Finished recording audio for: {', '.join(recorded_users)}. Here is the transcript: \n\n{transcript}")

    logging.info("Transcript created and sent")

@bot.command()
async def leave(ctx):
    if ctx.guild.id in connections:
        vc = connections[ctx.guild.id]
        await vc.disconnect()
        del connections[ctx.guild.id]
        await ctx.send("🚪 Left the voice channel.")
    else:
        await ctx.send("⚠️ I'm not in a voice channel.")

@bot.command()
async def stop_recording(ctx):
    if ctx.guild.id in connections:
        vc = connections[ctx.guild.id]
        vc.stop_recording()
        await ctx.send("🔴 Stopped recording.")
    else:
        await ctx.send("🚫 Not recording here")

print("Bot is starting...")
bot.run(environ.get("DISCORD_BOT_TOKEN"))

Expected Results

it works, responds to voice

Actual Results

errors out , or does nothing

Intents

the default

System Information

intents = discord.Intents.default() intents.message_content = True intents.guilds = True intents.voice_states = True

Checklist

Additional Context

n/a

Paillat-dev commented 3 days ago

@borick Could you please share the full error traceback ?