Szablon: Imiona psów (Dog name extraction → Pupprint)¶
Gotowy scenariusz „Dog name extraction (cards)" wyciąga imię psa z zamówienia personalizowanego (mail z Allegro / Erli / sklepu) i dodaje wpis do kolejki Pupprint — modułu generującego naklejki A4 z imionami psów.
Skąd biorą się te zamówienia
Klient zamawia spersonalizowaną kartę z imieniem psa. W mailu-zgłoszeniu z platformy podaje konkretne imię („Burek", „Reksio", lub kilka imion oddzielonych przecinkiem). Personalizowane SKU mają w katalogu Convex tag PERSONALIZACJA*. Scenariusz parsuje HTML maila (regex), liczy ile naklejek trzeba wydrukować, prosi LLM o wyciągnięcie imion i kolejkuje wpisy w puppy_names. Gdy uzbiera się 6 imion (rozmiar big) lub 9 (small), Pupprint generuje arkusz A4.
Co dostarcza szablon¶
Aktualnie operator robi to tak:
- Otwiera maila zamówienia.
- Czyta SKU produktów (z HTMLa, format
<p id="sku">2 x KIN130/105CZE</p>). - Liczy, ile imion ma wpisać.
- Czyta imię psa (
<p id="name">Burek</p>). - Wpisuje do panelu Pupprint: imię + rozmiar (big/small) + ilość kart.
- Czeka, aż uzbiera się arkusz, klika „Generuj".
Szablon automatyzuje 1–5. Punkt 6 (generacja arkusza) chodzi sam — Pupprint ma cron flush_expired_batches, który zamyka kolejki po określonym czasie.
Graf scenariusza¶
graph TD
src[source<br/><i>email</i>] --> filt[filter_dog<br/>Subject ma 'IMIĘ PSA']
filt -->|raise_on_skip<br/>kończy cicho| stop1((filtered_out))
filt --> parse[parse_cards<br/>Parse SKU × tag]
parse --> llm[llm_dog_name<br/>LLM: rozmiar + imiona]
llm --> append[append_card<br/>Pupprint queue]
append --> mark[mark_read<br/>Gmail: Seen]
mark --> done[mark_resolved<br/>Status: resolved]
7 węzłów + 6 krawędzi. Source (korzeń) → Filter → Parse personalization cards → LLM extract → Append puppy name → Mark email read → Update status.
Krok 1 — sklonuj szablon¶
W panelu Obsługa Klienta → Scenariusze:
- Znajdź kartę „Dog name extraction (cards)" (żółte tło, Starter C10).
- Edytuj → zmień nazwę na np. „Imiona psów — produkcja".
- Zapisz bez aktywacji.
Krok 2 — pasek triggera¶
- Źródło:
Email (Gmail / Mailcow). - Konto: konkretna skrzynka powiązana z platformą sprzedaży (np. konto Gmail, do którego Allegro / Erli wysyłają zgłoszenia o nowych zamówieniach).
- Gdy nastąpi:
Nowe zgłoszenie(new_issue).
Konto MUSI być wybrane
Inaczej scenariusz odpali na każdej skrzynce, w tym Twojej osobistej. Wpisanie konkretnego konta to też dodatkowa warstwa bezpieczeństwa — Twoje prywatne maile do support@ zostaną pominięte.
Krok 3 — filtr filter_dog¶
Domyślne ustawienia:
- Pole:
subject - Operator:
contains - Wartość:
IMIĘ PSA - Uwzględniaj wielkość liter:
false - Zgłoś sentinel przy skip:
true - Powód skip:
Subject does not contain 'IMIĘ PSA'
Co warto zmienić:
raise_on_skip = trueto kluczowe — gdy temat nie pasuje, scenariusz kończy cicho (status=filtered_out), nie zaśmieca DLQ. Nie zmieniaj tego.- Wartość — dostosuj do tego, jak Twoja platforma oznacza zamówienia z personalizacją. Allegro mailowe mają w temacie
IMIĘ PSA(wielkimi literami) — wynika z regexu wparse_personalization_cards. Erli ma podobne, ale sprawdź.
Krok 4 — parsowanie kart parse_cards¶
Węzeł parse_personalization_cards nie ma żadnych pól — robi swoje deterministycznie:
- Z HTMLa wszystkich wiadomości w wątku wycina paragrafy
<p id="...name">(imiona) i<p id="...sku">(SKU + ilość). - Sprawdza w katalogu Convex (
marketplace/products), czy SKU ma tag pasujący doPERSONALIZACJA*(case-insensitive). - Sumuje ilości tych spersonalizowanych SKU →
expected_cards.
Wynik (do wglądu po teście węzła):
{
"structured": true,
"expected_cards": 4,
"candidate_names": ["Burek", "Reksio", "Łatka", "Mruczek"],
"personalized_skus": [
{"sku": "KIN130/105CZE", "count": 2, "name": "Karta zwykła czerwona DUŻA"},
{"sku": "KIN130/106NIE", "count": 2, "name": "Karta zwykła niebieska DUŻA"}
],
"non_personalized_skus": [],
"unknown_skus": []
}
structured = true znaczy: HTML miał rozpoznane paragrafy. false znaczy: maile bez tej struktury (zwykła wiadomość od klienta) — downstream LLM dostaje pusty expected_cards i pracuje w trybie unstructured (jedno imię, koniec).
Krok 5 — LLM llm_dog_name¶
Domyślny prompt jest długi i precyzyjny — wynik wieloiteracyjnego dostrojenia (TASK-295). Kluczowe rzeczy:
Pracujesz z zamówieniem na spersonalizowaną kartę z imieniem psa.
Na podstawie TEMATU wiadomości ustal rozmiar kartonu:
temat zawierający "DUŻE" → size="big"
temat zawierający "MAŁE" → size="small"
Bez markera → domyślnie "big".
Dane z katalogu (mogą być puste dla wiadomości bez struktury HTML):
expected_cards={{results.parse_cards.expected_cards}}
candidate_names={{results.parse_cards.candidate_names}}
personalized_skus={{results.parse_cards.personalized_skus}}
Reguły dla pola names:
- candidate_names to TEKST wyciągnięty regex-em z paragrafu <p id="name">.
NIE jest to gwarantowane imię — klient mógł wpisać URL, zdanie, śmieci.
Twoim zadaniem jest ocena semantyczna:
· Pojedyncze słowo (1–3 krótkie) → ZAWSZE imię psa, choćby brzmiało dziwnie
(GRUBY, KULKA, PUCEK, TAKO, MICA — wszystko poprawne przezwiska).
· URL, długie zdanie, oczywisty nie-imię → wyciągnij jak najlepiej.
- expected_cards > 0 → zwróć DOKŁADNIE tyle imion (możesz powtarzać).
- expected_cards puste → wstaw imię (lub kilka połączonych w jeden string,
np. "Burek i Reksio") jako pierwszy element tablicy.
- Zachowaj polskie znaki i emotki, jeśli klient użył.
Odpowiedz JSON-em:
{"fields": {"size": "big"|"small", "names": [...]}, "confidence": 0..1}
Czego nie zmieniaj:
- Reguła „pojedyncze słowo = zawsze imię" — bez tego LLM zaczyna „poprawiać" („GRUBY → niepoprawne, użyję Reksio").
- Cycle-padding (powtarzanie imion gdy
expected_cards > liczba imion) — bez tego brakuje naklejek. - Zachowywanie emotek — klient płaci za personalizację 1:1.
Co możesz zmienić:
- Dodatkowy kontekst (np. „klienci sklepu zoologicznego, imiona zwykle 1-2 sylaby") — pomaga przy nietypowych imionach.
- Threshold confidence — domyślnie
0.7,raise_on_low_confidence: true. Niżej = więcej automatyzacji, więcej błędów. Wyżej = więcej eskalacji, mniej błędów.
Krok 6 — append_card¶
Dodaje wpisy do puppy_names (kolejki Pupprint):
- Tablica imion:
{{results.llm_dog_name.fields.names}}— placeholder. - Oczekiwana liczba kart:
{{results.parse_cards.expected_cards}}— placeholder. Może być pusty (LLM unstructured). - Rozmiar karty:
{{results.llm_dog_name.fields.size}}.
Logika reconciliacji (zaszyta w append_puppy_name.py):
| Stan wejścia | Co robi |
|---|---|
expected_cards = null (unstructured) |
Każde imię = jedna karta. |
expected_cards = 0 |
Rzuca błąd („structured + 0 personalized SKUs"). |
expected_cards = N, len(names) = N |
Pasuje 1:1. |
expected_cards = N, len(names) > N |
Rzuca błąd („more names than cards"). |
expected_cards = N, 1 ≤ len(names) < N |
Cycle-pad: powtarza imiona aż uzbiera się N. |
expected_cards = N, len(names) = 0 |
Rzuca błąd („zero names"). |
Błąd → przebieg trafia do DLQ → operator widzi w panelu Pupprint zakładkę „Wymaga uwagi".
Krok 7 — mark_read (oznacz Gmail jako przeczytane)¶
Brak pól. Po sukcesie scenariusza Gmail wątek dostaje flag \Seen przez IMAP. To jedyne miejsce, gdzie scenariusz pisze do platformy poza akcjami CS — patrz Source setup → Polityka read-only.
Operator może traktować Gmail jako kolejkę: wszystko nieprzeczytane = jeszcze nie obsłużone scenariuszem.
Krok 8 — test pojedynczego węzła¶
Krytyczne dla tego scenariusza, bo logika reconciliacji w append_card jest skomplikowana.
- Otwórz scenariusz w edytorze.
- Kliknij
parse_cards→ Test węzła → wybierz prawdziwe zgłoszenie z personalizacją (np. mail z Allegro o zamówieniu zKIN130). Sprawdźexpected_cardsicandidate_names. - Kliknij „Do upstream" — wynik wstawi się do
mock_results. - Kliknij
llm_dog_name→ Test węzła → ustawmock_issuez prawdziwym mailem,mock_resultsz poprzedniego kroku → uruchom. Sprawdźfields.namesifields.size. - Zwróć uwagę na
confidence:2(certain) — LLM jest pewien, scenariusz pójdzie doappend_card.1(vague) — LLM zwraca, ale niepewnie. Z domyślnymraise_on_low_confidence: trueprzebieg trafia do failure_handler ics_dead_letters.0(no_name) — LLM nie znalazł imienia, eskalacja.
Krok 9 — aktywacja¶
- Zaznacz Aktywny + Zapisz.
- Test na żywo: zamów coś personalizowanego u siebie (lub poproś operatora) — najlepiej z dziwnym imieniem („Pucek 🐶") żeby zweryfikować kompletny flow.
/marketplace/history/runs→ poczekaj 5–6 min → otwórz przebieg → statussuccess.Automatyzacje → Imiona psów→ sprawdź, czy nowe wpisy są w kolejce z prawidłowym imieniem i rozmiarem.
Krok 10 — monitoring na codzień¶
Po aktywacji obserwuj przez kilka tygodni:
/marketplace/history/runsfiltrowane po nazwie scenariusza — ile success, ile failed.- DLQ (
/marketplace/history/dlq) — czyść co tydzień, zapisuj patterny błędów. - Pupprint → „Wymaga uwagi" — wpisy ze scenariusza, które trafiły do failure-mode (np. LLM zwrócił 0 imion). Operator decyduje ręcznie.
Najczęstsze problemy wczesnym etapie:
| Symptom | Przyczyna | Naprawka |
|---|---|---|
parse_cards zwraca unknown_skus |
SKU nie ma w katalogu Convex (jeszcze niezsynchronizowany) | Synchronizuj BaseLinker → Convex (f/baselinker/sync_catalog). |
parse_cards zwraca expected_cards: 0 mimo że produkt jest spersonalizowany |
Tag w katalogu nie pasuje do regexu /PERSONALIZACJA/i |
Sprawdź w BaseLinkerze tag — może masz Personalizacja-bluza zamiast PERSONALIZACJA-bluza? |
| LLM zwraca imię z dodatkowym tekstem (np. „Burek - dziękuję") | Prompt potrzebuje doprecyzowania | Dodaj w promcie: „NIE dodawaj komentarza, tylko sam imię". |
Wszystkie scenariusze trafiają do DLQ z confidence too low |
Próg za wysoki | Zmień confidence_threshold w polach llm_dog_name (przez API — nie ma w UI). |
Adaptacja — niestandardowe rozmiary lub typy kart¶
Dla nowych typów produktów:
- Nowy rozmiar (np.
medium) — wymaga zmiany zarówno schematu (extract_schema.fields.size.enum), jak i runtime'uappend_puppy_name.py. To wymaga deweloperów — zgłoś przez Forgejo. - Nowy typ tagu (zamiast
PERSONALIZACJA, np.IMIE-WLASCICIELA) — wymaga zmiany regexu wparse_personalization_cards.py. Też przez deweloperów. - Inny język imion (rumuńskie, niemieckie znaki) — to prompt-only dostosowanie, możesz zrobić sam.
Cross-linki¶
- Pupprint — strona dla operatora (kolejka, generowanie arkuszy A4) — Automatyzacje → Pupprint.
- Reference węzłów — LLM extract, Parse personalization cards, Append puppy name, Mark email read.
- Builder — tutorial — pełny przewodnik.
- TASK-313 (sovereignty + dog-names) — śledzenie w backlog.
Dane techniczne¶
- Seed:
convex/convex/support/seed_templates.ts:buildDogNameExtractionGraph. - Tabela kolejki:
puppy_names(Convex), zarządzana zAutomatyzacje → Imiona psów. - Generator arkusza:
f/automations/pupprint/generate_grid.flow/. - Cron flush:
flush_expired_batches— zamyka niedopełnione kolejki po określonym czasie. - Tag personalizacji: regex
/PERSONALIZACJA/i(case-insensitive) natags[]produktu w katalogu Convex.