import discord from discord.ext import commands import whisper import asyncio import os import ctypes.util # ========================================== # 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 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}") 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: 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 Exception as e: print(f"❌ Błąd podczas przetwarzania audio: {e}") finally: # 4. Sprzątanie plików if os.path.exists(filename): os.remove(filename) @bot.event async def on_ready(): 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): """Wejdź na kanał głosowy""" if ctx.author.voice: channel = ctx.author.voice.channel await channel.connect() await ctx.send(f"Dołączyłem do: {channel.name}") else: await ctx.send("Musisz być na kanale głosowym, żebym mógł dołączyć.") @bot.command() async def start(ctx): """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 przetwórz""" if ctx.voice_client: print("Trwa zatrzymywanie nagrywania...") ctx.voice_client.stop_recording() await ctx.send("Przetwarzanie nagrania... Spójrz w konsolę.") else: await ctx.send("Nic teraz nie nagrywam.") @bot.command() async def leave(ctx): """Wyjdź z kanału""" if ctx.voice_client: await ctx.voice_client.disconnect() await ctx.send("Nara!") else: 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" if not token: print("❌ Brak tokena! Ustaw zmienną DISCORD_TOKEN lub wpisz go w kodzie.") else: bot.run(token)