Spaces:
Running
Running
collapsable thinking
Browse files- server.js +0 -2
- src/components/ask-ai/ask-ai.tsx +44 -19
server.js
CHANGED
|
@@ -289,8 +289,6 @@ app.post("/api/ask-ai", async (req, res) => {
|
|
| 289 |
? PROVIDERS[selectedModel.autoProvider]
|
| 290 |
: PROVIDERS[provider] ?? DEFAULT_PROVIDER;
|
| 291 |
|
| 292 |
-
console.log(provider, selectedProvider);
|
| 293 |
-
|
| 294 |
if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {
|
| 295 |
return res.status(400).send({
|
| 296 |
ok: false,
|
|
|
|
| 289 |
? PROVIDERS[selectedModel.autoProvider]
|
| 290 |
: PROVIDERS[provider] ?? DEFAULT_PROVIDER;
|
| 291 |
|
|
|
|
|
|
|
| 292 |
if (provider !== "auto" && TOKENS_USED >= selectedProvider.max_tokens) {
|
| 293 |
return res.status(400).send({
|
| 294 |
ok: false,
|
src/components/ask-ai/ask-ai.tsx
CHANGED
|
@@ -5,6 +5,7 @@ import { GrSend } from "react-icons/gr";
|
|
| 5 |
import classNames from "classnames";
|
| 6 |
import { toast } from "sonner";
|
| 7 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
|
|
|
| 8 |
|
| 9 |
import Login from "../login/login";
|
| 10 |
import { defaultHTML } from "../../../utils/consts";
|
|
@@ -14,7 +15,6 @@ import ProModal from "../pro-modal/pro-modal";
|
|
| 14 |
import { Button } from "../ui/button";
|
| 15 |
// @ts-expect-error not needed
|
| 16 |
import { MODELS } from "./../../../utils/providers";
|
| 17 |
-
import { X } from "lucide-react";
|
| 18 |
|
| 19 |
function AskAI({
|
| 20 |
html,
|
|
@@ -55,6 +55,9 @@ function AskAI({
|
|
| 55 |
if (isAiWorking || !prompt.trim()) return;
|
| 56 |
setisAiWorking(true);
|
| 57 |
setProviderError("");
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
let contentResponse = "";
|
| 60 |
let lastRenderTime = 0;
|
|
@@ -94,6 +97,7 @@ function AskAI({
|
|
| 94 |
const selectedModel = MODELS.find(
|
| 95 |
(m: { value: string }) => m.value === model
|
| 96 |
);
|
|
|
|
| 97 |
const read = async () => {
|
| 98 |
const { done, value } = await reader.read();
|
| 99 |
if (done) {
|
|
@@ -121,10 +125,11 @@ function AskAI({
|
|
| 121 |
if (selectedModel?.isThinker) {
|
| 122 |
const thinkMatch = contentResponse.match(/<think>[\s\S]*/)?.[0];
|
| 123 |
if (thinkMatch && !contentResponse?.includes("</think>")) {
|
| 124 |
-
if (
|
| 125 |
setOpenThink(true);
|
| 126 |
}
|
| 127 |
setThink(thinkMatch.replace("<think>", "").trim());
|
|
|
|
| 128 |
}
|
| 129 |
}
|
| 130 |
|
|
@@ -167,31 +172,51 @@ function AskAI({
|
|
| 167 |
}
|
| 168 |
}, [think]);
|
| 169 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
return (
|
| 171 |
<div className="bg-neutral-800 border border-neutral-700 rounded-lg ring-[5px] focus-within:ring-sky-500/50 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
|
| 172 |
{think && (
|
| 173 |
<div
|
| 174 |
ref={refThink}
|
| 175 |
-
className="w-full
|
| 176 |
>
|
| 177 |
-
<
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
{think}
|
| 193 |
</p>
|
| 194 |
-
</
|
| 195 |
</div>
|
| 196 |
)}
|
| 197 |
<div
|
|
|
|
| 5 |
import classNames from "classnames";
|
| 6 |
import { toast } from "sonner";
|
| 7 |
import { useLocalStorage, useUpdateEffect } from "react-use";
|
| 8 |
+
import { ChevronDown } from "lucide-react";
|
| 9 |
|
| 10 |
import Login from "../login/login";
|
| 11 |
import { defaultHTML } from "../../../utils/consts";
|
|
|
|
| 15 |
import { Button } from "../ui/button";
|
| 16 |
// @ts-expect-error not needed
|
| 17 |
import { MODELS } from "./../../../utils/providers";
|
|
|
|
| 18 |
|
| 19 |
function AskAI({
|
| 20 |
html,
|
|
|
|
| 55 |
if (isAiWorking || !prompt.trim()) return;
|
| 56 |
setisAiWorking(true);
|
| 57 |
setProviderError("");
|
| 58 |
+
setThink("");
|
| 59 |
+
setOpenThink(false);
|
| 60 |
+
setIsThinking(true);
|
| 61 |
|
| 62 |
let contentResponse = "";
|
| 63 |
let lastRenderTime = 0;
|
|
|
|
| 97 |
const selectedModel = MODELS.find(
|
| 98 |
(m: { value: string }) => m.value === model
|
| 99 |
);
|
| 100 |
+
let contentThink: string | undefined = undefined;
|
| 101 |
const read = async () => {
|
| 102 |
const { done, value } = await reader.read();
|
| 103 |
if (done) {
|
|
|
|
| 125 |
if (selectedModel?.isThinker) {
|
| 126 |
const thinkMatch = contentResponse.match(/<think>[\s\S]*/)?.[0];
|
| 127 |
if (thinkMatch && !contentResponse?.includes("</think>")) {
|
| 128 |
+
if ((contentThink?.length ?? 0) < 3) {
|
| 129 |
setOpenThink(true);
|
| 130 |
}
|
| 131 |
setThink(thinkMatch.replace("<think>", "").trim());
|
| 132 |
+
contentThink += chunk;
|
| 133 |
}
|
| 134 |
}
|
| 135 |
|
|
|
|
| 172 |
}
|
| 173 |
}, [think]);
|
| 174 |
|
| 175 |
+
useUpdateEffect(() => {
|
| 176 |
+
if (!isThinking) {
|
| 177 |
+
setOpenThink(false);
|
| 178 |
+
}
|
| 179 |
+
}, [isThinking]);
|
| 180 |
+
|
| 181 |
return (
|
| 182 |
<div className="bg-neutral-800 border border-neutral-700 rounded-lg ring-[5px] focus-within:ring-sky-500/50 ring-transparent z-10 absolute bottom-3 left-3 w-[calc(100%-20px)] group">
|
| 183 |
{think && (
|
| 184 |
<div
|
| 185 |
ref={refThink}
|
| 186 |
+
className="w-full border-b border-neutral-700 relative overflow-hidden"
|
| 187 |
>
|
| 188 |
+
<header
|
| 189 |
+
className="flex items-center justify-between px-5 py-2.5 group hover:bg-neutral-600/20 transition-colors duration-200 cursor-pointer"
|
| 190 |
+
onClick={() => {
|
| 191 |
+
setOpenThink(!openThink);
|
| 192 |
+
}}
|
| 193 |
+
>
|
| 194 |
+
<p className="text-sm font-medium text-neutral-300 group-hover:text-neutral-200 transition-colors duration-200">
|
| 195 |
+
{isThinking ? "AI is thinking..." : "AI's plan"}
|
| 196 |
+
</p>
|
| 197 |
+
<ChevronDown
|
| 198 |
+
className={classNames(
|
| 199 |
+
"size-4 text-neutral-400 group-hover:text-neutral-300 transition-all duration-200",
|
| 200 |
+
{
|
| 201 |
+
"rotate-180": openThink,
|
| 202 |
+
}
|
| 203 |
+
)}
|
| 204 |
+
/>
|
| 205 |
+
</header>
|
| 206 |
+
<main
|
| 207 |
+
className={classNames(
|
| 208 |
+
"overflow-y-auto transition-all duration-200 ease-in-out",
|
| 209 |
+
{
|
| 210 |
+
"max-h-[0px]": !openThink,
|
| 211 |
+
"min-h-[250px] max-h-[250px] border-t border-neutral-700":
|
| 212 |
+
openThink,
|
| 213 |
+
}
|
| 214 |
+
)}
|
| 215 |
+
>
|
| 216 |
+
<p className="text-[13px] text-neutral-400 whitespace-pre-line px-5 pb-4 pt-3">
|
| 217 |
{think}
|
| 218 |
</p>
|
| 219 |
+
</main>
|
| 220 |
</div>
|
| 221 |
)}
|
| 222 |
<div
|