尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證IZZ.ro — Romanian anti-clickbait news aggregator. RSS sources → AI summaries + multi-source dedup → static site (SSG) → GitHub Actions → Cloudflare Workers. Human-moderated. Live: izz.ro
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Agregator de știri românești construit pe o promisiune simplă: mai puțin zgomot, mai multă informație. Titlurile sunt reformulate faptic, fără cârlige emoționale. Rezumatele sunt scrise cu cuvinte proprii și duc întotdeauna la sursa originală. Când mai multe publicații relatează același eveniment, subiectul apare o singură dată, cu toate sursele enumerate. Imaginile sunt grafică generată pentru fiecare articol, nu fotografii preluate.檢視完整 README ↗
Portalul știrilor tale · izz.ro
Agregator de știri românești construit pe o promisiune simplă: mai puțin zgomot, mai multă informație. Titlurile sunt reformulate faptic, fără cârlige emoționale. Rezumatele sunt scrise cu cuvinte proprii și duc întotdeauna la sursa originală. Când mai multe publicații relatează același eveniment, subiectul apare o singură dată, cu toate sursele enumerate. Imaginile sunt grafică generată pentru fiecare articol, nu fotografii preluate.
Site-ul este 100% static (SSG), publicat serverless: pipeline-ul rulează în GitHub Actions, publicarea se face prin Cloudflare Workers. Fără server propriu, fără baze de date gestionate, fără publicitate.
/calendar/) — calendarul evenimentelor care urmează în știri./cauta/) — index Pagefind construit la fiecare build: rezultate pe măsură ce tastezi, în titluri și în rezumate, cu diacritice opționale („inundatii” găsește „inundații”), termeni marcați în rezultat, filtre pe categorie și pe tip de anunț oficial. Fără serviciu extern, fără chei. RSS (/feed.xml).static/site.webmanifest, service worker la /sw.js) cu citire offline: shellul se precachează la instalare, iar articolele se servesc stale-while-revalidate — ce ai mai citit rămâne disponibil fără net. Butonul de instalare apare discret, jos-stânga, și dispare definitiv după instalare sau după refuz.infra/PUSH-SETUP.md.Surse RSS (SOURCES din generator/config.py)
│
├─ fetch.py descărcare fluxuri
├─ state.py stare, dedup, expirare → data/articles.json (comis în repo)
├─ cluster.py grupare multi-sursă
├─ select.py selecție editorială
├─ process.py sinteză AI (model B/C)
├─ covers.py grafică proprie per articol
├─ moderation.py filtrare editorială → moderation.yaml (om în buclă)
└─ render.py randare Jinja2 → output/
└─ pagefind_index.py index de căutare → output/_pagefind/ (52 fișiere, fără fragmente)
Modelul de conținut B+C corespunde celor două tipuri vizibile pe site: rezumat dintr-o sursă (B) și sinteză multi-sursă (C). Starea persistă între rulări prin data/articles.json, comis în repo — nu există bază de date externă.
pip install -r requirements.txt
# Pipeline complet (RSS → AI → HTML în output/) + salvează starea
python -m generator.main
# Doar test, fără salvare sau randare (afișează rezultatul + sursele RSS moarte)
python -m generator.main --dry-run
# Vizualizare locală
python -m http.server 8000 --directory output
# → http://localhost:8000
Fără cheie AI, pipeline-ul folosește un fallback determinist (rezumat din descrierea RSS) — util pentru testat structura. Pentru reformulare reală, pune GEMINI_API_KEY în .env (vezi .env.example).
generator/ pipeline-ul: fetch · state · cluster · select · process (AI B/C)
covers · moderation · render · main · providers/
templates/ Jinja2 (autoescape ON): base · index · article · category · legal
search · calendar · instrumente · calculator · ghid/ghiduri · surse
sectiuni · subject · _card
static/ styles.css (temă auriu-dark) · logo · favicon · og-image · pictograme
PWA · site.webmanifest · theme.js · search.js · calc-salariu.js
fonts/ · harta-stiri/
content/ pagini legale și metodologice (markdown): method (Cum devin ideile funcții),
terms, privacy, corrections, security, images, takedown,
accessibility, contact
data/ articles.json — starea comisă în repo
moderation.yaml control editorial (om în buclă) — vezi REVIEW.md
infra/ Workerul publicat (infra/worker.js): compune fallback-ul 404 -> oglinda
(infra/worker-404-mirror.js) cu rutele de alerte (infra/push.js — VAPID,
criptare aes128gcm, KV). Configurarea alertelor: infra/PUSH-SETUP.md
tools/ utilitare operaționale: qa_check, feed_check, verify_release,
title_quality_audit, build_harta*, indexnow_submit etc.
tests/ teste Python
.github/ workflows (build, tests, monitor, editorial-quality, security…)
Documente de proiect comise: CLAUDE.md și AGENTS.md (reguli pentru dezvoltare asistată de agenți AI), REVIEW.md (fluxul de moderare), REGULI-SINTEZA.md (regulile de sinteză), specs/, notes/, sessions/ (istoric de lucru intern).
generator/config.py.moderation.yaml (fluxul e descris în REVIEW.md)..env local / secrete GitHub — nu se comit niciodată.| Scenariu | Configurare |
|---|---|
| Implicit | GEMINI_API_KEY (secret GitHub sau .env) · fluxul Gemini → Ollama local fallback |
| Claude API | secret ANTHROPIC_API_KEY + AI_PROVIDER: anthropic în build.yml |
| Router multi-provider (opțional) | AI_ROUTER_MODE=multi + AI_FALLBACK_PROVIDERS=groq,cerebras,mistral,openrouter |
| Fără cheie | fallback determinist din descrierea RSS |
Routerul multi-provider este o cascadă: providerul principal configurat, apoi providerii din AI_FALLBACK_PROVIDERS în ordinea declarată (endpointuri OpenAI-compatible), apoi Ollama dacă e activ. Un provider fără cheie proprie este ignorat automat; implicit rămâne AI_PROVIDER=gemini. Exemplu local:
AI_ROUTER_MODE=multi
AI_FALLBACK_PROVIDERS=groq,cerebras,mistral,openrouter
Arhitectura separă munca grea de publicare:
GitHub Actions — .github/workflows/build.yml, cron 13 * * * *: rulează pipeline-ul (fetch + AI, cu buget per rulare) și comite data/articles.json în repo. Secret necesar: GEMINI_API_KEY.
Încearcă orar, publică la ~2h: un job de poartă taie rularea dacă ultimul conținut e mai proaspăt de 105 minute. Cron-ul orar dens acoperă firings-urile sărite de planificatorul GitHub; pragul ține și numărul de build-uri Cloudflare la ~12/zi. (Plafonul de 500 build-uri/lună era al lui Pages și nu se mai aplică — vezi IZZ-0305.)
Publicarea pe Worker — .github/workflows/deploy-worker.yml: randează render-only, verifică output-ul înainte de producție (minim 1.000 de fișiere, bugetul de redirecte) și publică prin wrangler deploy. Workers Builds (integrarea git din Cloudflare) nu mai e pe cale: factura minutele de build (7.407 minute peste plafon, 22 aug – 21 sep 2026, $37,04), iar randarea a fost mutată pe runnerul GitHub (IZZ-0326). Configurația versionată stă în wrangler.jsonc:
main: infra/worker.js — nu mai e proiect assets-only. Workerul răspunde la /push/* și /sw.js, iar un 404 de articol expirat cade pe oglinda gh-pages;assets.directory: ./output;not_found_handling: "404-page" — fără linia asta, output/404.html nu ar fi servit niciodată;preview_urls: true — preview per ramură.Variabilele de mediu ale randării se pun din workflow-uri, nu dintr-un ecran Cloudflare: SITE_BASE doar pentru preview-uri, BUILD_COMMIT_SHA / BUILD_BRANCH pentru amprenta servită la /build.json (citită de tools/verify_release.py), iar PYTHON_VERSION vine din actions/setup-python. GEMINI nu e necesar aici — render-only nu apelează AI.
Fluxul: Actions face fetch + AI și salvează starea → comite pe main → declanșează explicit deploy-worker.yml (workflow_dispatch e singurul eveniment care mai pornește workflow-uri din GITHUB_TOKEN) → jobul de deploy randează fără AI, publică pe izz.ro și compară /build.json cu commitul așteptat. Cronul :53 al lui deploy-worker rămâne plasă de siguranță, nu calea normală. (Migrat de pe Cloudflare Pages pe Workers în august 2026.)
Din 22 septembrie 2026 contul e pe Workers Free, unde o versiune de Worker poate avea cel mult 20.000 de fișiere statice (Paid: 100.000). Cererile către fișiere statice rămân gratuite și nelimitate, deci constrângerea e strict numărul de fișiere.
Consecințe, toate versionate în cod:
Arta articolului se desenează în pagină (templates/_art.html + static/styles.css), nu se
mai servește ca art.jpg/art.webp. Compozițiile sunt tipografie și geometrie, deci ies identic
(și mai clar) din CSS. Rămân fișiere doar fotografiile reale și imaginile din date.
og:image propriu doar pentru cele mai noi OG_COVER_MAX_ARTICLES articole; restul folosesc
coperta categoriei din output/og/<categorie>.jpg.
ARTICLE_TTL_DAYS = 11 (aprobat la 25 octombrie 2026 pentru refacerea marjei; precedent: IZZ-0421/0422).
Supapă de siguranță: dacă ingestul sare peste ce a fost măsurat, randarea publică doar câte
articole încap (OUTPUT_FILE_BUDGET) și taie de la cel mai vechi. Peste OUTPUT_FILE_CEILING
randarea moare zgomotos — altfel Cloudflare ar refuza deploy-ul tăcut și site-ul ar îngheța.
Indexul de căutare se publică fără fragmente (generator/pagefind_index.py). Pagefind
scrie un fișier de fragment per pagină, iar la 9.451 de pagini asta ar însemna 23.941 de
fișiere — cu 19,7% peste plafon. curata_bundle() le șterge după ce a citit din ele
legătura id→articol, deci bundle-ul rămâne la 52 de fișiere (1,7 MB). Prețul: rezultatele
arată titlul (cu termenii marcați), categoria și data, nu un fragment de text. Detaliile,
măsurătorile și variantele respinse: specs/cautare-pagefind.md.
Măsoară cu python tools/count_output.py după python -m generator.main --render-only.
Detaliile și cifrele: specs/cloudflare-free-2026-09.md.
Calitatea editorială și disponibilitatea nu depind de intervenția manuală. Verificările deterministe rulează în GitHub Actions; o execuție eșuată devine vizibilă în pagina Actions și prin notificările GitHub.
| Verificare | Declanșare | Ce verifică |
|---|---|---|
tests.yml | PR-uri și schimbări de cod pe main | lint (ruff), teste Python, contractul titlurilor, randare, integritate HTML |
QA check (în build.yml) | după fiecare actualizare de conținut | surse incoerente, categorii goale, titluri oficiale goale sau peste 110 caractere |
editorial-quality.yml | zilnic, 06:37 UTC + manual | audit independent al titlurilor, raport JSON reținut 30 de zile |
monitor.yml | periodic, independent de deploy | lipsa răspunsului pe domeniul public sau căderea simultană a ambelor origini |
release-probe (în build.yml) | după publicare | potrivirea commitului publicat cu manifestul /build.json servit pe izz.ro |
Repo-ul include și analiză statică de securitate (CodeQL, Semgrep), verificarea dependențelor (Dependabot) și sonde de fum/trafic (smoke, visual, probe, trafic).
tools/title_quality_audit.py verifică regula de lectură mobilă, fără apeluri AI și fără servicii externe:
python tools/title_quality_audit.py
python tools/title_quality_audit.py --report title-quality-report.json
Un rezultat reușit garantează că titlul de afișare al fiecărui anunț oficial este nevid și are cel mult 110 caractere. Titlul instituției rămâne neschimbat în data/articles.json; reducerea se aplică doar câmpului de afișare, calculat la randare. Dacă regula este încălcată, workflow-ul eșuează și raportul conține exemplele concrete care necesită corectare.
Programarea GitHub acoperă controalele zilnice de consistență; pentru detectare garantată la minut a indisponibilității externe ar fi necesar un serviciu de monitorizare dedicat, configurat separat la nivel de cont.
Nu este necesară nicio acțiune la rulările verzi. Dacă un workflow devine roșu: deschide execuția din GitHub Actions, descarcă artefactul title-quality-report când e disponibil și corectează articolul sau regula indicată. După un commit, testele și verificarea release-ului rulează din nou automat.