Bot Telegram Motivazionale con Python e Ollama

Oggi vogliamo creare un Bot Telegram che invia frasi motivazionali ogni ora utilizzando un LLM locale. Funziona su Windows, Linux o macOS con almeno 8GB RAM per modelli base. Per fare ciò abbiamo bisogno di:

  • installare Ollama;
  • scaricare e configurare un modello LLM;
  • creare un bot su Telegram tramite BotFather;
  • creare un ambiente Python virtuale con le librerie necessarie.

Questo approccio garantisce privacy totale poiché tutto avviene localmente sul tuo computer, senza dipendere da API cloud. Di seguito, una guida dettagliata passo-passo per principianti, con codice completo e spiegazioni su come e perché ogni componente funziona.

Ollama: configurazione e scelta del modello

Windows

Per installare Ollama su Windows puoi scaricare l’eseguibile EXE da qui, oppure puoi aprire PowerShell e digitare:

irm https://ollama.com/install.ps1 | iex

Linux

Per installare Ollama su un sistema operativo Linux, quello che devi fare è aprire il terminale e digitare:

curl -fsSL https://ollama.com/install.sh | sh

macOs

Per installare Ollama su un sistema operativo macOs hai tre modalità differenti:

  • puoi scaricare il file dmg da qui
  • puoi aprire il terminale e digitare
curl -fsSL https://ollama.com/install.sh | sh
  • puoi aprire il terminale e digitare la formula di Homebrew
brew install ollama

Bisogna precisare che richiede macOs 14 Sonoma o le versioni successive.

Scegliamo il modello

La selezione del modello linguistico dipende dalle risorse hardware disponibili, specificamente dalla RAM di sistema e dalla VRAM della GPU. L’utilizzo di modelli sovradimensionati rispetto all’hardware causa latenze incompatibili con l’esecuzione asincrona dello script.

Viene riportata di seguito una tabella che aiuta a chiarire come bisogna orientarsi nella scelta del modello in base all’hardware a nostra disposizione (RAM, VRAM):

Parametri del ModelloRAM/VRAM MinimaModelli Ollama CompatibiliDestinazione Hardware
< 3 Miliardi (3B)4 GBphi3gemma:2bqwen:1.8bSistemi con risorse limitate, esecuzione in background a basso impatto.
7 – 8 Miliardi (7B-8B)8 GBllama3mistralgemma:7bPC standard. Bilanciamento tra velocità di inferenza e coerenza del testo.
13 – 14 Miliardi (13B)16 GBqwen:14bllama2:13bWorkstation o architetture con memoria unificata (es. Apple Silicon).
30+ Miliardi (30B+)32+ GBllama3:70bmixtralHardware server o configurazioni multi-GPU.

Per frasi motivazionali in italiano, mistral produce risultati molto naturali. Se la macchina ha poca RAM, llama3.2:3b (versione 3 miliardi di parametri) è un ottimo compromesso qualità/velocità e gira in meno di 2 secondi anche su CPU.

Procedura di download

Ollama gestisce l’acquisizione dei modelli tramite interfaccia a riga di comando (CLI). Per scaricare i pesi del modello nel sistema senza avviare l’inferenza, bisogna eseguire nel terminale il comando:

ollama pull <nome_modello>

Ad esempio, se volessimo usare il modello di Mistral, dovremmo usare il comando:

ollama pull mistral

Per scaricare il modello (se non già presente sul nostro sistema) e allocarlo immediatamente in memoria, allora dobbiamo utilizzare il comando:

ollama run <nome_modello>

Telegram: come si crea un bot?

Per creare un Bot con BotFather devi seguire questi passaggi:

  • Avvio di BotFather: Cerca @BotFather nella barra di ricerca di Telegram e avvia la conversazione premendo il tasto Avvia o inviando il comando /start.
  • Creazione del bot: Invia il comando /newbot.
  • Assegna un nome al bot: Inserisci il nome visualizzato del bot (es. Frasi Motivazionali). Questo nome può essere modificato in seguito e può contenere spazi.
  • Scelta dello username: Inserisci lo username univoco del bot. Deve terminare obbligatoriamente con la parola bot (es. FrasiMotivazionali_bot). Non può contenere spazi.
  • Archiviazione del Token: BotFather genererà un HTTP API Token, una stringa alfanumerica che bisogna necessariamente copiare e salvare; è necessaria per autenticare il bot e connetterlo a script o piattaforme esterne.
  • Configurazione opzionale: Utilizza i comandi /setdescription per la biografia del bot, /setuserpic per caricare un’immagine del profilo o /setcommands per definire la lista dei comandi rapidi.

