save work

This commit is contained in:
Red Adaya 2024-04-30 23:25:53 +08:00
parent 5e6cbf30e7
commit de81464082
3 changed files with 137 additions and 70 deletions

View File

@ -38,7 +38,7 @@
"monaco-editor": "0.48.0", "monaco-editor": "0.48.0",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"node-fetch": "^3.2.10", "node-fetch": "^3.2.10",
"overlayscrollbars": "^2.6.1", "overlayscrollbars": "^2.7.3",
"overlayscrollbars-react": "^0.5.5", "overlayscrollbars-react": "^0.5.5",
"papaparse": "^5.4.1", "papaparse": "^5.4.1",
"react": "^18.1.0", "react": "^18.1.0",

View File

@ -8,8 +8,7 @@ import { GlobalModel } from "@/models";
import { boundMethod } from "autobind-decorator"; import { boundMethod } from "autobind-decorator";
import { If, For } from "tsx-control-statements/components"; import { If, For } from "tsx-control-statements/components";
import { Markdown } from "@/elements"; import { Markdown } from "@/elements";
import * as appconst from "@/app/appconst"; import { OverlayScrollbars } from "overlayscrollbars";
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
import "./aichat.less"; import "./aichat.less";
@ -53,22 +52,141 @@ class AIChatKeybindings extends React.Component<{ AIChatObject: AIChat }, {}> {
} }
@mobxReact.observer @mobxReact.observer
class AIChat extends React.Component<{}, {}> { class ChatContent extends React.Component<{}, {}> {
chatListKeyCount: number = 0; chatListKeyCount: number = 0;
chatWindowScrollRef: React.RefObject<any>; containerRef: React.RefObject<HTMLDivElement> = React.createRef();
textAreaRef: React.RefObject<HTMLTextAreaElement>; chatWindowRef: React.RefObject<HTMLDivElement> = React.createRef();
osInstance: OverlayScrollbars = null;
componentDidMount() {
if (this.containerRef.current) {
this.osInstance = OverlayScrollbars(
this.containerRef.current,
{
scrollbars: { autoHide: "leave" },
},
{
initialized: (instance) => {
const { viewport } = instance.elements();
viewport.scrollTo({
behavior: "auto",
top: this.chatWindowRef.current.scrollHeight,
});
},
}
);
}
}
componentDidUpdate() {
if (this.containerRef?.current && this.osInstance) {
const { overflowAmount } = this.osInstance.state();
const { viewport } = this.osInstance.elements();
viewport.scrollTo({
behavior: "auto",
top: overflowAmount.y,
});
}
}
componentWillUnmount() {
if (this.osInstance) {
this.osInstance.destroy();
this.osInstance = null;
}
}
submitChatMessage(messageStr: string) {
const curLine = GlobalModel.inputModel.getCurLine();
const prtn = GlobalModel.submitChatInfoCommand(messageStr, curLine, false);
prtn.then((rtn) => {
if (!rtn.success) {
console.log("submit chat command error: " + rtn.error);
}
}).catch((_) => {});
}
getLinePos(elem: any): { numLines: number; linePos: number } {
const numLines = elem.value.split("\n").length;
const linePos = elem.value.substr(0, elem.selectionStart).split("\n").length;
return { numLines, linePos };
}
onTextAreaFocused(e: any) {
console.log("focused=====");
mobx.action(() => {
GlobalModel.inputModel.setAuxViewFocus(true);
})();
}
onTextAreaBlur(e: any) {
mobx.action(() => {
GlobalModel.inputModel.setAuxViewFocus(false);
})();
}
renderError(err: string): any {
return <div className="chat-msg-error">{err}</div>;
}
renderChatMessage(chatItem: OpenAICmdInfoChatMessageType): any {
const curKey = "chatmsg-" + this.chatListKeyCount;
this.chatListKeyCount++;
const senderClassName = chatItem.isassistantresponse ? "chat-msg-assistant" : "chat-msg-user";
const msgClassName = "chat-msg " + senderClassName;
let innerHTML: React.JSX.Element = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-user"></i>
</div>
<div className="msg-text">{chatItem.userquery}</div>
</>
);
if (chatItem.isassistantresponse) {
if (chatItem.assistantresponse.error != null && chatItem.assistantresponse.error != "") {
innerHTML = this.renderError(chatItem.assistantresponse.error);
} else {
innerHTML = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-sparkles"></i>
</div>
<Markdown text={chatItem.assistantresponse.message} codeSelect />
</>
);
}
}
return (
<div className={msgClassName} key={curKey}>
{innerHTML}
</div>
);
}
render() {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
const chitem: OpenAICmdInfoChatMessageType = null;
return (
<div ref={this.containerRef} className="content">
<div ref={this.chatWindowRef} className="chat-window">
<div className="filler"></div>
<For each="chitem" index="idx" of={chatMessageItems}>
{this.renderChatMessage(chitem)}
</For>
</div>
</div>
);
}
}
@mobxReact.observer
class AIChat extends React.Component<{}, {}> {
textAreaRef: React.RefObject<HTMLTextAreaElement> = React.createRef();
termFontSize: number = 14; termFontSize: number = 14;
constructor(props: any) {
super(props);
this.chatWindowScrollRef = React.createRef();
this.textAreaRef = React.createRef();
}
componentDidMount() { componentDidMount() {
const inputModel = GlobalModel.inputModel; const inputModel = GlobalModel.inputModel;
if (this.chatWindowScrollRef?.current != null) {
this.chatWindowScrollRef.current.scrollTop = this.chatWindowScrollRef.current.scrollHeight;
}
if (this.textAreaRef.current != null) { if (this.textAreaRef.current != null) {
this.textAreaRef.current.focus(); this.textAreaRef.current.focus();
// inputModel.setCmdInfoChatRefs(this.textAreaRef, this.chatWindowScrollRef); // inputModel.setCmdInfoChatRefs(this.textAreaRef, this.chatWindowScrollRef);
@ -77,13 +195,6 @@ class AIChat extends React.Component<{}, {}> {
this.onTextAreaChange(null); this.onTextAreaChange(null);
} }
componentDidUpdate() {
if (this.chatWindowScrollRef?.current != null) {
console.log("scrolling to bottom", this.chatWindowScrollRef.current.osInstance().scrollHeight);
this.chatWindowScrollRef.current.scrollTop = this.chatWindowScrollRef.current.scrollHeight;
}
}
requestChatUpdate() { requestChatUpdate() {
this.submitChatMessage(""); this.submitChatMessage("");
} }
@ -195,62 +306,18 @@ class AIChat extends React.Component<{}, {}> {
return <div className="chat-msg-error">{err}</div>; return <div className="chat-msg-error">{err}</div>;
} }
renderChatMessage(chatItem: OpenAICmdInfoChatMessageType): any {
const curKey = "chatmsg-" + this.chatListKeyCount;
this.chatListKeyCount++;
const senderClassName = chatItem.isassistantresponse ? "chat-msg-assistant" : "chat-msg-user";
const msgClassName = "chat-msg " + senderClassName;
let innerHTML: React.JSX.Element = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-user"></i>
</div>
<div className="msg-text">{chatItem.userquery}</div>
</>
);
if (chatItem.isassistantresponse) {
if (chatItem.assistantresponse.error != null && chatItem.assistantresponse.error != "") {
innerHTML = this.renderError(chatItem.assistantresponse.error);
} else {
innerHTML = (
<>
<div className="chat-msg-header">
<i className="fa-sharp fa-solid fa-sparkles"></i>
</div>
<Markdown text={chatItem.assistantresponse.message} codeSelect />
</>
);
}
}
return (
<div className={msgClassName} key={curKey}>
{innerHTML}
</div>
);
}
render() { render() {
const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice(); const chatMessageItems = GlobalModel.inputModel.AICmdInfoChatItems.slice();
const chitem: OpenAICmdInfoChatMessageType = null; console.log("chatMessageItems", chatMessageItems);
return ( return (
<div className="sidebar-aichat"> <div className="sidebar-aichat">
<AIChatKeybindings AIChatObject={this}></AIChatKeybindings> <AIChatKeybindings AIChatObject={this}></AIChatKeybindings>
<div className="titlebar"> <div className="titlebar">
<div className="title-string">Wave AI</div> <div className="title-string">Wave AI</div>
</div> </div>
<OverlayScrollbarsComponent <If condition={chatMessageItems.length > 0}>
ref={this.chatWindowScrollRef} <ChatContent />
className="content" </If>
options={{ scrollbars: { autoHide: "leave" } }}
>
<div className="chat-window">
<div className="filler"></div>
<For each="chitem" index="idx" of={chatMessageItems}>
{this.renderChatMessage(chitem)}
</For>
</div>
</OverlayScrollbarsComponent>
<div className="chat-input"> <div className="chat-input">
<textarea <textarea
key="main" key="main"

View File

@ -6938,7 +6938,7 @@ overlayscrollbars-react@^0.5.5:
resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.6.tgz#e9779f9fc2c1a3288570a45c83f8e42518bfb8c1" resolved "https://registry.yarnpkg.com/overlayscrollbars-react/-/overlayscrollbars-react-0.5.6.tgz#e9779f9fc2c1a3288570a45c83f8e42518bfb8c1"
integrity sha512-E5To04bL5brn9GVCZ36SnfGanxa2I2MDkWoa4Cjo5wol7l+diAgi4DBc983V7l2nOk/OLJ6Feg4kySspQEGDBw== integrity sha512-E5To04bL5brn9GVCZ36SnfGanxa2I2MDkWoa4Cjo5wol7l+diAgi4DBc983V7l2nOk/OLJ6Feg4kySspQEGDBw==
overlayscrollbars@^2.6.1: overlayscrollbars@^2.7.3:
version "2.7.3" version "2.7.3"
resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.7.3.tgz#68c18096c563391e37a2c7ca7463fbd03a945271" resolved "https://registry.yarnpkg.com/overlayscrollbars/-/overlayscrollbars-2.7.3.tgz#68c18096c563391e37a2c7ca7463fbd03a945271"
integrity sha512-HmNo8RPtuGUjBhUbVpZBHH7SHci5iSAdg5zSekCZVsjzaM6z8MIr3F9RXrzf4y7m+fOY0nx0+y0emr1fqQmfoA== integrity sha512-HmNo8RPtuGUjBhUbVpZBHH7SHci5iSAdg5zSekCZVsjzaM6z8MIr3F9RXrzf4y7m+fOY0nx0+y0emr1fqQmfoA==