Sistema di pre-risposta su Telegram
Contesto
Quando un bot deve eseguire un’elaborazione lunga prima di rispondere, la chat rimane muta. L’utente non sa se il bot ha ricevuto il comando, se sta lavorando o se si è fermato. Telegram offre tre strumenti API per gestire questo scenario:
sendChatAction— mostra un indicatore temporaneo (tip tapping, caricamento, etc.)sendMessage— invia un messaggio nella chateditMessageText— modifica il testo di un messaggio già inviato dallo stesso bot
Combinandoli si ottiene una “pre-risposta”: un messaggio provvisorio che viene progressivamente arricchito o sostituito dal risultato finale.
Funzionamento
Il flusso è semplice:
- si invia
sendChatAction("typing")per segnalare attività - si invia
sendMessage("Sto elaborando...")e si salva ilmessage_idrestituito - si esegue il lavoro
- si usa
editMessageTextsu quelmessage_idper pubblicare il risultato
Il punto chiave: editMessageText sostituisce il contenuto del messaggio, non aggiunge in coda. Per simulare un accumulo progressivo, il client deve conservare il testo precedente e concatenarlo con il nuovo frammento prima di inviare la modifica.
Adattamento per Bash (curl + array)
Prerequisiti
- Bash 4+
curlinstallatosed(POSIX, presente su ogni Unix-like)- array
BOT_TOKENSeCHAT_IDSgià definiti
Stato persistente per coppia bot/chat
Ogni invio può avere più bot token e più chat. Serve uno stato separato per ogni combinazione BOT_TOKEN|CHAT_ID, altrimenti la modifica colpirebbe un messaggio sbagliato.
declare -gA TELEGRAM_MSG_ID=()
declare -gA TELEGRAM_MSG_TEXT=()La chiave è una stringa concatenata con pipe:
_telegram_key() {
local bot_token="$1"
local chat_id="$2"
printf '%s|%s' "$bot_token" "$chat_id"
}telegram_msg
Invia il messaggio, estrae message_id dal JSON, e lo salva nell’associative array insieme al testo inviato.
telegram_msg() {
local msg="$1"
local response message_id key
for BOT_TOKEN in "${BOT_TOKENS[@]}"; do
for CHAT_ID in "${CHAT_IDS[@]}"; do
response="$(curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" \
--data-urlencode text="${msg}")" || true
message_id="$(printf '%s' "$response" | sed -n 's/.*"message_id":\([0-9]\{1,\}\).*/\1/p')"
if [[ -n "$message_id" ]]; then
key="$(_telegram_key "$BOT_TOKEN" "$CHAT_ID")"
TELEGRAM_MSG_ID["$key"]="$message_id"
TELEGRAM_MSG_TEXT["$key"]="$msg"
fi
done
done
}Note:
--data-urlencodeevita problemi con multilinea e caratteri specialisedestrae il solomessage_iddal JSON di risposta (cerca il pattern"message_id":NUMERO)- se la chiamata fallisce, non viene salvato alcun id
telegram_edit
Legge lo stato della coppia bot/chat, costruisce il nuovo testo (append o replace), chiama editMessageText e aggiorna lo stato.
telegram_edit() {
local new_chunk="$1"
local mode="${2:-append}" # append | replace
local BOT_TOKEN CHAT_ID key current_text new_text message_id
for BOT_TOKEN in "${BOT_TOKENS[@]}"; do
for CHAT_ID in "${CHAT_IDS[@]}"; do
key="$(_telegram_key "$BOT_TOKEN" "$CHAT_ID")"
message_id="${TELEGRAM_MSG_ID[$key]}"
current_text="${TELEGRAM_MSG_TEXT[$key]}"
[[ -z "$message_id" ]] && continue
if [[ "$mode" == "replace" ]]; then
new_text="$new_chunk"
else
new_text="${current_text}${new_chunk}"
fi
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/editMessageText" \
-d chat_id="${CHAT_ID}" \
-d message_id="${message_id}" \
--data-urlencode text="${new_text}" >/dev/null || true
TELEGRAM_MSG_TEXT["$key"]="$new_text"
done
done
}telegram_typing
Invia sendChatAction("typing") a tutte le destinazioni. Non richiede message_id.
telegram_typing() {
local BOT_TOKEN CHAT_ID
for BOT_TOKEN in "${BOT_TOKENS[@]}"; do
for CHAT_ID in "${CHAT_IDS[@]}"; do
curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendChatAction" \
-d chat_id="${CHAT_ID}" \
-d action="typing" >/dev/null || true
done
done
}Pattern di utilizzo
Base: typing + placeholder + replace finale
telegram_typing
telegram_msg "Elaborazione in corso..."
# lavoro lungo
sleep 5
telegram_edit "Risultato finale completo." replaceProgressivo: append a blocchi
telegram_typing
telegram_msg "Avvio procedura..."
ricevi_output_primo_passo
telegram_edit "\n- Step 1: completato"
ricevi_output_secondo_passo
telegram_edit "\n- Step 2: completato"
telegram_edit "\n\n**Fatto.**" replaceLimiti e note operative
| Aspetto | Dettaglio |
|---|---|
| Modifica | un bot può modificare solo i propri messaggi |
| Append | non esiste nel protocollo Telegram: è simulata via concatenazione lato client |
| Testo massimo | editMessageText ha lo stesso limite di sendMessage (4096 caratteri nella Bot API standard) |
| Troppe richieste | la Bot API ha rate limit: non chiamare telegram_edit più di ~20 volte al minuto per chat |
Messaggi già inviati via sendDocument | non sono editabili; in quel caso tenere separato un messaggio testuale di stato |
sendChatAction | va ripetuto ogni ~5 secondi perché Telegram lo dismette dopo pochi secondi; non scrive nulla in chat |
Estensioni possibili
- aggiungere
parse_mode=MarkdownoHTMLnei parametri disendMessageeeditMessageText - introdurre
disable_web_page_preview=trueper messaggi con link - errore handling esplicito (ritorno del codice HTTP o del campo
okdel JSON Telegram) - funzione
telegram_file()coordinata che invia un documento e un messaggio di stato separato