diff --git a/homelab-ai-bot/telegram_bot.py b/homelab-ai-bot/telegram_bot.py index 110405fd..536c5bf5 100644 --- a/homelab-ai-bot/telegram_bot.py +++ b/homelab-ai-bot/telegram_bot.py @@ -130,6 +130,31 @@ CHAT_ID: int | None = None ACTIVE_LLM_TASKS: dict[int, asyncio.Task] = {} + + +TG_MSG_LIMIT = 4096 +TG_CHUNK = 4000 + + +async def _reply_text_chunked(update: Update, text: str, reply_markup=None) -> None: + t = (text or "")[:250000] + if len(t) <= TG_MSG_LIMIT: + await update.message.reply_text(t, reply_markup=reply_markup) + return + i = 0 + part = 0 + n = len(t) + while i < n: + part += 1 + chunk = t[i : i + TG_CHUNK] + i += TG_CHUNK + is_last = i >= n + body = (f"[Teil {part}] " if part > 1 else "") + chunk + await update.message.reply_text( + body[:TG_MSG_LIMIT], + reply_markup=reply_markup if is_last else None, + ) + def _load_token_and_chat(): global CHAT_ID cfg = config.parse_config() @@ -466,7 +491,7 @@ async def handle_voice(update: Update, ctx: ContextTypes.DEFAULT_TYPE): memory_client.log_message(session_id, "user", text) memory_client.log_message(session_id, "assistant", answer) - await update.message.reply_text(answer[:4000], reply_markup=build_reply_keyboard(str(update.effective_chat.id))) + await _reply_text_chunked(update, answer, reply_markup=build_reply_keyboard(str(update.effective_chat.id))) audio_out = voice.synthesize(answer[:4000]) if audio_out: @@ -515,7 +540,7 @@ async def handle_photo(update: Update, ctx: ContextTypes.DEFAULT_TYPE): memory_client.log_message(session_id, "user", user_msg) memory_client.log_message(session_id, "assistant", answer) - await update.message.reply_text(answer[:4000], reply_markup=build_reply_keyboard(str(update.effective_chat.id))) + await _reply_text_chunked(update, answer, reply_markup=build_reply_keyboard(str(update.effective_chat.id))) except Exception as e: log.exception("Fehler bei Foto-Analyse") await update.message.reply_text(f"Fehler bei Bildanalyse: {e}") @@ -691,7 +716,7 @@ async def handle_document(update: Update, ctx: ContextTypes.DEFAULT_TYPE): memory_client.log_message(session_id, "user", user_msg) memory_client.log_message(session_id, "assistant", answer) - await update.message.reply_text(answer[:4000], reply_markup=build_reply_keyboard(str(update.effective_chat.id))) + await _reply_text_chunked(update, answer, reply_markup=build_reply_keyboard(str(update.effective_chat.id))) except Exception as e: log.exception("Fehler bei Bild-Dokument") await update.message.reply_text(f"Fehler bei Bildanalyse: {e}") @@ -728,7 +753,7 @@ async def handle_document(update: Update, ctx: ContextTypes.DEFAULT_TYPE): memory_client.log_message(session_id, "user", user_msg) memory_client.log_message(session_id, "assistant", answer) - await update.message.reply_text(answer[:4000], reply_markup=build_reply_keyboard(str(update.effective_chat.id))) + await _reply_text_chunked(update, answer, reply_markup=build_reply_keyboard(str(update.effective_chat.id))) except Exception as e: log.exception("Fehler bei PDF-Analyse") await update.message.reply_text(f"Fehler bei PDF: {e}") @@ -856,7 +881,7 @@ async def handle_message(update: Update, ctx: ContextTypes.DEFAULT_TYPE): suggest = context.last_suggest_result log.info("suggest_result: type=%s", suggest.get("type")) - await update.message.reply_text(answer[:4000], reply_markup=build_reply_keyboard(str(update.effective_chat.id))) + await _reply_text_chunked(update, answer, reply_markup=build_reply_keyboard(str(update.effective_chat.id))) except asyncio.CancelledError: log.info("Freitext-Lauf abgebrochen") return