-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtranslator_bot.py
More file actions
331 lines (273 loc) · 15.3 KB
/
Copy pathtranslator_bot.py
File metadata and controls
331 lines (273 loc) · 15.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
import os
import logging
import asyncio
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, filters, ContextTypes
from telegram.constants import ChatType
from openai import OpenAI
from dotenv import load_dotenv
import tempfile
import json
import re
from google.cloud import texttospeech
# Загружаем переменные окружения
load_dotenv()
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO,
handlers=[
logging.StreamHandler(),
logging.FileHandler('bot.log')
]
)
logger = logging.getLogger(__name__)
logger.info('🚀 Бот запускается...')
# Инициализация OpenAI
openai_client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
google_client = texttospeech.TextToSpeechClient()
LANG_EMOJIS = {
'ru': '🇷🇺',
'id': '🇮🇩',
'en': '🇺🇸'
}
VOICES = {
'ru': 'shimmer', # женский голос 👩
'id': 'nova', # женский голос 👩
'en': 'echo' # мужской голос 👨
}
def clean_text(text: str) -> str:
"""Очищает текст от лишних пробелов и знаков препинания"""
text = re.sub(r'\s+', ' ', text)
text = re.sub(r'\s+([.,!?])', r'\1', text)
text = re.sub(r'[«»"""]', '"', text)
return text.strip()
async def transcribe_audio(audio_file_path: str) -> tuple[str, str]:
"""Преобразует аудио в текст используя Whisper API"""
try:
logger.info(f"Начинаем транскрибацию файла: {audio_file_path}")
with open(audio_file_path, "rb") as audio_file:
response = openai_client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
response_format="verbose_json"
)
logger.info(f"Получен ответ от Whisper API: {response}")
return response.text, 'ru' if 'russian' in response.language.lower() else 'id'
except Exception as e:
logger.error(f"Ошибка при транскрибации: {str(e)}", exc_info=True)
raise
async def translate_with_gpt(text: str, source_lang: str) -> dict:
"""Переводит текст используя ChatGPT"""
translations = {source_lang: clean_text(text)}
try:
logger.info(f"🔄 Начинаем перевод текста: {text} с языка {source_lang}")
# Формируем промпт для GPT
if source_lang == 'ru':
system_prompt = """You are a professional translator with expertise in Russian, English, and Indonesian languages.
Your task is to translate the given Russian text while:
1. 🎯 Preserving the original meaning and context
2. 💫 Using natural, fluent language in the target languages
3. 🎭 Maintaining the tone and style of the original text
4. 🔍 Being attentive to cultural nuances
5. 📚 Using appropriate idioms when applicable
Return translations in this exact JSON format:
{"english": "translation", "indonesian": "translation"}"""
else:
system_prompt = """You are a professional translator with expertise in Indonesian, English, and Russian languages.
Your task is to translate the given Indonesian text while:
1. 🎯 Preserving the original meaning and context
2. 💫 Using natural, fluent language in the target languages
3. 🎭 Maintaining the tone and style of the original text
4. 🔍 Being attentive to cultural nuances
5. 📚 Using appropriate idioms when applicable
Return translations in this exact JSON format:
{"english": "translation", "russian": "translation"}"""
user_prompt = f"Translate this text with attention to context and cultural nuances: {text}"
response = openai_client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
],
response_format={ "type": "json_object" }
)
# Парсим JSON ответ
result = json.loads(response.choices[0].message.content)
logger.info(f"Получен перевод: {result}")
if source_lang == 'ru':
translations['en'] = clean_text(result['english'])
translations['id'] = clean_text(result['indonesian'])
else:
translations['en'] = clean_text(result['english'])
translations['ru'] = clean_text(result['russian'])
except Exception as e:
logger.error(f"Ошибка при переводе: {str(e)}", exc_info=True)
translations['en'] = "Error during translation"
translations['id' if source_lang == 'ru' else 'ru'] = "Error during translation"
return translations
async def generate_audio(text: str, lang: str) -> bytes:
"""Генерирует аудио из текста используя OpenAI TTS или Google TTS для индонезийского языка"""
try:
logger.info(f"🔊 Генерируем аудио для текста: {text} на языке {lang}")
# Для индонезийского языка используем Google Cloud TTS
if lang == 'id':
input_text = texttospeech.SynthesisInput(text=text)
voice = texttospeech.VoiceSelectionParams(
language_code='id-ID',
name='id-ID-Standard-A'
)
audio_config = texttospeech.AudioConfig(
audio_encoding=texttospeech.AudioEncoding.MP3
)
response = google_client.synthesize_speech(
input=input_text,
voice=voice,
audio_config=audio_config
)
return response.audio_content
# Для остальных языков используем OpenAI TTS как раньше
if lang not in VOICES:
logger.error(f"❌ Неподдерживаемый язык для TTS: {lang}")
raise ValueError(f"Unsupported language for TTS: {lang}")
response = openai_client.audio.speech.create(
model="tts-1",
voice=VOICES[lang],
input=text
)
return response.content
except Exception as e:
logger.error(f"❌ Ошибка при генерации аудио: {str(e)}", exc_info=True)
raise
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик команды /start"""
await update.message.reply_text(
'Привет! Я бот для перевода голосовых сообщений.\n\n'
'Я автоматически определяю язык (русский или индонезийский) и перевожу:\n'
'Русский → Индонезийский\n'
'Индонезийский → Русский\n'
' + добавляю перевод на английский\n\n'
'Просто отправь мне голосовое сообщение!'
)
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Обработчик команды /help"""
await update.message.reply_text(
'Как использовать бота:\n\n'
'1. Отправьте голосовое сообщение\n'
'2. Бот определит язык\n'
'3. Переведет на другие языки\n'
'4. Покажет все переводы\n'
'5. Отправит аудио с переводом\n\n'
'Поддерживаемые языки:\n'
'Русский\n'
'Индонезийский\n'
'Английский (дополнительно)'
)
async def handle_business_voice(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Обработка голосовых сообщений в бизнес-режиме"""
# Проверяем наличие голосового сообщения
if hasattr(update, 'business_message') and update.business_message and update.business_message.voice:
chat_type = update.business_message.chat.type if update.business_message.chat else "unknown"
logger.info(f"🎯 Получено бизнес-сообщение. Тип чата: {chat_type}")
await handle_voice(update, context, is_business=True)
elif hasattr(update, 'message') and update.message and update.message.voice:
# Если это обычное голосовое сообщение
await handle_voice(update, context, is_business=False)
async def handle_voice(update: Update, context: ContextTypes.DEFAULT_TYPE, is_business: bool = False):
"""Обработка голосовых сообщений"""
try:
# Определяем сообщение для обработки
msg_obj = update.business_message if is_business else update.message
# Отправляем сообщение о начале обработки
processing_msg = await msg_obj.reply_text("🎯 Обрабатываю голосовое сообщение...\n\n🔄 Это займет несколько секунд")
# Скачиваем голосовое сообщение
voice = await msg_obj.voice.get_file()
# Создаем временный файл для аудио
with tempfile.NamedTemporaryFile(suffix='.ogg', delete=False) as temp_audio:
# Скачиваем аудио во временный файл
await voice.download_to_drive(temp_audio.name)
logger.info(f"💾 Сохранено голосовое сообщение: {temp_audio.name}")
try:
# Распознаем речь и определяем язык через Whisper API
detected_text, detected_lang = await transcribe_audio(temp_audio.name)
logger.info(f"🎯 Распознан текст: {detected_text}, язык: {detected_lang}")
# Получаем переводы через ChatGPT
translations = await translate_with_gpt(detected_text, detected_lang)
logger.info(f"📝 Получены переводы: {translations}")
# Формируем текстовое сообщение с эмодзи
message = f"""🎯 Определен язык: {LANG_EMOJIS[detected_lang]}
💭 Исходный текст:
{LANG_EMOJIS[detected_lang]} {translations[detected_lang]}
🌟 Переводы:
{LANG_EMOJIS['en']} {translations['en']}
{LANG_EMOJIS['id' if detected_lang == 'ru' else 'ru']} {translations['id' if detected_lang == 'ru' else 'ru']}
🎤 Отправляю озвученный перевод..."""
# Формируем текстовый ответ
response_text = f"""🎯 Определен язык: {LANG_EMOJIS[detected_lang]}
💬 Исходный текст:
{LANG_EMOJIS[detected_lang]} {translations[detected_lang]}
🌟 Переводы:
{LANG_EMOJIS['en']} {translations['en']}
{LANG_EMOJIS['id' if detected_lang == 'ru' else 'ru']} {translations['id' if detected_lang == 'ru' else 'ru']}
🎤 Отправляю озвученный перевод..."""
# Отправляем текстовый перевод
await msg_obj.reply_text(response_text)
# Генерируем и отправляем аудио перевода на целевом языке
target_lang = 'id' if detected_lang == 'ru' else 'ru'
target_text = translations[target_lang]
logger.info(f"🎙 Генерируем аудио перевода на языке {target_lang}: {target_text}")
audio_content = await generate_audio(target_text, target_lang)
# Сохраняем аудио во временный файл
with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as temp_tts:
temp_tts.write(audio_content)
logger.info(f"💾 Сохранено аудио перевода: {temp_tts.name}")
# Отправляем аудио перевода
await msg_obj.reply_voice(temp_tts.name)
finally:
# Удаляем временные файлы
os.unlink(temp_audio.name)
if 'temp_tts' in locals():
os.unlink(temp_tts.name)
# Заменяем сообщение о процессе на звездочку
try:
logger.info("✨ Завершаем обработку...")
await asyncio.sleep(2)
await processing_msg.edit_text("✨")
except Exception as e:
logger.debug(f"💬 Не удалось изменить сообщение: {str(e)}")
except Exception as e:
logger.error(f"❌ Ошибка при обработке голосового сообщения: {str(e)}", exc_info=True)
try:
# Пытаемся отправить ответ через правильный объект сообщения
error_message = "😔 Извините, произошла ошибка при обработке сообщения."
if is_business and hasattr(update, 'business_message') and update.business_message:
await update.business_message.reply_text(error_message)
elif hasattr(update, 'message') and update.message:
await update.message.reply_text(error_message)
except Exception as reply_error:
logger.error(f"❌ Ошибка при отправке сообщения об ошибке: {str(reply_error)}")
def main():
"""Запуск бота"""
# Получаем токены из переменных окружения
telegram_token = os.getenv('TELEGRAM_TOKEN')
if not telegram_token:
logger.error("Не найден токен Telegram бота!")
return
if not os.getenv('OPENAI_API_KEY'):
logger.error("Не найден токен OpenAI API!")
return
# Создаем приложение
application = Application.builder().token(telegram_token).build()
# Добавляем обработчики
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
# Обработка всех голосовых сообщений
application.add_handler(MessageHandler(
filters.ALL,
handle_business_voice,
block=False
))
# Запускаем бота
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == '__main__':
main()