6.7 KiB
6.7 KiB
ETM Telegram Bot — Réécriture Python
Contexte métier
Entreprise ETM-Schurig SARL — installateur RGE (PV, PAC, IRVE, HEMS) en Alsace. Bot Telegram pour les techniciens terrain — remplace les appels téléphoniques.
Stack cible
- python-telegram-bot v20+ (async)
- python-nextcloud ou WebDAV direct (httpx) pour Nextcloud
- Ollama (LLM local) pour FAQ/SAV intelligent — phase 2
- SQLite ou fichier JSON pour la session/état utilisateur
- Déployé sur le VPS Proxmox existant (même infra que n8n)
Credentials
| Paramètre | Valeur |
|---|---|
| Bot Token | 8608752199:AAGZ9Vyop0MVm4msxUyDsUuoNvN1hKM12vc |
| Groupe Chat Chantier | -5208574803 |
| Groupe ETM-Magasinier | -5056192608 |
| Patrick ID | 8022751692 |
| Nextcloud WebDAV | https://cloud.etm-schurig.eu/remote.php/webdav |
| Nextcloud User | Patrick.Schurig |
| Nextcloud Deck API | https://cloud.etm-schurig.eu/index.php/apps/deck/api/v1/ |
Fonctionnalités MVP
3 actions via boutons inline
| Bouton | callback_data | Règles |
|---|---|---|
| 📸 Fin de Chantier | fin |
Photo obligatoire + légende NomClient / Notes |
| ⚠️ Alerte SAV | sav |
Photo optionnelle + NomChantier / Description |
| 📦 Matériel Manquant | materiel |
Texte seul accepté + NomChantier / - item1 - item2 |
Format de saisie universel
NomChantier / description ou liste avec - comme séparateur
Exemples :
Müller / onduleur + batterie posésMüller / - cuivre 28mm - disconnecteur - soupape anti-gel
Chemins Nextcloud
Fin chantier : Chantiers/YYYYMMDD_Client/30_Photos_Chantier/photo_timestamp.jpg
SAV : SAV_Urgent/YYYY-MM-DD_Client/photo.jpg
Matériel : Logistique/Manquants/Client/photo_timestamp.jpg
Notifications
| Action | Destinataire | Contenu |
|---|---|---|
| Fin chantier | Groupe Chat Chantier -5208574803 |
✅ + ouvrier + chantier + chemin Nextcloud + "prépare la facture" |
| SAV | Groupe ETM-SAV (à créer) | 🚨 + ouvrier + chantier + description + photo |
| Matériel | Groupe ETM-Magasinier -5056192608 |
📦 + ouvrier + chantier + liste formatée |
Cartes Nextcloud Deck (phase 1b)
- Tableau : ETM Chantiers
- 3 colonnes :
Fin de Chantier/SAV/Matériel - Créer une carte automatiquement à chaque signalement
Architecture Python recommandée
etm_bot/
├── main.py # Entry point, ConversationHandler
├── config.py # Tokens, IDs, URLs (chargés depuis .env)
├── handlers/
│ ├── menu.py # /start, boutons inline
│ ├── fin_chantier.py # Workflow fin de chantier
│ ├── sav.py # Workflow SAV
│ └── materiel.py # Workflow matériel manquant
├── services/
│ ├── nextcloud.py # Upload WebDAV + Deck API
│ ├── telegram.py # Helpers send_message, notify_group
│ └── llm.py # Ollama FAQ/SAV — phase 2
├── models/
│ └── session.py # État conversation par user_id (dict en mémoire ou SQLite)
└── requirements.txt
États ConversationHandler
MENU = 0
ATTENTE_PHOTO_FIN = 1
ATTENTE_CONTENU_SAV = 2
ATTENTE_CONTENU_MATERIEL = 3
Phase 2 — Wiki/FAQ SAV avec Ollama
Quand un technicien signale un SAV, proposer automatiquement des solutions :
# services/llm.py
async def chercher_solution_sav(description: str) -> str:
# Appel Ollama local (mistral ou llama3)
response = await ollama.chat(
model="mistral",
messages=[{
"role": "system",
"content": "Tu es un expert en installation photovoltaïque, PAC et IRVE. "
"Donne des pistes de diagnostic pour ce problème terrain."
}, {
"role": "user",
"content": description
}]
)
return response["message"]["content"]
Exemples de questions SAV que le LLM doit pouvoir traiter :
- "onduleur Fronius affiche erreur 567"
- "PAC ne démarre plus après coupure EDF"
- "borne IRVE ne charge plus depuis hier"
Prochaine session — ordre de travail
pip install python-telegram-bot httpx python-dotenv+ scaffold du projet- Implémenter
ConversationHandleravec les 3 états - Upload WebDAV sur Nextcloud (tester avec une vraie photo)
- Notifications groupes Telegram
- Cartes Nextcloud Deck
- (optionnel) Intégration Ollama FAQ SAV
⚠️ Priorité n°1 — Gestion albums multi-photos (media_group_id)
Problème
Un technicien envoie 5-8 photos d'un coup (onduleur, batteries, HEMS, tableau, câblage...).
Telegram envoie chaque photo comme un webhook séparé avec le même media_group_id.
Il faut les regrouper avant d'uploader et n'envoyer qu'une seule notification.
Solution Python
# Collecter les photos d'un même album pendant 2 secondes
media_groups = {} # media_group_id → liste de fichiers
async def handle_photo(update, context):
msg = update.message
group_id = msg.media_group_id
if group_id:
# Ajouter à l'album en cours
if group_id not in media_groups:
media_groups[group_id] = {
'photos': [],
'caption': msg.caption or '',
'chat_id': msg.chat_id,
'user': msg.from_user
}
# Déclencher l'upload après 3 secondes (le temps de tout recevoir)
context.job_queue.run_once(
upload_album, 3,
data={'group_id': group_id},
name=group_id
)
media_groups[group_id]['photos'].append(
msg.photo[-1].file_id # Meilleure qualité
)
else:
# Photo seule — uploader directement
await upload_single_photo(msg)
async def upload_album(context):
group_id = context.job.data['group_id']
album = media_groups.pop(group_id, None)
if not album:
return
# Uploader toutes les photos
for i, file_id in enumerate(album['photos']):
file = await context.bot.get_file(file_id)
# Upload WebDAV → Nextcloud/Chantiers/YYYYMMDD_Client/30_Photos_Chantier/photo_01.jpg
await upload_to_nextcloud(file, album['caption'], i + 1)
# Une seule notification
await notify_fin_chantier(album, len(album['photos']))
Notification finale (exemple 6 photos)
✅ Fin de chantier
👷 Patrick Schurig
🏠 Chantier : Müller
📸 6 photos archivées → Nextcloud/Chantiers/20260325_Müller/30_Photos_Chantier/
💶 Tu peux préparer la facture finale.
Nommage des photos sur Nextcloud
30_Photos_Chantier/
├── photo_01_20260325_143201.jpg
├── photo_02_20260325_143202.jpg
├── photo_03_20260325_143203.jpg
...
└── photo_06_20260325_143208.jpg