[Python] Edit a telegram bot message dynamically when using stream=True in...

Discussão em 'Python' iniciado por Stack, Novembro 30, 2024.

  1. Stack

    Stack Membro Participativo

    I'm developing a telegram bot using aiogram which takes user's message as a prompt and generates a response using google-generativeai GenerativeModel. It works fine in normal mode, where I wait for a complete response, but I want to yield chunks of response with the stream=True parameter and add new chunks to a telegram message with message.edit_text() function. The problem is that I'm encountering an error: aiogram.exceptions.TelegramBadRequest: Telegram server says - Bad Request: can't parse entities: Can't find end of the entity starting at byte offset 73

    Here are my functions:

    from aiogram import Bot, Dispatcher, Router, types
    from aiogram.client.default import DefaultBotProperties
    from aiogram.enums import ParseMode
    from google.api_core.exceptions import BadRequest as GoogleBadRequest

    from app.database import engine
    from app.models import Language, TelegramUser
    from app.services.ai import generate_response
    from app.services.users import get_or_create_telegram_user, get_translated_message as _, refresh_last_interaction_date


    bot = Bot(token=TOKEN,
    default=DefaultBotProperties())

    dp = Dispatcher()

    telegram_router = Router()

    dp.include_router(telegram_router)

    ...

    @dp.message()
    async def handle_prompt(message: types.Message):
    async with AsyncSession(engine) as db:
    user, __ = await get_or_create_telegram_user(message, db)
    prompt = message.text

    temp_message_text = await _("timer_1", user.language_id, db)
    temp_message = await message.answer(temp_message_text)

    # Accumulate the complete response
    accumulated_text = ""

    try:
    async for chunk in generate_response(prompt):
    accumulated_text += chunk

    # Send the complete response with correct formatting
    await temp_message.edit_text(
    accumulated_text,
    disable_web_page_preview=True,
    parse_mode=ParseMode.MARKDOWN
    )

    except Exception as e:
    print(f"Error in handle_prompt: {e}")
    await temp_message.edit_text("An error occurred during processing.")

    finally:
    await refresh_last_interaction_date(user.chat_id, db)


    # ai.py

    from typing import AsyncGenerator

    import google.generativeai as genai

    from app.constants import GEMINI_API_KEY
    from app.utils.helpers import sync_to_async_iterable

    # Set up the Gemini API configuration
    genai.configure(api_key=GEMINI_API_KEY)

    # Initialize the Gemini model
    model = genai.GenerativeModel(model_name="gemini-1.5-flash")


    async def generate_response(prompt: str, **kwargs) -> AsyncGenerator[str, None]:
    try:
    response = sync_to_async_iterable(model.generate_content(prompt, stream=True, **kwargs))
    async for content in response:
    yield content.text
    except Exception as e:
    print(f"Error in generate_response: {e}")
    yield "An error occurred during processing." # Yield an error message


    The problem is that when I get chunks of the response, sometimes a markdown opening symbol is present in the chunk, but the closing symbol is not. If this happens, the error aiogram.exceptions.TelegramBadRequest: Telegram server says - Bad Request: can't parse entities: Can't find end of the entity starting at byte offset .. occurs. I've tried both ParseMode.MARKDOWN and ParseMode.MARKDOWN_V2, but the problem is the same. I've tried to remove parse_mode parameter if this exception is raised, but it didn't seem to help.

    I've found out that generate_contents() returns a text formatted with markdown2 and that Telegram requires strict formatting.

    I'm not very familiar with markdown formatting and asynchronous programming and I need help with this problem.

    Python version: 3.10.8
    Packages used:

    aiogram==3.15.0
    google-generativeai==0.8.3

    Continue reading...

Compartilhe esta Página