← Torna ai progetti
Live Case Study

nicolasilvestre.it — il sito che si aggiorna da solo

Un agente AI legge le fonti tech ogni giorno, seleziona, scrive e pubblica. Il chatbot risponde ai visitatori e prenota appuntamenti. Zero CMS, zero piattaforme, zero intervento umano a regime.

Ho costruito questo sito per rispondere a una domanda concreta: un agente AI può davvero gestire un sito editoriale, dalla raccolta delle notizie alla pubblicazione, senza che io debba intervenire ogni giorno? La risposta, dopo qualche settimana di rodaggio, è sì.

Non ho usato WordPress, Ghost o qualunque altro CMS. Non ho usato piattaforme no-code. Ho scritto il backend in Python con FastAPI, ho collegato un modello LLM via API, ho configurato un paio di cron job e ho lasciato girare. Quello che segue è una descrizione tecnica di come funziona ogni parte del sistema.

Non è perfetto. Ma funziona, è in produzione, e mi ha insegnato più di qualsiasi tutorial.


14+
fonti monitorate ogni giorno (RSS, GitHub, Arxiv, HF, HN)
4
cicli news al giorno (07:00, 13:00, 17:00, 20:00)
1
pipeline articoli ogni sera (21:00) — 5 articoli completi
~0
interventi manuali a regime, una volta configurato

Il sistema si divide in tre layer principali: le fonti dati in input, il backend Python che le elabora, e il frontend statico che mostra il risultato. Il tutto gira su un VPS Contabo con Nginx come reverse proxy e Let’s Encrypt per SSL.

RSS ×14
GitHub
Arxiv
HF Papers
HN
Backend FastAPI — uvicorn :8000
Ubuntu 22.04 / Contabo VPS
article_agent.py — pipeline articoli
news_digest.py — pipeline news
chatbot.py — Oliver / RAG
bot_telegram.py — notifiche admin
DeepSeek LLM API
ChromaDB RAG
SQLite DB
Nginx — reverse proxy + SSL
Frontend statico — HTML / CSS / JS
Visitatore

Generazione articoli


Ogni sera alle 21:00 un job automatico legge i feed RSS, chiede al modello di selezionare gli argomenti migliori e genera cinque articoli completi in HTML. Nessuna fase manuale.

01
APScheduler triggera alle 21:00
Il job è registrato in agent.py all’avvio di FastAPI. Nessun crontab di sistema: APScheduler gira in-process e si integra nel lifecycle dell’app.
02
Lettura feed RSS da sources_config.py
article_agent.py chiama get_active_rss_feeds() da sources_config.py — il registro centrale che contiene tutte le 14 fonti attive: TechCrunch AI, The Verge, Ars Technica, MIT Tech Review, OpenAI Blog, Anthropic Blog, Google AI, Nvidia, Meta AI, HuggingFace, The Batch, Wired Italia e altre.
03
DeepSeek seleziona i 5 topic del giorno
I titoli e abstract raccolti vengono passati al modello con un prompt che chiede di scegliere i 5 argomenti più rilevanti e originali, evitando duplicati tematici e notizie già trattate di recente.
04
Generazione HTML completo per ogni articolo
Per ogni topic selezionato, il modello genera un articolo completo in HTML: introduzione, sezioni con titoli, conclusione, call-to-action. Il prompt include un components-guide.txt con i componenti HTML disponibili nel design system.
05
Salvataggio in SQLite come draft
content_orchestrator.py salva ogni articolo generato nel database SQLite con stato draft. Da qui è possibile revisionare o bloccare la pubblicazione via Telegram prima che vada live.
06
Pubblicazione automatica via HTML injection
Il sistema inietta l’HTML degli articoli nella homepage tra i marcatori <!-- AGENT: ARTICLES_START --> e <!-- AGENT: ARTICLES_END -->. Nessun rebuild, nessun framework: il file HTML viene riscritto sul server e Nginx lo serve immediatamente.

Digest news AI/tech


Quattro volte al giorno il sistema raccoglie notizie da fonti eterogenee — RSS, repository GitHub emergenti, paper Arxiv, HuggingFace Daily Papers e Hacker News — e le processa per la sezione /news/.

