Files
trueconf_bot/transcription_bot/handlers.py
T
Денис Кривоченко 974ecbb36d fix: restore missing logger definition
2026-07-31 00:46:21 +07:00

166 lines
6.8 KiB
Python

# /opt/trueconf_bot/transcription_bot/handlers.py
import io
import os
import asyncio
import logging
import httpx
from ldap3 import Server, Connection, ALL
from trueconf import Router, Message
from config.config import *
from utils import states
from utils.menu import MENU_TEXT
from utils.texts import (
EMOJI_DIGITS,
TRANSCRIPTION_MAIN_MENU_TEXT,
transcription_error_bad_extension,
TRANSCRIPTION_UPLOADING_TEXT,
transcription_success_received,
system_error_text,
UNKNOWN_MAIN_CMD_TEXT,
)
# 🔌 Импортируем централизованную функцию сбора статистики из main
from utils.stats_logger import log_menu_stats
# =========================================================
# СИСТЕМА ОТПРАВКИ ОШИБОК НА ПОЧТУ
# =========================================================
global _last_transcription_email_time
_last_transcription_email_time = 0.0
def _transcription_log_and_notify_email(action: str, error_details: str):
global _last_transcription_email_time
current_time = time.time()
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
if current_time - _last_transcription_email_time < 10.0:
return
_last_transcription_email_time = current_time
try:
import smtplib
from email.mime.text import MIMEText
msg = MIMEMultipart()
msg['From'] = str(getattr(config.config, 'DEFAULT_EMAIL_FROM', 'bot@noreply.com'))
to_emails = getattr(config.config, 'ALERTS_SUPPORT_EMAILS', ['admin@example.com'])
msg['To'] = ', '.join(to_emails) if isinstance(to_emails, list) else str(to_emails)
msg['Subject'] = f'TrueConf Bot Error: Транскрипция - {action}'
body = f'Обнаружена ошибка в транскрипции.\nВремя: {timestamp}\nДействие: {action}\nДетали:\n{error_details}'
msg.attach(MIMEText(body, 'plain', 'utf-8'))
with smtplib.SMTP(getattr(config.config, 'SMTP_SERVER', 'localhost'), int(getattr(config.config, 'SMTP_PORT', 25))) as server:
server.send_message(msg)
except Exception:
pass
import time
from datetime import datetime
logger = logging.getLogger(__name__)
router = Router()
# ✅ Полный список разрешенных расширений (Аудио, Видео, Проф. форматы)
ALLOWED_EXTENSIONS = [
# Аудио
'.mp3', '.aac', '.m4a', '.flac', '.ogg', '.oga', '.opus', '.wma',
'.aif', '.aiff', '.ac3', '.eac3', '.dts', '.thd', '.au', '.caf',
'.wv', '.ape', '.tta', '.wav',
# Видео
'.mp4', '.m4v', '.mkv', '.mka', '.mk3d', '.avi', '.mov', '.flv',
'.webm', '.wmv', '.ts', '.m2ts', '.mpg', '.mpeg', '.vob',
# Профессиональные и вещательные
'.mxf', '.gxf', '.nucap',
# Специфические
'.4xm', '.bik', '.smk', '.cak'
]
# --- Функция получения Email из Active Directory ---
def get_user_email_sync(login: str) -> str:
try:
from utils.ad_search import search_by_login
entries = search_by_login(login, ["mail"])
if entries and 'mail' in entries[0] and entries[0].mail.value:
return str(entries[0].mail.value)
except Exception as e:
logger.error(f"Ошибка поиска email в AD: {e}")
_transcription_log_and_notify_email("Поиск email в AD", str(e))
return DEFAULT_REQUESTER
@router.message()
async def transcription_handler(msg: Message):
user_id = msg.from_user.id
# Работаем только если включен режим расшифровки
if states.get_state(user_id) != "TRANSCRIPTION_MODE":
return
# Помечаем сообщение как обработанное
msg.handled = True
user_login = user_id.split('@')[0] if '@' in user_id else user_id
msg_text = getattr(msg.content, "text", "").strip() if hasattr(msg.content, "text") else ""
is_attachment = hasattr(msg.type, "name") and msg.type.name == "ATTACHMENT"
cmd = msg_text.lower()
# 🔄 НОРМАЛИЗАЦИЯ КНОПОК ВК-ЭМОДЗИ
for raw_num, emoji_num in EMOJI_DIGITS.items():
if cmd == emoji_num:
cmd = raw_num
break
# --- ВЫХОД (Кнопки 0 и 9 приведены к единому стандарту) ---
if cmd in ["0", "9", "/start", "меню"]:
log_menu_stats(user_id, "Speech-to-Text", "Выход в главное меню")
states.clear_state(user_id)
await msg.answer(MENU_TEXT, parse_mode="html")
return
# --- ОБРАБОТКА ФАЙЛА ---
if is_attachment:
file_name = getattr(msg.content, "file_name", "").lower()
file_id = getattr(msg.content, "file_id", None)
# Проверка расширения
ext = os.path.splitext(file_name)[1]
if ext not in ALLOWED_EXTENSIONS:
await msg.answer(transcription_error_bad_extension(ext), parse_mode="html")
return
await msg.answer(TRANSCRIPTION_UPLOADING_TEXT, parse_mode="html")
try:
# 1. Добываем почту из AD
user_email = await asyncio.to_thread(get_user_email_sync, user_login)
# 2. Качаем файл (возвращает bytes)
downloaded_file = await states.tc_bot.download_file_by_id(file_id)
# 3. Отправка на API
async with httpx.AsyncClient(timeout=120.0) as client:
files = {'file': (file_name, io.BytesIO(downloaded_file), 'application/octet-stream')}
payload = {
'email': user_email,
'generate_summary': 'true'
}
response = await client.post(TRANSCRIPTION_API_URL, files=files, data=payload)
if response.status_code == 200:
log_menu_stats(user_id, "Speech-to-Text", f"Отправка встречи на расшифровку ({ext})")
await msg.answer(transcription_success_received(user_email), parse_mode="html")
else:
_transcription_log_and_notify_email(f"API транскрипции вернул статус {response.status_code}", str(response.text[:500]))
await msg.answer(system_error_text(EMOJI_DIGITS), parse_mode="html")
except Exception as e:
logger.error(f"Transcription Upload Error: {e}")
_transcription_log_and_notify_email("Загрузка/отправка файла на транскрипцию", str(e))
await msg.answer(system_error_text(EMOJI_DIGITS), parse_mode="html")
return
# --- ЗАГЛУШКА НА НЕИЗВЕСТНЫЙ ТЕКСТ / СТАНДАРТНАЯ ОШИБКА ВВОДА ---
await msg.answer(UNKNOWN_MAIN_CMD_TEXT, parse_mode="html")