I was trying to create a bot in discord that would perform the function of double translation in voice channels, this code is written through the deepseek neural network. I ran into such a problem that when downloading discord.py [voice] discord is not installed.sinks, without which, as I understand it, work is not possible, I cannot find this library separately. And if possible, write down what can be added, corrected, and how best to do it. import os import asyncio import discord from discord.ext import commands from discord.sinks import MP3Sink # Импорт из стандартной библиотеки from transformers import ( WhisperForConditionalGeneration, WhisperProcessor, AutoTokenizer, AutoModelForSeq2SeqLM ) from gtts import gTTS from io import BytesIO import logging # Настройка логирования logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Конфигурация (замените на свои значения) DISCORD_TOKEN = "---------------------" VOICE_CHANNEL_ID = 937370496989806607 # ID голосового канала TEXT_CHANNEL_ID = 937370496989806605 # ID текстового канала # Модели WHISPER_MODEL_NAME = "openai/whisper-large-v2" NLLB_MODEL_NAME = "facebook/nllb-200-distilled-600M" # Языки SOURCE_LANG = "eng_Latn" TARGET_LANG = "rus_Cyrl" class VoiceTranslateBot(commands.Bot): def __init__(self, **kwargs): intents = discord.Intents.all() super().__init__(command_prefix='!', intents=intents) self.voice_client = None self.whisper_processor = None self.whisper_model = None self.nllb_tokenizer = None self.nllb_model = None self.audio_queue = asyncio.Queue() async def setup_hook(self): await self.load_models() await self.connect_to_voice() self.loop.create_task(self.audio_processing_loop()) async def load_models(self): logger.info("Загружаем модели...") self.whisper_processor = WhisperProcessor.from_pretrained(WHISPER_MODEL_NAME) self.whisper_model = WhisperForConditionalGeneration.from_pretrained(WHISPER_MODEL_NAME).to('cuda') self.nllb_tokenizer = AutoTokenizer.from_pretrained(NLLB_MODEL_NAME) self.nllb_model = AutoModelForSeq2SeqLM.from_pretrained(NLLB_MODEL_NAME).to('cuda') logger.info("Модели загружены.") async def connect_to_voice(self): channel = self.get_channel(VOICE_CHANNEL_ID) if channel: self.voice_client = await channel.connect() # Начинаем запись с использованием MP3Sink self.voice_client.start_recording( MP3Sink(), self.on_voice_data, self.loop ) logger.info("Подключено и начата запись.") else: logger.warning("Голосовой канал не найден!") async def on_voice_data(self, sink, audio_data, *args): """Callback при получении аудиоданных""" for user_id, data in audio_data.items(): if user_id != self.user.id: # Игнорируем собственный голос await self.audio_queue.put(data.file.read()) async def audio_processing_loop(self): """Цикл обработки аудио""" while True: audio_bytes = await self.audio_queue.get() try: text = await self.transcribe_audio(audio_bytes) if text.strip(): await self.process_translation(text) except Exception as e: logger.error(f"Ошибка обработки аудио: {e}") async def transcribe_audio(self, audio_bytes): """Распознавание речи через Whisper""" with open("temp_input.wav", "wb") as f: f.write(audio_bytes) from transformers import pipeline transcriber = pipeline( "automatic-speech-recognition", model=self.whisper_model, tokenizer=self.whisper_processor, device=0 ) result = transcriber("temp_input.wav") os.remove("temp_input.wav") return result['text'] def translate_text(self, text): """Перевод текста через NLLB""" self.nllb_tokenizer.src_lang = SOURCE_LANG encoded = self.nllb_tokenizer(text, return_tensors="pt").to('cuda') forced_bos_token_id = self.nllb_tokenizer.lang_code_to_id[TARGET_LANG] generated_ids = self.nllb_model.generate(**encoded, forced_bos_token_id=forced_bos_token_id) return self.nllb_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] def synthesize_speech(self, text, lang='ru'): """Синтез речи через gTTS""" tts = gTTS(text=text, lang=lang) fp = BytesIO() tts.write_to_fp(fp) fp.seek(0) return fp async def process_translation(self, text): """Обработка перевода""" translated = self.translate_text(text) logger.info(f"Перевод: {translated}") audio_fp = self.synthesize_speech(translated) await self.play_audio(audio_fp) async def play_audio(self, audio_fp): """Воспроизведение аудио""" source = discord.FFmpegPCMAudio(audio_fp, pipe=True) if self.voice_client.is_playing(): self.voice_client.stop() self.voice_client.play(source) async def on_ready(self): logger.info(f"Бот запущен как {self.user}") # Запуск бота bot = VoiceTranslateBot() bot.run("-------") Log - E:\Translator\Python>python voice_translate_discord.py Traceback (most recent call last): File "E:\Translator\Python\voice_translate_discord.py", line 5, in <module> from discord.sinks import MP3Sink # Импорт из стандартной библиотеки ModuleNotFoundError: No module named 'discord.sinks' New code - import os import asyncio import logging from io import BytesIO import discord from discord.ext import commands from discord.sinks import MP3Sink from discord.sinks.core import Filters from transformers import ( WhisperForConditionalGeneration, WhisperProcessor, AutoTokenizer, AutoModelForSeq2SeqLM ) from gtts import gTTS from transformers import pipeline # Настройка базового логирования logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.StreamHandler(), logging.FileHandler('bot.log', encoding='utf-8') ] ) logger = logging.getLogger(__name__) # Конфигурация DISCORD_TOKEN = "--------------" VOICE_CHANNEL_ID = 937370496989806607 TEXT_CHANNEL_ID = 937370496989806605 # Модели WHISPER_MODEL_NAME = "openai/whisper-large-v2" NLLB_MODEL_NAME = "facebook/nllb-200-distilled-600M" # Языки SOURCE_LANG = "eng_Latn" TARGET_LANG = "rus_Cyrl" class VoiceTranslateBot(commands.Bot): def __init__(self, **kwargs): intents = discord.Intents.all() super().__init__(command_prefix='!', intents=intents) self.voice_client = None self.whisper_processor = None self.whisper_model = None self.nllb_tokenizer = None self.nllb_model = None self.audio_queue = asyncio.Queue() self.recording_sink = None async def setup_hook(self): await self.load_models() self.loop.create_task(self.audio_processing_loop()) async def load_models(self): """Загрузка моделей обработки языка""" logger.info("Загружаем модели...") try: self.whisper_processor = WhisperProcessor.from_pretrained(WHISPER_MODEL_NAME) self.whisper_model = WhisperForConditionalGeneration.from_pretrained(WHISPER_MODEL_NAME).to('cuda') self.nllb_tokenizer = AutoTokenizer.from_pretrained(NLLB_MODEL_NAME) self.nllb_model = AutoModelForSeq2SeqLM.from_pretrained(NLLB_MODEL_NAME).to('cuda') logger.info("Модели успешно загружены.") except Exception as e: logger.error(f"Ошибка загрузки моделей: {e}") raise @commands.command() async def join(self, ctx): """Подключиться к голосовому каналу пользователя""" try: if ctx.author.voice is None: await ctx.send("Вы не в голосовом канале!") return if self.voice_client and self.voice_client.is_connected(): await ctx.send("Бот уже подключен к голосовому каналу!") return self.voice_client = await ctx.author.voice.channel.connect(timeout=30.0, reconnect=True) # Настройка аудио захвата self.recording_sink = MP3Sink( filters=Filters( filter_users=[self.user.id], filter_audio_data=lambda data: True ), output_path="recordings" ) self.voice_client.start_recording( self.recording_sink, self.on_voice_data, self.loop ) await ctx.send(f"Подключился к каналу {ctx.author.voice.channel.name} и начал запись!") logger.info(f"Подключение к голосовому каналу {ctx.author.voice.channel.id}") except discord.Forbidden: await ctx.send("Ошибка: Нет прав на подключение к голосовому каналу!") logger.error("Нет прав на подключение к голосовому каналу") except discord.HTTPException as e: await ctx.send(f"Ошибка сети: {e}") logger.error(f"Ошибка сети при подключении: {e}") except Exception as e: await ctx.send(f"Неизвестная ошибка: {e}") logger.error(f"Ошибка подключения: {e}") @commands.command() async def leave(self, ctx): """Отключиться от голосового канала""" if not self.voice_client or not self.voice_client.is_connected(): await ctx.send("Бот не подключен к голосовому каналу!") return try: if self.voice_client.is_recording(): self.voice_client.stop_recording() await self.voice_client.disconnect() self.voice_client = None await ctx.send("Отключился от голосового канала!") logger.info("Отключение от голосового канала") except Exception as e: await ctx.send(f"Ошибка отключения: {e}") logger.error(f"Ошибка отключения: {e}") async def on_voice_data(self, sink, audio_data): """Обработка входящих аудиоданных""" try: for user_id, data in audio_data.items(): user = self.get_user(user_id) logger.info(f"Получены аудиоданные от {user.name if user else user_id}") await self.audio_queue.put((user_id, data.file.read())) except Exception as e: logger.error(f"Ошибка обработки аудиоданных: {e}") async def audio_processing_loop(self): """Основной цикл обработки аудио""" while True: user_id, audio_bytes = await self.audio_queue.get() try: text = await self.transcribe_audio(audio_bytes) if text.strip(): await self.process_translation(user_id, text) except Exception as e: logger.error(f"Ошибка обработки аудио: {e}") async def transcribe_audio(self, audio_bytes): """Распознавание речи через Whisper""" try: temp_file = "temp_input.wav" with open(temp_file, "wb") as f: f.write(audio_bytes) transcriber = pipeline( "automatic-speech-recognition", model=self.whisper_model, tokenizer=self.whisper_processor, device=0 ) result = transcriber(temp_file) os.remove(temp_file) return result['text'] except Exception as e: logger.error(f"Ошибка транскрибации: {e}") return "" def translate_text(self, text): """Перевод текста через NLLB""" try: self.nllb_tokenizer.src_lang = SOURCE_LANG encoded = self.nllb_tokenizer(text, return_tensors="pt").to('cuda') forced_bos_token_id = self.nllb_tokenizer.lang_code_to_id[TARGET_LANG] generated_ids = self.nllb_model.generate(**encoded, forced_bos_token_id=forced_bos_token_id) return self.nllb_tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0] except Exception as e: logger.error(f"Ошибка перевода: {e}") return text def synthesize_speech(self, text, lang='ru'): """Синтез речи через gTTS""" try: tts = gTTS(text=text, lang=lang) fp = BytesIO() tts.write_to_fp(fp) fp.seek(0) return fp except Exception as e: logger.error(f"Ошибка синтеза речи: {e}") return None async def process_translation(self, user_id, text): """Обработка перевода""" try: translated = self.translate_text(text) logger.info(f"Перевод от пользователя {user_id}: {translated}") if audio_fp := self.synthesize_speech(translated): await self.play_audio(audio_fp) except Exception as e: logger.error(f"Ошибка обработки перевода: {e}") async def play_audio(self, audio_fp): """Воспроизведение аудио""" try: if not self.voice_client or not self.voice_client.is_connected(): logger.warning("Невозможно воспроизвести: нет подключения к голосовому каналу") return source = discord.FFmpegPCMAudio(audio_fp, pipe=True) if self.voice_client.is_playing(): self.voice_client.stop() self.voice_client.play(source) except Exception as e: logger.error(f"Ошибка воспроизведения аудио: {e}") async def on_ready(self): """Обработчик события готовности бота""" logger.info(f"Бот запущен как {self.user} (ID: {self.user.id})") logger.info(f"Доступные серверы: {len(self.guilds)}") for guild in self.guilds: logger.info(f"- {guild.name} (ID: {guild.id})") if __name__ == "__main__": # Проверка зависимостей try: from discord.sinks import MP3Sink from discord.sinks.core import Filters except ImportError as e: logger.error( "Требуется установить зависимости:\n" "pip install py-cord[voice] transformers gtts\n" f"Ошибка: {e}" ) raise # Создание необходимых директорий os.makedirs("recordings", exist_ok=True) # Запуск бота bot = VoiceTranslateBot() bot.run("---------------") Log - E:\Translator\Python>python voice_translate_discord.py 2025-07-10 16:07:07,467 - discord.client - INFO - logging in using static token 2025-07-10 16:07:08,229 - discord.gateway - INFO - Shard ID None has sent the IDENTIFY payload. 2025-07-10 16:07:08,497 - discord.gateway - INFO - Shard ID None has connected to Gateway: ["gateway-prd-us-east1-b-zn7s",{"micros":95814,"calls":["id_created",{"micros":387,"calls":[]},"session_lookup_time",{"micros":535,"calls":[]},"session_lookup_finished",{"micros":11,"calls":[]},"discord-sessions-prd-2-46",{"micros":94607,"calls":["start_session",{"micros":61890,"calls":["discord-api-rpc-5758b8d864-csz2n",{"micros":44247,"calls":["get_user",{"micros":14425},"get_guilds",{"micros":3725},"send_scheduled_deletion_message",{"micros":13},"guild_join_requests",{"micros":2},"authorized_ip_coro",{"micros":12},"pending_payments",{"micros":4408},"apex_experiments",{"micros":6542},"user_activities",{"micros":3},"played_application_ids",{"micros":2}]}]},"starting_guild_connect",{"micros":29,"calls":[]},"presence_started",{"micros":8920,"calls":[]},"guilds_started",{"micros":71,"calls":[]},"lobbies_started",{"micros":1,"calls":[]},"guilds_connect",{"micros":0,"calls":[]},"presence_connect",{"micros":23675,"calls":[]},"connect_finished",{"micros":23679,"calls":[]},"build_ready",{"micros":15,"calls":[]},"clean_ready",{"micros":0,"calls":[]},"optimize_ready",{"micros":1,"calls":[]},"split_ready",{"micros":0,"calls":[]}]}]}] (Session ID: dd0d615ff919f6b371a568dce7816632). 2025-07-10 16:07:10,508 - __main__ - INFO - Бот запущен как Translator bot#8792 (ID: 1392200178802360560) 2025-07-10 16:07:10,508 - __main__ - INFO - Доступные серверы: 1 2025-07-10 16:07:10,509 - __main__ - INFO - - Сервер cRATE (ID: 937370496989806602) Ignoring exception in command None: discord.ext.commands.errors.CommandNotFound: Command "join" is not found Continue reading...