From 4c0c7794c85cfdbcd61a7ee5cb9a29494fd0444b Mon Sep 17 00:00:00 2001
From: "A.J. Shulman" <Shulman.aj@gmail.com>
Date: Tue, 20 Aug 2024 15:17:25 -0400
Subject: better styling, now thoughts and actions are hidden, scroll works
 better
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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
---
 src/client/views/nodes/ChatBox/ChatBox.tsx | 101 ++++++++++++++++++++---------
 1 file changed, 72 insertions(+), 29 deletions(-)

(limited to 'src/client/views/nodes/ChatBox/ChatBox.tsx')

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>
-- 
cgit v1.2.3-70-g09d2

