4ef90b30bc
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m38s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m43s
Testy / Build obrazu silnika B (swisseph) (pull_request) Failing after 24s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 24s
build / build (push) Successful in 59s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m47s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m53s
Testy / Build obrazu silnika B (swisseph) (push) Failing after 29s
Testy / Kontrola składni wszystkich warstw (push) Successful in 18s
Domyslnie model LOKALNY — prompt niesie oryginalne opisy z baz, wiec domyslnie NIC nie opuszcza sieci. Chmura wlaczana swiadomie (LOG-32). - app/llm/: LLMProvider (jak EphemerisEngine z LOG-24) + dwie implementacje. Lokalny serwer modelu (Ollama/vLLM/llama.cpp) i OpenAI mowia TYM SAMYM protokolem /chat/completions, wiec obsluguje je jedna klasa; Anthropic ma wlasny /v1/messages. Napisane na samym httpx — bez SDK openai/anthropic: mniej zaleznosci i pelna kontrola nad tym, co wychodzi z sieci. - Kazdy dostawca deklaruje `leaves_lan` — interfejs MUSI jawnie mowic, czy tresc baz opuszcza siec; UI na tej podstawie ostrzega. - Ponawianie z backoffem (429/5xx), timeouty, czytelne bledy zamiast stacktrace. - Klucz wylacznie z LLM_API_KEY (sekret), nigdy w repo ani w UI. - POST /chart/horoscope + GET /llm/health. WAZNE: prompt jest zwracany ZAWSZE — takze gdy model padnie lub brakuje klucza. Dzieki temu awaria dostawcy nie blokuje pracy: prompt mozna skopiowac i uzyc recznie. Prezentacja: wybor modelu (lokalny/Anthropic/OpenAI), przycisk „Napisz horoskop (AI)", wynik z informacja kto go napisal, czy dane opuscily siec, ile wskazan weszlo, oraz zastrzezenie ze to nie porada medyczna (PRE-15). Testy: 13 nowych (transport podstawiony — zaden prawdziwy model nie wolany), calosc 131 passed / 1 skipped. Zweryfikowane e2e na atrapie serwera modelu: horoskop napisany, leaves_lan=false, tokeny zliczone; a przy padnietym modelu / braku klucza / zlym dostawcy — czytelny blad i zachowany prompt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
"""Kontrakt dostawcy modelu językowego (LOG-31).
|
|
|
|
Analogicznie do `EphemerisEngine` (LOG-24): prezentacja i reszta logiki nie wiedzą,
|
|
kto pisze tekst — lokalny model na naszym sprzęcie czy dostawca w chmurze.
|
|
|
|
Kluczowa własność dla bezpieczeństwa baz (LOG-32): każdy dostawca deklaruje
|
|
`leaves_lan`. Prompt niesie ORYGINALNE opisy z baz, więc interfejs musi jawnie
|
|
mówić, czy ta treść opuszcza naszą sieć — UI ma na tej podstawie ostrzegać.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
from dataclasses import dataclass, field
|
|
|
|
|
|
@dataclass
|
|
class Completion:
|
|
"""Wynik generowania — tekst + metryki do rozliczenia i podglądu."""
|
|
|
|
text: str
|
|
model: str
|
|
provider: str
|
|
leaves_lan: bool
|
|
usage: dict = field(default_factory=dict) # prompt_tokens / completion_tokens
|
|
|
|
|
|
class LLMError(RuntimeError):
|
|
"""Błąd wołania modelu — z komunikatem nadającym się do pokazania użytkownikowi."""
|
|
|
|
|
|
class LLMProvider(ABC):
|
|
name: str = "?"
|
|
#: czy treść promptu (a więc opisy z baz) opuszcza naszą sieć
|
|
leaves_lan: bool = True
|
|
|
|
@abstractmethod
|
|
def generate(self, prompt: str, max_tokens: int) -> Completion:
|
|
"""Zwraca gotowy tekst. Rzuca LLMError przy niepowodzeniu."""
|
|
|
|
@abstractmethod
|
|
def health(self) -> dict:
|
|
"""Czy dostawca jest osiągalny i skonfigurowany."""
|