01
Cache aggiornata alle 06:45
sources_extra.py interroga GitHub (3 query configurabili: repos nuovissimi, emergenti, tool MCP), Arxiv (categorie cs.AI, cs.LG, cs.CL, cs.CV, cs.MA), HuggingFace Daily Papers e Hacker News via Algolia API. I risultati finiscono in sources_cache.json.
02
news_digest.py raccoglie alle 07, 13, 17, 20
Ad ogni ciclo, il digest aggrega fonti RSS + fonti extra dalla cache. Filtra per keyword AI/ML, deduplicazione URL e finestra temporale (ultime 24h).
03
DeepSeek analizza e assegna trend_score
Il modello classifica ogni notizia per categoria (Modelli, Tool, Ricerca, Prodotti, Normativa), estrae un takeaway sintetico e assegna un trend_score da 0 a 100 in base a rilevanza e originalità.
04
Generazione AI brief giornaliero
Una volta al giorno il modello produce un brief testuale con i tre temi portanti della giornata nel mondo AI. Viene esposto via /api/news/brief e visualizzato come sezione collassabile nella pagina news.
05
Salvataggio SQLite ed esposizione API
Notizie e brief vengono salvati in SQLite. Il frontend le legge via /api/news?limit=N&category=X e /api/news/brief, con polling automatico ogni 5 minuti.

Oliver — il chatbot RAG


Oliver è il chatbot integrato nel sito. Non è un wrapper diretto al modello: c’è una state machine che gestisce la conversazione, un layer RAG che legge i documenti su Nicola, e un’integrazione Telegram per il booking degli appuntamenti.

chatting
booking_name
booking_contact
booking_reason
booking_slot
done
RAG
Retrieval Augmented Generation su ChromaDB
Oliver indicizza 6 documenti .md nella cartella backend/docs/: chi è Nicola, cosa fa, i suoi progetti, i valori, come prenotare. Gli embedding vengono generati con all-MiniLM-L6-v2 di HuggingFace e salvati in ChromaDB. A ogni messaggio, recupera i chunk più rilevanti e li inietta nel contesto prima di chiamare DeepSeek.
BOT
Notifiche e comandi via Telegram
Quando un visitatore completa il flusso di booking, Oliver invia una notifica a Nicola su Telegram con nome, contatto, motivo e slot scelto. Da Telegram è possibile rispondere con /conferma [id] o /rifiuta [id]. Il chatbot aggiorna il visitatore in tempo reale.
SEC
Protezioni anti-injection
Ogni messaggio in input passa per _sanitize_input() (limite 600 caratteri) e _is_injection_attempt() (15 pattern IT+EN). Se viene rilevato un tentativo di injection, Oliver risponde con un messaggio fisso senza passare il testo al modello. Il pattern matching avviene pre-LLM, lato Python.
Approfondisci Oliver →

Layer Tecnologia
Frontend HTML / CSS / JS statico — nessun framework, nessun build step
Backend Python 3.11, FastAPI, uvicorn su porta 8000
LLM DeepSeek deepseek-chat via API OpenAI-compatibile
RAG LangChain LCEL 1.x, ChromaDB, HuggingFace all-MiniLM-L6-v2
Scheduler APScheduler in-process, 5 job configurati
Database SQLite — articoli, news, brief, chat, prenotazioni
Bot python-telegram-bot, long-polling async nel lifespan FastAPI
Rate limiting slowapi — 10 req/min per IP sull’endpoint /chat
Server Contabo VPS, Ubuntu 22.04 LTS, Nginx reverse proxy, Let’s Encrypt SSL

Cosa ho imparato costruendo questo


Un agente AI non è magia: è un loop con un LLM dentro. Il modello fa una cosa sola bene: trasformare testo in testo. Tutto il resto — recupero dati, scheduling, salvataggio, notifiche — è codice Python ordinario intorno a quella chiamata API.
Il punto difficile non è il modello, è l’infrastruttura intorno. Scegliere il modello giusto è la parte facile. Gestire i fallimenti di rete, i feed RSS malformati, i rate limit delle API esterne — quello richiede tempo.
ChromaDB con embeddings locali basta per RAG su documenti piccoli. Non serve un servizio vettoriale costoso. Sei file .md su un VPS da 6 euro al mese funzionano benissimo.
APScheduler è sorprendentemente affidabile. Avevo paura di dover gestire un crontab di sistema separato. Un job in-process, dentro FastAPI, con lifespan context manager, non ha mai perso un’esecuzione in settimane.
Telegram come interfaccia admin è la cosa migliore che ho fatto. Nessun pannello da costruire, nessuna autenticazione da gestire. Un comando /status dal telefono mi dice tutto quello che succede sul server in tre secondi.

Vuoi capire come funziona Oliver? Puoi leggere il dettaglio tecnico o provarlo direttamente.