fix(chat): run assistant typewriter only once per message
This commit is contained in:
parent
ec63e28887
commit
7ce2857aff
@ -177,6 +177,7 @@ function filterAgentRoutingNoise(text: string): string {
|
|||||||
const IMAGE_DONE_SUMMARY = "已完成本次生成,如需微调可继续告诉我。";
|
const IMAGE_DONE_SUMMARY = "已完成本次生成,如需微调可继续告诉我。";
|
||||||
const ASSISTANT_TYPEWRITER_SECTION_REGEX =
|
const ASSISTANT_TYPEWRITER_SECTION_REGEX =
|
||||||
/(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】|###\s*输出设置|【\s*输出设置\s*】)/;
|
/(?:###\s*需求理解|【\s*需求理解\s*】|###\s*图片分析|【\s*图片分析\s*】|###\s*执行计划|【\s*执行计划\s*】|###\s*输出设置|【\s*输出设置\s*】)/;
|
||||||
|
const ASSISTANT_TYPEWRITER_STORAGE_KEY = "assistant-typewriter-completed-keys-v1";
|
||||||
const MODEL_BADGE_LINE_REGEX =
|
const MODEL_BADGE_LINE_REGEX =
|
||||||
/^\s*[◈◇◆🔹⬡✦•·]\s*([A-Za-z][A-Za-z0-9 .:+\-_/()]{2,})\s*$/im;
|
/^\s*[◈◇◆🔹⬡✦•·]\s*([A-Za-z][A-Za-z0-9 .:+\-_/()]{2,})\s*$/im;
|
||||||
const MODEL_BADGE_LINE_GLOBAL_REGEX =
|
const MODEL_BADGE_LINE_GLOBAL_REGEX =
|
||||||
@ -221,6 +222,60 @@ function shouldUseAssistantTypewriter(text: string): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const completedTypewriterKeys = new Set<string>();
|
const completedTypewriterKeys = new Set<string>();
|
||||||
|
let completedTypewriterKeysLoaded = false;
|
||||||
|
|
||||||
|
function loadCompletedTypewriterKeys() {
|
||||||
|
if (completedTypewriterKeysLoaded) return;
|
||||||
|
completedTypewriterKeysLoaded = true;
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const raw = window.localStorage.getItem(ASSISTANT_TYPEWRITER_STORAGE_KEY);
|
||||||
|
if (!raw) return;
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (!Array.isArray(parsed)) return;
|
||||||
|
parsed.forEach((key) => {
|
||||||
|
if (typeof key === "string" && key.trim()) {
|
||||||
|
completedTypewriterKeys.add(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function persistCompletedTypewriterKeys() {
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
try {
|
||||||
|
const keep = Array.from(completedTypewriterKeys).slice(-400);
|
||||||
|
window.localStorage.setItem(
|
||||||
|
ASSISTANT_TYPEWRITER_STORAGE_KEY,
|
||||||
|
JSON.stringify(keep)
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasCompletedTypewriter(typingKey: string) {
|
||||||
|
loadCompletedTypewriterKeys();
|
||||||
|
return completedTypewriterKeys.has(typingKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
function markTypewriterCompleted(typingKey: string) {
|
||||||
|
loadCompletedTypewriterKeys();
|
||||||
|
completedTypewriterKeys.add(typingKey);
|
||||||
|
if (completedTypewriterKeys.size > 450) {
|
||||||
|
const overflow = completedTypewriterKeys.size - 400;
|
||||||
|
const iterator = completedTypewriterKeys.values();
|
||||||
|
for (let i = 0; i < overflow; i += 1) {
|
||||||
|
const next = iterator.next();
|
||||||
|
if (next.done) break;
|
||||||
|
completedTypewriterKeys.delete(next.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
persistCompletedTypewriterKeys();
|
||||||
|
}
|
||||||
|
|
||||||
function AssistantTypewriter({
|
function AssistantTypewriter({
|
||||||
typingKey,
|
typingKey,
|
||||||
@ -232,9 +287,10 @@ function AssistantTypewriter({
|
|||||||
children: (displayText: string) => ReactNode;
|
children: (displayText: string) => ReactNode;
|
||||||
}) {
|
}) {
|
||||||
const content = String(text || "");
|
const content = String(text || "");
|
||||||
const [displayText, setDisplayText] = useState(() =>
|
const [displayText, setDisplayText] = useState(() => {
|
||||||
completedTypewriterKeys.has(typingKey) ? content : ""
|
if (typeof window === "undefined") return content;
|
||||||
);
|
return hasCompletedTypewriter(typingKey) ? content : "";
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
@ -242,7 +298,7 @@ function AssistantTypewriter({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completedTypewriterKeys.has(typingKey)) {
|
if (hasCompletedTypewriter(typingKey)) {
|
||||||
setDisplayText(content);
|
setDisplayText(content);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -259,7 +315,7 @@ function AssistantTypewriter({
|
|||||||
setDisplayText(content.slice(0, cursor));
|
setDisplayText(content.slice(0, cursor));
|
||||||
if (cursor >= content.length) {
|
if (cursor >= content.length) {
|
||||||
window.clearInterval(timer);
|
window.clearInterval(timer);
|
||||||
completedTypewriterKeys.add(typingKey);
|
markTypewriterCompleted(typingKey);
|
||||||
}
|
}
|
||||||
}, tickMs);
|
}, tickMs);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user