92 lines
2.5 KiB
TypeScript
92 lines
2.5 KiB
TypeScript
import hljs from "deps/hljs.ts";
|
|
|
|
export class ChatResponse {
|
|
element = (<article className="assistant" />);
|
|
|
|
currentLine: Text | undefined;
|
|
|
|
codeBlockContext: Element | undefined;
|
|
thinkingContext: HTMLDetailsElement | undefined;
|
|
|
|
currentContext(): Element {
|
|
if (this.codeBlockContext) return this.codeBlockContext;
|
|
if (this.thinkingContext) return this.thinkingContext;
|
|
return this.element;
|
|
}
|
|
|
|
finalizeLine() {
|
|
if (!this.currentLine?.textContent) return;
|
|
const line = this.currentLine.textContent;
|
|
|
|
if (!this.thinkingContext && line === "<think>") {
|
|
this.thinkingContext = (
|
|
<details open>
|
|
<summary>{`<think />`}</summary>
|
|
</details>
|
|
) as HTMLDetailsElement;
|
|
this.thinkingContext.dataset.inProgress = "";
|
|
this.element.append(this.thinkingContext);
|
|
this.currentLine.remove();
|
|
} else if (this.thinkingContext && line === "</think>") {
|
|
this.currentLine.remove();
|
|
this.thinkingContext.open = false;
|
|
delete this.thinkingContext.dataset.inProgress;
|
|
this.thinkingContext = undefined;
|
|
}
|
|
|
|
if (line.startsWith("```")) {
|
|
const remainder = line.substring(3).trimStart();
|
|
this.currentLine.remove();
|
|
|
|
if (!this.codeBlockContext) {
|
|
const pre = (
|
|
<pre>
|
|
<code className={`language-${remainder}`} />
|
|
</pre>
|
|
);
|
|
this.currentContext().append(pre);
|
|
this.codeBlockContext = pre.querySelector("code")!;
|
|
} else {
|
|
hljs.highlightElement(this.codeBlockContext as HTMLElement);
|
|
|
|
this.codeBlockContext = undefined;
|
|
this.currentContext().append(remainder);
|
|
}
|
|
}
|
|
}
|
|
|
|
append(text: string) {
|
|
const tokens = text
|
|
.split(/(\s+)/)
|
|
.flatMap(s => s.split(/(\n)/))
|
|
.filter(s => s);
|
|
for (const token of tokens) {
|
|
if (token === "\n") {
|
|
if (!this.currentLine) continue;
|
|
|
|
this.finalizeLine();
|
|
this.currentLine.appendData(token);
|
|
this.currentLine = undefined;
|
|
continue;
|
|
}
|
|
|
|
if (this.currentLine === undefined) {
|
|
this.currentLine = document.createTextNode(token);
|
|
this.currentContext().append(this.currentLine);
|
|
} else {
|
|
this.currentLine.appendData(token);
|
|
}
|
|
}
|
|
|
|
if (this.thinkingContext) {
|
|
this.thinkingContext.scrollTop =
|
|
this.thinkingContext.scrollHeight - this.thinkingContext.clientHeight;
|
|
}
|
|
}
|
|
|
|
finalize() {
|
|
this.finalizeLine();
|
|
|
|
// TODO: check if we have a dangling think section or code block and lift it back out
|
|
}
|
|
}
|