feat: thinking style optimize

This commit is contained in:
Hk-Gosuto
2025-03-03 15:33:19 +08:00
parent ac9bdf642e
commit 78dd2d4258
8 changed files with 216 additions and 13 deletions

View File

@@ -147,6 +147,7 @@ import {
WebTranscriptionApi,
} from "../utils/speech";
import { FileInfo } from "../client/platforms/utils";
import { ThinkingContent } from "./thinking-content";
const ttsPlayer = createTTSPlayer();
@@ -2151,6 +2152,7 @@ function _Chat() {
))}
</div>
)}
{!isUser && <ThinkingContent message={message} />}
<div className={styles["chat-message-item"]}>
<Markdown
key={message.streaming ? "loading" : "done"}

View File

@@ -0,0 +1,106 @@
.thinking-container {
position: relative;
border: var(--border-in-light);
border-radius: 10px;
margin-top: 10px;
overflow: hidden;
transition: all 0.3s ease;
box-shadow: var(--card-shadow);
.thinking-header {
position: sticky;
top: 0;
background: var(--white);
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: var(--border-in-light);
.thinking-title {
display: flex;
align-items: center;
gap: 5px;
font-size: 12px;
color: var(--black);
padding: 2px 5px;
border-radius: 5px;
}
.thinking-toggle {
display: flex;
align-items: center;
gap: 5px;
font-size: 12px;
color: var(--black);
padding: 2px 5px;
border-radius: 5px;
transition: background-color 0.3s ease;
cursor: pointer;
&:hover {
background-color: rgba(0, 0, 0, 0.05);
text-decoration: none;
}
}
}
.thinking-content-wrapper {
position: relative;
overflow: hidden;
}
.thinking-content {
font-size: 12px;
line-height: 1.5;
white-space: pre-wrap;
color: var(--black);
overflow-wrap: break-word;
scroll-behavior: smooth;
max-height: 50px;
overflow-y: hidden;
position: relative;
transition:
max-height 0.3s ease,
overflow-y 0.3s ease;
padding: 10px;
.thinking-content-text {
position: relative;
z-index: 0;
}
&.expanded {
overflow-y: auto;
max-height: 300px;
}
}
.thinking-content-top,
.thinking-content-bottom {
position: absolute;
left: 0;
right: 0;
height: 30px;
pointer-events: none;
z-index: 1;
}
.thinking-content-top {
top: 0;
background: linear-gradient(
to bottom,
var(--white) 0%,
rgba(255, 255, 255, 0) 100%
);
}
.thinking-content-bottom {
bottom: 0;
background: linear-gradient(
to top,
var(--white) 0%,
rgba(255, 255, 255, 0) 100%
);
}
}

View File

@@ -0,0 +1,67 @@
import clsx from "clsx";
import { useState, useRef, useEffect } from "react";
import { ChatMessage } from "../store";
import Locale from "../locales";
import styles from "./thinking-content.module.scss";
import MaxIcon from "../icons/max.svg";
import MinIcon from "../icons/min.svg";
export function ThinkingContent({ message }: { message: ChatMessage }) {
const [expanded, setExpanded] = useState(false);
const thinkingContentRef = useRef<HTMLDivElement>(null);
const thinkingContent = message.reasoningContent;
const isThinking =
message.streaming && thinkingContent && thinkingContent.length > 0;
// Auto-scroll to bottom of thinking container
useEffect(() => {
if (isThinking && thinkingContentRef.current) {
requestAnimationFrame(() => {
if (thinkingContentRef.current) {
thinkingContentRef.current.scrollTop =
thinkingContentRef.current.scrollHeight;
}
});
}
}, [thinkingContent, isThinking, expanded]);
if (!thinkingContent) return null;
return (
<div
className={clsx(
styles["thinking-container"],
expanded && styles["expanded"],
)}
>
<div className={styles["thinking-header"]}>
<div className={styles["thinking-title"]}>
{Locale.Chat.Thinking.Title}
</div>
<div
className={styles["thinking-toggle"]}
onClick={() => setExpanded(!expanded)}
>
{expanded ? <MinIcon /> : <MaxIcon />}
</div>
</div>
<div className={styles["thinking-content-wrapper"]}>
{!expanded && <div className={styles["thinking-content-top"]}></div>}
<div
className={clsx(
styles["thinking-content"],
expanded && styles["expanded"],
)}
ref={thinkingContentRef}
>
<div className={styles["thinking-content-text"]}>
{thinkingContent}
</div>
</div>
{!expanded && <div className={styles["thinking-content-bottom"]}></div>}
</div>
</div>
);
}