Implement audio record management features in AsyncBotDB and AudioRepository

- Added methods to delete audio moderation records and retrieve all audio records in async_db.py.
- Enhanced AudioRepository with functionality to delete audio records by file name and retrieve all audio message records.
- Improved logging for audio record operations to enhance monitoring and debugging capabilities.
- Updated related handlers to ensure proper integration of new audio management features.
This commit is contained in:
2025-09-05 01:31:50 +03:00
parent fc0517c011
commit 5f6882d348
32 changed files with 2661 additions and 214 deletions

View File

@@ -24,10 +24,10 @@ from helper_bot.handlers.private.constants import BUTTON_TEXTS
# Local imports - metrics
from helper_bot.utils.metrics import (
metrics,
track_time,
track_errors,
db_query_time
db_query_time,
track_file_operations
)
class VoiceHandlers:
@@ -126,6 +126,7 @@ class VoiceHandlers:
@track_errors("voice_handlers", "voice_bot_button_handler")
async def voice_bot_button_handler(self, message: types.Message, state: FSMContext, bot_db: MagicData("bot_db"), settings: MagicData("settings")):
"""Обработчик кнопки 'Голосовой бот' из основной клавиатуры"""
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) нажал кнопку 'Голосовой бот'")
try:
# Проверяем, получал ли пользователь приветственное сообщение
welcome_received = await bot_db.check_voice_bot_welcome_received(message.from_user.id)
@@ -140,7 +141,7 @@ class VoiceHandlers:
logger.info(f"Пользователь {message.from_user.id}: вызываем start")
await self.start(message, state, bot_db, settings)
except Exception as e:
logger.error(f"Ошибка при проверке приветственного сообщения: {e}")
logger.error(f"Ошибка при проверке приветственного сообщения для пользователя {message.from_user.id}: {e}")
# В случае ошибки вызываем start
await self.start(message, state, bot_db, settings)
@@ -169,6 +170,7 @@ class VoiceHandlers:
state: FSMContext,
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) запросил информацию об эмодзи")
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
user_emoji = await check_user_emoji(message)
await state.set_state(STATE_START)
@@ -183,6 +185,7 @@ class VoiceHandlers:
state: FSMContext,
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) вызвал функцию help_function")
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
await update_user_info(VOICE_BOT_NAME, message)
help_message = messages.get_message(get_first_name(message), 'HELP_MESSAGE')
@@ -194,6 +197,7 @@ class VoiceHandlers:
@track_time("start", "voice_handlers")
@track_errors("voice_handlers", "start")
@db_query_time("mark_voice_bot_welcome_received", "audio_moderate", "update")
async def start(
self,
message: types.Message,
@@ -201,7 +205,7 @@ class VoiceHandlers:
bot_db: MagicData("bot_db"),
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id}: вызывается функция start")
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}): вызывается функция start")
await state.set_state(STATE_START)
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
await update_user_info(VOICE_BOT_NAME, message)
@@ -210,13 +214,14 @@ class VoiceHandlers:
# Создаем сервис и отправляем приветственные сообщения
voice_service = VoiceBotService(bot_db, settings)
await voice_service.send_welcome_messages(message, user_emoji)
logger.info(f"Приветственные сообщения отправлены пользователю {message.from_user.id}")
# Отмечаем, что пользователь получил приветственное сообщение
try:
await bot_db.mark_voice_bot_welcome_received(message.from_user.id)
logger.info(f"Пользователь {message.from_user.id}: отмечен как получивший приветствие")
except Exception as e:
logger.error(f"Ошибка при отметке получения приветствия: {e}")
logger.error(f"Ошибка при отметке получения приветствия для пользователя {message.from_user.id}: {e}")
@track_time("cancel_handler", "voice_handlers")
@track_errors("voice_handlers", "cancel_handler")
@@ -233,6 +238,7 @@ class VoiceHandlers:
markup = await get_reply_keyboard(self.db, message.from_user.id)
await message.answer(text='Добро пожаловать в меню!', reply_markup=markup, parse_mode='HTML')
await state.set_state(FSM_STATES["START"])
logger.info(f"Пользователь {message.from_user.id} возвращен в главное меню")
@track_time("refresh_listen_function", "voice_handlers")
@track_errors("voice_handlers", "refresh_listen_function")
@@ -243,6 +249,7 @@ class VoiceHandlers:
bot_db: MagicData("bot_db"),
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) вызвал функцию refresh_listen_function")
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
await update_user_info(VOICE_BOT_NAME, message)
markup = get_main_keyboard()
@@ -269,6 +276,7 @@ class VoiceHandlers:
bot_db: MagicData("bot_db"),
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) вызвал функцию standup_write")
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
markup = types.ReplyKeyboardRemove()
record_voice_message = messages.get_message(get_first_name(message), 'RECORD_VOICE_MESSAGE')
@@ -279,7 +287,7 @@ class VoiceHandlers:
if message_with_date:
await message.answer(text=message_with_date, parse_mode="html")
except Exception as e:
logger.error(f'Не удалось получить дату последнего сообщения - {e}')
logger.error(f'Не удалось получить дату последнего сообщения для пользователя {message.from_user.id}: {e}')
await state.set_state(STATE_STANDUP_WRITE)
@@ -309,6 +317,7 @@ class VoiceHandlers:
message.voice.file_id,
markup_for_voice
)
logger.info(f"Голосовое сообщение пользователя {message.from_user.id} отправлено в группу постов (message_id: {sent_message.message_id})")
# Сохраняем в базу инфо о посте
await bot_db.set_user_id_and_message_id_for_voice_bot(sent_message.message_id, message.from_user.id)
@@ -318,6 +327,7 @@ class VoiceHandlers:
await message.answer(text=voice_saved_message, reply_markup=markup)
await state.set_state(STATE_START)
else:
logger.warning(f"Голосовое сообщение пользователя {message.from_user.id} не прошло валидацию")
unknown_content_message = messages.get_message(get_first_name(message), 'UNKNOWN_CONTENT_MESSAGE')
await message.forward(chat_id=settings['Telegram']['group_for_logs'])
await message.answer(text=unknown_content_message, reply_markup=markup)
@@ -326,22 +336,27 @@ class VoiceHandlers:
@track_time("standup_listen_audio", "voice_handlers")
@track_errors("voice_handlers", "standup_listen_audio")
@track_file_operations("voice")
@db_query_time("standup_listen_audio", "audio_moderate", "mixed")
async def standup_listen_audio(
self,
message: types.Message,
bot_db: MagicData("bot_db"),
settings: MagicData("settings")
):
logger.info(f"Пользователь {message.from_user.id} ({message.from_user.full_name}) запросил прослушивание аудио")
markup = get_main_keyboard()
# Создаем сервис для работы с аудио
voice_service = VoiceBotService(bot_db, settings)
try:
#TODO: удалить логику из хендлера
# Получаем случайное аудио
audio_data = await voice_service.get_random_audio(message.from_user.id)
if not audio_data:
logger.warning(f"Для пользователя {message.from_user.id} не найдено доступных аудио для прослушивания")
no_audio_message = messages.get_message(get_first_name(message), 'NO_AUDIO_MESSAGE')
await message.answer(text=no_audio_message, reply_markup=markup)
try:
@@ -349,7 +364,7 @@ class VoiceHandlers:
if message_with_date:
await message.answer(text=message_with_date, parse_mode="html")
except Exception as e:
logger.error(f'Не удалось получить последнюю дату {e}')
logger.error(f'Не удалось получить последнюю дату для пользователя {message.from_user.id}: {e}')
return
audio_for_user, date_added, user_emoji = audio_data
@@ -359,7 +374,13 @@ class VoiceHandlers:
# Проверяем существование файла
if not path.exists():
logger.error(f"Файл не найден: {path}")
logger.error(f"Файл не найден: {path} для пользователя {message.from_user.id}")
# Дополнительная диагностика
logger.error(f"Директория {VOICE_USERS_DIR} существует: {Path(VOICE_USERS_DIR).exists()}")
if Path(VOICE_USERS_DIR).exists():
files_in_dir = list(Path(VOICE_USERS_DIR).glob("*.ogg"))
logger.error(f"Файлы в директории: {[f.name for f in files_in_dir]}")
await message.answer(
text="Файл аудио не найден. Обратитесь к администратору.",
reply_markup=markup
@@ -368,7 +389,7 @@ class VoiceHandlers:
# Проверяем размер файла
if path.stat().st_size == 0:
logger.error(f"Файл пустой: {path}")
logger.error(f"Файл пустой: {path} для пользователя {message.from_user.id}")
await message.answer(
text="Файл аудио поврежден. Обратитесь к администратору.",
reply_markup=markup
@@ -383,13 +404,20 @@ class VoiceHandlers:
else:
caption = f'Дата записи: {date_added}'
logger.info(f"Подготовлено голосовое сообщение для пользователя {message.from_user.id}: {caption}")
try:
await message.bot.send_voice(
chat_id=message.chat.id,
voice=voice,
caption=caption,
reply_markup=markup
)
from helper_bot.utils.rate_limiter import send_with_rate_limit
async def _send_voice():
return await message.bot.send_voice(
chat_id=message.chat.id,
voice=voice,
caption=caption,
reply_markup=markup
)
await send_with_rate_limit(_send_voice, message.chat.id)
# Маркируем сообщение как прослушанное только после успешной отправки
await voice_service.mark_audio_as_listened(audio_for_user, message.from_user.id)
@@ -404,7 +432,7 @@ class VoiceHandlers:
except Exception as voice_error:
if "VOICE_MESSAGES_FORBIDDEN" in str(voice_error):
# Если голосовые сообщения запрещены, отправляем информативное сообщение
logger.info(f"Пользователь {message.from_user.id} запретил получение голосовых сообщений")
logger.warning(f"Пользователь {message.from_user.id} запретил получение голосовых сообщений")
privacy_message = "🔇 К сожалению, у тебя закрыт доступ к получению голосовых сообщений.\n\nДля продолжения взаимодействия с ботом необходимо дать возможность мне присылать войсы в настройках приватности Telegram.\n\n💡 Как это сделать:\n1. Открой настройки Telegram\n2. Перейди в 'Конфиденциальность и безопасность'\n3. Выбери 'Голосовые сообщения'\n4. Разреши получение от 'Всех' или добавь меня в исключения"
@@ -412,10 +440,11 @@ class VoiceHandlers:
return # Выходим без записи о прослушивании
else:
logger.error(f"Ошибка при отправке голосового сообщения пользователю {message.from_user.id}: {voice_error}")
raise voice_error
except Exception as e:
logger.error(f"Ошибка при прослушивании аудио: {e}")
logger.error(f"Ошибка при прослушивании аудио для пользователя {message.from_user.id}: {e}")
await message.answer(
text="Произошла ошибка при получении аудио. Попробуйте позже.",
reply_markup=markup