feat(ui): okno postepu z logiem podczas pisania horoskopu #19

Merged
gitea merged 1 commits from feat/progress-console into master 2026-07-23 11:54:09 +00:00
Owner

Problem

Generowanie trwa minutami, a zwykly POST formularza nie dawal zadnego sygnalu —
aplikacja wygladala na zawieszona.

Rozwiazanie

Okno z logiem, zegarem i spinnerem. Log pokazuje rzeczywiste zdarzenia z serwera,
nie udawany pasek postepu
— inaczej bylby ozdobnikiem udajacym wiedze, ktorej klient nie ma.

Przyklad z przebiegu na zywo:

22:57:56  Wysylam zadanie...
22:57:56  Licze horoskop i szukam wskazan w bazach...
22:57:56  Prompt gotowy: 3294 znakow, wskazan 0
22:57:56  Dostawca: local, model: llama3.1:8b
22:57:56  Prompt 915 tok. · okno modelu 200000 · na odpowiedz 8000
22:57:56  Tura 1: wysylam do modelu (limit 8000 tokenow)...
22:57:58  Tura 1: odebrano 239 znakow w 2.0s — odpowiedz urwana, poprosze o dokonczenie
22:57:58  Tura 2: wysylam do modelu (limit 7600 tokenow)...
22:58:00  Gotowe: 262 znakow w 2 turach.

Jak to dziala

  • app/progress.py — strumien NDJSON (a nie SSE, bo EventSource obsluguje tylko GET,
    a to POST z cialem). Praca leci w watku roboczym, generator odpompowuje kolejke —
    dzieki temu zdarzenia docieraja w trakcie pracy, a nie dopiero na koncu. Heartbeat
    co 10 s, zeby proxy nie uznalo polaczenia za martwe.
  • providers.generate(..., on_event) — raportuje kazda ture (start, czas, liczba
    znakow, czy urwana). To tura trwa, wiec bez tego log pokazywalby „wysylam do modelu"
    i cisze przez minuty — czyli ten sam problem, tylko ladniej.
  • POST /chart/horoscope/stream w logice + proxy /horoscope/stream w prezentacji.

Wynik bez przeladowania: ostatnie zdarzenie niesie gotowy HTML, wyrenderowany z tego
samego szablonu co przeladowanie strony (_prompt_result.html wydzielony z _prompt_block.html).
Jedno zrodlo prawdy dla wygladu wyniku — zero duplikacji widoku w JS.

Degradacja: bez strumieniowania w przegladarce formularz idzie klasycznie i wszystko
dziala jak wczesniej, tylko bez okna. Zerwane polaczenie konczy sie komunikatem w logu,
nie cisza. Spinner respektuje prefers-reduced-motion.

Blad znaleziony przy tescie na zywo

Petla kontynuacji odejmowala od budzetu zamowiony limit tury zamiast tokenow
faktycznie wyprodukowanych. Pierwsza tura zjadala caly budzet, wiec urwana odpowiedz
nigdy nie doczekala sie dokonczenia i wracala do uzytkownika jako calosc. Widac to bylo
dopiero na strumieniu — w logu byla jedna tura zakonczona „odpowiedz urwana", po czym koniec.
Naprawione, pokryte testem regresyjnym.

Weryfikacja

  • 176 passed / 1 skipped (logika) + 17 (prezentacja); nowe testy: budzet liczony
    z wyprodukowanych tokenow, emisja zdarzen postepu.
  • Na zywo z wolna atrapa modelu (3 tury po 2 s): zdarzenia z poprawnymi czasami,
    okno z 11 liniami logu, kontynuacja po urwaniu, wynik wstawiony bez przeladowania strony.
