added gamefication

This commit is contained in:
2026-07-01 08:21:48 +03:00
parent 3e48b3a41c
commit 32c211676f
17 changed files with 1085 additions and 67 deletions
+34 -52
View File
@@ -1,6 +1,5 @@
import asyncio
import logging
import random
from datetime import datetime
from zoneinfo import ZoneInfo
@@ -10,11 +9,10 @@ from sqlalchemy import select
from app.config import get_settings
from app.db.base import SessionLocal
from app.db.models import User
from app.character.service import CharacterService
from app.homelab.comfyui import ComfyUIClient, random_rofl_pose
from app.homelab.comfyui import ComfyUIClient
from app.homelab.context import resolve_timezone
from app.homelab.digest import build_morning_digest
from app.homelab.image_gen import generate_image
from app.homelab.evening_summary import LLM_TIMEOUT_SEC, build_evening_notice
from app.homelab.monitoring import check_netdata_alerts
from app.homelab_scoped.notices import post_chat_notice
from app.homelab.state import get_state, set_state
@@ -31,7 +29,7 @@ async def homelab_watcher_loop() -> None:
try:
await asyncio.sleep(WATCH_INTERVAL_SEC)
await _tick_morning_digest()
await _tick_rofl()
await _tick_evening_summary()
settings = get_settings()
_netdata_tick += WATCH_INTERVAL_SEC
if _netdata_tick >= settings.netdata_poll_interval_sec:
@@ -99,9 +97,9 @@ async def _comfyui_reachable(base_url: str) -> bool:
return False
async def _tick_rofl() -> None:
async def _tick_evening_summary() -> None:
settings = get_settings()
if not settings.comfyui_enabled or not settings.comfyui_rofl_enabled:
if not settings.evening_summary_enabled:
return
db = SessionLocal()
@@ -113,59 +111,43 @@ async def _tick_rofl() -> None:
tz = ZoneInfo(tz_name)
except Exception:
tz = ZoneInfo("Europe/Moscow")
now = datetime.now(tz)
last_raw = get_state(db, f"last_comfy_rofl_at:{user.id}")
if last_raw:
try:
last_at = datetime.fromisoformat(last_raw)
if last_at.tzinfo is None:
last_at = last_at.replace(tzinfo=tz)
if (now - last_at).total_seconds() < settings.comfyui_rofl_min_interval_hours * 3600:
continue
except ValueError:
pass
if random.random() > settings.comfyui_rofl_probability:
now = datetime.now(tz)
target_min = settings.evening_summary_hour * 60 + settings.evening_summary_minute
current_min = now.hour * 60 + now.minute
if current_min < target_min or current_min >= target_min + 3:
continue
today = now.date().isoformat()
count_key = f"comfy_rofl_count_{today}:{user.id}"
count_raw = get_state(db, count_key) or "0"
state_key = f"last_evening_summary_date:{user.id}"
if get_state(db, state_key) == today:
continue
image_enabled = settings.evening_summary_image_enabled and settings.comfyui_enabled
if image_enabled:
client = ComfyUIClient()
if not await _comfyui_reachable(client.base_url):
logger.warning("Evening summary: ComfyUI unreachable, text only")
image_enabled = False
try:
count = int(count_raw)
except ValueError:
count = 0
if count >= settings.comfyui_rofl_max_per_day:
continue
client = ComfyUIClient()
if not await _comfyui_reachable(client.base_url):
continue
card = CharacterService(db, user.id).get_card().get("data", {})
appearance = (card.get("appearance_tags") or "").strip()
if not appearance:
continue
pose = random_rofl_pose()
try:
result = await asyncio.wait_for(
generate_image(db, user_id=user.id, draw_self=True, scene_description=pose),
timeout=settings.comfyui_timeout_sec + 15,
notice = await asyncio.wait_for(
build_evening_notice(
db,
user.id,
now.date(),
tz,
image_enabled=image_enabled,
),
timeout=settings.comfyui_timeout_sec + LLM_TIMEOUT_SEC,
)
except (asyncio.TimeoutError, httpx.TimeoutException, httpx.ConnectError) as exc:
logger.warning("Rofl image skipped (ComfyUI): %s", exc)
except asyncio.TimeoutError:
logger.warning("Evening summary timed out for user %s", user.id)
continue
if not result.get("ok"):
logger.warning("Rofl image failed: %s", result.get("error"))
if not notice:
continue
url = result.get("url", "")
post_chat_notice(
f"🎨 **Рофл дня**\n\n![rofl]({url})\n\n_{pose}_",
user.id,
)
set_state(db, count_key, str(count + 1))
set_state(db, f"last_comfy_rofl_at:{user.id}", now.isoformat())
post_chat_notice(notice, user.id)
set_state(db, state_key, today)
finally:
db.close()