From f09f851e316ba115be4d9505f828f774e83b4a03 Mon Sep 17 00:00:00 2001 From: Furas Date: Wed, 4 Feb 2026 23:30:01 +0100 Subject: [PATCH] i dont even know --- voice_bot.py | 172 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 67 deletions(-) diff --git a/voice_bot.py b/voice_bot.py index 2483b02..f5df9da 100644 --- a/voice_bot.py +++ b/voice_bot.py @@ -1,107 +1,145 @@ import discord from discord.ext import commands -import speech_recognition as sr +import whisper import asyncio import os +import ctypes.util -# Konfiguracja intencji (uprawnień) -intents = discord.Intents.default() -intents.message_content = True -intents.voice_states = True +# ========================================== +# 1. FIX NA OPUS (DLA ARCH LINUX / LINUXA) +# ========================================== +# To naprawia błąd "Error occurred while decoding opus frame" +opus_path = ctypes.util.find_library('opus') +loaded_opus = False -bot = commands.Bot(command_prefix="!", intents=intents) -r = sr.Recognizer() +if opus_path: + print(f"✅ System znalazł bibliotekę Opus: {opus_path}") + try: + discord.opus.load_opus(opus_path) + loaded_opus = True + except Exception as e: + print(f"⚠️ Błąd ładowania systemowego Opus: {e}") -# Funkcja callback - uruchamiana po zakończeniu nagrywania -async def finished_callback(sink, channel: discord.TextChannel, *args): - print("Nagrywanie zakończone. Przetwarzanie audio...") - - # sink.audio_data.items() zwraca pary: user_id, AudioData - for user_id, audio in sink.audio_data.items(): - filename = f"audio_{user_id}.wav" - - # Zapisz plik na dysku - with open(filename, "wb") as f: - f.write(audio.file.read()) # Używamy .read() dla pewności - - # --- Reszta kodu bez zmian (rozpoznawanie mowy) --- +if not loaded_opus: + # Jeśli system nie znalazł, próbujemy standardowych ścieżek + print("⚠️ Próba ręcznego ładowania Opus...") + libs = ['libopus.so.0', 'libopus.so', 'libopus.so.0.8.0'] + for lib in libs: try: - with sr.AudioFile(filename) as source: - # Załaduj audio do pamięci - audio_data = r.record(source) - # Użyj Google Web Speech API (darmowe, ale ma limity) - text = r.recognize_google(audio_data, language="pl-PL") - - user = await bot.fetch_user(user_id) - output = f"Użytkownik {user.name} powiedział: {text}" - - # Print do konsoli (zgodnie z prośbą) - print(output) - # Opcjonalnie wyślij na kanał tekstowy: - # await channel.send(output) + discord.opus.load_opus(lib) + print(f"✅ Załadowano ręcznie: {lib}") + loaded_opus = True + break + except: + pass + +if not loaded_opus: + print("❌ CRITICAL: Nie udało się załadować Opus via ctypes. Nagrywanie może nie działać!") + +# ========================================== +# 2. KONFIGURACJA WHISPER (LOKALNE AI) +# ========================================== +print("⏳ Ładowanie modelu Whisper (może to chwilę potrwać przy starcie)...") +# 'base' jest szybki. Jeśli chcesz super dokładności, zmień na 'small' (wolniejszy) +audio_model = whisper.load_model("base") +print("✅ Model Whisper gotowy!") + +# ========================================== +# 3. KONFIGURACJA BOTA +# ========================================== +intents = discord.Intents.default() +intents.message_content = True +bot = commands.Bot(command_prefix="!", intents=intents) + +async def finished_callback(sink, channel: discord.TextChannel, *args): + """Funkcja uruchamiana PO zatrzymaniu nagrywania""" + print("⏹️ Nagrywanie zakończone. Rozpoczynam transkrypcję lokalną...") + + recorded_users = sink.audio_data.items() + + for user_id, audio in recorded_users: + # 1. Zapisz plik audio na dysk + filename = f"user_{user_id}.wav" + try: + with open(filename, "wb") as f: + f.write(audio.file.read()) + + # 2. Transkrypcja Whisperem + # fp16=False jest ważne, jeśli jedziesz na CPU, żeby nie było warningów + result = audio_model.transcribe(filename, language="pl", fp16=False) + text = result['text'].strip() + + # 3. Wypisz wynik + if text: + user = await bot.fetch_user(user_id) + print(f"🎤 [ROZPOZNANO] {user.name}: {text}") + # Jeśli chcesz wysłać na czat, odkomentuj poniższe: + # await channel.send(f"**{user.name}**: {text}") + else: + print(f"🎤 [CISZA] User {user_id} nic nie powiedział.") - except sr.UnknownValueError: - print(f"Nie zrozumiano mowy użytkownika {user_id}.") - except sr.RequestError as e: - print(f"Błąd serwisu Google Speech Recognition: {e}") except Exception as e: - print(f"Wystąpił błąd: {e}") + print(f"❌ Błąd podczas przetwarzania audio: {e}") finally: - # Posprzątaj pliki tymczasowe + # 4. Sprzątanie plików if os.path.exists(filename): os.remove(filename) @bot.event async def on_ready(): - print(f'Zalogowano jako {bot.user}') + print(f'🚀 Bot zalogowany jako: {bot.user}') + print('Gotowy do działania! Użyj !join, potem !start i !stop.') @bot.command() async def join(ctx): - """Bot dołącza do Twojego kanału głosowego""" + """Wejdź na kanał głosowy""" if ctx.author.voice: channel = ctx.author.voice.channel await channel.connect() - await ctx.send(f"Dołączono do {channel}") + await ctx.send(f"Dołączyłem do: {channel.name}") else: - await ctx.send("Musisz być na kanale głosowym!") + await ctx.send("Musisz być na kanale głosowym, żebym mógł dołączyć.") @bot.command() async def start(ctx): - """Zacznij nagrywanie""" - if ctx.voice_client: - print("Rozpoczynam nagrywanie...") - # WaveSink nagrywa do formatu WAV - ctx.voice_client.start_recording( - discord.sinks.WaveSink(), - finished_callback, - ctx.channel, - ) - await ctx.send("Nasłuchuję... wpisz !stop aby transkrybować.") - else: - await ctx.send("Bot nie jest połączony z kanałem głosowym.") + """Zacznij nagrywać""" + if not ctx.voice_client: + return await ctx.send("Nie jestem na kanale głosowym! Użyj !join") + + print("🔴 Rozpoczynam nasłuch...") + # WAŻNE: To wymaga biblioteki py-cord, nie starego discord.py + ctx.voice_client.start_recording( + discord.sinks.WaveSink(), # Nagrywamy do WAV (Whisper to lubi) + finished_callback, # Po stopie wywołaj tę funkcję + ctx.channel, # Przekaż kanał tekstowy do callbacka + ) + await ctx.send("Nasłuchuję... (wpisz !stop aby zakończyć)") @bot.command() async def stop(ctx): - """Zatrzymaj nagrywanie i wypisz tekst""" + """Zatrzymaj nagrywanie i przetwórz""" if ctx.voice_client: - print("Zatrzymywanie nagrywania...") + print("Trwa zatrzymywanie nagrywania...") ctx.voice_client.stop_recording() - await ctx.send("Zatrzymano nagrywanie. Sprawdź konsolę.") + await ctx.send("Przetwarzanie nagrania... Spójrz w konsolę.") else: - await ctx.send("Bot nic nie nagrywa.") + await ctx.send("Nic teraz nie nagrywam.") @bot.command() async def leave(ctx): - """Bot wychodzi z kanału""" + """Wyjdź z kanału""" if ctx.voice_client: await ctx.voice_client.disconnect() - await ctx.send("Rozłączono.") + await ctx.send("Nara!") else: - await ctx.send("Bot nie jest połączony.") + await ctx.send("Nie jestem połączony.") + +# Uruchomienie +# Wstaw tutaj swój token albo ustaw zmienną środowiskową DISCORD_TOKEN +token = os.getenv("DISCORD_TOKEN") +# token = "TU_WSTAW_TOKEN_JESLI_NIE_UZYWASZ_ENV" -# Uruchom bota -token = os.getenv("DISCORD_TOKEN") if not token: - raise SystemExit("Missing DISCORD_TOKEN environment variable. Set it and retry.") - -bot.run(token) \ No newline at end of file + print("❌ Brak tokena! Ustaw zmienną DISCORD_TOKEN lub wpisz go w kodzie.") +else: + bot.run(token) \ No newline at end of file