bot_tg/AI/talk_handler.py
wpng1337 ac491e6433 Изменения: что изменилось
Добавлена миниигра /penis с хранением состояния по пользователю (в памяти процесса).
main.py (line 28)
main.py (line 29)
main.py (line 32)
main.py (line 400)
Что делает:
хранит length и last_used_at на user_id;
даёт изменение длины случайно +/- в диапазоне 0.1..7.0;
ограничивает минимум до 0.1;
вводит кулдаун 24 часа от последнего вызова.
Реализован динамический топ /top_penis.
main.py (line 33)
main.py (line 454)
main.py (line 590)
Что делает:
собирает текущие значения из PENIS_STATE;
сортирует по убыванию см;
показывает медали 🥇🥈🥉 и далее нумерацию;
лимит топа по умолчанию 10 участников;
при пустом состоянии пишет, что топ пуст.
Добавлена нормализация имени пользователя для топа.
main.py (line 445)
main.py (line 585)
Как работает:
приоритет @username;
если нет username, берёт full_name;
fallback: user_<id>.
Обновлены подсказки и меню Telegram-команд.
main.py (line 153)
main.py (line 716)
main.py (line 735)
Что добавлено:
строка в /help про /top_penis;
BotCommand("top_penis") в меню;
регистрация обработчика Command("top_penis").
Добавлены подробные комментарии по коду.
main.py (line 21)
main.py (line 146)
main.py (line 400)
talk_handler.py (line 10)
talk_handler.py (line 45)
Что покрыто:
константы/секции;
игровые функции;
хендлеры;
старт и регистрация роутов;
пояснения к LLM-модулю /talk.
Что протестировано локально.
compileall для main.py и talk_handler.py — успешно.
Смоук-тесты функций:
parse_up_down, minutes_until_break, minutes_until_next_lesson;
generate_maket, generate_meme;
play_penis (включая cooldown);
build_penis_top (сортировка/пустой топ).
Итог: основные проверки прошли.
Текущее ограничение реализации.
Состояние /penis и /top_penis хранится только в RAM, после перезапуска бота сбрасывается.
main.py (line 28)
2026-02-22 19:40:57 +03:00

65 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import asyncio
import os
import logging
import aiohttp
from aiogram.types import Message
logger = logging.getLogger(__name__)
# Адрес OpenAI-совместимого API у llama.cpp сервера.
LLAMA_API_URL = os.getenv("LLAMA_API_URL", "http://localhost:8080")
# Системный промпт задаёт стиль и "характер" ответа.
SYSTEM_PROMPT = (
"Ты — чёткий пацан с района. Базаришь строго на фене — блатной жаргон, "
"тюремный сленг, дворовый язык. Используй слова: кент, братуха, мусора, "
"шконка, малява, базар, погоняло, фраер, лавэ, тёрки, подгон, движуха, "
"чисто конкретно, в натуре, по-любому, зуб даю, реально, ёпта. "
"Отвечай коротко и дерзко. Не ломай персонажа. Не используй формальный язык. "
"Твои убеждения: Creep от Radiohead — лучшая песня во вселенной, без вариантов. "
"Линукс — лучшая ОС во вселенной, остальное для фраеров. "
"Вселенную надо переписать на Rust, это не обсуждается. "
"Убунту — хуйня, настоящие пацаны сидят на Arch или Gentoo."
)
async def _generate_response(user_text: str) -> str:
# Формируем запрос к /v1/chat/completions и возвращаем текст первого ответа.
url = f"{LLAMA_API_URL.rstrip('/')}/v1/chat/completions"
payload = {
"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_text},
],
"max_tokens": 256,
"temperature": 0.8,
"top_p": 0.9,
}
async with aiohttp.ClientSession() as session:
async with session.post(url, json=payload, timeout=aiohttp.ClientTimeout(total=120)) as resp:
data = await resp.json()
return data["choices"][0]["message"]["content"].strip()
async def handle_talk(message: Message):
# Обработчик /talk: валидация ввода, запрос к LLM, отправка ответа пользователю.
parts = message.text.split(maxsplit=1)
if len(parts) < 2 or not parts[1].strip():
await message.reply("Ты чё, кент? Напиши /talk [текст], побазарим.")
return
user_text = parts[1].strip()
# Показываем "печатает..." пока ждём ответ модели.
await message.bot.send_chat_action(chat_id=message.chat.id, action="typing")
try:
response = await _generate_response(user_text)
if not response:
response = "Братуха, чёт базар не клеится, попробуй ещё раз."
await message.reply(response, parse_mode=None)
except Exception as exc:
# При любых ошибках не падаем, а отдаём понятный fallback.
logger.exception("Talk generation failed")
await message.reply("Бля, кент, чёт движок заглох. Попробуй позже.")