Python – Sporchiamoci le mani

Prerequisiti:
Devi avere installato Python (versione 3.10 o superiore) sul tuo computer. Se non ce l’hai, scaricalo dal sito ufficiale e installalo seguendo le istruzioni.

Prepariamo il nostro ambiente di lavoro. Per prima cosa dobbiamo creare il nostro ambiente virtuale (virtual environment) Python dove andremo ad installare tutte le nostre librerie:

  • Andiamo sul Desktop e creiamo una nuova cartella e chiamiamola “Progetto_Motivazione”
  • Apriamo un terminale e scriviamo cd ~/Desktop/Progetto_Motivazione per entrare nella cartella
  • Ora che ci troviamo all’interno, creiamo l’ambiente virtuale con python -m venv progetto_motivazione
  • Attiviamo l’ambiente con progetto_motivazione\Scripts\activate se state su Windows o source progetto_motivazione/bin/activate se state su Linux o MacOs

Ora che abbiamo attivato l’ambiente, siamo pronti ad installare le librerie che ci servono per creare lo script; in particolare, ci servirà la libreria python-telegram-bot per gestire le API di Telegram e ollama per comunicare con il modello locale. Per fare ciò le installiamo nel nostro ambiente con il comando pip install:

pip install "python-telegram-bot[job-queue]" ollama python-dotenv

Il comando pip install "python-telegram-bot[job-queue]" installa APScheduler (job scheduler asincrono) utile per inviare i messaggi al nostro bot ogni ora. Inoltre, la libreria ufficiale ollama-python espone un’interfaccia asincrona (AsyncClient) perfettamente compatibile con il runtime asyncio usato da python-telegram-bot v20+. Questo ci permette di fare la chiamata LLM senza bloccare il loop degli eventi del bot. Infine, la libreria python-dotenv è utile per caricare le variabili necessarie dal file .env che deve essere creato all’interno della cartella del progetto e che conterrà le seguenti informazioni:

TELEGRAM_TOKEN=il_tuo_token              # Ottenuto in precedenza da @BotFather
CHAT_ID=il_tuo_id                        # ID del bot (ottenilo con @userinfobot)
OLLAMA_MODEL=il_modello_che_vuoi_usare   # Il modello di Ollama scaricato in locale (es mistral, llama3.2:3b, ...) 

Creiamo un prompt che verrà usato dal modello per istruirlo su cosa deve fare, ad esempio potremmo pensare di utilizzare il seguente:

Oppure potremmo usare un prompt del tipo:

Perché funziona? I prompt “system” definiscono il ruolo del modello, riducendo allucinazioni e garantendo output concisi. Per generare efficientemente la singola frase in un contesto di conversazioni stateless, cioè dove non viene memorizzato lo stato, nello script useremo ollama.chat().

Una volta salvate queste informazioni, creiamo lo script python che andrà ad animare il nostro bot.

"""
Bot Telegram - Frasi Motivazionali con Ollama
==============================================
Requisiti:
    pip install "python-telegram-bot[job-queue]" ollama python-dotenv

File .env necessario:
    BOT_TOKEN=il_tuo_token
    CHAT_ID=il_tuo_chat_id
    OLLAMA_MODEL=il_tuo_modello
"""

import asyncio
import logging
import os

import ollama
from dotenv import load_dotenv
from telegram.ext import Application

# Carica le variabili da .env
load_dotenv()

TOKEN   = os.environ["BOT_TOKEN"]
CHAT_ID = int(os.environ["CHAT_ID"])
MODELLO = os.getenv("OLLAMA_MODEL", "mistral")

# Imposta intervallo di tempo in secondi
INTERVALLO = 3600

logging.basicConfig(
    format="%(asctime)s | %(levelname)s | %(message)s",
    level=logging.INFO,
)

