# Notes de deploiement - OpenSquared PWA Date: 2026-04-26 ## Depot ```text https://gitea.open-squared.tech/admin/openbot.git branche main ``` Commits importants: ```text fb8cc4d Initial PWA assistant proof of concept 94148e8 Rename installed PWA to OpenSquared 1f815fa Version PWA icon asset to refresh Android cache 1b9933d Fix voice button audio unlock hang ``` Derniers changements locaux a deployer: ```text - Service systemd `opensquared-assistant` pour tourner hors session Putty. - Raccourci optionnel `/usr/local/bin/openbot`. - Mode mains libres: `Demarrer` ecoute en continu, envoi apres 2 secondes de silence. - TTS par defaut via voix navigateur `fr-FR` pour eviter l'accent anglais Groq. - Voix navigateur adoucie avec preference pour voix feminine francaise. - Ajout de contacts email par conversation. - Carnet de contacts prod dans `/root/openbot/data/contacts.json`. - Memoire professionnelle SQLite dans `/root/openbot/data/memory.sqlite`. - Cache PWA: opensquared-assistant-v7. ``` ## VPS ```text Serveur: 46.202.173.47 Dossier app: /root/openbot Domaine: bot.open-squared.tech URL: https://bot.open-squared.tech ``` L'app Flask a ete testee sur: ```text http://46.202.173.47:8080/health https://bot.open-squared.tech/health ``` ## Python Sur le VPS, `python3 -m venv .venv` a d'abord echoue car `python3.12-venv` manquait. Correctif: ```bash apt update apt install -y python3.12-venv cd /root/openbot python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## Service systemd Installer ou mettre a jour le service: ```bash cd /root/openbot cp deploy/opensquared-assistant.service /etc/systemd/system/opensquared-assistant.service systemctl daemon-reload systemctl enable --now opensquared-assistant ``` Commandes quotidiennes: ```bash systemctl start opensquared-assistant systemctl stop opensquared-assistant systemctl restart opensquared-assistant systemctl status opensquared-assistant journalctl -u opensquared-assistant -f ``` Raccourci optionnel: ```bash install -m 755 /root/openbot/deploy/openbot /usr/local/bin/openbot openbot start openbot stop openbot restart openbot logs ``` ## HTTPS et Nginx Docker Le VPS utilise deja un `docker-compose.yml` avec un conteneur `nginx`. Montage nginx: ```text /root/tradon/nginx/conf -> /etc/nginx/conf.d /etc/letsencrypt -> /etc/letsencrypt:ro /root/tradon/nginx/certbot -> /var/www/certbot ``` Le bloc HTTP doit servir les challenges avant la redirection: ```nginx location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://$host$request_uri; } ``` Certificat cree avec: ```bash certbot certonly --webroot \ -w /root/tradon/nginx/certbot \ -d bot.open-squared.tech ``` Le bloc HTTPS `bot.open-squared.tech` doit utiliser: ```nginx ssl_certificate /etc/letsencrypt/live/bot.open-squared.tech/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/bot.open-squared.tech/privkey.pem; ``` Proxy depuis nginx Docker vers Flask sur l'hote: ```nginx proxy_pass http://172.17.0.1:8080; ``` Verifier: ```bash docker exec nginx nginx -t docker exec nginx nginx -s reload curl -I https://bot.open-squared.tech/health ``` ## PWA Android Nom installe: ```text OpenSquared ``` Icone: ```text static/icons/icon-v2.svg ``` Pour forcer Android/Chrome a prendre la nouvelle icone: 1. `git pull` sur le VPS. 2. Ouvrir `https://bot.open-squared.tech/icons/icon-v2.svg`. 3. Desinstaller l'ancienne PWA. 4. Reinstaller depuis Chrome. ## Cache et bouton micro Le bouton `Demarrer` etait non reactif sur navigateur parce que `unlockAudio()` pouvait rester bloque sur `audio.play()` avec un audio vide. Correctif applique: - `unlockAudio()` utilise maintenant `AudioContext`. - `index.html` charge `/app.js?v=5`. - Service worker: `opensquared-assistant-v5`. - Le bouton `Demarrer` lance le mode mains libres. - Le message vocal est envoye automatiquement apres 2 secondes de silence. - La voix par defaut est celle du navigateur en `fr-FR`, via `TTS_PROVIDER=browser`. - La version v6 privilegie une voix feminine francaise si disponible sur l'appareil. - Les contacts peuvent etre ajoutes en disant par exemple: `Ajoute Sophie avec l'adresse sophie@example.com`. - Le service systemd definit `CONTACTS_FILE=/root/openbot/data/contacts.json`. - La version v7 ajoute une memoire professionnelle SQLite pour clients, projets, taches, notes et depots Git. - Le service systemd definit `MEMORY_DB=/root/openbot/data/memory.sqlite`. Si le bouton ne reagit pas apres un deploiement: ```text PC: Ctrl+F5 Android: fermer l'app, rouvrir Chrome, ou desinstaller/reinstaller la PWA ``` Si ca persiste, ouvrir F12 -> Console et lire l'erreur JS. ## Fin de session - 2026-04-27 Etat fonctionnel vise: - L'app ne depend plus d'une session Putty ouverte. - `systemd` gere le processus `opensquared-assistant`. - Gunicorn lance `app:app` depuis `/root/openbot`. - Le bouton `Demarrer` active une ecoute mains libres. - Une phrase est transmise automatiquement apres environ 2 secondes de silence. - La reponse est lue avec une voix navigateur francaise, adoucie et preferee feminine si disponible. - Les contacts email peuvent etre ajoutes par conversation. - Les clients, projets, taches, notes et depots Git associes peuvent etre memorises en SQLite. Commits a avoir sur le VPS: ```text f876b3a Add hands-free PWA mode and systemd service 94e14a3 Add soft French voice and contact saving ``` Checklist VPS: ```bash cd /root/openbot git pull cp deploy/opensquared-assistant.service /etc/systemd/system/opensquared-assistant.service systemctl daemon-reload systemctl enable --now opensquared-assistant install -m 755 deploy/openbot /usr/local/bin/openbot openbot restart openbot status ``` Commandes utiles: ```bash openbot start openbot stop openbot restart openbot logs systemctl status opensquared-assistant journalctl -u opensquared-assistant -f ``` Variables importantes: ```text TTS_PROVIDER=browser CONTACTS_FILE=/root/openbot/data/contacts.json MEMORY_DB=/root/openbot/data/memory.sqlite ``` Exemples vocaux: ```text Ajoute Sophie avec l'adresse sophie@example.com Envoie un email a Sophie SAFTCO est un nouveau client, note quelque part que je dois rappeler le directeur Associe le repo /root/openbot/repos/saftco au projet Portail SAFTCO Qu'est-ce que tu sais sur SAFTCO ? ``` Attention cache mobile: - `index.html` charge `/app.js?v=7`. - Service worker: `opensquared-assistant-v7`. - Si Android garde l'ancien JS, fermer/rouvrir Chrome ou reinstaller la PWA. ## Session memoire professionnelle et routeur SQL - 2026-04-27 Objectif: - Construire une memoire professionnelle utilisable par l'assistant vocal. - Stocker clients, projets, taches, notes et repos associes. - Permettre des questions naturelles du type: - `Quels sont mes clients ?` - `Que dois-je faire pour ICT ?` - `Pour quel client ai-je le plus de taches ?` - `Note que pour FAIRCOT je dois tester le lien vers le PDF.` Problemes observes pendant les tests: - Les premieres versions etaient trop basees sur des regex et des actions en dur. - Les formulations vocales variables, les typos et les phrases de suivi rendaient cette approche fragile. - Exemple: `note le comme une tache pour FAIRCOT` devait comprendre que `le` faisait reference au message precedent, pas a une regle specifique. - Les actions de lecture specialisees se multipliaient trop vite: liste clients, liste taches, taches par client, client avec le plus de taches, etc. - Risque identifie: creer une action rigide pour chaque question probable au lieu de laisser le modele raisonner sur le schema. Architecture retenue: - SQLite reste le stockage principal. - Le modele recoit: - le schema de la base, - un extrait de memoire actuelle, - l'historique recent de conversation, - le dernier message utilisateur. - Un routeur LLM decide entre trois sorties: - `action`: ecriture controlee, par exemple ajouter client, ajouter tache, terminer tache, ajouter repo. - `interroger_base`: lecture SQL readonly generee par le modele. - `clarification`: question a Laurent si la cible ou l'intention est ambigue. - Les lectures globales ne doivent plus devenir une explosion d'actions codees en dur. - Pour une question analytique, le modele genere un `SELECT`, puis l'app execute uniquement ce SQL en lecture seule. Pourquoi ce choix: - Les questions metier sont ouvertes et evoluent vite. - Le modele est meilleur pour mapper une demande naturelle vers une intention ou une requete SQL que des regex fragiles. - Le dernier message reste prioritaire, mais le modele doit raisonner avec l'historique recent pour comprendre `lui`, `le`, `cette tache`, `ce client`. - Les ecritures restent controlees par une liste d'actions permises afin d'eviter qu'un SQL genere ne modifie la base. - Les lectures sont flexibles via SQL readonly, mais protegees par validation. Securite SQL readonly: - `memory.execute_read_query()` accepte uniquement une seule requete `SELECT`. - Les points-virgules, commentaires SQL, `PRAGMA`, `INSERT`, `UPDATE`, `DELETE`, `DROP`, etc. sont rejetes. - SQLite `set_authorizer` bloque les operations non autorisees. - Les tables lisibles sont limitees a: - `clients` - `projects` - `tasks` - `repositories` - `memories` - Le resultat est limite pour eviter les sorties trop longues. Corrections importantes de la session: - Le routeur utilise maintenant davantage d'historique recent pour les phrases de suivi. - Le prompt de secours ne demande plus au modele de produire du JSON d'action; cela evite de concurrencer le routeur. - Les anciennes fonctions regex sont considerees comme heritage/code mort si elles ne sont plus appelees. - Correction du bug `"'id'"` en rouge: - cause: des lignes SQL de synthese etaient stockees dans le contexte comme si elles etaient toujours des taches completes avec `id` et `title`; - fix: le contexte n'assume plus que chaque ligne possede ces champs. Decision importante: - Ne pas ajouter de micro-regles specifiques comme `pending_note` pour chaque cas de suivi. - Preferer un routeur LLM qui evalue l'intention avec toute la conversation recente. - Si le modele doute, il doit demander une precision plutot que choisir une action au hasard. Limite actuelle: - La qualite depend beaucoup du modele Groq utilise pour le routage. - Si les references implicites continuent a echouer, tester un modele plus fort ou separer en deux appels: - appel 1: comprendre l'intention et la cible avec l'historique; - appel 2: generer l'action ou le SQL readonly. Etat mental a garder pour la suite: - Pour les ecritures: actions explicites, schema stable, confirmation si doute. - Pour les lectures: SQL readonly genere par le modele. - Pour les phrases ambigues: clarification utilisateur. - Eviter de transformer chaque bug conversationnel en regex supplementaire.