gmao/app_new/templates/outlook/context_config.html
2026-08-14 16:02:25 +00:00

460 lines
No EOL
21 KiB
HTML

{% extends "base.html" %}
{% block title %}Contexte GMAO - Configuration{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="row mb-4">
<div class="col">
<h1>🧠 Contexte GMAO pour Hermes</h1>
<p class="text-muted">Configurez le contexte qui sera utilisé par Hermes pour interpréter chaque email</p>
</div>
<div class="col-auto">
<a href="{{ url_for('outlook_dashboard.auto_interpret_page') }}" class="btn btn-primary">
<i class="fas fa-robot"></i> Interprétation automatique
</a>
</div>
</div>
<!-- Aperçu du contexte -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="mb-0">📋 Aperçu du contexte actuel</h5>
<button class="btn btn-sm btn-outline-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#contextPreview">
Afficher/Masquer
</button>
</div>
<div class="collapse show" id="contextPreview">
<div class="card-body">
<pre id="fullContextPreview" class="bg-light p-3 rounded" style="white-space: pre-wrap; max-height: 200px; overflow-y: auto;">Chargement...</pre>
</div>
</div>
</div>
</div>
</div>
<!-- Prompt injecté -->
<div class="row mb-4">
<div class="col-12">
<div class="card border-info">
<div class="card-header bg-info text-white d-flex justify-content-between align-items-center">
<h5 class="mb-0">🤖 Prompt injecté à Hermes</h5>
<button class="btn btn-sm btn-outline-light" type="button" data-bs-toggle="collapse" data-bs-target="#promptPreview">
Afficher/Masquer
</button>
</div>
<div class="collapse" id="promptPreview">
<div class="card-body">
<p class="text-muted small mb-2">Ce prompt est envoyé à Hermes avec chaque email analysé. La première partie est fixe, le contexte GMAO est configurable ci-dessous.</p>
<p class="text-info small mb-2"><i class="fas fa-paperclip"></i> Les pièces jointes PDF sont automatiquement extraites et ajoutées au contenu avec <code>[CONTENU PDF]:</code></p>
<pre id="promptFullPreview" class="bg-dark text-light p-3 rounded" style="white-space: pre-wrap; max-height: 400px; overflow-y: auto; font-size: 12px;">Chargement...</pre>
</div>
</div>
</div>
</div>
</div>
<!-- Formulaire de configuration -->
<form id="contextForm">
<div class="row">
<!-- Colonne gauche: Informations établissement -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-primary text-white">
<h5 class="mb-0"><i class="fas fa-building"></i> Établissement</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="establishment_name" class="form-label">Nom de l'établissement</label>
<input type="text" class="form-control" id="establishment_name" name="establishment_name"
placeholder="Ex: Collège Jean Jaurès">
<div class="form-text">Le nom complet de votre collège</div>
</div>
<div class="mb-3">
<label for="establishment_type" class="form-label">Type d'établissement</label>
<select class="form-select" id="establishment_type" name="establishment_type">
<option value="">-- Sélectionner --</option>
<option value="Collège public">Collège public</option>
<option value="Collège privé">Collège privé</option>
<option value="Lycée public">Lycée public</option>
<option value="Lycée privé">Lycée privé</option>
<option value="École primaire">École primaire</option>
<option value="Autre">Autre</option>
</select>
</div>
<div class="mb-3">
<label for="address" class="form-label">Adresse complète</label>
<textarea class="form-control" id="address" name="address" rows="2"
placeholder="Ex: 15 rue de la République, 77000 Melun"></textarea>
</div>
</div>
</div>
</div>
<!-- Colonne droite: Contacts -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-info text-white">
<h5 class="mb-0"><i class="fas fa-address-book"></i> Contacts utiles</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="contact_info" class="form-label">Contacts et entreprises</label>
<textarea class="form-control" id="contact_info" name="contact_info" rows="6"
placeholder="Listez les contacts importants:
- Entreprise de chauffage: ABC Chauffage, Tél: 01 60 00 00 00
- Électricien: Jean Dupont, Tél: 06 00 00 00 00
- Mairie: Service technique, Tél: 01 60 00 00 01"></textarea>
<div class="form-text">Contacts des entreprises et prestataires</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Contexte technique -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-secondary text-white">
<h5 class="mb-0"><i class="fas fa-cogs"></i> Contexte technique</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="technical_context" class="form-label">Informations techniques</label>
<textarea class="form-control" id="technical_context" name="technical_context" rows="5"
placeholder="Décrivez les bâtiments, surfaces, installations:
Ex: Le collège compte 3 bâtiments:
- Bâtiment A (principal): 2500m², 2 étages
- Bâtiment B (technologie): 800m²
- Bâtiment C (gymnase): 1200m²
Chauffage: gaz, chaudière Viessmann de 2015
VMC: centrale avec récupération de chaleur"></textarea>
<div class="form-text">Description des bâtiments, installations, surfaces</div>
</div>
</div>
</div>
</div>
<!-- Équipements -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-warning">
<h5 class="mb-0"><i class="fas fa-tools"></i> Équipements principaux</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="equipment_context" class="form-label">Liste des équipements</label>
<textarea class="form-control" id="equipment_context" name="equipment_context" rows="5"
placeholder="Listez les équipements principaux:
Ex:
- Chaudière Viessmann Vitodens 200 (2015) - Bâtiment A
- VMC Aldes 800 m³/h - Bâtiment A
- Ascenseur ThyssenKrupp (2010) - Bâtiment A
- Portail automatique Nice - Entrée principale
- Climatiseur réversible Daikin (2020) - Bâtiment administration"></textarea>
<div class="form-text">Équipements à surveiller et maintenir</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Procédures -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-danger text-white">
<h5 class="mb-0"><i class="fas fa-clipboard-list"></i> Procédures</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="procedure_context" class="form-label">Procédures spécifiques</label>
<textarea class="form-control" id="procedure_context" name="procedure_context" rows="5"
placeholder="Décrivez les procédures spécifiques:
Ex:
- Urgence chauffage: contacter ABC Chauffage au 01 60 00 00 00 (24h/24)
- Fuite d'eau: couper l'arrivée générale (vanne dans le local technique A)
- Alarme incendie: appeler les pompiers puis la direction
- Intervention externe: créer une demande via GMAO avant intervention"></textarea>
<div class="form-text">Procédures d'urgence et protocoles</div>
</div>
</div>
</div>
</div>
<!-- Personnel -->
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-header bg-success text-white">
<h5 class="mb-0"><i class="fas fa-users"></i> Personnel</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="staff_info" class="form-label">Informations sur le personnel</label>
<textarea class="form-control" id="staff_info" name="staff_info" rows="5"
placeholder="Décrivez le personnel:
Ex:
- Éric (chef): Responsable maintenance
- Alban (technicien): Interventions quotidiennes, PRONOTE, téléphonie
- Martine (secrétariat): Demandes d'intervention, commandes
L'équipe technique compte 2 agents polyvalents."></textarea>
<div class="form-text">Rôles et responsabilités de l'équipe</div>
</div>
</div>
</div>
</div>
</div>
<!-- Instructions Hermes -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header bg-dark text-white">
<h5 class="mb-0"><i class="fas fa-robot"></i> Instructions personnalisées pour Hermes</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label for="hermes_instructions" class="form-label">Instructions spécifiques</label>
<textarea class="form-control" id="hermes_instructions" name="hermes_instructions" rows="4"
placeholder="Instructions personnalisées pour l'IA Hermes:
Ex:
- Toujours formuler les réponses en français
- Classer les demandes par ordre de priorité
- Proposer des interventions dans la GMAO quand c'est pertinent
- Mentionner les contacts appropriés pour chaque type de problème
- Indiquer si une intervention urgente est nécessaire"></textarea>
<div class="form-text">Instructions spécifiques pour orienter les réponses de Hermes</div>
</div>
</div>
</div>
</div>
</div>
<!-- Expéditeurs exclus -->
<div class="row mb-4">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="fas fa-ban"></i> Expéditeurs exclus</h5>
</div>
<div class="card-body">
<div class="mb-3">
<label class="form-label">Emails à exclure de l'interprétation</label>
<textarea id="excluded_senders" class="form-control" rows="4"
placeholder="newsletter@exemple.com
publicite@entreprise.fr
noreply@service.fr
Un email par ligne - ces expéditeurs seront ignorés lors de l'analyse"></textarea>
<div class="form-text">Ces expéditeurs seront ignorés lors de l'analyse automatique des emails (newsletters, publicités, notifications système, etc.)</div>
</div>
</div>
</div>
</div>
</div>
<!-- Boutons d'action -->
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between">
<button type="button" class="btn btn-outline-secondary" onclick="resetForm()">
<i class="fas fa-undo"></i> Réinitialiser
</button>
<button type="submit" class="btn btn-success btn-lg">
<i class="fas fa-save"></i> Sauvegarder le contexte
</button>
</div>
</div>
</div>
</form>
</div>
<!-- Toast pour les notifications -->
<div class="toast-container position-fixed bottom-0 end-0 p-3">
<div id="saveToast" class="toast" role="alert">
<div class="toast-header">
<strong class="me-auto">Contexte GMAO</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
</div>
<div class="toast-body" id="toastMessage">
Sauvegardé avec succès
</div>
</div>
</div>
<script>
// Charger le contexte existant
document.addEventListener('DOMContentLoaded', function() {
loadContext();
});
function loadContext() {
fetch('/outlook/api/context')
.then(response => response.json())
.then(data => {
// Remplir le formulaire
document.getElementById('establishment_name').value = data.establishment_name || '';
document.getElementById('establishment_type').value = data.establishment_type || '';
document.getElementById('address').value = data.address || '';
document.getElementById('technical_context').value = data.technical_context || '';
document.getElementById('equipment_context').value = data.equipment_context || '';
document.getElementById('procedure_context').value = data.procedure_context || '';
document.getElementById('staff_info').value = data.staff_info || '';
document.getElementById('contact_info').value = data.contact_info || '';
document.getElementById('hermes_instructions').value = data.hermes_instructions || '';
document.getElementById('excluded_senders').value = data.excluded_senders || '';
// Afficher l'aperçu
updatePreview(data.full_context);
})
.catch(error => {
console.error('Erreur chargement contexte:', error);
});
}
function updatePreview(context) {
const preview = document.getElementById('fullContextPreview');
if (context && context.trim()) {
preview.textContent = context;
} else {
preview.textContent = 'Aucun contexte configuré. Remplissez le formulaire ci-dessous pour définir le contexte utilisé par Hermes.';
preview.classList.add('text-muted');
}
// Afficher le prompt complet
updatePromptPreview(context);
}
function updatePromptPreview(gmaoContext) {
const promptPreview = document.getElementById('promptFullPreview');
// Prompt système fixe
const systemPrompt = `Tu es un assistant pour la GMAO (Gestion de Maintenance Assistée par Ordinaire) d'un établissement scolaire.
Analyse cet email et EXTRAIS les informations pour créer une ou plusieurs interventions/tâches.
IMPORTANT: Tu DOIS répondre UNIQUEMENT avec un JSON valide, sans texte avant ni après.
Types possibles:
- "curative": Panne, problème, réparation nécessaire (ex: fuite, équipement cassé)
- "preventive": Maintenance planifiée, contrôle périodique (ex: inspection, entretien)
- "administrative": Tâche administrative à effectuer (ex: déposer des documents, remplir un formulaire, rappel)
- "formation": Formation à suivre, session de formation (ex: formation sécurité, recyclage)
- "information": Information simple, pas d'action requise
Actions possibles:
- "create": Créer une nouvelle intervention/tâche
- "update": Mettre à jour une intervention existante
- "inform": Juste informer, pas d'action
ATTENTION: Un email peut contenir PLUSIEURS tâches différentes (ex: plusieurs dates, plusieurs actions).
Dans ce cas, crée une entrée pour chaque tâche identifiée.
Format de réponse obligatoire:
{
"analyses": [
{
"type": "curative|preventive|administrative|formation|information",
"action": "create|update|inform",
"confidence": 0.0-1.0,
"intervention": {
"titre": "Titre court et descriptif",
"description": "Description détaillée du problème ou de la tâche",
"urgence": "basse|normale|haute|urgente",
"lieu": "Localisation précise (bâtiment, salle, étage...)",
"equipement": "Équipement concerné si applicable",
"intervenant_suggere": "Type d'intervenant suggéré (plombier, électricien, etc.)",
"date_intervention": "YYYY-MM-DD ou null si non spécifiée"
},
"date_suggestion": "YYYY-MM-DD ou null",
"resume_court": "Résumé en une phrase"
}
],
"nb_taches": 1,
"resume_global": "Résumé de l'email en une phrase"
}`;
let fullPrompt = systemPrompt;
if (gmaoContext && gmaoContext.trim()) {
fullPrompt += '\n\n=== CONTEXTE GMAO DE L\'ÉTABLISSEMENT ===\n' + gmaoContext + '\n=== FIN DU CONTEXTE ===';
}
fullPrompt += '\n\n=== EMAIL À ANALYSER ===\n[Sujet: ...]\n[Corps: ...]\n\n=== PIÈCES JOINTES ===\n[PDF: document.pdf]\n[CONTENU PDF]:\nTexte extrait du PDF automatiquement...\n=== FIN DES PIÈCES JOINTES ===\n=== FIN DE L\'EMAIL ===\n\nFournis ton analyse:';
promptPreview.textContent = fullPrompt;
}
// Soumission du formulaire
document.getElementById('contextForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = {
establishment_name: document.getElementById('establishment_name').value,
establishment_type: document.getElementById('establishment_type').value,
address: document.getElementById('address').value,
technical_context: document.getElementById('technical_context').value,
equipment_context: document.getElementById('equipment_context').value,
procedure_context: document.getElementById('procedure_context').value,
staff_info: document.getElementById('staff_info').value,
contact_info: document.getElementById('contact_info').value,
hermes_instructions: document.getElementById('hermes_instructions').value,
excluded_senders: document.getElementById('excluded_senders').value
};
fetch('/outlook/api/context', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(formData)
})
.then(response => response.json())
.then(data => {
if (data.success) {
showToast(data.message, 'success');
updatePreview(data.full_context);
} else {
showToast(data.error || 'Erreur lors de la sauvegarde', 'danger');
}
})
.catch(error => {
showToast('Erreur de communication', 'danger');
console.error('Erreur:', error);
});
});
function resetForm() {
if (confirm('Réinitialiser le formulaire ? Les données non sauvegardées seront perdues.')) {
loadContext();
}
}
function showToast(message, type) {
const toast = document.getElementById('saveToast');
const toastBody = document.getElementById('toastMessage');
toastBody.textContent = message;
toast.classList.remove('bg-success', 'bg-danger', 'text-white');
if (type === 'success') {
toast.classList.add('bg-success', 'text-white');
} else if (type === 'danger') {
toast.classList.add('bg-danger', 'text-white');
}
const bsToast = new bootstrap.Toast(toast);
bsToast.show();
}
</script>
{% endblock %}