Il Webserver NAO Gimmick è un backend scritto in Python sviluppato nell’ambito del progetto GEM del Liceo Scientifico A. Calini. Il suo scopo è estendere le capacità comunicative del robot umanoide NAO, rendendolo uno strumento di supporto per persone con difficoltà uditive (tramite sottotitoli e Lingua dei Segni Italiana), per persone che non conoscono l’italiano (tramite la traduzione simultanea) e per persone non vedenti (tramite la sintesi vocale).
Il server viene avviato come processo Python autonomo, si mette in ascolto su tutte le interfacce di rete alla porta 3000 e rimane attivo fino a interruzione manuale. La pagina radice (`GET /`) serve una dashboard HTML (`nao_test.html`) pensata per il debug manuale degli endpoint durante lo sviluppo.
Architettura generale
Il sistema è costruito attorno alla classe `BaseHTTPRequestHandler` della libreria standard Python, che gestisce le richieste HTTP in ingresso. Le richieste POST vengono smistate verso handler dedicati in base al path, ciascuno dei quali si occupa di una funzionalità specifica. Per le operazioni più pesanti o asincrone — come la traduzione via rete o la manipolazione di flussi multimediali — il server si appoggia rispettivamente ad `asyncio` e a processi `subprocess` separati, evitando di bloccare il thread principale.
La riproduzione dei video finali non avviene direttamente sul server: esiste un servizio ausiliario in ascolto su un secondo host (`192.168.1.30:8000`) che gestisce una libreria di file video. Il server principale interroga questo servizio per sapere quali file sono già disponibili, li trasferisce in formato Base64 se mancanti, e poi gli ordina di riprodurli.
Generazione di video sottotitolati (`/sub`)
Quando il robot NAO deve mostrare un testo accompagnato da sottotitoli visivi, chiama l’endpoint `/sub` passando il testo e la lingua desiderata. Il server avvia una pipeline di montaggio video automatizzata che si articola in più fasi sequenziali.
Per prima cosa il testo viene sintetizzato in un file audio (`speech.wav`) tramite la libreria `pyttsx3`, selezionando automaticamente la voce nella lingua corretta e impostando la velocità di lettura a 160 parole al minuto. Parallelamente, viene estratto un segmento di durata equivalente da un video di sfondo (`background.mp4`), scegliendo casualmente il punto di partenza all’interno dei primi quattro minuti del file. Il segmento estratto viene poi unito all’audio sintetizzato tramite `ffmpeg`, previa conversione dell’audio dal formato WAV al formato AAC per garantire la compatibilità con il container MP4.
Una volta ottenuto il video base (`nosub.mp4`), entra in gioco il force alignment: la libreria `forcealign` analizza l’audio e il testo per associare a ogni singola parola un timestamp preciso di inizio e fine. Questi dati vengono usati da `MoviePy` per generare clip testuali — font FreeSansBold, dimensione 250, colore bianco con bordo nero su risoluzione 3840×2160 — che vengono sovrapposti al video in modo perfettamente sincronizzato con il parlato. Il video finale (`final.mp4`) viene poi inviato al servizio di riproduzione e infine eliminato insieme a tutti i file intermedi.
Interprete di Lingua dei Segni Italiana (`/lis`)
Il modulo LIS è il più articolato del sistema ed è stato progettato per affrontare la mancanza di un database completo di segni. Quando riceve una frase, il server la normalizza (tutto minuscolo, punteggiatura rimossa, apostrofi separati) e filtra le parole grammaticali prive di un segno autonomo: articoli determinativi e indeterminativi, preposizioni semplici e tutte le loro forme articolate.
Per ogni parola significativa rimasta, il sistema segue una gerarchia di risoluzione a più livelli. Il primo controllo è sulla cache locale (`aliases.json`): se la parola — o il suo lemma, ottenuto tramite la libreria `simplemma` — è già presente, viene usato direttamente il file video associato. Se la cache non contiene la voce, il server tenta di scaricare il video corrispondente dal portale SpreadTheSign tramite `yt-dlp`, prima cercando la parola nella sua forma originale e poi nella forma base lemmatizzata. Se anche questo tentativo fallisce, vengono provate varianti morfologiche euristiche: ad esempio, un aggettivo al femminile viene convertito al maschile (sostituendo la desinenza `-a` con `-o`), e i verbi con pronomi clitici vengono ricondotti alla forma infinitiva base (rimuovendo suffissi come `-si`, `-mi`, `-ti` e simili).
Se nessun segno viene trovato con nessuno di questi metodi, il sistema ricorre alla dattilologia d’emergenza: le singole lettere della parola vengono composte in sequenza usando i video dell’alfabeto manuale (`/alphabet/`), e il video risultante viene rallentato a un quarto della velocità originale (0.25x) per favorire la comprensione. Anche i risultati della dattilologia vengono salvati nella cache per evitare di ripetere l’operazione in futuro. Tutta la sequenza di video viene infine inviata al servizio di riproduzione per essere mostrata a schermo.
Sintesi vocale (/speak)
L’endpoint `/speak` accetta un testo e un codice lingua e avvia la sintesi vocale tramite `pyttsx3`. Il server seleziona automaticamente tra le voci installate quella corrispondente alla lingua richiesta (con una gestione particolare per l’inglese, che richiede il codice `en-gb` invece di `en`), imposta la velocità di lettura a 130 parole al minuto e riproduce l’audio localmente.
Riconoscimento vocale (`/reco`)
Per il riconoscimento vocale, il robot invia al server un file audio codificato in Base64. Il server decodifica i byte, li scrive temporaneamente su disco come file WAV, lo processa tramite la libreria `SpeechRecognition` usando le API Google Web Speech, e restituisce la trascrizione testuale come stringa JSON. Il file temporaneo viene eliminato immediatamente dopo l’elaborazione, sia per ragioni di privacy che per mantenere pulito il filesystem.
Traduzione (`/trans`)
La traduzione è gestita in modo asincrono tramite la libreria `googletrans`, che si appoggia alle API di Google Translate. Il server supporta il rilevamento automatico della lingua sorgente e la conversione verso qualsiasi lingua target specificata nella richiesta. L’uso di `asyncio` permette di minimizzare la latenza dell’operazione di rete senza bloccare il server durante l’attesa della risposta.


Lascia un commento