1
0
mirror of https://github.com/coalaura/whiskr.git synced 2025-09-09 09:19:54 +00:00

better searching

This commit is contained in:
Laura
2025-08-14 03:53:14 +02:00
parent 8a790df2af
commit c740cd293d
14 changed files with 582 additions and 143 deletions

View File

@@ -22,11 +22,10 @@
let autoScrolling = false,
jsonMode = false,
searchTool = false,
interacted = false;
searchTool = false;
function scroll(force = false) {
if (!autoScrolling && !force) {
function scroll() {
if (!autoScrolling) {
return;
}
@@ -44,6 +43,7 @@
#reasoning;
#text;
#tool;
#tags = [];
#statistics;
#error = false;
@@ -61,6 +61,7 @@
#_reasoning;
#_text;
#_edit;
#_tool;
#_statistics;
constructor(role, reasoning, text) {
@@ -156,6 +157,35 @@
}
});
// message tool
this.#_tool = make("div", "tool");
this.#_message.appendChild(this.#_tool);
// tool call
const _call = make("div", "call");
this.#_tool.appendChild(_call);
_call.addEventListener("click", () => {
this.#_tool.classList.toggle("expanded");
});
// tool call name
const _callName = make("div", "name");
_call.appendChild(_callName);
// tool call arguments
const _callArguments = make("div", "arguments");
_call.appendChild(_callArguments);
// tool call result
const _callResult = make("div", "result", "markdown");
this.#_tool.appendChild(_callResult);
// message options
const _opts = make("div", "options");
@@ -220,7 +250,7 @@
img.classList.add("image");
img.addEventListener("load", () => {
scroll(!interacted);
scroll();
});
});
}
@@ -232,6 +262,21 @@
);
}
#updateToolHeight() {
const result = this.#_tool.querySelector(".result");
this.#_tool.style.setProperty("--height", `${result.scrollHeight}px`);
}
#morph(from, to) {
morphdom(from, to, {
childrenOnly: true,
onBeforeElUpdated: (fromEl, toEl) => {
return !fromEl.isEqualNode || !fromEl.isEqualNode(toEl);
},
});
}
#patch(name, element, md, after = false) {
if (!element.firstChild) {
element.innerHTML = render(md);
@@ -258,12 +303,7 @@
this.#_diff.innerHTML = html;
morphdom(element, this.#_diff, {
childrenOnly: true,
onBeforeElUpdated: (fromEl, toEl) => {
return !fromEl.isEqualNode || !fromEl.isEqualNode(toEl);
},
});
this.#morph(element, this.#_diff);
this.#_diff.innerHTML = "";
@@ -284,6 +324,34 @@
this.#_message.classList.toggle("has-tags", this.#tags.length > 0);
}
if (!only || only === "tool") {
if (this.#tool) {
const { name, args, result } = this.#tool;
const _name = this.#_tool.querySelector(".name"),
_arguments = this.#_tool.querySelector(".arguments"),
_result = this.#_tool.querySelector(".result");
_name.title = `Show ${name} call result`;
_name.textContent = name;
_arguments.title = args;
_arguments.textContent = args;
_result.innerHTML = render(result || "*processing*");
this.#_tool.setAttribute("data-tool", name);
} else {
this.#_tool.removeAttribute("data-tool");
}
this.#_message.classList.toggle("has-tool", !!this.#tool);
this.#updateToolHeight();
noScroll || scroll();
}
if (!only || only === "statistics") {
let html = "";
@@ -353,6 +421,10 @@
text: this.#text,
};
if (this.#tool) {
data.tool = this.#tool;
}
if (this.#reasoning && full) {
data.reasoning = this.#reasoning;
}
@@ -365,7 +437,7 @@
data.tags = this.#tags;
}
if (this.#statistics) {
if (this.#statistics && full) {
data.statistics = this.#statistics;
}
@@ -425,11 +497,23 @@
if (state) {
this.#_message.classList.add(state);
} else {
if (this.#tool && !this.#tool.result) {
this.#tool.result = "failed to run tool";
this.#render("tool");
}
}
this.#state = state;
}
setTool(tool) {
this.#tool = tool;
this.#render("tool");
}
addReasoning(chunk) {
this.#reasoning += chunk;
@@ -652,19 +736,23 @@
obj.showError(message.error);
}
if (message.statistics) {
obj.setStatistics(message.statistics);
}
if (message.tags) {
message.tags.forEach((tag) => obj.addTag(tag));
}
if (message.tool) {
obj.setTool(message.tool);
}
if (message.statistics) {
obj.setStatistics(message.statistics);
}
});
scroll(true);
scroll();
// small fix, sometimes when hard reloading we don't scroll all the way
setTimeout(scroll, 250, true);
setTimeout(scroll, 250);
}
function pushMessage() {
@@ -691,9 +779,7 @@
});
$bottom.addEventListener("click", () => {
interacted = true;
scroll(true);
scroll();
});
$role.addEventListener("change", () => {
@@ -702,11 +788,12 @@
$model.addEventListener("change", () => {
const model = $model.value,
data = model ? models[model] : null;
data = model ? models[model] : null,
tags = data?.tags || [];
storeValue("model", model);
if (data?.tags.includes("reasoning")) {
if (tags.includes("reasoning")) {
$reasoningEffort.parentNode.classList.remove("none");
$reasoningTokens.parentNode.classList.toggle(
"none",
@@ -717,7 +804,13 @@
$reasoningTokens.parentNode.classList.add("none");
}
$json.classList.toggle("none", !data?.tags.includes("json"));
const hasJson = tags.includes("json"),
hasTools = tags.includes("tools");
$json.classList.toggle("none", !hasJson);
$search.classList.toggle("none", !hasTools);
$search.parentNode.classList.toggle("none", !hasJson && !hasTools);
});
$prompt.addEventListener("change", () => {
@@ -862,19 +955,36 @@
.filter((data) => data?.text),
};
const message = new Message("assistant", "", "");
let message, generationID;
message.setState("waiting");
function finish() {
if (!message) {
return;
}
if (jsonMode) {
message.addTag("json");
message.setState(false);
setTimeout(message.loadGenerationData.bind(message), 750, generationID);
message = null;
generationID = null;
}
if (searchTool) {
message.addTag("search");
function start() {
message = new Message("assistant", "", "");
message.setState("waiting");
if (jsonMode) {
message.addTag("json");
}
if (searchTool) {
message.addTag("search");
}
}
let generationID;
start();
stream(
"/-/chat",
@@ -890,21 +1000,30 @@
if (!chunk) {
controller = null;
message.setState(false);
finish();
$chat.classList.remove("completing");
setTimeout(() => {
message.loadGenerationData(generationID);
}, 750);
return;
}
if (!message && chunk.type !== "end") {
start();
}
switch (chunk.type) {
case "id":
generationID = chunk.text;
break;
case "tool":
message.setState("tooling");
message.setTool(chunk.text);
if (chunk.text.result) {
finish();
}
break;
case "reason":
message.setState("reasoning");