Update static/index.html
Browse files- static/index.html +96 -8
static/index.html
CHANGED
|
@@ -58,6 +58,13 @@
|
|
| 58 |
<div style="margin-bottom: 20px;">
|
| 59 |
<label for="apiKey" style="display: block; margin-bottom: 5px; font-weight: bold;">Clé API :</label>
|
| 60 |
<input type="password" id="apiKey" placeholder="Entrez votre clé API..." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
<small style="color: #666; font-size: 12px;">La clé est stockée uniquement dans votre navigateur pour cette session.</small>
|
| 62 |
</div>
|
| 63 |
|
|
@@ -120,7 +127,74 @@
|
|
| 120 |
throw error;
|
| 121 |
}
|
| 122 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 124 |
function connect() {
|
| 125 |
// Adapte le protocole (ws ou wss pour le sécurisé)
|
| 126 |
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
@@ -135,13 +209,27 @@
|
|
| 135 |
|
| 136 |
ws.onmessage = async function(event) {
|
| 137 |
try {
|
| 138 |
-
|
| 139 |
-
const prompt = messageData.prompt;
|
| 140 |
-
const model = messageData.model;
|
| 141 |
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
const responsePhrase = await callOpenAI(prompt, model);
|
| 146 |
|
| 147 |
// Vérifier à nouveau que la connexion est ouverte
|
|
@@ -152,9 +240,9 @@
|
|
| 152 |
addLog('Erreur: WebSocket fermé pendant l\'appel API');
|
| 153 |
}
|
| 154 |
|
| 155 |
-
} catch (
|
| 156 |
-
console.error('Erreur
|
| 157 |
-
addLog(`Erreur
|
| 158 |
}
|
| 159 |
};
|
| 160 |
|
|
|
|
| 58 |
<div style="margin-bottom: 20px;">
|
| 59 |
<label for="apiKey" style="display: block; margin-bottom: 5px; font-weight: bold;">Clé API :</label>
|
| 60 |
<input type="password" id="apiKey" placeholder="Entrez votre clé API..." style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
| 61 |
+
<div style="margin-bottom: 20px;">
|
| 62 |
+
<label for="defaultModel" style="display: block; margin-bottom: 5px; font-weight: bold;">Modèle par défaut :</label>
|
| 63 |
+
<select id="defaultModel" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px;">
|
| 64 |
+
<option value="">Chargement des modèles...</option>
|
| 65 |
+
</select>
|
| 66 |
+
<small style="color: #666; font-size: 12px;">Modèle utilisé si non spécifié par Python.</small>
|
| 67 |
+
</div>
|
| 68 |
<small style="color: #666; font-size: 12px;">La clé est stockée uniquement dans votre navigateur pour cette session.</small>
|
| 69 |
</div>
|
| 70 |
|
|
|
|
| 127 |
throw error;
|
| 128 |
}
|
| 129 |
}
|
| 130 |
+
// Fonction pour récupérer la liste des modèles
|
| 131 |
+
async function loadAvailableModels() {
|
| 132 |
+
const apiKey = document.getElementById('apiKey').value.trim();
|
| 133 |
+
const modelSelect = document.getElementById('defaultModel');
|
| 134 |
+
|
| 135 |
+
if (!apiKey) {
|
| 136 |
+
modelSelect.innerHTML = '<option value="gemini-2.5-pro">gemini-2.5-pro (défaut)</option>';
|
| 137 |
+
addLog('Saisissez votre clé API pour charger les modèles disponibles');
|
| 138 |
+
return;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
try {
|
| 142 |
+
addLog('Chargement des modèles disponibles...');
|
| 143 |
+
const response = await fetch('https://llm.synapse.thalescloud.io/v1/models', {
|
| 144 |
+
method: 'GET',
|
| 145 |
+
headers: {
|
| 146 |
+
'Authorization': `Bearer ${apiKey}`
|
| 147 |
+
}
|
| 148 |
+
});
|
| 149 |
+
|
| 150 |
+
if (!response.ok) {
|
| 151 |
+
throw new Error(`Erreur API: ${response.status}`);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
const data = await response.json();
|
| 155 |
+
|
| 156 |
+
// Vider le select et ajouter les options
|
| 157 |
+
modelSelect.innerHTML = '';
|
| 158 |
+
|
| 159 |
+
if (data.data && Array.isArray(data.data)) {
|
| 160 |
+
data.data.forEach(model => {
|
| 161 |
+
const option = document.createElement('option');
|
| 162 |
+
option.value = model.id;
|
| 163 |
+
option.textContent = model.id;
|
| 164 |
+
if (model.id === 'gemini-2.5-pro') {
|
| 165 |
+
option.selected = true; // Sélectionner par défaut
|
| 166 |
+
}
|
| 167 |
+
modelSelect.appendChild(option);
|
| 168 |
+
});
|
| 169 |
+
addLog(`${data.data.length} modèles chargés`);
|
| 170 |
+
} else {
|
| 171 |
+
// Fallback si la structure de réponse est différente
|
| 172 |
+
modelSelect.innerHTML = '<option value="gemini-2.5-pro" selected>gemini-2.5-pro (défaut)</option>';
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
} catch (error) {
|
| 176 |
+
console.error('Erreur lors du chargement des modèles:', error);
|
| 177 |
+
addLog(`Erreur chargement modèles: ${error.message}`);
|
| 178 |
+
// Ajouter une option par défaut en cas d'erreur
|
| 179 |
+
modelSelect.innerHTML = '<option value="gemini-2.5-pro" selected>gemini-2.5-pro (défaut)</option>';
|
| 180 |
+
}
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
// Écouter les changements sur le champ API Key pour recharger les modèles
|
| 184 |
+
document.getElementById('apiKey').addEventListener('input', debounce(loadAvailableModels, 1000));
|
| 185 |
|
| 186 |
+
// Fonction debounce pour éviter trop d'appels
|
| 187 |
+
function debounce(func, wait) {
|
| 188 |
+
let timeout;
|
| 189 |
+
return function executedFunction(...args) {
|
| 190 |
+
const later = () => {
|
| 191 |
+
clearTimeout(timeout);
|
| 192 |
+
func(...args);
|
| 193 |
+
};
|
| 194 |
+
clearTimeout(timeout);
|
| 195 |
+
timeout = setTimeout(later, wait);
|
| 196 |
+
};
|
| 197 |
+
}
|
| 198 |
function connect() {
|
| 199 |
// Adapte le protocole (ws ou wss pour le sécurisé)
|
| 200 |
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
|
|
| 209 |
|
| 210 |
ws.onmessage = async function(event) {
|
| 211 |
try {
|
| 212 |
+
let prompt, model;
|
|
|
|
|
|
|
| 213 |
|
| 214 |
+
// Essayer de parser comme JSON (nouveau format)
|
| 215 |
+
try {
|
| 216 |
+
const messageData = JSON.parse(event.data);
|
| 217 |
+
prompt = messageData.prompt;
|
| 218 |
+
model = messageData.model;
|
| 219 |
+
} catch (parseError) {
|
| 220 |
+
// Si ce n'est pas du JSON, traiter comme ancien format (string simple)
|
| 221 |
+
prompt = event.data;
|
| 222 |
+
model = null;
|
| 223 |
+
}
|
| 224 |
|
| 225 |
+
// Si aucun modèle spécifié, utiliser celui sélectionné dans l'UI
|
| 226 |
+
if (!model) {
|
| 227 |
+
model = document.getElementById('defaultModel').value || 'gemini-2.5-pro';
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
console.log(`Message reçu - Prompt: "${prompt}", Modèle: "${model}"`);
|
| 231 |
+
addLog(`Message reçu - Prompt: "${prompt}", Modèle: "${model}"`);
|
| 232 |
+
|
| 233 |
const responsePhrase = await callOpenAI(prompt, model);
|
| 234 |
|
| 235 |
// Vérifier à nouveau que la connexion est ouverte
|
|
|
|
| 240 |
addLog('Erreur: WebSocket fermé pendant l\'appel API');
|
| 241 |
}
|
| 242 |
|
| 243 |
+
} catch (error) {
|
| 244 |
+
console.error('Erreur traitement message:', error);
|
| 245 |
+
addLog(`Erreur traitement message: ${error.message}`);
|
| 246 |
}
|
| 247 |
};
|
| 248 |
|