aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ChatBox/ChatBox.tsx
diff options
context:
space:
mode:
authorA.J. Shulman <Shulman.aj@gmail.com>2024-08-20 15:17:25 -0400
committerA.J. Shulman <Shulman.aj@gmail.com>2024-08-20 15:17:25 -0400
commit4c0c7794c85cfdbcd61a7ee5cb9a29494fd0444b (patch)
treeabf99fc24966e65a0e0db3f8e17ccb6edcff2d4c /src/client/views/nodes/ChatBox/ChatBox.tsx
parent4b6ce2ffcb82c1a7467ef7ed8b67b97094a8f6b6 (diff)
better styling, now thoughts and actions are hidden, scroll works better
next steps: - [ ] Ensure it doesn’t create more web documents when one already exists - [ ] Citations should not be rendered on the next line but on the same line as the text - [ ] If invalid XML, run get 3.5 to verify and fix XML based one examples - [ ] Making sure if you ask for other information, it doesn’t go to the same website. Providing website history in use rules for the search tool and website scraper tool or in the prompt directly
Diffstat (limited to 'src/client/views/nodes/ChatBox/ChatBox.tsx')
-rw-r--r--src/client/views/nodes/ChatBox/ChatBox.tsx101
1 files changed, 72 insertions, 29 deletions
diff --git a/src/client/views/nodes/ChatBox/ChatBox.tsx b/src/client/views/nodes/ChatBox/ChatBox.tsx
index 36416a330..4a98f8dc1 100644
--- a/src/client/views/nodes/ChatBox/ChatBox.tsx
+++ b/src/client/views/nodes/ChatBox/ChatBox.tsx
@@ -21,6 +21,8 @@ import { DocumentManager } from '../../../util/DocumentManager';
import { v4 as uuidv4 } from 'uuid';
import { chunk } from 'lodash';
import { DocUtils } from '../../../documents/DocUtils';
+import { createRef } from 'react';
+import { ClientUtils } from '../../../../ClientUtils';
dotenv.config();
@@ -37,10 +39,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@observable private linked_csv_files: { filename: string; id: string; text: string }[] = [];
private openai: OpenAI;
private vectorstore_id: string;
- private documents: AI_Document[] = [];
- private _oldWheel: any;
private vectorstore: Vectorstore;
private agent: Agent; // Add the ChatBot instance
+ private _oldWheel: HTMLDivElement | null = null;
+ private messagesRef: React.RefObject<HTMLDivElement>;
public static LayoutString(fieldKey: string) {
return FieldView.LayoutString(ChatBox, fieldKey);
@@ -59,6 +61,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
this.vectorstore = new Vectorstore(this.vectorstore_id, this.retrieveDocIds);
this.agent = new Agent(this.vectorstore, this.retrieveSummaries, this.retrieveFormattedHistory, this.retrieveCSVData, this.addLinkedUrlDoc);
+ this.messagesRef = React.createRef<HTMLDivElement>();
reaction(
() => this.history.map((msg: AssistantMessage) => ({ role: msg.role, content: msg.content, follow_up_questions: msg.follow_up_questions, citations: msg.citations })),
@@ -133,6 +136,23 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return new OpenAI(configuration);
}
+ addScrollListener = () => {
+ if (this.messagesRef.current) {
+ this.messagesRef.current.addEventListener('wheel', this.onPassiveWheel, { passive: false });
+ }
+ };
+
+ removeScrollListener = () => {
+ if (this.messagesRef.current) {
+ this.messagesRef.current.removeEventListener('wheel', this.onPassiveWheel);
+ }
+ };
+
+ scrollToBottom = () => {
+ if (this.messagesRef.current) {
+ }
+ };
+
onPassiveWheel = (e: WheelEvent) => {
if (this._props.isContentActive()) {
e.stopPropagation();
@@ -160,6 +180,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.current_message = { ...this.current_message, processing_info: update };
}
});
+ this.scrollToBottom();
};
const finalMessage = await this.agent.askAgent(trimmedText, onUpdate);
@@ -176,8 +197,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.history.push({ role: ASSISTANT_ROLE.ASSISTANT, content: [{ index: 0, type: TEXT_TYPE.ERROR, text: 'Sorry, I encountered an error while processing your request.', citation_ids: null }], processing_info: [] });
} finally {
this.isLoading = false;
+ this.scrollToBottom();
}
}
+ this.scrollToBottom();
};
@action
@@ -202,6 +225,11 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
doc.chunk_simpl = JSON.stringify({ chunks: [chunkToAdd] });
};
+ @computed
+ get userName() {
+ return ClientUtils.CurrentUserEmail;
+ }
+
@action
handleCitationClick = (citation: Citation) => {
console.log('Citation clicked:', citation);
@@ -276,6 +304,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return highlight_doc;
};
+ componentDidUpdate() {
+ this.scrollToBottom();
+ }
+
componentDidMount() {
this._props.setContentViewBox?.(this);
if (this.dataDoc.data) {
@@ -332,6 +364,11 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
console.log('Deleted docs: ', change.oldValue);
}
});
+ this.addScrollListener();
+ }
+
+ componentWillUnmount() {
+ this.removeScrollListener();
}
@computed
@@ -411,35 +448,41 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
render() {
return (
- <div className="chatBox">
- {this.isUploadingDocs && <div className="uploading-overlay"></div>}
- <div
- className="scroll-box chat-content"
- ref={r => {
- this._oldWheel?.removeEventListener('wheel', this.onPassiveWheel);
- this._oldWheel = r;
- r?.addEventListener('wheel', this.onPassiveWheel, { passive: false });
- }}>
- <div className="messages">
- {this.history.map((message, index) => (
- <MessageComponentBox key={index} message={message} index={index} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} />
- ))}
- {!this.current_message ? null : (
- <MessageComponentBox
- key={this.history.length}
- message={this.current_message}
- index={this.history.length}
- onFollowUpClick={this.handleFollowUpClick}
- onCitationClick={this.handleCitationClick}
- updateMessageCitations={this.updateMessageCitations}
- />
- )}
+ <div className="chat-box">
+ {this.isUploadingDocs && (
+ <div className="uploading-overlay">
+ <div className="spinner"></div>
</div>
+ )}
+ <div className="chat-header">
+ <h2>{this.userName()}'s AI Assistant</h2>
</div>
- <form onSubmit={this.askGPT} className="chat-form">
- <input type="text" name="messageInput" autoComplete="off" placeholder="Type a message..." value={this.inputValue} onChange={e => (this.inputValue = e.target.value)} />
- <button type="submit" disabled={this.isLoading}>
- {this.isLoading ? 'Thinking...' : 'Send'}
+ <div className="chat-messages" ref={this.messagesRef}>
+ {this.history.map((message, index) => (
+ <MessageComponentBox key={index} message={message} index={index} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} />
+ ))}
+ {this.current_message && (
+ <MessageComponentBox
+ key={this.history.length}
+ message={this.current_message}
+ index={this.history.length}
+ onFollowUpClick={this.handleFollowUpClick}
+ onCitationClick={this.handleCitationClick}
+ updateMessageCitations={this.updateMessageCitations}
+ />
+ )}
+ </div>
+ <form onSubmit={this.askGPT} className="chat-input">
+ <input type="text" name="messageInput" autoComplete="off" placeholder="Type your message here..." value={this.inputValue} onChange={e => (this.inputValue = e.target.value)} />
+ <button className="submit-button" type="submit" disabled={this.isLoading}>
+ {this.isLoading ? (
+ <div className="spinner"></div>
+ ) : (
+ <svg viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round">
+ <line x1="22" y1="2" x2="11" y2="13"></line>
+ <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
+ </svg>
+ )}
</button>
</form>
</div>