add optional web search functionality with UI updates and backend integration

This commit is contained in:
2026-09-20 20:41:01 +02:00
parent abd5238252
commit 781f15b503
16 changed files with 603 additions and 41 deletions
+29 -2
View File
@@ -1,4 +1,5 @@
import {del, get, post, put, stream} from "./app/api.js?v=20260909-account-controls";
import {appendSources, createWebSearchToggle} from "./app/webSearch.js";
import {closeChatDrawer, openChatDrawer} from "./app/chatDrawer.js?v=20260909-account-controls";
import {onboardingPrompts, requestedChatId} from "./app/constants.js?v=20260909-account-controls";
import {getModelProfile} from "./app/modelProfiles.js?v=20260909-account-controls";
@@ -102,6 +103,8 @@ import {
} from "./app/dom.js?v=20260909-account-controls";
const headerModelButton = document.getElementById("headerModelButton");
const webSearchButton = document.getElementById("webSearch");
const webSearchToggle = createWebSearchToggle(webSearchButton);
let isProcessing = false, activeChatId = null, editingPersonaId = null, editingPersonaType = "assistant", currentUsername = "";
let chatSessions = [], currentMessages = [], assistantPersonas = [], userPersonas = [];
@@ -738,6 +741,13 @@ function addMessage(contentOrMessage, isUser = false, isLoading = false, options
}
msgDiv.append(header, body);
if (!isMessageUser) appendSources(msgDiv, message.sources);
if (message.deliveryStatus === "failed" && message.errorMessage) {
const error = document.createElement("p");
error.className = "status";
error.textContent = message.errorMessage;
msgDiv.appendChild(error);
}
if (actions.childElementCount) {
msgDiv.appendChild(actions);
}
@@ -1348,6 +1358,7 @@ async function unpublishPersona(id) { const res = await post(`/personas/${id}/un
function setLoadingState(loading, overlayOptions = null) {
isProcessing = loading;
msgInput.disabled = loading;
webSearchButton.disabled = loading;
sendBtn.classList.toggle("loading", loading);
messagesDiv.querySelectorAll('[data-message-action="regenerate"]').forEach((button) => {
button.disabled = loading || button.dataset.retryLimitReached === "true";
@@ -1797,6 +1808,7 @@ async function sendMessage() {
if (isProcessing) return;
const message = msgInput.value.trim();
if (!message) return;
const webSearch = webSearchToggle.enabled;
if (!activeChatId) await createNewChat();
const currentChat = getChatById(activeChatId);
if (currentChat && !currentChat.assistant_persona_id && currentChat.title === "New chat") {
@@ -1810,9 +1822,16 @@ async function sendMessage() {
const loadingMsg = addMessage({role: "bot", content: ""}, false, true, {isNewest: true});
const loadingBody = loadingMsg.querySelector(".msg-content");
const loadingShell = loadingMsg.querySelector(".loading-shell");
const loadingLabel = loadingMsg.querySelector(".loading-copy strong");
if (webSearch) loadingLabel.textContent = "Searching the web...";
try {
let streamError = null;
await stream("/chat/stream", {message, model: modelSelect.value, chatId: activeChatId}, {
await stream("/chat/stream", {message, model: modelSelect.value, chatId: activeChatId, webSearch}, {
onStatus: ({status, sourceCount}) => {
webSearchToggle.reset();
loadingLabel.textContent = status === "searching" ? "Searching the web..."
: sourceCount === 0 ? "No web results found. Generating response..." : "Generating response...";
},
onChunk: ({fullReply}) => {
if (loadingBody) {
loadingShell?.classList.add("hidden");
@@ -1820,13 +1839,17 @@ async function sendMessage() {
setMessageContent(loadingBody, fullReply);
}
},
onDone: () => {},
onDone: () => { webSearchToggle.reset(); },
onError: ({error}) => {
streamError = error || "Failed to generate reply.";
}
});
if (messagesDiv.contains(loadingMsg)) messagesDiv.removeChild(loadingMsg);
if (streamError) {
if (webSearch) {
msgInput.value = message;
resizeComposerInput();
}
addMessage(`[Error: ${streamError}]`);
setNotice(streamError, "error");
return;
@@ -1838,6 +1861,10 @@ async function sendMessage() {
setNotice("Reply received.", "success");
} catch {
if (messagesDiv.contains(loadingMsg)) messagesDiv.removeChild(loadingMsg);
if (webSearch) {
msgInput.value = message;
resizeComposerInput();
}
addMessage("[Error: Network error]"); setNotice("Network error while sending message.", "error");
} finally {
setLoadingState(false); msgInput.focus(); updateChatActionState();