gmao/app_new/templates/admin/settings.html

201 lines
8.6 KiB
HTML
Raw Normal View History

2026-08-14 18:02:25 +02:00
{% extends "base.html" %}
{% block title %}Paramètres - Administration{% endblock %}
{% block content %}
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1><i class="bi bi-gear"></i> Paramètres de l'application</h1>
<p class="text-muted">Configuration des intégrations et services</p>
</div>
<a href="{{ url_for('admin.index') }}" class="btn btn-outline-secondary">
<i class="bi bi-arrow-left"></i> Retour
</a>
</div>
<div class="row">
<div class="col-lg-6 mb-4">
<div class="card h-100"><div class="card-header"><h5 class="mb-0"><i class="bi bi-shield-lock"></i> API REST GMAO</h5></div><div class="card-body">
<p class="text-muted small">La clé donne un accès en lecture à lAPI. Elle nest jamais conservée en clair et ne sera affichée quune fois.</p>
<form method="post" action="{{ url_for('admin.generate_api_key') }}" class="d-inline"><button class="btn btn-primary" type="submit"><i class="bi bi-arrow-repeat"></i> Générer ou renouveler</button></form>
<form method="post" action="{{ url_for('admin.revoke_api_key') }}" class="d-inline"><button class="btn btn-outline-danger" type="submit"><i class="bi bi-x-circle"></i> Révoquer</button></form>
</div></div>
</div>
2026-08-14 18:02:25 +02:00
<!-- Section OpenRouter -->
<div class="col-lg-6 mb-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="bi bi-key"></i> OpenRouter API
</h5>
</div>
<div class="card-body">
<p class="text-muted small mb-3">
La clé API OpenRouter est utilisée pour l'interprétation des emails par l'IA.
Obtenez votre clé sur <a href="https://openrouter.ai/keys" target="_blank">openrouter.ai/keys</a>
</p>
<form id="openrouter-form">
<div class="mb-3">
<label for="openrouter-key" class="form-label">Clé API OpenRouter</label>
<div class="input-group">
<input type="password" class="form-control" id="openrouter-key"
placeholder="sk-or-v1-..."
value="{{ openrouter_key or '' }}">
<button class="btn btn-outline-secondary" type="button" onclick="toggleKeyVisibility()">
<i class="bi bi-eye" id="eye-icon"></i>
</button>
</div>
<div class="form-text">
{% if openrouter_key %}
<span class="text-success"><i class="bi bi-check-circle"></i> Clé configurée ({{ openrouter_key[:10] }}...{{ openrouter_key[-4:] }})</span>
{% else %}
<span class="text-warning"><i class="bi bi-exclamation-triangle"></i> Aucune clé configurée</span>
{% endif %}
</div>
</div>
<button type="submit" class="btn btn-primary">
<i class="bi bi-save"></i> Sauvegarder
</button>
<button type="button" class="btn btn-outline-secondary ms-2" onclick="testApiKey()">
<i class="bi bi-play"></i> Tester
</button>
</form>
<div id="test-result" class="mt-3" style="display:none;"></div>
</div>
</div>
</div>
<!-- Section Modèle IA -->
<div class="col-lg-6 mb-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0">
<i class="bi bi-cpu"></i> Modèle IA
</h5>
</div>
<div class="card-body">
<p class="text-muted small mb-3">
Modèle utilisé pour l'interprétation des emails GMAO.
</p>
<div class="mb-3">
<label class="form-label">Modèle actuel</label>
<input type="text" class="form-control" value="poolside/laguna-m.1:free" readonly>
<div class="form-text">
<span class="text-success"><i class="bi bi-check-circle"></i> Modèle gratuit et rapide</span>
</div>
</div>
<div class="alert alert-info small">
<i class="bi bi-info-circle"></i>
<strong>Modèles recommandés:</strong>
<ul class="mb-0 mt-1">
<li><code>poolside/laguna-m.1:free</code> - Gratuit, rapide</li>
<li><code>openrouter/optimus-alpha</code> - Plus puissant</li>
<li><code>anthropic/claude-3-haiku</code> - Haute qualité</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Section Contexte GMAO -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">
<i class="bi bi-building"></i> Contexte GMAO
</h5>
</div>
<div class="card-body">
<p class="text-muted">
Le contexte GMAO est utilisé par l'IA pour mieux interpréter les emails.
Il contient des informations sur votre établissement, équipements, procédures, etc.
</p>
<a href="{{ url_for('outlook_dashboard.context_config') }}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Configurer le contexte GMAO
</a>
</div>
</div>
</div>
<script>
function toggleKeyVisibility() {
const input = document.getElementById('openrouter-key');
const icon = document.getElementById('eye-icon');
if (input.type === 'password') {
input.type = 'text';
icon.classList.remove('bi-eye');
icon.classList.add('bi-eye-slash');
} else {
input.type = 'password';
icon.classList.remove('bi-eye-slash');
icon.classList.add('bi-eye');
}
}
document.getElementById('openrouter-form').addEventListener('submit', function(e) {
e.preventDefault();
const key = document.getElementById('openrouter-key').value;
const btn = e.target.querySelector('button[type="submit"]');
const originalText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Sauvegarde...';
fetch('/admin/settings/openrouter', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({api_key: key})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Erreur: ' + data.error);
}
})
.catch(error => {
alert('Erreur: ' + error.message);
})
.finally(() => {
btn.disabled = false;
btn.innerHTML = originalText;
});
});
function testApiKey() {
const key = document.getElementById('openrouter-key').value;
if (!key) {
alert('Entrez une clé API');
return;
}
const resultDiv = document.getElementById('test-result');
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<div class="alert alert-info"><i class="bi bi-hourglass-split"></i> Test en cours...</div>';
fetch('https://openrouter.ai/api/v1/models', {
headers: {'Authorization': 'Bearer ' + key}
})
.then(response => {
if (response.ok) {
resultDiv.innerHTML = '<div class="alert alert-success"><i class="bi bi-check-circle"></i> Clé API valide !</div>';
} else {
resultDiv.innerHTML = '<div class="alert alert-danger"><i class="bi bi-x-circle"></i> Clé API invalide</div>';
}
})
.catch(error => {
resultDiv.innerHTML = '<div class="alert alert-danger"><i class="bi bi-x-circle"></i> Erreur: ' + error.message + '</div>';
});
}
</script>
{% endblock %}