mirror of
https://github.com/coalaura/whiskr.git
synced 2025-09-08 17:06:42 +00:00
better searching
This commit is contained in:
@@ -193,11 +193,11 @@ body.loading #version {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#messages .message .tag-json {
|
||||
.message .tag-json {
|
||||
background-image: url(icons/json-mode.svg);
|
||||
}
|
||||
|
||||
#messages .message .tag-search {
|
||||
.message .tag-search {
|
||||
background-image: url(icons/search-tool.svg);
|
||||
}
|
||||
|
||||
@@ -218,6 +218,7 @@ body.loading #version {
|
||||
}
|
||||
|
||||
.message .reasoning,
|
||||
.message .tool,
|
||||
.message .text {
|
||||
display: block;
|
||||
background: transparent;
|
||||
@@ -234,12 +235,13 @@ body.loading #version {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#messages .message .reasoning,
|
||||
#messages .message div.text {
|
||||
.message .reasoning,
|
||||
.message .tool,
|
||||
.message div.text {
|
||||
background: #24273a;
|
||||
}
|
||||
|
||||
#messages .message textarea.text {
|
||||
.message textarea.text {
|
||||
background: #181926;
|
||||
}
|
||||
|
||||
@@ -260,6 +262,7 @@ body.loading #version {
|
||||
background: #1b1d2a;
|
||||
}
|
||||
|
||||
.message .tool .result,
|
||||
.message .reasoning-text {
|
||||
background: #1e2030;
|
||||
border-radius: 6px;
|
||||
@@ -282,11 +285,15 @@ body.loading #version {
|
||||
}
|
||||
|
||||
.message.has-reasoning:not(.has-text) div.text,
|
||||
.message.has-tool:not(.has-text) div.text,
|
||||
.message:not(.has-tool) .tool,
|
||||
.message:not(.has-reasoning) .reasoning {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#messages .message div.text {
|
||||
.message .tool,
|
||||
.message:not(.has-tool):not(.has-text) .reasoning,
|
||||
.message:not(.has-tool) div.text {
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
}
|
||||
@@ -295,6 +302,7 @@ body.loading #version {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.tool .call,
|
||||
.reasoning .toggle {
|
||||
position: relative;
|
||||
padding: 0 22px;
|
||||
@@ -303,6 +311,8 @@ body.loading #version {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.tool .call .name::after,
|
||||
.tool .call::before,
|
||||
.reasoning .toggle::after,
|
||||
.reasoning .toggle::before {
|
||||
content: "";
|
||||
@@ -314,6 +324,7 @@ body.loading #version {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.tool .call .name::after,
|
||||
.reasoning .toggle::after {
|
||||
background-image: url(icons/chevron.svg);
|
||||
left: unset;
|
||||
@@ -325,6 +336,65 @@ body.loading #version {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.message.has-tool .text {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.message .tool {
|
||||
--height: 0px;
|
||||
overflow: hidden;
|
||||
transition: 150ms;
|
||||
height: calc(90px + var(--height));
|
||||
}
|
||||
|
||||
.message .tool:not(.expanded) {
|
||||
height: 62px;
|
||||
}
|
||||
|
||||
.tool .call {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
font-family: "Comic Code", ui-monospace, "Cascadia Mono", "Segoe UI Mono", "Ubuntu Mono", "Roboto Mono", Menlo, Monaco, Consolas, monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.tool .call .arguments {
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.tool .call .name::after,
|
||||
.tool .call::before {
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.tool .call .name::after {
|
||||
right: -22px;
|
||||
}
|
||||
|
||||
.tool.expanded .call .name::after {
|
||||
transform: translateY(-50%) rotate(180deg);
|
||||
}
|
||||
|
||||
.tool .call::before {
|
||||
background-image: url(icons/tool.svg);
|
||||
}
|
||||
|
||||
.tool .call .name {
|
||||
position: relative;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
.message .tool .result {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.message .options {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
@@ -355,6 +425,13 @@ body.loading #version {
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.message.tooling .tool .call::before {
|
||||
animation: rotating-y 1.2s linear infinite;
|
||||
background-image: url(icons/spinner.svg);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.message .text::before {
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -510,13 +587,15 @@ body.loading #version,
|
||||
.reasoning .toggle::before,
|
||||
.reasoning .toggle::after,
|
||||
#bottom,
|
||||
#messages .message .role::before,
|
||||
#messages .message .tag-json,
|
||||
#messages .message .tag-search,
|
||||
#messages .message .copy,
|
||||
#messages .message .edit,
|
||||
#messages .message .delete,
|
||||
.message .role::before,
|
||||
.message .tag-json,
|
||||
.message .tag-search,
|
||||
.message .copy,
|
||||
.message .edit,
|
||||
.message .delete,
|
||||
.pre-copy,
|
||||
.tool .call .name::after,
|
||||
.tool .call::before,
|
||||
.message .statistics .provider::before,
|
||||
.message .statistics .ttft::before,
|
||||
.message .statistics .tps::before,
|
||||
@@ -540,9 +619,9 @@ body.loading #version,
|
||||
.message .statistics .ttft::before,
|
||||
.message .statistics .tps::before,
|
||||
.message .statistics .tokens::before,
|
||||
#messages .message .tag-json,
|
||||
#messages .message .tag-search,
|
||||
#messages .message .role::before {
|
||||
.message .tag-json,
|
||||
.message .tag-search,
|
||||
.message .role::before {
|
||||
content: "";
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@@ -553,7 +632,7 @@ input.invalid {
|
||||
}
|
||||
|
||||
.pre-copy,
|
||||
#messages .message .copy {
|
||||
.message .copy {
|
||||
background-image: url(icons/copy.svg);
|
||||
}
|
||||
|
||||
@@ -562,15 +641,15 @@ input.invalid {
|
||||
background-image: url(icons/check.svg);
|
||||
}
|
||||
|
||||
#messages .message .edit {
|
||||
.message .edit {
|
||||
background-image: url(icons/edit.svg);
|
||||
}
|
||||
|
||||
#messages .message.editing .edit {
|
||||
.message.editing .edit {
|
||||
background-image: url(icons/save.svg);
|
||||
}
|
||||
|
||||
#messages .message .delete {
|
||||
.message .delete {
|
||||
background-image: url(icons/delete.svg);
|
||||
}
|
||||
|
||||
@@ -692,4 +771,14 @@ label[for="reasoning-tokens"] {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotating-y {
|
||||
from {
|
||||
transform: translateY(-50%) rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateY(-50%) rotate(360deg);
|
||||
}
|
||||
}
|
11
static/css/icons/tool.svg
Normal file
11
static/css/icons/tool.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||
<svg width="256px" height="256px" viewBox="-2.4 -2.4 28.80 28.80" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||
|
||||
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
|
||||
<g id="SVGRepo_iconCarrier"> <path d="M15.6316 7.63137C15.2356 7.23535 15.0376 7.03735 14.9634 6.80902C14.8981 6.60817 14.8981 6.39183 14.9634 6.19098C15.0376 5.96265 15.2356 5.76465 15.6316 5.36863L18.47 2.53026C17.7168 2.18962 16.8806 2 16.0002 2C12.6865 2 10.0002 4.68629 10.0002 8C10.0002 8.49104 10.0592 8.9683 10.1705 9.42509C10.2896 9.91424 10.3492 10.1588 10.3387 10.3133C10.3276 10.4751 10.3035 10.5612 10.2289 10.7051C10.1576 10.8426 10.0211 10.9791 9.74804 11.2522L3.50023 17.5C2.6718 18.3284 2.6718 19.6716 3.50023 20.5C4.32865 21.3284 5.6718 21.3284 6.50023 20.5L12.748 14.2522C13.0211 13.9791 13.1576 13.8426 13.2951 13.7714C13.4391 13.6968 13.5251 13.6727 13.6869 13.6616C13.8414 13.651 14.086 13.7106 14.5751 13.8297C15.0319 13.941 15.5092 14 16.0002 14C19.3139 14 22.0002 11.3137 22.0002 8C22.0002 7.11959 21.8106 6.28347 21.47 5.53026L18.6316 8.36863C18.2356 8.76465 18.0376 8.96265 17.8092 9.03684C17.6084 9.1021 17.3921 9.1021 17.1912 9.03684C16.9629 8.96265 16.7649 8.76465 16.3689 8.36863L15.6316 7.63137Z" stroke="#cad3f5" stroke-width="1.56" stroke-linecap="round" stroke-linejoin="round"/> </g>
|
||||
|
||||
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
@@ -176,6 +176,10 @@
|
||||
padding-left: 28px;
|
||||
}
|
||||
|
||||
.markdown> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown blockquote>*,
|
||||
.markdown td>*,
|
||||
.markdown th>*,
|
||||
|
@@ -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");
|
||||
|
Reference in New Issue
Block a user