## Problem Generowanie trwa minutami, a zwykly POST formularza nie dawal **zadnego** sygnalu — aplikacja wygladala na zawieszona. ## Rozwiazanie Okno z logiem, zegarem i spinnerem. **Log pokazuje rzeczywiste zdarzenia z serwera, nie udawany pasek postepu** — inaczej bylby ozdobnikiem udajacym wiedze, ktorej klient nie ma. Przyklad z przebiegu na zywo: ``` 22:57:56 Wysylam zadanie... 22:57:56 Licze horoskop i szukam wskazan w bazach... 22:57:56 Prompt gotowy: 3294 znakow, wskazan 0 22:57:56 Dostawca: local, model: llama3.1:8b 22:57:56 Prompt 915 tok. · okno modelu 200000 · na odpowiedz 8000 22:57:56 Tura 1: wysylam do modelu (limit 8000 tokenow)... 22:57:58 Tura 1: odebrano 239 znakow w 2.0s — odpowiedz urwana, poprosze o dokonczenie 22:57:58 Tura 2: wysylam do modelu (limit 7600 tokenow)... 22:58:00 Gotowe: 262 znakow w 2 turach. ``` ## Jak to dziala - **`app/progress.py`** — strumien NDJSON (a nie SSE, bo `EventSource` obsluguje tylko GET, a to POST z cialem). Praca leci w **watku roboczym**, generator odpompowuje kolejke — dzieki temu zdarzenia docieraja **w trakcie** pracy, a nie dopiero na koncu. Heartbeat co 10 s, zeby proxy nie uznalo polaczenia za martwe. - **`providers.generate(..., on_event)`** — raportuje **kazda ture** (start, czas, liczba znakow, czy urwana). To tura trwa, wiec bez tego log pokazywalby „wysylam do modelu" i cisze przez minuty — czyli ten sam problem, tylko ladniej. - `POST /chart/horoscope/stream` w logice + proxy `/horoscope/stream` w prezentacji. **Wynik bez przeladowania:** ostatnie zdarzenie niesie **gotowy HTML**, wyrenderowany z tego samego szablonu co przeladowanie strony (`_prompt_result.html` wydzielony z `_prompt_block.html`). Jedno zrodlo prawdy dla wygladu wyniku — zero duplikacji widoku w JS. **Degradacja:** bez strumieniowania w przegladarce formularz idzie klasycznie i wszystko dziala jak wczesniej, tylko bez okna. Zerwane polaczenie konczy sie komunikatem w logu, nie cisza. Spinner respektuje `prefers-reduced-motion`. ## Blad znaleziony przy tescie na zywo Petla kontynuacji odejmowala od budzetu **zamowiony limit tury** zamiast tokenow **faktycznie wyprodukowanych**. Pierwsza tura zjadala caly budzet, wiec urwana odpowiedz **nigdy nie doczekala sie dokonczenia** i wracala do uzytkownika jako calosc. Widac to bylo dopiero na strumieniu — w logu byla jedna tura zakonczona „odpowiedz urwana", po czym koniec. Naprawione, pokryte testem regresyjnym. ## Weryfikacja - **176 passed / 1 skipped** (logika) + **17** (prezentacja); nowe testy: budzet liczony z wyprodukowanych tokenow, emisja zdarzen postepu. - **Na zywo** z wolna atrapa modelu (3 tury po 2 s): zdarzenia z poprawnymi czasami, okno z 11 liniami logu, kontynuacja po urwaniu, wynik wstawiony bez przeladowania strony.
gitea added 1 commit 2026-07-22 20:59:28 +00:00
feat(ui): okno postepu z logiem podczas pisania horoskopu
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 11m21s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m50s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 34s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s
build / build (push) Successful in 1m49s
Testy / Testy warstwy logicznej (silnik) (push) Successful in 11m20s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 10m0s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 37s
Testy / Kontrola składni wszystkich warstw (push) Successful in 25s
114b7eebdf
Generowanie trwa minutami, a zwykly POST nie dawal zadnego sygnalu — aplikacja
wygladala na zawieszona. Teraz w trakcie pracy pojawia sie okno z logiem,
zegarem i spinnerem.

Log pokazuje RZECZYWISTE zdarzenia z serwera, nie udawany pasek postepu:
- app/progress.py — strumien NDJSON; praca leci w watku roboczym, generator
  odpompowuje kolejke, wiec zdarzenia docz w TRAKCIE pracy, nie na koncu;
  heartbeat co 10s, zeby proxy nie uznalo polaczenia za martwe,
- providers.generate(..., on_event) — raportuje kazda ture (start, czas trwania,
  liczba znakow, czy urwana), bo to tura trwa,
- POST /chart/horoscope/stream w logice + proxy /horoscope/stream w prezentacji.

Wynik: ostatnie zdarzenie niesie GOTOWY HTML wyrenderowany z tego samego
szablonu, ktory renderuje przeladowanie strony (_prompt_result.html wydzielony
z _prompt_block.html). Jedno zrodlo prawdy dla wygladu wyniku — okno wstawia go
bez przeladowania.

Degradacja: bez strumieniowania w przegladarce formularz idzie klasycznie
i wszystko dziala jak wczesniej, tylko bez okna. Blad polaczenia konczy sie
komunikatem w logu, nie cisza.

BLAD ZNALEZIONY PRZY TESCIE NA ZYWO: petla kontynuacji odejmowala od budzetu
ZAMOWIONY limit tury zamiast tokenow faktycznie wyprodukowanych — pierwsza tura
zjadala caly budzet, wiec urwana odpowiedz nigdy nie doczekala sie dokonczenia
i wracala do uzytkownika jako calosc. Naprawione i pokryte testem regresyjnym.

Testy: 176 passed / 1 skipped (logika) + 17 (prezentacja). Zweryfikowane na zywo
z wolna atrapa modelu: zdarzenia z poprawnymi czasami, okno z 11 liniami logu,
wynik wstawiony bez przeladowania strony.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gitea merged commit 114b7eebdf into master 2026-07-23 11:54:09 +00:00
gitea deleted branch feat/progress-console 2026-07-23 11:54:11 +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#19