i dont even know
This commit is contained in:
172
voice_bot.py
172
voice_bot.py
@@ -1,107 +1,145 @@
|
|||||||
import discord
|
import discord
|
||||||
from discord.ext import commands
|
from discord.ext import commands
|
||||||
import speech_recognition as sr
|
import whisper
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
|
import ctypes.util
|
||||||
|
|
||||||
# Konfiguracja intencji (uprawnień)
|
# ==========================================
|
||||||
intents = discord.Intents.default()
|
# 1. FIX NA OPUS (DLA ARCH LINUX / LINUXA)
|
||||||
intents.message_content = True
|
# ==========================================
|
||||||
intents.voice_states = True
|
# 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)
|
if opus_path:
|
||||||
r = sr.Recognizer()
|
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
|
if not loaded_opus:
|
||||||
async def finished_callback(sink, channel: discord.TextChannel, *args):
|
# Jeśli system nie znalazł, próbujemy standardowych ścieżek
|
||||||
print("Nagrywanie zakończone. Przetwarzanie audio...")
|
print("⚠️ Próba ręcznego ładowania Opus...")
|
||||||
|
libs = ['libopus.so.0', 'libopus.so', 'libopus.so.0.8.0']
|
||||||
# sink.audio_data.items() zwraca pary: user_id, AudioData
|
for lib in libs:
|
||||||
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) ---
|
|
||||||
try:
|
try:
|
||||||
with sr.AudioFile(filename) as source:
|
discord.opus.load_opus(lib)
|
||||||
# Załaduj audio do pamięci
|
print(f"✅ Załadowano ręcznie: {lib}")
|
||||||
audio_data = r.record(source)
|
loaded_opus = True
|
||||||
# Użyj Google Web Speech API (darmowe, ale ma limity)
|
break
|
||||||
text = r.recognize_google(audio_data, language="pl-PL")
|
except:
|
||||||
|
pass
|
||||||
user = await bot.fetch_user(user_id)
|
|
||||||
output = f"Użytkownik {user.name} powiedział: {text}"
|
if not loaded_opus:
|
||||||
|
print("❌ CRITICAL: Nie udało się załadować Opus via ctypes. Nagrywanie może nie działać!")
|
||||||
# Print do konsoli (zgodnie z prośbą)
|
|
||||||
print(output)
|
# ==========================================
|
||||||
# Opcjonalnie wyślij na kanał tekstowy:
|
# 2. KONFIGURACJA WHISPER (LOKALNE AI)
|
||||||
# await channel.send(output)
|
# ==========================================
|
||||||
|
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:
|
except Exception as e:
|
||||||
print(f"Wystąpił błąd: {e}")
|
print(f"❌ Błąd podczas przetwarzania audio: {e}")
|
||||||
finally:
|
finally:
|
||||||
# Posprzątaj pliki tymczasowe
|
# 4. Sprzątanie plików
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
os.remove(filename)
|
os.remove(filename)
|
||||||
|
|
||||||
@bot.event
|
@bot.event
|
||||||
async def on_ready():
|
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()
|
@bot.command()
|
||||||
async def join(ctx):
|
async def join(ctx):
|
||||||
"""Bot dołącza do Twojego kanału głosowego"""
|
"""Wejdź na kanał głosowy"""
|
||||||
if ctx.author.voice:
|
if ctx.author.voice:
|
||||||
channel = ctx.author.voice.channel
|
channel = ctx.author.voice.channel
|
||||||
await channel.connect()
|
await channel.connect()
|
||||||
await ctx.send(f"Dołączono do {channel}")
|
await ctx.send(f"Dołączyłem do: {channel.name}")
|
||||||
else:
|
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()
|
@bot.command()
|
||||||
async def start(ctx):
|
async def start(ctx):
|
||||||
"""Zacznij nagrywanie"""
|
"""Zacznij nagrywać"""
|
||||||
if ctx.voice_client:
|
if not ctx.voice_client:
|
||||||
print("Rozpoczynam nagrywanie...")
|
return await ctx.send("Nie jestem na kanale głosowym! Użyj !join")
|
||||||
# WaveSink nagrywa do formatu WAV
|
|
||||||
ctx.voice_client.start_recording(
|
print("🔴 Rozpoczynam nasłuch...")
|
||||||
discord.sinks.WaveSink(),
|
# WAŻNE: To wymaga biblioteki py-cord, nie starego discord.py
|
||||||
finished_callback,
|
ctx.voice_client.start_recording(
|
||||||
ctx.channel,
|
discord.sinks.WaveSink(), # Nagrywamy do WAV (Whisper to lubi)
|
||||||
)
|
finished_callback, # Po stopie wywołaj tę funkcję
|
||||||
await ctx.send("Nasłuchuję... wpisz !stop aby transkrybować.")
|
ctx.channel, # Przekaż kanał tekstowy do callbacka
|
||||||
else:
|
)
|
||||||
await ctx.send("Bot nie jest połączony z kanałem głosowym.")
|
await ctx.send("Nasłuchuję... (wpisz !stop aby zakończyć)")
|
||||||
|
|
||||||
@bot.command()
|
@bot.command()
|
||||||
async def stop(ctx):
|
async def stop(ctx):
|
||||||
"""Zatrzymaj nagrywanie i wypisz tekst"""
|
"""Zatrzymaj nagrywanie i przetwórz"""
|
||||||
if ctx.voice_client:
|
if ctx.voice_client:
|
||||||
print("Zatrzymywanie nagrywania...")
|
print("Trwa zatrzymywanie nagrywania...")
|
||||||
ctx.voice_client.stop_recording()
|
ctx.voice_client.stop_recording()
|
||||||
await ctx.send("Zatrzymano nagrywanie. Sprawdź konsolę.")
|
await ctx.send("Przetwarzanie nagrania... Spójrz w konsolę.")
|
||||||
else:
|
else:
|
||||||
await ctx.send("Bot nic nie nagrywa.")
|
await ctx.send("Nic teraz nie nagrywam.")
|
||||||
|
|
||||||
@bot.command()
|
@bot.command()
|
||||||
async def leave(ctx):
|
async def leave(ctx):
|
||||||
"""Bot wychodzi z kanału"""
|
"""Wyjdź z kanału"""
|
||||||
if ctx.voice_client:
|
if ctx.voice_client:
|
||||||
await ctx.voice_client.disconnect()
|
await ctx.voice_client.disconnect()
|
||||||
await ctx.send("Rozłączono.")
|
await ctx.send("Nara!")
|
||||||
else:
|
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:
|
if not token:
|
||||||
raise SystemExit("Missing DISCORD_TOKEN environment variable. Set it and retry.")
|
print("❌ Brak tokena! Ustaw zmienną DISCORD_TOKEN lub wpisz go w kodzie.")
|
||||||
|
else:
|
||||||
bot.run(token)
|
bot.run(token)
|
||||||
Reference in New Issue
Block a user