Перейти к основному содержимому

AI-бот со streaming

Бот который пересылает сообщения в LLM (OpenAI/llama.cpp/локальный) и стримит ответ обратно.

Ключевые приёмы

  • sendChatAction "typing" — индикатор «бот печатает»
  • editMessageText — обновляем сообщение по мере прихода chunks из LLM

Пример (Python + aiogram + OpenAI)

import asyncio, os
from openai import AsyncOpenAI
from aiogram import Bot, Dispatcher, F
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer
from aiogram.types import Message
from aiogram.filters import CommandStart

session = AiohttpSession(api=TelegramAPIServer.from_base('https://api.telefon.chat'))
bot = Bot(token=os.environ['BOT_TOKEN'], session=session)
dp = Dispatcher()
ai = AsyncOpenAI(api_key=os.environ['OPENAI_API_KEY'])

@dp.message(CommandStart())
async def start(m: Message):
await m.answer('Привет! Спрашивай что угодно.')

@dp.message(F.text)
async def chat(m: Message):
# Показываем «печатает...»
await bot.send_chat_action(m.chat.id, 'typing')

# Создаём пустое сообщение, потом будем редактировать
placeholder = await m.answer('⏳ Думаю...')

# Стрим из OpenAI
accumulated = ''
last_edit = 0

response = await ai.chat.completions.create(
model='gpt-4',
messages=[{'role': 'user', 'content': m.text}],
stream=True
)

async for chunk in response:
delta = chunk.choices[0].delta.content or ''
accumulated += delta

# Редактируем не чаще 1 раза в секунду чтобы не упереться в rate limit
now = asyncio.get_event_loop().time()
if now - last_edit > 1.2:
try:
await bot.edit_message_text(
chat_id=m.chat.id,
message_id=placeholder.message_id,
text=accumulated + ' ▍'
)
last_edit = now
except Exception:
pass

# Финальное обновление без курсора
await bot.edit_message_text(
chat_id=m.chat.id,
message_id=placeholder.message_id,
text=accumulated
)

if __name__ == '__main__':
asyncio.run(dp.start_polling(bot))

Боевой пример

karfly/chatgpt_telegram_bot — github.com/karfly/chatgpt_telegram_bot. ~7k★. Поддержка диалогов, голосового ввода (whisper), генерации картинок (DALL-E), персон (assistant/coder/translator).

Совет

Для генерации с локальной моделью используйте OpenAI-совместимый endpoint типа llama.cpp /v1/chat/completions — код API клиента не меняется.