feat(logic): dostawcy LLM i pisanie horoskopu (LOG-31) #11

Merged
gitea merged 1 commits from feat/log31-llm-provider into master 2026-07-21 18:35:39 +00:00
Owner

PR stackowany na #9 (potrzebuje prompt.py z LOG-29/30). Merguj po #9;
po zmergowaniu #9 i #10 moze wymagac trywialnego rebase (logic_client.py dotykaja oba).

Decyzja, ktora ksztaltuje ten PR

Wybrales lokalny domyslnie, chmura na zadanie — i tak to zbudowalem.
Prompt niesie oryginalne opisy z baz, wiec domyslnie nic nie opuszcza sieci.

Architektura

LLMProvider — ta sama idea co EphemerisEngine (LOG-24): reszta systemu nie wie,
kto pisze tekst.

Dostawca Protokol leaves_lan
local (domyslny) — Ollama / vLLM / llama.cpp /chat/completions false
openai /chat/completions true
anthropic /v1/messages true

Lokalny serwer modelu i OpenAI mowia tym samym protokolem, wiec obsluguje je jedna
klasa. Calosc na samym httpx — bez SDK openai/anthropic: mniej zaleznosci, mniejsza
powierzchnia ataku i pelna kontrola nad tym, co realnie wychodzi z sieci.

leaves_lan jest czescia kontraktu — interfejs musi jawnie powiedziec, czy tresc baz
opuscila siec. UI ostrzega na tej podstawie, zamiast zgadywac po nazwie dostawcy.

Odpornosc

  • ponawianie z backoffem (429/5xx), timeouty, czytelne komunikaty zamiast stacktrace;
  • klucz wylacznie z LLM_API_KEY (sekret) — nigdy w repo, w UI ani w logach;
  • prompt zwracany ZAWSZE — takze gdy model padnie albo brakuje klucza. Awaria dostawcy
    nie blokuje pracy: prompt mozna skopiowac i uzyc recznie.

Konfiguracja: LLM_PROVIDER, LLM_MODEL, LLM_BASE_URL, LLM_API_KEY, LLM_TIMEOUT,
LLM_MAX_TOKENS. Endpointy: POST /chart/horoscope, GET /llm/health.

Prezentacja (PRE-14/15)

Wybor modelu, przycisk Napisz horoskop (AI), a przy wyniku: kto go napisal, jaki model,
czy dane opuscily siec, ile wskazan weszlo, oraz zastrzezenie, ze to nie porada medyczna.
Nad przyciskami stale ostrzezenie, ze prompt zawiera opisy z baz i dane urodzeniowe.

Weryfikacja

  • 13 nowych testow (transport podstawiony MockTransportzaden prawdziwy model nie
    jest wolany
    ): generowanie, leaves_lan, klucz wysylany tylko gdy ustawiony, retry po 429,
    bledne odpowiedzi, wymog klucza, nieznany dostawca. Calosc: 131 passed / 1 skipped.
  • E2E na atrapie serwera modelu: horoskop napisany, leaves_lan=false, tokeny zliczone,
    a atrapa potwierdzila, ze dostala pelny prompt z sekcja danych i wymogiem cytowania.
  • Sciezki awaryjne: model padl / brak klucza / zly dostawca -> czytelny blad i zachowany
    prompt
    (3340 znakow) do uzycia recznego.

Zeby ruszylo u Ciebie

Domyslny adres lokalnego modelu to http://localhost:11434/v1 (Ollama). Trzeba postawic
serwer modelu i ewentualnie wskazac LLM_BASE_URL / LLM_MODEL. Bez tego Napisz horoskop
zwroci czytelny blad, a prompt i tak bedzie gotowy do skopiowania.

