diff --git a/.github/chat.png b/.github/chat.png index 659ffdf..f2e29b7 100644 Binary files a/.github/chat.png and b/.github/chat.png differ diff --git a/chat.go b/chat.go index c7c9d44..6a3397b 100644 --- a/chat.go +++ b/chat.go @@ -61,6 +61,12 @@ func (r *Request) Parse() (*openrouter.ChatCompletionRequest, error) { }) } + h := "high" + + request.Reasoning = &openrouter.ChatCompletionReasoning{ + Effort: &h, + } + return &request, nil } diff --git a/static/css/chat.css b/static/css/chat.css index c6c7b74..0200176 100644 --- a/static/css/chat.css +++ b/static/css/chat.css @@ -150,8 +150,8 @@ body { width: 100%; } -.message .text { - padding-bottom: 10px; +.message .reasoning { + padding-top: 14px; } .message:not(.editing) textarea.text, @@ -159,6 +159,7 @@ body { display: none; } +.message .reasoning, .message div.text { background: #24273a; } @@ -167,6 +168,10 @@ body { background: #181926; } +.reasoning-text pre { + background: #1b1d2a; +} + .message .reasoning-text { --height: auto; height: calc(var(--height) + 20px); @@ -186,16 +191,20 @@ body { margin-top: 10px; } +.message.has-reasoning:not(.has-text) div.text, .message:not(.has-reasoning) .reasoning { display: none; } +.message.has-reasoning .text { + padding-top: 4px; +} + .reasoning .toggle { position: relative; padding: 0 20px; font-weight: 600; font-size: 14px; - margin-top: 2px; } .reasoning .toggle::after, @@ -203,7 +212,7 @@ body { content: ""; background-image: url(icons/reasoning.svg); position: absolute; - top: 0; + top: -2px; left: -2px; width: 20px; height: 20px; @@ -213,7 +222,6 @@ body { background-image: url(icons/chevron.svg); left: unset; right: -2px; - top: 1px; transition: 150ms; } @@ -298,6 +306,8 @@ select { textarea { resize: none; + font-size: 15px; + line-height: 23px; } button { diff --git a/static/js/chat.js b/static/js/chat.js index 555b827..83835bb 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -65,7 +65,7 @@ this.#_message.appendChild(this.#_role); // message reasoning (wrapper) - const _reasoning = make("div", "reasoning", "markdown"); + const _reasoning = make("div", "reasoning"); this.#_message.appendChild(_reasoning); @@ -87,7 +87,7 @@ }); // message reasoning (content) - this.#_reasoning = make("div", "reasoning-text"); + this.#_reasoning = make("div", "reasoning-text", "markdown"); _reasoning.appendChild(this.#_reasoning); @@ -187,6 +187,12 @@ if (!only || only === "text") { this.#_text.innerHTML = render(this.#text); + + if (this.#text) { + this.#_message.classList.add("has-text"); + } else { + this.#_message.classList.remove("has-text"); + } } if (!noScroll) { @@ -443,23 +449,23 @@ }); $role.addEventListener("change", () => { - localStorage.setItem("role", $role.value); + storeValue("role", $role.value); }); $model.addEventListener("change", () => { - localStorage.setItem("model", $model.value); + storeValue("model", $model.value); }); $prompt.addEventListener("change", () => { - localStorage.setItem("prompt", $prompt.value); + storeValue("prompt", $prompt.value); }); $temperature.addEventListener("input", () => { - localStorage.setItem("temperature", $temperature.value); + storeValue("temperature", $temperature.value); }); $message.addEventListener("input", () => { - localStorage.setItem("message", $message.value); + storeValue("message", $message.value); }); $add.addEventListener("click", () => { diff --git a/static/js/dropdown.js b/static/js/dropdown.js index 059a882..08bb763 100644 --- a/static/js/dropdown.js +++ b/static/js/dropdown.js @@ -45,6 +45,8 @@ set: (value) => { descriptor.set.call(this.#_select, value); + this.#_select.dispatchEvent(new Event("change")); + this.#set(value); }, }); @@ -78,7 +80,7 @@ _opt.textContent = option.label; _opt.addEventListener("click", () => { - this.#set(option.value); + this.#_select.value = option.value; this.#_dropdown.classList.remove("open"); }); diff --git a/static/js/markdown.js b/static/js/markdown.js index 0f0e6e6..3abd932 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -18,14 +18,15 @@ let code; if (lang && hljs.getLanguage(lang)) { - code = hljs.highlight(text, { + code = hljs.highlight(text.trim(), { language: lang, }); } else { - code = hljs.highlightAuto(text); + code = hljs.highlightAuto(text.trim()); } token.escaped = true; + token.lang = code.language || "plaintext"; token.text = code.value; },