Добавил retry для скачивания аудиосообщений
This commit is contained in:
39
src/audio.py
39
src/audio.py
@@ -1,6 +1,9 @@
|
||||
from telegram import Bot
|
||||
import asyncio
|
||||
|
||||
from src.config import DATA_PARTIAL_DIR
|
||||
from telegram import Bot
|
||||
from telegram.error import NetworkError, TimedOut
|
||||
|
||||
from src.config import DATA_PARTIAL_DIR, MAX_RETRY_ATTEMPTS, RETRY_DELAYS
|
||||
from src.database import upsert_recording
|
||||
from src.logger import logger
|
||||
from src.scenarios import get_audio_filename
|
||||
@@ -15,22 +18,38 @@ async def save_voice_message(
|
||||
replica_index: int,
|
||||
duration: int,
|
||||
) -> None:
|
||||
"""Сохраняет голосовое сообщение в data_partial/."""
|
||||
# Создаём директорию если нужно
|
||||
"""Сохраняет голосовое сообщение в data_partial/ с retry логикой."""
|
||||
scenario_dir = DATA_PARTIAL_DIR / scenario_id
|
||||
scenario_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Скачиваем файл
|
||||
file = await bot.get_file(file_id)
|
||||
filename = get_audio_filename(replica_index, speaker_id, user_id)
|
||||
filepath = scenario_dir / filename
|
||||
|
||||
await file.download_to_drive(filepath)
|
||||
for attempt in range(MAX_RETRY_ATTEMPTS):
|
||||
try:
|
||||
file = await bot.get_file(file_id)
|
||||
await file.download_to_drive(filepath)
|
||||
|
||||
# Записываем в БД (duration из метаданных Telegram)
|
||||
upsert_recording(user_id, scenario_id, replica_index, float(duration))
|
||||
# Успех - записываем в БД
|
||||
upsert_recording(user_id, scenario_id, replica_index, float(duration))
|
||||
logger.debug(f"Saved voice: {filepath} ({duration}s)")
|
||||
return
|
||||
|
||||
logger.debug(f"Saved voice: {filepath} ({duration}s)")
|
||||
except (TimedOut, NetworkError) as e:
|
||||
if attempt < MAX_RETRY_ATTEMPTS - 1:
|
||||
delay = RETRY_DELAYS[attempt]
|
||||
logger.warning(
|
||||
f"Network error on attempt {attempt + 1}/"
|
||||
f"{MAX_RETRY_ATTEMPTS}: {e}. "
|
||||
f"Retrying in {delay}s..."
|
||||
)
|
||||
await asyncio.sleep(delay)
|
||||
else:
|
||||
logger.error(
|
||||
f"Failed to save voice after {MAX_RETRY_ATTEMPTS} "
|
||||
f"attempts: {e}"
|
||||
)
|
||||
raise
|
||||
|
||||
|
||||
def format_duration(seconds: float) -> str:
|
||||
|
||||
@@ -24,3 +24,12 @@ DATA_PARTIAL_DIR: Path = BASE_DIR / "data_partial"
|
||||
SCENARIOS_DIR: Path = BASE_DIR / "scenarios"
|
||||
DB_DIR: Path = BASE_DIR / "db"
|
||||
DB_PATH: Path = DB_DIR / "bot.db"
|
||||
|
||||
# Таймауты для Telegram API (в секундах)
|
||||
TELEGRAM_CONNECT_TIMEOUT: int = 10
|
||||
TELEGRAM_READ_TIMEOUT: int = 30
|
||||
TELEGRAM_WRITE_TIMEOUT: int = 30
|
||||
|
||||
# Настройки retry
|
||||
MAX_RETRY_ATTEMPTS: int = 3
|
||||
RETRY_DELAYS: tuple[float, ...] = (1.0, 2.0, 4.0)
|
||||
|
||||
@@ -6,6 +6,7 @@ from telegram import (
|
||||
ReplyKeyboardRemove,
|
||||
Update,
|
||||
)
|
||||
from telegram.error import TelegramError
|
||||
from telegram.ext import ContextTypes
|
||||
|
||||
from src.config import ADMIN_LOGIN
|
||||
@@ -47,6 +48,7 @@ from src.messages import (
|
||||
SPECIFY_GENDER_TEXT,
|
||||
TRACK_SAVED_TEXT,
|
||||
VOICE_EXPECTED_TEXT,
|
||||
VOICE_SAVE_ERROR_TEXT,
|
||||
)
|
||||
from src.scenarios import find_available_track
|
||||
|
||||
@@ -869,15 +871,20 @@ async def handle_voice_message(
|
||||
real_replica_index = replicas[session.replica_index].replica_index
|
||||
|
||||
voice = update.message.voice
|
||||
await save_voice_message(
|
||||
context.bot,
|
||||
voice.file_id,
|
||||
user.id,
|
||||
session.scenario_id,
|
||||
session.speaker_id,
|
||||
real_replica_index,
|
||||
max(1, voice.duration), # телеграм возвращает с точностью до секунд
|
||||
)
|
||||
try:
|
||||
await save_voice_message(
|
||||
context.bot,
|
||||
voice.file_id,
|
||||
user.id,
|
||||
session.scenario_id,
|
||||
session.speaker_id,
|
||||
real_replica_index,
|
||||
max(1, voice.duration), # телеграм возвращает с точностью до секунд
|
||||
)
|
||||
except TelegramError as e:
|
||||
logger.error(f"Failed to save voice for user {user.id}: {e}")
|
||||
await update.message.reply_text(VOICE_SAVE_ERROR_TEXT)
|
||||
return
|
||||
|
||||
track_length = get_track_length(session.scenario_id, session.speaker_id)
|
||||
|
||||
|
||||
@@ -69,6 +69,14 @@ REPEAT_REPLICA_TEXT = "🔄 Перезапись реплики {num}/{total}:"
|
||||
|
||||
VOICE_EXPECTED_TEXT = "❌ Пожалуйста, отправьте голосовое сообщение с озвучкой реплики."
|
||||
|
||||
VOICE_SAVE_ERROR_TEXT = """❌ Произошла ошибка при сохранении аудиозаписи.
|
||||
|
||||
Возможные причины:
|
||||
• Временные проблемы с сетью
|
||||
• Проблемы с серверами Telegram
|
||||
|
||||
Пожалуйста, попробуйте отправить голосовое сообщение ещё раз."""
|
||||
|
||||
TRACK_SAVED_TEXT = """✅ Дорожка сохранена!
|
||||
|
||||
🙏 Спасибо большое за вашу помощь! Если у вас есть желание и возможность, вы можете озвучить ещё несколько дорожек!
|
||||
|
||||
Reference in New Issue
Block a user