163ace4283
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m14s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 10m19s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 46s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 27s
build / build (push) Successful in 1m18s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m45s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m2s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 36s
Testy / Kontrola składni wszystkich warstw (push) Successful in 23s
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>
116 lines
5.2 KiB
HTML
116 lines
5.2 KiB
HTML
{# 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">
|
|
<label>Budżet promptu
|
|
<select name="prompt_budget">
|
|
{% set pb = form.prompt_budget or 'medium' %}
|
|
<option value="concise" {{ 'selected' if pb == 'concise' else '' }}>zwięzły (~4 tys. znaków)</option>
|
|
<option value="medium" {{ 'selected' if pb == 'medium' else '' }}>średni (~12 tys.)</option>
|
|
<option value="extensive" {{ 'selected' if pb == 'extensive' else '' }}>obszerny (~30 tys.)</option>
|
|
<option value="huge" {{ 'selected' if pb == 'huge' else '' }}>bardzo obszerny (~120 tys.)</option>
|
|
<option value="max" {{ 'selected' if pb == 'max' else '' }}>maksymalny kontekst modelu</option>
|
|
</select>
|
|
</label>
|
|
<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ą
|
|
sieć</strong>. Możesz najpierw obejrzeć prompt, a dopiero potem wysłać.
|
|
</p>
|
|
|
|
{% if prompt_result %}
|
|
{% set st = prompt_result.stats %}
|
|
|
|
{# --- wynik: napisany horoskop (LOG-31) + transparentność (PRE-15) --- #}
|
|
{% if prompt_result.horoscope %}
|
|
<div class="meta">
|
|
Horoskop napisany przez: <strong>{{ prompt_result.provider }}</strong> ·
|
|
model: {{ prompt_result.model }}
|
|
{% if prompt_result.usage and prompt_result.usage.completion_tokens %}
|
|
· tokeny odpowiedzi: {{ prompt_result.usage.completion_tokens }}
|
|
{% endif %}
|
|
{% if prompt_result.leaves_lan %}
|
|
· <strong class="retro">dane opuściły sieć</strong>
|
|
{% else %}
|
|
· dane nie opuściły sieci
|
|
{% endif %}
|
|
</div>
|
|
<div class="actions">
|
|
<button type="button" class="ghost" data-copy="#horoscopeText">Kopiuj horoskop</button>
|
|
</div>
|
|
<textarea id="horoscopeText" class="prompt" rows="20" readonly>{{ prompt_result.horoscope }}</textarea>
|
|
<p class="muted small">
|
|
Treść wygenerował model językowy na podstawie {{ st.included }} wskazań z baz.
|
|
<strong>Nie stanowi porady medycznej, prawnej ani finansowej.</strong>
|
|
</p>
|
|
{% endif %}
|
|
|
|
{% if prompt_result.warnings %}
|
|
{% for w in prompt_result.warnings %}
|
|
<p class="muted small"><strong>Uwaga:</strong> {{ w }}</p>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
{% if prompt_result.token_plan %}
|
|
{% set tp = prompt_result.token_plan %}
|
|
<p class="muted small">
|
|
Tokeny: prompt {{ tp.prompt_tokens }} · okno modelu {{ tp.context_window }} ·
|
|
zarezerwowane na odpowiedź {{ tp.max_output }}
|
|
{% if prompt_result.usage and prompt_result.usage.turns and prompt_result.usage.turns > 1 %}
|
|
· odpowiedź złożona z {{ prompt_result.usage.turns }} tur (model dokańczał urwany tekst)
|
|
{% endif %}
|
|
</p>
|
|
{% endif %}
|
|
|
|
{% if prompt_result.llm_error %}
|
|
<div class="error">
|
|
Nie udało się napisać horoskopu: {{ prompt_result.llm_error }}<br>
|
|
Prompt poniżej jest gotowy — możesz go skopiować i użyć ręcznie.
|
|
</div>
|
|
{% endif %}
|
|
|
|
{# --- prompt: zawsze dostępny do podglądu i skopiowania --- #}
|
|
<div class="meta">
|
|
Prompt · {{ st.chars }} znaków (~{{ st.est_tokens }} tokenów) ·
|
|
budżet: {{ st.budget }} ·
|
|
wskazań: <strong>{{ st.included }}</strong>
|
|
{% if st.omitted %}· pominięto: <strong>{{ st.omitted }}</strong>{% endif %}
|
|
{% if st.deduplicated %}· scalono powtórek: {{ st.deduplicated }}{% endif %}
|
|
</div>
|
|
|
|
{% if st.omitted %}
|
|
<p class="muted small">
|
|
Pominięto {{ st.omitted }} najsłabszych wskazań (próg wagi {{ st.min_score_included }}).
|
|
Chcesz komplet — wybierz obszerniejszy budżet i wygeneruj ponownie.
|
|
</p>
|
|
{% endif %}
|
|
|
|
{% if prompt_result.data_error %}
|
|
<div class="error">{{ prompt_result.data_error }} — prompt złożony z samych wyliczeń.</div>
|
|
{% endif %}
|
|
|
|
<div class="actions">
|
|
<button type="button" class="ghost" data-copy="#promptText">Kopiuj prompt</button>
|
|
<span class="muted small">Możesz też wkleić go samodzielnie do ChatGPT lub Claude.</span>
|
|
</div>
|
|
<textarea id="promptText" class="prompt" rows="14" readonly>{{ prompt_result.prompt }}</textarea>
|
|
{% endif %}
|