added RAG, Multiuser, TG bot

This commit is contained in:
2026-06-13 20:20:56 +00:00
parent 66e1b0e29e
commit c8a9429bed
142 changed files with 19901 additions and 8790 deletions
+92 -91
View File
@@ -1,91 +1,92 @@
import logging
from sqlalchemy.orm import Session
from app.character.service import CharacterService
from app.chat.notice_inbox import post_character_comment_to_latest_chat, post_notice_to_latest_chat
from app.chat.notices import format_phase_completed_notice
from app.db.models import PomodoroSession
from app.llm.client import LLMClient
from app.pomodoro.cycle import PHASE_LONG_BREAK, PHASE_SHORT_BREAK, PHASE_WORK, CycleManager
from app.pomodoro.service import PomodoroService
logger = logging.getLogger(__name__)
PHASE_LABELS = {
PHASE_WORK: "работа",
PHASE_SHORT_BREAK: "короткий перерыв",
PHASE_LONG_BREAK: "длинный перерыв",
}
class PomodoroCompletionHandler:
def __init__(self, db: Session):
self.db = db
self.pomodoro = PomodoroService(db)
self.cycle = CycleManager(db)
self.llm = LLMClient()
self.character = CharacterService()
async def _generate_llm_comment(
self,
session: PomodoroSession,
next_phase: str | None,
) -> str:
cycle = self.cycle.to_dict()
phase_label = PHASE_LABELS.get(session.phase, session.phase)
next_label = PHASE_LABELS.get(next_phase, "пауза") if next_phase else "отдых, цикл сброшен"
work_done = cycle["completed_work_sessions"]
if session.phase == PHASE_WORK:
work_done += 1
system = self.character.get_system_prompt()
user_prompt = f"""Фаза помидоро «{phase_label}» только что завершилась.
Задача: {session.task_note or 'без описания'}
Прогресс цикла: {work_done}/{cycle['sessions_until_long_break']} работ.
Следующая фаза: {next_label}.
Напиши пользователю короткое сообщение (2-4 предложения) на русском: поздравь, поддержи или предложи отдохнуть. Без markdown и без эмодзи."""
result = await self.llm.complete(
[
{"role": "system", "content": system},
{"role": "user", "content": user_prompt},
],
temperature=0.8,
visible_reply=True,
)
return (result.get("content") or "").strip() or "Фаза завершена. Хорошая работа."
def _resolve_next_phase(self, session: PomodoroSession) -> str | None:
phase = session.phase
cycle = self.cycle.get()
if phase == PHASE_WORK:
if cycle.completed_work_sessions + 1 >= cycle.sessions_until_long_break:
return PHASE_LONG_BREAK
return PHASE_SHORT_BREAK
if phase == PHASE_SHORT_BREAK:
return PHASE_WORK
if phase == PHASE_LONG_BREAK:
return None
return None
async def process(self, session: PomodoroSession) -> None:
if session.completion_notified:
return
next_phase = self._resolve_next_phase(session)
notice = format_phase_completed_notice(session, next_phase)
post_notice_to_latest_chat(notice)
try:
comment = await self._generate_llm_comment(session, next_phase)
if comment:
post_character_comment_to_latest_chat(comment)
except Exception:
logger.exception("Pomodoro LLM comment failed (phase=%s)", session.phase)
self.cycle.bump_notify_seq()
self.pomodoro.mark_notified(session)
self.pomodoro.advance_after_completion(session)
logger.info("Pomodoro phase completed (phase=%s, next=%s)", session.phase, next_phase)
import logging
from sqlalchemy.orm import Session
from app.character.service import CharacterService
from app.chat.notice_inbox import post_character_comment_to_latest_chat, post_notice_to_latest_chat
from app.chat.notices import format_phase_completed_notice
from app.db.models import PomodoroSession
from app.llm.client import LLMClient
from app.pomodoro.cycle import PHASE_LONG_BREAK, PHASE_SHORT_BREAK, PHASE_WORK, CycleManager
from app.pomodoro.service import PomodoroService
logger = logging.getLogger(__name__)
PHASE_LABELS = {
PHASE_WORK: "работа",
PHASE_SHORT_BREAK: "короткий перерыв",
PHASE_LONG_BREAK: "длинный перерыв",
}
class PomodoroCompletionHandler:
def __init__(self, db: Session, user_id: int):
self.db = db
self.user_id = user_id
self.pomodoro = PomodoroService(db, user_id)
self.cycle = CycleManager(db, user_id)
self.llm = LLMClient()
self.character = CharacterService(db, user_id)
async def _generate_llm_comment(
self,
session: PomodoroSession,
next_phase: str | None,
) -> str:
cycle = self.cycle.to_dict()
phase_label = PHASE_LABELS.get(session.phase, session.phase)
next_label = PHASE_LABELS.get(next_phase, "пауза") if next_phase else "отдых, цикл сброшен"
work_done = cycle["completed_work_sessions"]
if session.phase == PHASE_WORK:
work_done += 1
system = self.character.get_system_prompt()
user_prompt = f"""Фаза помидоро «{phase_label}» только что завершилась.
Задача: {session.task_note or 'без описания'}
Прогресс цикла: {work_done}/{cycle['sessions_until_long_break']} работ.
Следующая фаза: {next_label}.
Напиши пользователю короткое сообщение (2-4 предложения) на русском: поздравь, поддержи или предложи отдохнуть. Без markdown и без эмодзи."""
result = await self.llm.complete(
[
{"role": "system", "content": system},
{"role": "user", "content": user_prompt},
],
temperature=0.8,
visible_reply=True,
)
return (result.get("content") or "").strip() or "Фаза завершена. Хорошая работа."
def _resolve_next_phase(self, session: PomodoroSession) -> str | None:
phase = session.phase
cycle = self.cycle.get()
if phase == PHASE_WORK:
if cycle.completed_work_sessions + 1 >= cycle.sessions_until_long_break:
return PHASE_LONG_BREAK
return PHASE_SHORT_BREAK
if phase == PHASE_SHORT_BREAK:
return PHASE_WORK
if phase == PHASE_LONG_BREAK:
return None
return None
async def process(self, session: PomodoroSession) -> None:
if session.completion_notified:
return
next_phase = self._resolve_next_phase(session)
notice = format_phase_completed_notice(session, next_phase)
post_notice_to_latest_chat(notice, self.user_id)
try:
comment = await self._generate_llm_comment(session, next_phase)
if comment:
post_character_comment_to_latest_chat(comment, self.user_id)
except Exception:
logger.exception("Pomodoro LLM comment failed (phase=%s)", session.phase)
self.cycle.bump_notify_seq()
self.pomodoro.mark_notified(session)
self.pomodoro.advance_after_completion(session)
logger.info("Pomodoro phase completed (phase=%s, next=%s)", session.phase, next_phase)