parent
bdb909bd48
commit
780669b958
196
src/handlers.py
196
src/handlers.py
|
|
@ -4,7 +4,7 @@ from telegram import Update
|
|||
from telegram.ext import ContextTypes
|
||||
from telegram.constants import ParseMode
|
||||
from .youtube_utils import extract_youtube_urls, extract_video_id, get_transcript
|
||||
from .openai_utils import summarize_long_text
|
||||
from .openai_utils import summarize_long_text, chunk_text, summarize_text
|
||||
from .db import save_video_summary, check_if_url_exists
|
||||
from .config import TRANSCRIPT_LANGUAGES
|
||||
|
||||
|
|
@ -40,7 +40,8 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
# Opcjonalnie: sprawdź, czy już istnieje w bazie, zanim zaczniesz przetwarzać
|
||||
# if await check_if_url_exists(url):
|
||||
# logger.info(f"URL {url} już istnieje w bazie danych. Pomijam.")
|
||||
# await context.bot.send_message(
|
||||
# await safe_send_message(
|
||||
# context.bot,
|
||||
# chat_id=chat_id,
|
||||
# text=f"Informacje o filmie {url} są już w bazie.",
|
||||
# disable_web_page_preview=True
|
||||
|
|
@ -63,7 +64,8 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
title = f"Film YouTube {video_id}" # Użyj zastępczego tytułu
|
||||
except Exception as e:
|
||||
logger.warning(f"Nie udało się pobrać transkrypcji dla ID filmu: {video_id}: {str(e)}")
|
||||
await context.bot.send_message(
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Nie udało się pobrać transkrypcji dla filmu: {url}",
|
||||
disable_web_page_preview=True
|
||||
|
|
@ -71,30 +73,50 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
processed_urls_in_message.add(url)
|
||||
continue # Potrzebujemy transkrypcji do streszczenia
|
||||
|
||||
await context.bot.send_chat_action(chat_id=chat_id, action='typing')
|
||||
|
||||
# Wygeneruj streszczenie
|
||||
summary = await summarize_long_text(transcript)
|
||||
if not summary:
|
||||
logger.error(f"Nie udało się wygenerować streszczenia dla ID filmu: {video_id}")
|
||||
await context.bot.send_message(
|
||||
# Informuj o rozpoczęciu przetwarzania
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Nie udało się wygenerować streszczenia dla filmu: {title} ({url})",
|
||||
text=f"*Rozpoczynam przetwarzanie filmu:*\n{escape_markdown_v2(title)}\n\n*Link:* {escape_markdown_v2(url)}",
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
processed_urls_in_message.add(url)
|
||||
continue
|
||||
|
||||
# Zapisz do bazy danych
|
||||
saved = await save_video_summary(url, title, transcript, summary)
|
||||
if saved:
|
||||
logger.info(f"Pomyślnie przetworzono i zapisano film: {title} ({url})")
|
||||
response_text = (
|
||||
f"*Przetworzono film:* {escape_markdown_v2(title)}\n\n"
|
||||
f"*Link:* {escape_markdown_v2(url)}\n\n"
|
||||
f"*Streszczenie:*\n{escape_markdown_v2(summary)}"
|
||||
# Podziel tekst na fragmenty do przetworzenia
|
||||
chunks = await chunk_text(transcript)
|
||||
all_summaries = []
|
||||
combined_summary = ""
|
||||
|
||||
# Dla każdego fragmentu, wygeneruj i wyślij streszczenie
|
||||
for i, chunk in enumerate(chunks):
|
||||
await context.bot.send_chat_action(chat_id=chat_id, action='typing')
|
||||
progress_msg = f"Przetwarzanie fragmentu {i+1}/{len(chunks)}..."
|
||||
logger.info(progress_msg)
|
||||
|
||||
# Jeśli jest więcej niż jeden fragment, powiadom użytkownika o postępie
|
||||
if len(chunks) > 1 and i == 0:
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Film jest długi, podzielono transkrypcję na {len(chunks)} części. Przetwarzam każdą z nich...",
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
# Użyj funkcji do wysyłania długich wiadomości
|
||||
|
||||
try:
|
||||
# Generuj streszczenie fragmentu
|
||||
partial_summary = await summarize_text(
|
||||
chunk,
|
||||
is_partial=len(chunks) > 1,
|
||||
part_num=i+1,
|
||||
total_parts=len(chunks)
|
||||
)
|
||||
all_summaries.append(partial_summary)
|
||||
|
||||
# Jeśli mamy więcej niż jeden fragment, wysyłaj postęp na bieżąco
|
||||
if len(chunks) > 1:
|
||||
part_header = f"*Streszczenie - część {i+1}/{len(chunks)}:*\n\n"
|
||||
response_text = f"{part_header}{escape_markdown_v2(partial_summary)}"
|
||||
|
||||
await send_long_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
|
|
@ -102,9 +124,74 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Błąd podczas streszczania fragmentu {i+1}: {str(e)}")
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Wystąpił błąd podczas przetwarzania fragmentu {i+1}/{len(chunks)}: {str(e)}",
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
|
||||
# Jeśli mamy więcej niż 3 fragmenty, generuj końcowe streszczenie
|
||||
if len(chunks) > 3:
|
||||
await context.bot.send_chat_action(chat_id=chat_id, action='typing')
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text="Tworzę ostateczne streszczenie łączące wszystkie fragmenty...",
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
|
||||
try:
|
||||
# Połącz wszystkie częściowe streszczenia
|
||||
combined_text = "\n\n".join(all_summaries)
|
||||
combined_summary = await summarize_text(
|
||||
combined_text,
|
||||
is_final_summary=True
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Błąd podczas generowania końcowego streszczenia: {str(e)}")
|
||||
# Jeśli końcowe streszczenie się nie powiedzie, użyj połączonych częściowych
|
||||
combined_summary = "\n\n".join(all_summaries)
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text="Nie udało się wygenerować końcowego streszczenia. Wyświetlam połączone częściowe streszczenia.",
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
else:
|
||||
# Dla mniejszej liczby fragmentów po prostu połącz streszczenia
|
||||
combined_summary = "\n\n".join(all_summaries)
|
||||
|
||||
# Zapisz pełne streszczenie do bazy danych
|
||||
saved = await save_video_summary(url, title, transcript, combined_summary)
|
||||
|
||||
# Wyślij końcowe streszczenie, jeśli były więcej niż 3 fragmenty
|
||||
if len(chunks) > 3:
|
||||
final_text = f"*Ostateczne streszczenie filmu:*\n*{escape_markdown_v2(title)}*\n\n{escape_markdown_v2(combined_summary)}"
|
||||
await send_long_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=final_text,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
|
||||
# Podsumowanie procesu
|
||||
if saved:
|
||||
logger.info(f"Pomyślnie przetworzono i zapisano film: {title} ({url})")
|
||||
if len(chunks) <= 3: # Nie wysyłaj podsumowania ponownie dla dłuższych filmów
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Pomyślnie zapisano streszczenie filmu w bazie danych: {title}",
|
||||
disable_web_page_preview=True
|
||||
)
|
||||
else:
|
||||
logger.error(f"Nie udało się zapisać danych do bazy dla filmu: {title} ({url})")
|
||||
await context.bot.send_message(
|
||||
await safe_send_message(
|
||||
context.bot,
|
||||
chat_id=chat_id,
|
||||
text=f"Wystąpił błąd podczas zapisywania danych dla filmu: {title} ({url})",
|
||||
disable_web_page_preview=True
|
||||
|
|
@ -115,8 +202,61 @@ async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||
# Funkcja pomocnicza do escape'owania znaków specjalnych MarkdownV2
|
||||
def escape_markdown_v2(text: str) -> str:
|
||||
"""Ucieka znaki specjalne dla parsowania Telegram MarkdownV2."""
|
||||
escape_chars = r'_*[]()~`>#+-=|{}.!'
|
||||
return re.sub(f'([{re.escape(escape_chars)}])', r'\\\1', text)
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
# Pełna lista znaków specjalnych w Telegram MarkdownV2
|
||||
escape_chars = r'-'
|
||||
|
||||
# Zamieniamy każdy znak specjalny na jego wersję z dwoma backslashami przed nim
|
||||
return re.sub(f'([{re.escape(escape_chars)}])', r'\1', text)
|
||||
|
||||
# Ulepszona funkcja do bezpiecznego wysyłania wiadomości
|
||||
async def safe_send_message(bot, chat_id, text, parse_mode=None, disable_web_page_preview=False, max_retries=3):
|
||||
"""
|
||||
Bezpiecznie wysyła wiadomość, obsługując błędy związane z formatowaniem.
|
||||
|
||||
Args:
|
||||
bot: Instancja bota Telegram
|
||||
chat_id: ID czatu
|
||||
text: Tekst do wysłania
|
||||
parse_mode: Tryb parsowania (None, HTML, Markdown, MarkdownV2)
|
||||
disable_web_page_preview: Czy wyłączyć podgląd linków
|
||||
max_retries: Maksymalna liczba prób
|
||||
|
||||
Returns:
|
||||
Obiekt wysłanej wiadomości lub None w przypadku błędu
|
||||
"""
|
||||
# Próbuj wysłać z formatowaniem
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return await bot.send_message(
|
||||
chat_id=chat_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
disable_web_page_preview=disable_web_page_preview
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Błąd wysyłania wiadomości (próba {attempt+1}/{max_retries}): {str(e)}")
|
||||
error_msg = str(e).lower()
|
||||
|
||||
# Jeśli jest to błąd parsowania Markdown
|
||||
if "parse" in error_msg and "entities" in error_msg:
|
||||
# Spróbuj ponownie bez formatowania
|
||||
if attempt == max_retries - 1:
|
||||
logger.info("Wysyłam wiadomość bez formatowania")
|
||||
try:
|
||||
return await bot.send_message(
|
||||
chat_id=chat_id,
|
||||
text=text,
|
||||
parse_mode=None, # Bez formatowania
|
||||
disable_web_page_preview=disable_web_page_preview
|
||||
)
|
||||
except Exception as e2:
|
||||
logger.error(f"Nie udało się wysłać wiadomości nawet bez formatowania: {str(e2)}")
|
||||
return None
|
||||
|
||||
return None
|
||||
|
||||
# Funkcja do dzielenia długich wiadomości
|
||||
async def send_long_message(bot, chat_id, text, parse_mode=None, disable_web_page_preview=False):
|
||||
|
|
@ -135,7 +275,8 @@ async def send_long_message(bot, chat_id, text, parse_mode=None, disable_web_pag
|
|||
|
||||
if len(text) <= max_length:
|
||||
# Jeśli wiadomość nie przekracza limitu, wyślij ją normalnie
|
||||
return await bot.send_message(
|
||||
return await safe_send_message(
|
||||
bot,
|
||||
chat_id=chat_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
|
|
@ -150,7 +291,8 @@ async def send_long_message(bot, chat_id, text, parse_mode=None, disable_web_pag
|
|||
# Wyślij części wiadomości
|
||||
for i, part in enumerate(parts):
|
||||
part_header = f"*Część {i+1}/{len(parts)}*\n\n" if parse_mode == ParseMode.MARKDOWN_V2 else f"Część {i+1}/{len(parts)}\n\n"
|
||||
await bot.send_message(
|
||||
await safe_send_message(
|
||||
bot,
|
||||
chat_id=chat_id,
|
||||
text=part_header + part,
|
||||
parse_mode=parse_mode,
|
||||
|
|
|
|||
Loading…
Reference in New Issue