Files
2026-09-11 19:47:15 +03:00

41 lines
1.8 KiB
Python

"""Базовый интерфейс «мозга» (LLM) + результат запроса.
История диалога — простой список {"role": "user"|"assistant", "text": str},
чтобы провайдеры и будущая машина состояний не зависели от формата API.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import List, Optional
DialogHistory = List[dict] # [{"role": "user"|"assistant", "text": str}, ...]
@dataclass
class LlmResult:
"""Ответ LLM: сырой текст + очищенный для озвучки."""
question: str
raw_text: str # как прислала модель (с разметкой, если была)
cleaned_text: str # после clean_for_speech() — именно это озвучиваем
generation_sec: float
model: str = ""
def __str__(self) -> str:
return (f"[{self.model}] {self.generation_sec:.2f} c, "
f"{len(self.cleaned_text)} симв.: {self.cleaned_text!r}")
class LlmProvider(ABC):
"""Интерфейс провайдера LLM (сейчас OpenRouter, при надобности — локальный ollama)."""
name: str = "base"
context_block: str = "" # доп. контекст (долговременная память); подставляется в system
@abstractmethod
def ask(self, question: str, history: Optional[DialogHistory] = None) -> LlmResult:
"""Задать вопрос, получить ответ. history — предыдущие реплики диалога."""
def close(self) -> None:
"""Освободить ресурсы (по умолчанию — ничего)."""