def genera_frase() -> str:
    """Chiama Ollama e restituisce una frase motivazionale."""
    risposta = ollama.chat(
        model=MODELLO,
        messages=[
            {
                "role": "system",
                "content": (
                    "Sei un coach motivazionale. "
                    "Genera UNA sola frase in italiano, breve (max 40 parole), "
                    "ispiratrice e originale. "
                    "Rispondi SOLO con la frase, senza virgolette né introduzioni."
                ),
            },
            {"role": "user", "content": "Dammi una frase motivazionale."},
        ],
    )
    return risposta["message"]["content"].strip()

async def invia_frase(context) -> None:
    """Job eseguito ogni ora: genera e invia la frase al CHAT_ID."""
    frase = await asyncio.to_thread(genera_frase)
    await context.bot.send_message(chat_id=CHAT_ID, text=f"Frase: {frase}")
    logging.info(f"Frase inviata: {frase}")

def main():
    app = Application.builder().token(TOKEN).build()

    # Invia la prima frase dopo 5 secondi, poi ogni ora
    app.job_queue.run_repeating(invia_frase, interval=INTERVALLO, first=5)

    logging.info("Bot avviato.")
    app.run_polling(drop_pending_updates=True)

if __name__ == "__main__":
    main()

Spiegazione del codice

Importazioni
  • asyncio è la libreria standard di Python per la programmazione asincrona — il bot usa questa modalità per poter fare più cose contemporaneamente senza bloccarsi.
  • logging stampa messaggi informativi nel terminale mentre il bot gira.
  • os serve a leggere le variabili d’ambiente.
  • ollama è il client Python per parlare con il modello locale.
  • load_dotenv legge il file .env e carica le variabili.
  • Application è la classe principale di python-telegram-bot che gestisce tutto.
Configurazione
  • La funzione load_dotenv() apre il file .env e carica le variabili in memoria. os.environ["BOT_TOKEN"] legge la variabile — la sintassi con le parentesi quadre fa sì che Python si blocchi subito con un errore chiaro se la variabile manca, invece di fallire in modo misterioso più avanti.
  • Il CHAT_ID viene convertito in intero con int() perché Telegram si aspetta un numero, non una stringa. os.getenv("OLLAMA_MODEL", "mistral") invece usa la seconda forma: se la variabile non c’è nel .env, usa "mistral" come valore predefinito.
La funzione genera_frase()

È una funzione normale (non async), perché ollama.chat() è una chiamata sincrona — aspetta la risposta prima di andare avanti. ollama.chat() accetta una lista di messaggi nello stesso formato usato da ChatGPT: il messaggio system dà le istruzioni al modello (il “personaggio” che deve interpretare), il messaggio user è la richiesta vera e propria. La risposta arriva come dizionario e risposta["message"]["content"] è il testo generato. .strip() rimuove eventuali spazi o ritorni a capo all’inizio e alla fine.

Il job che invia il messaggio: invia_frase()

Questa è una funzione async perché viene eseguita dentro il loop asincrono del bot. Il punto critico è asyncio.to_thread(genera_frase): poiché genera_frase() è lenta (Ollama può impiegare 2-5 secondi), se la chiamassimo direttamente bloccheremmo l’intero bot per quel tempo. asyncio.to_thread() sposta l’esecuzione in un thread separato, lasciando libero il bot di fare altro nel frattempo. await significa “aspetta che finisca, ma senza bloccare”. Dopodiché context.bot.send_message() invia il testo via API Telegram al CHAT_ID specificato.

Il main()
  • Il metodo Application.builder().token(TOKEN).build() costruisce l’oggetto principale del bot con il token.
  • Il metodo job_queue.run_repeating() pianifica invia_frase ogni 3600 secondi (1 ora), con la prima esecuzione dopo 5 secondi dall’avvio — utile per verificare subito che tutto funzioni.
  • Invece, run_polling() avvia il bot in modalità long polling: invia continuamente richieste ai server Telegram per sapere se sono arrivati nuovi messaggi o comandi, e mantiene il processo vivo.
  • Infine, drop_pending_updates=True ignora i messaggi arrivati mentre il bot era spento.
Torna in alto