diff options
author | A.J. Shulman <Shulman.aj@gmail.com> | 2024-07-11 12:06:04 -0400 |
---|---|---|
committer | A.J. Shulman <Shulman.aj@gmail.com> | 2024-07-11 12:06:04 -0400 |
commit | f1cdfc1d02488c4a513fbf67f729f702526a345d (patch) | |
tree | 1f1145e4ecc7d00c77c66198003318f0fcc568b3 | |
parent | e0e4871224e626240dc899c653cd0eb9f54c3693 (diff) |
not working well (files don't get filename immediately_
-rw-r--r-- | src/client/documents/DocumentTypes.ts | 1 | ||||
-rw-r--r-- | src/client/documents/Documents.ts | 5 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/ChatBox.tsx | 36 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/MessageComponent.tsx | 33 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/CollectionTool.ts | 0 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/tools/RAGTool.ts | 9 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/vectorstore/VectorstoreUpload.ts | 45 |
7 files changed, 95 insertions, 34 deletions
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index 8f95068db..cb1625381 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -28,6 +28,7 @@ export enum DocumentType { DATAVIZ = 'dataviz', LOADING = 'loading', SIMULATION = 'simulation', // physics simulation + MESSAGE = 'message', // chat message // special purpose wrappers that either take no data or are compositions of lower level types LINK = 'link', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a67e6b4f6..ea5eca804 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -791,6 +791,11 @@ export namespace Docs { export function RTFDocument(field: RichTextField, options: DocumentOptions = {}, fieldKey: string = 'text') { return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey); } + + export function MessageDocument(field: string, options: DocumentOptions = {}, fieldKey: string = 'data') { + return InstanceFromProto(Prototypes.get(DocumentType.MESSAGE), field, options, undefined, fieldKey); + } + export function TextDocument(text: string, options: DocumentOptions = {}, fieldKey: string = 'text') { const rtf = { doc: { diff --git a/src/client/views/nodes/ChatBox/ChatBox.tsx b/src/client/views/nodes/ChatBox/ChatBox.tsx index 64ab2888b..9b2a92564 100644 --- a/src/client/views/nodes/ChatBox/ChatBox.tsx +++ b/src/client/views/nodes/ChatBox/ChatBox.tsx @@ -11,7 +11,7 @@ import { LinkManager } from '../../../util/LinkManager'; import { ViewBoxAnnotatableComponent } from '../../DocComponent'; import { FieldView, FieldViewProps } from '../FieldView'; import './ChatBox.scss'; -import MessageComponent from './MessageComponent'; +import MessageComponentBox from './MessageComponent'; import { ASSISTANT_ROLE, AssistantMessage, AI_Document, convertToAIDocument, Citation } from './types'; import { Vectorstore } from './vectorstore/VectorstoreUpload'; import { CollectionFreeFormDocumentView } from '../CollectionFreeFormDocumentView'; @@ -19,6 +19,7 @@ import { CollectionFreeFormView } from '../../collections/collectionFreeForm'; import { Agent } from './Agent'; import dotenv from 'dotenv'; import { DocData } from '../../../../fields/DocSymbols'; +import { DocumentView } from '../DocumentView'; dotenv.config(); @observer @@ -33,7 +34,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @observable inputValue: string = ''; @observable private _visibleDocs: Doc[] = []; private openai: OpenAI; - private vectorstore_id: string; + // private vectorstore_id: string; private documents: AI_Document[] = []; private _oldWheel: any; private vectorstore: Vectorstore; @@ -61,22 +62,8 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } @action - addAIDocs = async (visible_docs: Doc[]) => { - console.log('All Docs:', visible_docs); - visible_docs?.forEach(async doc => { - if (doc[DocData].ai_document) { - this.documents.push(convertToAIDocument(JSON.parse(StrCast(doc[DocData].ai_document)))); - } else { - const local_file_path: string = CsvCast(doc.data, PDFCast(doc.data))?.url?.pathname; - if (local_file_path) { - const { document_json } = await Networking.PostToServer('/createDocument', { file_path: local_file_path }); - const ai_document: AI_Document = convertToAIDocument(document_json); - this.documents.push(ai_document); - await this.vectorstore.addDocument(ai_document); - doc[DocData].ai_document = JSON.stringify(document_json); - } - } - }); + addDocsToVectorstore = async (visible_docs: Doc[]) => { + await this.vectorstore.addAIDocs(visible_docs); this.isInitializing = false; }; @@ -107,6 +94,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } }; + // getAssistantResponse() { + // return Docs.Create.MessageDocument(text, {}); + // } + @action askGPT = async (event: React.FormEvent<HTMLFormElement>): Promise<void> => { event.preventDefault(); @@ -241,7 +232,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { reaction( () => this.visibleDocs, visibleDocs => { - this._visibleDocs = visibleDocs; + this._visibleDocs.push(...visibleDocs.filter(visibleDoc => !this._visibleDocs.includes(visibleDoc))); } ); observe( @@ -255,7 +246,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { if ((change as any).addedCount > 0) { // maybe check here if its already in the urls datadoc array so doesn't add twice console.log((change as any).added as Doc[]); - this.addAIDocs((change as any).added as Doc[]); + this.addDocsToVectorstore((change as any).added as Doc[]); } // (change as any).removed.forEach((link: any) => remLinkFromDoc(toRealField(link))); break; @@ -295,10 +286,11 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }}> <div className="messages"> {this.history.map((message, index) => ( - <MessageComponent key={index} message={message} index={index} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} /> + //<DocumentView key={index} Document={message} index={index} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} /> + <MessageComponentBox key={index} message={message} index={index} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} /> ))} {this.current_message && ( - <MessageComponent + <MessageComponentBox key={this.history.length} message={this.current_message} index={this.history.length} diff --git a/src/client/views/nodes/ChatBox/MessageComponent.tsx b/src/client/views/nodes/ChatBox/MessageComponent.tsx index 91671a24a..38faf7e00 100644 --- a/src/client/views/nodes/ChatBox/MessageComponent.tsx +++ b/src/client/views/nodes/ChatBox/MessageComponent.tsx @@ -2,6 +2,8 @@ import React from 'react'; import { observer } from 'mobx-react'; import { AssistantMessage, CHUNK_TYPE, Citation } from './types'; import { TbInfoCircleFilled } from 'react-icons/tb'; +import { Docs } from '../../../documents/Documents'; +import { DocumentType } from '../../../documents/DocumentTypes'; interface MessageComponentProps { message: AssistantMessage; @@ -11,7 +13,18 @@ interface MessageComponentProps { updateMessageCitations: (index: number, citations: Citation[]) => void; } -const MessageComponent: React.FC<MessageComponentProps> = function ({ message, index, onFollowUpClick, onCitationClick, updateMessageCitations }) { +const MessageComponentBox: React.FC<MessageComponentProps> = function ({ message, index, onFollowUpClick, onCitationClick, updateMessageCitations }) { + // public static LayoutString(fieldKey: string) { + // return FieldView.LayoutString(MessageComponentBox, fieldKey); + // } + + // the presentation view that renders this slide + + // @computed + // get chatBoxView() { + // return this.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as ChatBox; + // } + const renderContent = (text: string) => { const citationRegex = /<citation chunk_id="([^"]*)" type="([^"]*)">([^<]*)<\/citation>/g; const parts = []; @@ -68,4 +81,20 @@ const MessageComponent: React.FC<MessageComponentProps> = function ({ message, i ); }; -export default observer(MessageComponent); +// Docs.Prototypes.TemplateMap.set(DocumentType.MESSAGE, { +// layout: { view: MessageComponentBox, dataField: 'data' }, +// options: { +// acl: '', +// _height: 35, +// _xMargin: 10, +// _yMargin: 10, +// _layout_nativeDimEditable: true, +// _layout_reflowVertical: true, +// _layout_reflowHorizontal: true, +// defaultDoubleClick: 'ignore', +// systemIcon: 'BsFileEarmarkTextFill', +// layout_borderRounding: '10px', +// }, +// }); + +export default observer(MessageComponentBox); diff --git a/src/client/views/nodes/ChatBox/tools/CollectionTool.ts b/src/client/views/nodes/ChatBox/tools/CollectionTool.ts new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/client/views/nodes/ChatBox/tools/CollectionTool.ts diff --git a/src/client/views/nodes/ChatBox/tools/RAGTool.ts b/src/client/views/nodes/ChatBox/tools/RAGTool.ts index 185efa0ba..36e4bc3ce 100644 --- a/src/client/views/nodes/ChatBox/tools/RAGTool.ts +++ b/src/client/views/nodes/ChatBox/tools/RAGTool.ts @@ -39,6 +39,7 @@ export class RAGTool extends BaseTool<{ hypothetical_document_chunk: string }> { !!!IMPORTANT Before you close the tag with </answer>, within the answer tags provide a set of 3 follow-up questions inside a <follow_up_questions> tag and individually within <question> tags. These should relate to the document, the current query, and the chat_history and should aim to help the user better understand whatever they are looking for. Also, ensure that the answer tags are wrapped with the correct step tags as well.`, + `Performs a RAG (Retrieval-Augmented Generation) search on user documents and returns a set of document chunks (either images or text) that can be used to provide a grounded response based on user documents @@ -49,6 +50,14 @@ export class RAGTool extends BaseTool<{ hypothetical_document_chunk: string }> { ); } + changeSummaries(summaries: string) { + this.briefSummary = `Performs a RAG (Retrieval-Augmented Generation) search on user documents and returns a set of document chunks (either images or text) that can be used to provide a grounded response based on user documents. + +!!!IMPORTANT Use the RAG tool ANYTIME the question may potentially (even if you are not sure) relate to one of the user's documents. +Here are the summaries of the user's documents: +${summaries}`; + } + async execute(args: { hypothetical_document_chunk: string }): Promise<any> { const relevantChunks = await this.vectorstore.retrieve(args.hypothetical_document_chunk); return this.getFormattedChunks(relevantChunks); diff --git a/src/client/views/nodes/ChatBox/vectorstore/VectorstoreUpload.ts b/src/client/views/nodes/ChatBox/vectorstore/VectorstoreUpload.ts index 1f483ad61..5e8e6b23a 100644 --- a/src/client/views/nodes/ChatBox/vectorstore/VectorstoreUpload.ts +++ b/src/client/views/nodes/ChatBox/vectorstore/VectorstoreUpload.ts @@ -3,7 +3,11 @@ import { CohereClient } from 'cohere-ai'; import { EmbedResponse } from 'cohere-ai/api'; import dotenv from 'dotenv'; -import { Chunk, AI_Document } from '../types'; +import { Chunk, AI_Document, convertToAIDocument } from '../types'; +import { Doc } from '../../../../../fields/Doc'; +import { DocData } from '../../../../../fields/DocSymbols'; +import { CsvCast, PDFCast, StrCast } from '../../../../../fields/Types'; +import { Networking } from '../../../../Network'; dotenv.config(); @@ -12,7 +16,7 @@ export class Vectorstore { private index!: Index; private cohere: CohereClient; private indexName: string = 'pdf-chatbot'; - private documents: AI_Document[] = []; + documents: AI_Document[] = []; constructor() { const pineconeApiKey = process.env.PINECONE_API_KEY; @@ -49,10 +53,35 @@ export class Vectorstore { this.index = this.pinecone.Index(this.indexName); } - async addDocument(document: AI_Document) { - this.documents.push(document); - await this.indexDocument(document); - console.log(`Document added: ${document.file_name}`); + async addAIDocs(visible_docs: Doc[]) { + console.log('All Docs:', visible_docs); + visible_docs?.forEach(async doc => { + await this.addAIDoc(doc); + }); + } + + async addAIDoc(doc: Doc) { + if (doc[DocData]?.ai_document) { + this.documents.push(convertToAIDocument(JSON.parse(StrCast(doc[DocData].ai_document)))); + console.log(`Document already added: ${doc[DocData].file_name}`); + } else { + console.log(doc); + const local_file_path: string = CsvCast(doc.data)?.url?.pathname ?? PDFCast(doc.data)?.url?.pathname; + console.log('Local File Path:', local_file_path); + if (local_file_path) { + const { document_json } = await Networking.PostToServer('/createDocument', { file_path: local_file_path }); + console.log('Document JSON:', document_json); + const ai_document: AI_Document = convertToAIDocument(document_json); + this.documents.push(ai_document); + await this.indexDocument(ai_document); + console.log(`Document added: ${ai_document.file_name}`); + doc[DocData].ai_document = JSON.stringify(document_json); + } + } + } + + getSummaries(): string { + return this.documents.map((doc, index) => `${index + 1}) ${doc.summary}`).join('\n') + '\n'; } private async indexDocument(document: AI_Document) { @@ -111,8 +140,4 @@ export class Vectorstore { return []; } } - - getSummaries(): string { - return this.documents.map((doc, index) => `${index + 1}) ${doc.summary}`).join('\n') + '\n'; - } } |