Базовая обнова, запрет на комментирование фоток /ebalnik ну и поменял ai чтобы пиздел меньше, а не километровыми пастами #29
4 changed files with 43 additions and 8 deletions
0
.codex
Normal file
0
.codex
Normal file
|
|
@ -2,6 +2,7 @@ import asyncio
|
|||
import os
|
||||
import logging
|
||||
import sqlite3
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import aiohttp
|
||||
|
|
@ -69,6 +70,8 @@ _CONTEXT_SIZE = 20
|
|||
_MAX_PROMPT_CHARS = 8_000
|
||||
# Путь к SQLite базе (берётся из переменной окружения или из config)
|
||||
_DB_PATH = os.getenv("CHAT_HISTORY_DB_PATH", "/db/chat_history.sqlite3")
|
||||
_MAX_REPLY_SENTENCES = 3
|
||||
_MAX_REPLY_CHARS = 280
|
||||
|
||||
|
||||
def _init_db() -> None:
|
||||
|
|
@ -139,20 +142,49 @@ def _build_messages(chat_id: int, system_prompt: str, current_text: str, current
|
|||
return messages
|
||||
|
||||
|
||||
def _shorten_reply(text: str, max_sentences: int = _MAX_REPLY_SENTENCES, max_chars: int = _MAX_REPLY_CHARS) -> str:
|
||||
"""Ограничивает ответ до 1-3 предложений и разумной длины."""
|
||||
cleaned = " ".join((text or "").replace("\n", " ").split()).strip()
|
||||
if not cleaned:
|
||||
return "Братуха, коротко: чёт пусто получилось."
|
||||
|
||||
# Делим по окончаниям предложений, сохраняя знаки.
|
||||
parts = re.split(r"(?<=[.!?…])\s+", cleaned)
|
||||
sentences = [p.strip() for p in parts if p.strip()]
|
||||
|
||||
if not sentences:
|
||||
# На случай ответа без пунктуации.
|
||||
words = cleaned.split()
|
||||
return " ".join(words[:25]).strip()
|
||||
|
||||
short = " ".join(sentences[:max_sentences]).strip()
|
||||
|
||||
# Дополнительный предохранитель по символам.
|
||||
if len(short) > max_chars:
|
||||
clipped = short[:max_chars].rstrip()
|
||||
last_break = max(clipped.rfind("."), clipped.rfind("!"), clipped.rfind("?"), clipped.rfind("…"))
|
||||
if last_break >= 40:
|
||||
clipped = clipped[: last_break + 1].rstrip()
|
||||
short = clipped
|
||||
|
||||
return short
|
||||
|
||||
|
||||
async def _generate_response(chat_id: int, user_text: str, user_name: str) -> str:
|
||||
# Формируем запрос к /v1/chat/completions с историей чата и возвращаем текст первого ответа.
|
||||
url = f"{LLAMA_API_URL.rstrip('/')}/v1/chat/completions"
|
||||
msgs = await asyncio.to_thread(_build_messages, chat_id, SYSTEM_PROMPT, user_text, user_name)
|
||||
payload = {
|
||||
"messages": msgs,
|
||||
"max_tokens": 200,
|
||||
"max_tokens": 90,
|
||||
"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()
|
||||
content = data["choices"][0]["message"]["content"].strip()
|
||||
return _shorten_reply(content)
|
||||
|
||||
|
||||
async def handle_talk(message: Message):
|
||||
|
|
@ -230,14 +262,15 @@ async def generate_autoreply(chat_id: int, text: str, user_name: str) -> str:
|
|||
msgs = await asyncio.to_thread(_build_messages, chat_id, AUTOREPLY_SYSTEM_PROMPT, text, user_name)
|
||||
payload = {
|
||||
"messages": msgs,
|
||||
"max_tokens": 150,
|
||||
"max_tokens": 70,
|
||||
"temperature": 0.9,
|
||||
"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()
|
||||
content = data["choices"][0]["message"]["content"].strip()
|
||||
return _shorten_reply(content)
|
||||
|
||||
|
||||
# Инициализация БД при импорте модуля
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
CAPTIONS = [
|
||||
"Hot stuff 🔥",
|
||||
"Sexy content 😏"
|
||||
"Sexy content 😏",
|
||||
"ШПАЧИХА"
|
||||
]
|
||||
|
||||
async def handle_nude_cmd(message: types.Message):
|
||||
|
|
|
|||
7
main.py
7
main.py
|
|
@ -1145,6 +1145,10 @@ async def handle_keywords(message: Message):
|
|||
chat_id = message.chat.id
|
||||
user_name = (message.from_user.first_name or "кент") if message.from_user else "кент"
|
||||
|
||||
# /ebalnik должен глушить все авто-реакции в чате, включая медиа/фото-ветки.
|
||||
if chat_id in _autoreply_disabled_chats:
|
||||
return
|
||||
|
||||
if any(re.search(rf'\b{word}\b', text_lower) for word in config.KEYWORDS):
|
||||
audio_path = config.BASE_DIR / "maket" / "Radiohead - Creep.mp3"
|
||||
if audio_path.exists():
|
||||
|
|
@ -1171,9 +1175,6 @@ async def handle_keywords(message: Message):
|
|||
# Записываем каждое обычное сообщение в историю чата
|
||||
await asyncio.to_thread(push_message, chat_id, "user", user_name, message.text)
|
||||
|
||||
if chat_id in _autoreply_disabled_chats:
|
||||
return
|
||||
|
||||
import time as _time
|
||||
now = _time.time()
|
||||
triggered = any(trigger in text_lower for trigger in config.AUTOREPLY_TRIGGERS)
|
||||
|
|
|
|||
Loading…
Reference in a new issue