Spaces:
Running
Running
Upload index.html
Browse files- static/index.html +33 -7
static/index.html
CHANGED
|
@@ -140,6 +140,7 @@
|
|
| 140 |
.typing-indicator span { display: inline-block; animation: blink 1.4s infinite both; font-size: 1.5rem; line-height: 1; margin: 0 2px;}
|
| 141 |
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
| 142 |
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
|
|
|
| 143 |
@keyframes blink { 0% { opacity: 0.2; transform: scale(0.8); } 20% { opacity: 1; transform: scale(1.2); } 100% { opacity: 0.2; transform: scale(0.8); } }
|
| 144 |
|
| 145 |
/* Modals & Toggles */
|
|
@@ -315,8 +316,8 @@
|
|
| 315 |
|
| 316 |
<div class="toggle-group">
|
| 317 |
<div>
|
| 318 |
-
<strong>Recherche Web</strong>
|
| 319 |
-
<div style="font-size: 0.8rem; color: #a6adc8;">
|
| 320 |
</div>
|
| 321 |
<label class="switch"><input type="checkbox" id="toggleWebSearch"><span class="slider"></span></label>
|
| 322 |
</div>
|
|
@@ -603,6 +604,16 @@
|
|
| 603 |
if (m.isThinking && fullText) m.isThinking = false;
|
| 604 |
this.updateMessageDOM(aiIndex);
|
| 605 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 606 |
finishSmoothStream(aiIndex) {
|
| 607 |
const s = this._smoothStreams[aiIndex];
|
| 608 |
const chat = this.getActiveChat();
|
|
@@ -1058,7 +1069,9 @@
|
|
| 1058 |
let contentHTML = '';
|
| 1059 |
|
| 1060 |
if (m.isThinking) {
|
| 1061 |
-
contentHTML =
|
|
|
|
|
|
|
| 1062 |
} else if (m.isImageGenerated) {
|
| 1063 |
contentHTML = `<div class="img-gen-wrapper" style="min-height: auto; max-width: 350px;">
|
| 1064 |
<img src="${m.content}" class="loaded" style="max-width: 100%; border-radius: 8px;" alt="Image Générée">
|
|
@@ -1156,7 +1169,9 @@
|
|
| 1156 |
|
| 1157 |
const bodyEl = wrapper.querySelector('.message');
|
| 1158 |
if (m.isThinking) {
|
| 1159 |
-
bodyEl.innerHTML =
|
|
|
|
|
|
|
| 1160 |
} else if (m.isImageGenerated) {
|
| 1161 |
bodyEl.innerHTML = `<div class="img-gen-wrapper" style="min-height: auto; max-width: 350px;">
|
| 1162 |
<img src="${m.content}" class="loaded" style="max-width: 100%; border-radius: 8px;" alt="Image Générée">
|
|
@@ -1623,7 +1638,9 @@ Structure actuelle du workspace :
|
|
| 1623 |
${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
| 1624 |
}
|
| 1625 |
|
| 1626 |
-
|
|
|
|
|
|
|
| 1627 |
|
| 1628 |
let history = [];
|
| 1629 |
if (provider !== 'gemini') { history.push({ role: 'system', content: systemMsg }); }
|
|
@@ -1753,7 +1770,8 @@ ${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
|
| 1753 |
Structure actuelle du workspace :
|
| 1754 |
${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
| 1755 |
}
|
| 1756 |
-
|
|
|
|
| 1757 |
|
| 1758 |
const messages = chat.messages.slice(0, aiIndex).map(m => {
|
| 1759 |
return { role: m.role, content: this.buildMessageContentForAI(m) };
|
|
@@ -1783,7 +1801,8 @@ ${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
|
| 1783 |
body: JSON.stringify({
|
| 1784 |
chat_id: chat.id, chat_title: chat.title, message_id: msg.id, provider, model,
|
| 1785 |
apiKey: creds.apiKey || '', baseUrl: creds.baseUrl || '',
|
| 1786 |
-
system, messages, recent_messages: recentMessages
|
|
|
|
| 1787 |
}),
|
| 1788 |
signal: this.abortController.signal
|
| 1789 |
});
|
|
@@ -1849,14 +1868,21 @@ ${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
|
| 1849 |
if (eventName === 'sync') {
|
| 1850 |
this.syncSmoothContent(aiIndex, payload.content || '');
|
| 1851 |
if (payload.tokens) chat.messages[aiIndex].tokens = payload.tokens;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1852 |
} else if (eventName === 'delta') {
|
|
|
|
| 1853 |
this.pushSmoothChunk(aiIndex, payload.text || '');
|
| 1854 |
} else if (eventName === 'done') {
|
|
|
|
| 1855 |
if (payload.tokens) chat.messages[aiIndex].tokens = payload.tokens;
|
| 1856 |
if (payload.promptTokens) chat.messages[aiIndex].promptTokens = payload.promptTokens;
|
| 1857 |
if (payload.completionTokens) chat.messages[aiIndex].completionTokens = payload.completionTokens;
|
| 1858 |
this.finishSmoothStream(aiIndex);
|
| 1859 |
} else if (eventName === 'error') {
|
|
|
|
| 1860 |
this.pushSmoothChunk(aiIndex, "\n**Erreur API:** " + (payload.message || 'inconnue'));
|
| 1861 |
this.finishSmoothStream(aiIndex);
|
| 1862 |
}
|
|
|
|
| 140 |
.typing-indicator span { display: inline-block; animation: blink 1.4s infinite both; font-size: 1.5rem; line-height: 1; margin: 0 2px;}
|
| 141 |
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
| 142 |
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
| 143 |
+
.search-status { display: flex; align-items: center; gap: 8px; font-size: 0.9rem; opacity: 0.85; }
|
| 144 |
@keyframes blink { 0% { opacity: 0.2; transform: scale(0.8); } 20% { opacity: 1; transform: scale(1.2); } 100% { opacity: 0.2; transform: scale(0.8); } }
|
| 145 |
|
| 146 |
/* Modals & Toggles */
|
|
|
|
| 316 |
|
| 317 |
<div class="toggle-group">
|
| 318 |
<div>
|
| 319 |
+
<strong>Recherche Web (agent)</strong>
|
| 320 |
+
<div style="font-size: 0.8rem; color: #a6adc8;">L'IA décide si une recherche est utile, interroge plusieurs sites via le serveur MCP de victor (HuggingFace), puis répond avec les résultats. Nécessite le mode connecté (compte + serveur).</div>
|
| 321 |
</div>
|
| 322 |
<label class="switch"><input type="checkbox" id="toggleWebSearch"><span class="slider"></span></label>
|
| 323 |
</div>
|
|
|
|
| 604 |
if (m.isThinking && fullText) m.isThinking = false;
|
| 605 |
this.updateMessageDOM(aiIndex);
|
| 606 |
},
|
| 607 |
+
// Affiche/efface un statut court pendant une étape agentique invisible
|
| 608 |
+
// (ex: "Je vais rechercher sur le web...") à la place des "...", tant que le
|
| 609 |
+
// message est encore en isThinking. Jamais utilisé pour montrer le détail des tool calls.
|
| 610 |
+
setSearchStatus(aiIndex, text) {
|
| 611 |
+
const chat = this.getActiveChat();
|
| 612 |
+
const m = chat && chat.messages[aiIndex];
|
| 613 |
+
if (!m) return;
|
| 614 |
+
m.searchStatus = text || undefined;
|
| 615 |
+
if (m.isThinking) this.updateMessageDOM(aiIndex);
|
| 616 |
+
},
|
| 617 |
finishSmoothStream(aiIndex) {
|
| 618 |
const s = this._smoothStreams[aiIndex];
|
| 619 |
const chat = this.getActiveChat();
|
|
|
|
| 1069 |
let contentHTML = '';
|
| 1070 |
|
| 1071 |
if (m.isThinking) {
|
| 1072 |
+
contentHTML = m.searchStatus
|
| 1073 |
+
? `<div class="search-status"><i class="fas fa-search fa-spin"></i> ${this.escapeHtml(m.searchStatus)}</div>`
|
| 1074 |
+
: `<div class="typing-indicator"><span>.</span><span>.</span><span>.</span></div>`;
|
| 1075 |
} else if (m.isImageGenerated) {
|
| 1076 |
contentHTML = `<div class="img-gen-wrapper" style="min-height: auto; max-width: 350px;">
|
| 1077 |
<img src="${m.content}" class="loaded" style="max-width: 100%; border-radius: 8px;" alt="Image Générée">
|
|
|
|
| 1169 |
|
| 1170 |
const bodyEl = wrapper.querySelector('.message');
|
| 1171 |
if (m.isThinking) {
|
| 1172 |
+
bodyEl.innerHTML = m.searchStatus
|
| 1173 |
+
? `<div class="search-status"><i class="fas fa-search fa-spin"></i> ${this.escapeHtml(m.searchStatus)}</div>`
|
| 1174 |
+
: `<div class="typing-indicator"><span>.</span><span>.</span><span>.</span></div>`;
|
| 1175 |
} else if (m.isImageGenerated) {
|
| 1176 |
bodyEl.innerHTML = `<div class="img-gen-wrapper" style="min-height: auto; max-width: 350px;">
|
| 1177 |
<img src="${m.content}" class="loaded" style="max-width: 100%; border-radius: 8px;" alt="Image Générée">
|
|
|
|
| 1638 |
${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
| 1639 |
}
|
| 1640 |
|
| 1641 |
+
// Note : en mode local (sans serveur), la recherche web réelle n'est pas
|
| 1642 |
+
// disponible — pas d'instruction de "simulation" pour éviter les réponses
|
| 1643 |
+
// inventées ; ce toggle n'a d'effet réel qu'en mode connecté (voir triggerAiResponseCloud).
|
| 1644 |
|
| 1645 |
let history = [];
|
| 1646 |
if (provider !== 'gemini') { history.push({ role: 'system', content: systemMsg }); }
|
|
|
|
| 1770 |
Structure actuelle du workspace :
|
| 1771 |
${JSON.stringify(Object.keys(this.state.virtualFiles))}`;
|
| 1772 |
}
|
| 1773 |
+
// La recherche web réelle (agent + MCP victor/websearch) est décidée et exécutée
|
| 1774 |
+
// côté serveur dans run_job() si webSearchEnabled est transmis — voir plus bas.
|
| 1775 |
|
| 1776 |
const messages = chat.messages.slice(0, aiIndex).map(m => {
|
| 1777 |
return { role: m.role, content: this.buildMessageContentForAI(m) };
|
|
|
|
| 1801 |
body: JSON.stringify({
|
| 1802 |
chat_id: chat.id, chat_title: chat.title, message_id: msg.id, provider, model,
|
| 1803 |
apiKey: creds.apiKey || '', baseUrl: creds.baseUrl || '',
|
| 1804 |
+
system, messages, recent_messages: recentMessages,
|
| 1805 |
+
webSearchEnabled: !!this.state.settings.webSearch
|
| 1806 |
}),
|
| 1807 |
signal: this.abortController.signal
|
| 1808 |
});
|
|
|
|
| 1868 |
if (eventName === 'sync') {
|
| 1869 |
this.syncSmoothContent(aiIndex, payload.content || '');
|
| 1870 |
if (payload.tokens) chat.messages[aiIndex].tokens = payload.tokens;
|
| 1871 |
+
} else if (eventName === 'status') {
|
| 1872 |
+
// Étape agentique invisible (ex: décision + exécution de la recherche web) :
|
| 1873 |
+
// affiche un statut court à la place des "...", sans jamais montrer le détail des tool calls.
|
| 1874 |
+
this.setSearchStatus(aiIndex, payload.text || '');
|
| 1875 |
} else if (eventName === 'delta') {
|
| 1876 |
+
this.setSearchStatus(aiIndex, null);
|
| 1877 |
this.pushSmoothChunk(aiIndex, payload.text || '');
|
| 1878 |
} else if (eventName === 'done') {
|
| 1879 |
+
this.setSearchStatus(aiIndex, null);
|
| 1880 |
if (payload.tokens) chat.messages[aiIndex].tokens = payload.tokens;
|
| 1881 |
if (payload.promptTokens) chat.messages[aiIndex].promptTokens = payload.promptTokens;
|
| 1882 |
if (payload.completionTokens) chat.messages[aiIndex].completionTokens = payload.completionTokens;
|
| 1883 |
this.finishSmoothStream(aiIndex);
|
| 1884 |
} else if (eventName === 'error') {
|
| 1885 |
+
this.setSearchStatus(aiIndex, null);
|
| 1886 |
this.pushSmoothChunk(aiIndex, "\n**Erreur API:** " + (payload.message || 'inconnue'));
|
| 1887 |
this.finishSmoothStream(aiIndex);
|
| 1888 |
}
|