feat(ui): interaktywny wybor modelu u dostawcy
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m48s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m52s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 35s
Testy / Kontrola składni wszystkich warstw (push) Successful in 20s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 14m4s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m56s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 35s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s

Uzytkownik wybiera nie tylko dostawce, ale konkretny model — Fable czy Opus
u Anthropica, gpt-4o-mini czy gpt-5 u OpenAI, cokolwiek ma pobrane lokalnie.

- app/llm/catalog.py: podpowiedzi modeli per dostawca wraz z oknem kontekstu,
  nadpisywalne przez <DOSTAWCA>_MODELS; GET /llm/models wystawia je dla UI.
- Pole modelu w UI jest TEKSTOWE z datalista, nie zamknietym <select> — konto
  moze miec dostep do modeli, o ktorych kod nie wie, a nowe wychodza szybciej,
  niz aktualizuje sie katalog. Puste pole = model domyslny dostawcy.
- static/models.js: zmiana dostawcy przelacza podpowiedzi, podmienia placeholder
  na model domyslny i pokazuje okno kontekstu wybranego modelu.
- build_provider(name, model) — model z zadania wygrywa nad konfiguracja.

WAZNE (znalezione przy tescie e2e): liczenie budzetu „maksymalny kontekst modelu"
szlo przez build_provider(), ktory WYMAGA klucza API — bez klucza budzet cicho
spadal do wartosci zapasowej i byl identyczny dla wszystkich modeli Anthropic.
Budzet zalezy wylacznie od okna kontekstu, wiec doszlo resolve_model(), ktore
rozwiazuje nazwe modelu bez budowania dostawcy. Teraz budzet realnie sie rozni:
Opus/Fable 3,48 mln znakow, Haiku 536 tys., gpt-4o-mini 438 tys., llama3.1 8 tys.

Pewnosc danych w katalogu: modele Anthropic pochodza z oficjalnej dokumentacji
API (okna i limity zgodne z limits.py); modele OpenAI to podpowiedzi, ktorych
nie weryfikowalem; lokalne zaleza od tego, co masz pobrane.

Testy: 174 passed / 1 skipped (logika) + 17 (prezentacja). Nowy test strukturalny
pilnuje, ze KAZDE wywolanie w dol niesie wybrany model i dostawce — dokladnie ta
klasa bledu zlapala brakujacy parametr przy horoskopie okresowym.
Zweryfikowane w przegladarce: przelaczanie dostawcy podmienia liste modeli.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 19:06:31 +02:00
parent e6dc649013
commit 46a21427db
11 changed files with 312 additions and 26 deletions
@@ -1,3 +1,6 @@
{# Katalog modeli wstrzykiwany przez handler — pole jest tekstowe, więc
można wpisać dowolny model, do którego konto ma dostęp. #}
<script type="application/json" id="llmCatalog">{{ llm_catalog | tojson }}</script>
{# Wspólny blok: sterowanie generowaniem + prompt (LOG-29/30) + horoskop (LOG-31).
Używany na ekranach Interpretacje i Kalendarz. #}
<div class="opts">
@@ -11,15 +14,22 @@
<option value="max" {{ 'selected' if pb == 'max' else '' }}>maksymalny kontekst modelu</option>
</select>
</label>
<label>Model
<select name="llm_provider">
<label>Dostawca
<select name="llm_provider" id="llmProvider">
{% set lp = form.llm_provider or 'local' %}
<option value="local" {{ 'selected' if lp == 'local' else '' }}>lokalny — nic nie opuszcza sieci</option>
<option value="anthropic" {{ 'selected' if lp == 'anthropic' else '' }}>Anthropic — dane wychodzą</option>
<option value="openai" {{ 'selected' if lp == 'openai' else '' }}>OpenAI — dane wychodzą</option>
</select>
</label>
<label>Model
<input type="text" name="llm_model" id="llmModel" list="llmModelList"
value="{{ form.llm_model or '' }}" placeholder="domyślny dostawcy"
autocomplete="off">
<datalist id="llmModelList"></datalist>
</label>
</div>
<p class="muted small" id="llmModelHint"></p>
<p class="muted small">
Prompt zawiera <strong>oryginalne opisy z baz</strong> oraz dane urodzeniowe. Model lokalny
przetwarza je u nas; wybór dostawcy w chmurze oznacza, że ta treść <strong>opuszcza naszą
@@ -90,4 +90,5 @@
<script src="/static/now.js"></script>
<script src="/static/copy.js"></script>
<script src="/static/models.js"></script>
{% endblock %}
@@ -80,4 +80,5 @@
<script src="/static/now.js"></script>
<script src="/static/copy.js"></script>
<script src="/static/models.js"></script>
{% endblock %}