> **PR stackowany na #9** (potrzebuje `prompt.py` z LOG-29/30). Merguj po #9; > po zmergowaniu #9 i #10 moze wymagac trywialnego rebase (`logic_client.py` dotykaja oba). ## Decyzja, ktora ksztaltuje ten PR Wybrales **lokalny domyslnie, chmura na zadanie** — i tak to zbudowalem. Prompt niesie **oryginalne opisy z baz**, wiec domyslnie **nic nie opuszcza sieci**. ## Architektura `LLMProvider` — ta sama idea co `EphemerisEngine` (LOG-24): reszta systemu nie wie, kto pisze tekst. | Dostawca | Protokol | `leaves_lan` | |---|---|---| | `local` (**domyslny**) — Ollama / vLLM / llama.cpp | `/chat/completions` | **false** | | `openai` | `/chat/completions` | true | | `anthropic` | `/v1/messages` | true | Lokalny serwer modelu i OpenAI mowia **tym samym** protokolem, wiec obsluguje je jedna klasa. Calosc na **samym httpx — bez SDK `openai`/`anthropic`**: mniej zaleznosci, mniejsza powierzchnia ataku i pelna kontrola nad tym, co realnie wychodzi z sieci. **`leaves_lan` jest czescia kontraktu** — interfejs musi jawnie powiedziec, czy tresc baz opuscila siec. UI ostrzega na tej podstawie, zamiast zgadywac po nazwie dostawcy. ## Odpornosc - ponawianie z backoffem (429/5xx), timeouty, czytelne komunikaty zamiast stacktrace; - klucz **wylacznie** z `LLM_API_KEY` (sekret) — nigdy w repo, w UI ani w logach; - **prompt zwracany ZAWSZE** — takze gdy model padnie albo brakuje klucza. Awaria dostawcy nie blokuje pracy: prompt mozna skopiowac i uzyc recznie. Konfiguracja: `LLM_PROVIDER`, `LLM_MODEL`, `LLM_BASE_URL`, `LLM_API_KEY`, `LLM_TIMEOUT`, `LLM_MAX_TOKENS`. Endpointy: `POST /chart/horoscope`, `GET /llm/health`. ## Prezentacja (PRE-14/15) Wybor modelu, przycisk **Napisz horoskop (AI)**, a przy wyniku: kto go napisal, jaki model, **czy dane opuscily siec**, ile wskazan weszlo, oraz zastrzezenie, ze to nie porada medyczna. Nad przyciskami stale ostrzezenie, ze prompt zawiera opisy z baz i dane urodzeniowe. ## Weryfikacja - **13 nowych testow** (transport podstawiony `MockTransport` — **zaden prawdziwy model nie jest wolany**): generowanie, `leaves_lan`, klucz wysylany tylko gdy ustawiony, retry po 429, bledne odpowiedzi, wymog klucza, nieznany dostawca. Calosc: **131 passed / 1 skipped**. - **E2E na atrapie serwera modelu**: horoskop napisany, `leaves_lan=false`, tokeny zliczone, a atrapa **potwierdzila**, ze dostala pelny prompt z sekcja danych i wymogiem cytowania. - **Sciezki awaryjne**: model padl / brak klucza / zly dostawca -> czytelny blad **i zachowany prompt** (3340 znakow) do uzycia recznego. ## Zeby ruszylo u Ciebie Domyslny adres lokalnego modelu to `http://localhost:11434/v1` (Ollama). Trzeba postawic serwer modelu i ewentualnie wskazac `LLM_BASE_URL` / `LLM_MODEL`. Bez tego `Napisz horoskop` zwroci czytelny blad, a prompt i tak bedzie gotowy do skopiowania.
gitea added 1 commit 2026-07-21 18:35:25 +00:00
feat(logic): dostawcy LLM i pisanie horoskopu (LOG-31)
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
4ef90b30bc
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>
gitea force-pushed feat/log31-llm-provider from a8b2321dd7 to 4ef90b30bc 2026-07-21 18:35:25 +00:00 Compare
gitea merged commit 4ef90b30bc into master 2026-07-21 18:35:39 +00:00
gitea deleted branch feat/log31-llm-provider 2026-07-21 18:35:39 +00:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: gitea/astrololo#11