diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/nodes/chatbot/agentsystem/Agent.ts | 15 | ||||
-rw-r--r-- | src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx | 472 |
2 files changed, 203 insertions, 284 deletions
diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts index a2a575f19..4d3f1e4e7 100644 --- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts +++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts @@ -1,25 +1,22 @@ import dotenv from 'dotenv'; import { XMLBuilder, XMLParser } from 'fast-xml-parser'; +import { escape } from 'lodash'; // Imported escape from lodash import OpenAI from 'openai'; import { ChatCompletionMessageParam } from 'openai/resources'; -import { escape } from 'lodash'; // Imported escape from lodash +import { DocumentOptions } from '../../../../documents/Documents'; import { AnswerParser } from '../response_parsers/AnswerParser'; import { StreamedAnswerParser } from '../response_parsers/StreamedAnswerParser'; +import { BaseTool } from '../tools/BaseTool'; import { CalculateTool } from '../tools/CalculateTool'; -import { CreateCSVTool } from '../tools/CreateCSVTool'; +import { CreateAnyDocumentTool } from '../tools/CreateAnyDocTool'; +import { CreateDocTool } from '../tools/CreateDocumentTool'; import { DataAnalysisTool } from '../tools/DataAnalysisTool'; import { NoTool } from '../tools/NoTool'; -import { RAGTool } from '../tools/RAGTool'; import { SearchTool } from '../tools/SearchTool'; -import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool'; +import { Parameter, ParametersType, TypeMap } from '../types/tool_types'; import { AgentMessage, ASSISTANT_ROLE, AssistantMessage, Observation, PROCESSING_TYPE, ProcessingInfo, TEXT_TYPE } from '../types/types'; import { Vectorstore } from '../vectorstore/Vectorstore'; import { getReactPrompt } from './prompts'; -import { BaseTool } from '../tools/BaseTool'; -import { Parameter, ParametersType, TypeMap } from '../types/tool_types'; -import { CreateDocTool } from '../tools/CreateDocumentTool'; -import { DocumentOptions } from '../../../../documents/Documents'; -import { CreateAnyDocumentTool } from '../tools/CreateAnyDocTool'; dotenv.config(); diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx index b89498d7d..83b50c8c6 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx @@ -14,12 +14,12 @@ import OpenAI, { ClientOptions } from 'openai'; import * as React from 'react'; import { v4 as uuidv4 } from 'uuid'; import { ClientUtils } from '../../../../../ClientUtils'; -import { Doc, DocListCast } from '../../../../../fields/Doc'; +import { Doc, DocListCast, Opt } from '../../../../../fields/Doc'; import { DocData, DocViews } from '../../../../../fields/DocSymbols'; -import { CsvCast, DocCast, PDFCast, RTFCast, StrCast, NumCast } from '../../../../../fields/Types'; +import { CsvCast, DocCast, NumCast, PDFCast, RTFCast, StrCast } from '../../../../../fields/Types'; import { Networking } from '../../../../Network'; import { DocUtils } from '../../../../documents/DocUtils'; -import { DocumentType } from '../../../../documents/DocumentTypes'; +import { CollectionViewType, DocumentType } from '../../../../documents/DocumentTypes'; import { Docs, DocumentOptions } from '../../../../documents/Documents'; import { DocumentManager } from '../../../../util/DocumentManager'; import { LinkManager } from '../../../../util/LinkManager'; @@ -33,7 +33,6 @@ import { Vectorstore } from '../vectorstore/Vectorstore'; import './ChatBox.scss'; import MessageComponentBox from './MessageComponent'; import { ProgressBar } from './ProgressBar'; -import { RichTextField } from '../../../../../fields/RichTextField'; dotenv.config(); @@ -45,17 +44,17 @@ dotenv.config(); @observer export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // MobX observable properties to track UI state and data - @observable history: AssistantMessage[] = []; - @observable.deep current_message: AssistantMessage | undefined = undefined; - @observable isLoading: boolean = false; - @observable uploadProgress: number = 0; - @observable currentStep: string = ''; - @observable expandedScratchpadIndex: number | null = null; - @observable inputValue: string = ''; - @observable private linked_docs_to_add: ObservableSet = observable.set(); - @observable private linked_csv_files: { filename: string; id: string; text: string }[] = []; - @observable private isUploadingDocs: boolean = false; - @observable private citationPopup: { text: string; visible: boolean } = { text: '', visible: false }; + @observable private _history: AssistantMessage[] = []; + @observable.deep private _current_message: AssistantMessage | undefined = undefined; + @observable private _isLoading: boolean = false; + @observable private _uploadProgress: number = 0; + @observable private _currentStep: string = ''; + @observable private _expandedScratchpadIndex: number | null = null; + @observable private _inputValue: string = ''; + @observable private _linked_docs_to_add: ObservableSet = observable.set(); + @observable private _linked_csv_files: { filename: string; id: string; text: string }[] = []; + @observable private _isUploadingDocs: boolean = false; + @observable private _citationPopup: { text: string; visible: boolean } = { text: '', visible: false }; // Private properties for managing OpenAI API, vector store, agent, and UI elements private openai: OpenAI; @@ -96,7 +95,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // Reaction to update dataDoc when chat history changes reaction( () => - this.history.map((msg: AssistantMessage) => ({ + this._history.map((msg: AssistantMessage) => ({ role: msg.role, content: msg.content, follow_up_questions: msg.follow_up_questions, @@ -115,20 +114,20 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @action addDocToVectorstore = async (newLinkedDoc: Doc) => { - this.uploadProgress = 0; - this.currentStep = 'Initializing...'; - this.isUploadingDocs = true; + this._uploadProgress = 0; + this._currentStep = 'Initializing...'; + this._isUploadingDocs = true; try { // Add the document to the vectorstore await this.vectorstore.addAIDoc(newLinkedDoc, this.updateProgress); } catch (error) { console.error('Error uploading document:', error); - this.currentStep = 'Error during upload'; + this._currentStep = 'Error during upload'; } finally { - this.isUploadingDocs = false; - this.uploadProgress = 0; - this.currentStep = ''; + this._isUploadingDocs = false; + this._uploadProgress = 0; + this._currentStep = ''; } }; @@ -139,8 +138,8 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @action updateProgress = (progress: number, step: string) => { - this.uploadProgress = progress; - this.currentStep = step; + this._uploadProgress = progress; + this._currentStep = step; }; /** @@ -177,7 +176,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const csvId = id ?? uuidv4(); // Add CSV details to linked files - this.linked_csv_files.push({ + this._linked_csv_files.push({ filename: CsvCast(newLinkedDoc.data).url.pathname, id: csvId, text: csvData, @@ -199,7 +198,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @action toggleToolLogs = (index: number) => { - this.expandedScratchpadIndex = this.expandedScratchpadIndex === index ? null : index; + this._expandedScratchpadIndex = this._expandedScratchpadIndex === index ? null : index; }; /** @@ -258,7 +257,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @action askGPT = async (event: React.FormEvent): Promise<void> => { event.preventDefault(); - this.inputValue = ''; + this._inputValue = ''; // Extract the user's message const textInput = (event.currentTarget as HTMLFormElement).elements.namedItem('messageInput') as HTMLInputElement; @@ -268,13 +267,13 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { try { textInput.value = ''; // Add the user's message to the history - this.history.push({ + this._history.push({ role: ASSISTANT_ROLE.USER, content: [{ index: 0, type: TEXT_TYPE.NORMAL, text: trimmedText, citation_ids: null }], processing_info: [], }); - this.isLoading = true; - this.current_message = { + this._isLoading = true; + this._current_message = { role: ASSISTANT_ROLE.ASSISTANT, content: [], citations: [], @@ -284,9 +283,9 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // Define callbacks for real-time processing updates const onProcessingUpdate = (processingUpdate: ProcessingInfo[]) => { runInAction(() => { - if (this.current_message) { - this.current_message = { - ...this.current_message, + if (this._current_message) { + this._current_message = { + ...this._current_message, processing_info: processingUpdate, }; } @@ -296,9 +295,9 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const onAnswerUpdate = (answerUpdate: string) => { runInAction(() => { - if (this.current_message) { - this.current_message = { - ...this.current_message, + if (this._current_message) { + this._current_message = { + ...this._current_message, content: [{ text: answerUpdate, type: TEXT_TYPE.NORMAL, index: 0, citation_ids: [] }], }; } @@ -310,22 +309,22 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // Update the history with the final assistant message runInAction(() => { - if (this.current_message) { - this.history.push({ ...finalMessage }); - this.current_message = undefined; - this.dataDoc.data = JSON.stringify(this.history); + if (this._current_message) { + this._history.push({ ...finalMessage }); + this._current_message = undefined; + this.dataDoc.data = JSON.stringify(this._history); } }); } catch (err) { console.error('Error:', err); // Handle error in processing - this.history.push({ + 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._isLoading = false; this.scrollToBottom(); } } @@ -339,8 +338,8 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @action updateMessageCitations = (index: number, citations: Citation[]) => { - if (this.history[index]) { - this.history[index].citations = citations; + if (this._history[index]) { + this._history[index].citations = citations; } }; @@ -381,17 +380,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * @param data The CSV data content. */ @action - createCSVInDash = async (url: string, title: string, id: string, data: string) => { - const doc = DocCast(await DocUtils.DocumentFromType('csv', url, { title: title, text: RTFCast(data) })); - - const linkDoc = Docs.Create.LinkDocument(this.Document, doc); - LinkManager.Instance.addLink(linkDoc); - - doc && this._props.addDocument?.(doc); - await DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, () => {}); - - this.addCSVForAnalysis(doc, id); - }; + createCSVInDash = (url: string, title: string, id: string, data: string) => + DocUtils.DocumentFromType('csv', url, { title: title, text: RTFCast(data) }).then(doc => { + if (doc) { + LinkManager.Instance.addLink(Docs.Create.LinkDocument(this.Document, doc)); + this._props.addDocument?.(doc); + DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, () => {}).then(() => this.addCSVForAnalysis(doc, id)); + } + }); /** * Creates a text document in the dashboard and adds it for analysis. @@ -401,40 +397,35 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * @param id The unique ID for the document. */ @action - private createCollectionWithChildren = async (data: any, insideCol: boolean): Promise<Doc[]> => { - // Create an array of promises for each document - const childDocPromises = data.map(async doc => { - const parsedDoc = doc; - if (parsedDoc.doc_type !== 'collection') { - // Handle non-collection documents - return await this.whichDoc(parsedDoc.doc_type, parsedDoc.data, { backgroundColor: parsedDoc.backgroundColor, _width: parsedDoc.width, _height: parsedDoc.height }, parsedDoc.id, insideCol); - } else { - // Recursively process collections - const nestedDocs = await this.createCollectionWithChildren(parsedDoc.data, true); - const collectionOptions: DocumentOptions = { - title: parsedDoc.title, - backgroundColor: parsedDoc.backgroundColor, - _width: parsedDoc.width, - _height: parsedDoc.height, - _layout_fitWidth: true, - _freeform_backgroundGrid: true, - }; - const collectionDoc = DocCast(Docs.Create.FreeformDocument(nestedDocs, collectionOptions)); - return collectionDoc; - } - }); - - // Await all child document creations concurrently - const nestedResults = await Promise.all(childDocPromises); - // Flatten any nested arrays from recursive collection calls - const childDocs = nestedResults.flat() as Doc[]; - childDocs.forEach(doc => { - console.log(DocCast(doc)); - console.log(DocCast(doc)[DocData].data); - console.log(DocCast(doc)[DocData].data); - }); - return childDocs; - }; + private createCollectionWithChildren = (data: { doc_type: string; id: string; data: any; title: string; width: number; height: number; backgroundColor: string }[], insideCol: boolean): Promise<Doc[]> => + Promise.all( + data.map(doc => + doc.doc_type !== 'collection' // Handle non-collection documents + ? this.whichDoc(doc.doc_type, doc.data, { backgroundColor: doc.backgroundColor, _width: doc.width, _height: doc.height }, doc.id, insideCol) + : // Recursively process collections + this.createCollectionWithChildren(doc.data, true).then(nestedDocs => + Docs.Create.FreeformDocument(nestedDocs, { + title: doc.title, + backgroundColor: doc.backgroundColor, + _width: doc.width, + _height: doc.height, + _layout_fitWidth: true, + _freeform_backgroundGrid: true, + }) + ) + ) + .flat() // prettier-ignore + ).then(childDocs => childDocs.filter(doc => doc).map(doc => doc!)); + // .then(nestedResults => { + // // Flatten any nested arrays from recursive collection calls + // const childDocs = nestedResults.flat() as Doc[]; + // childDocs.forEach(doc => { + // console.log(DocCast(doc)); + // console.log(DocCast(doc)[DocData].data); + // console.log(DocCast(doc)[DocData].data); + // }); + // return childDocs; + // }); // @action // createSingleFlashcard = (data: any, options: DocumentOptions) => { @@ -442,101 +433,53 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { // } @action - whichDoc = async (doc_type: string, data: string, options: DocumentOptions, id: string, insideCol: boolean): Promise<Doc> => { - let doc; - switch (doc_type) { - case 'text': - doc = DocCast(Docs.Create.TextDocument(data, options)); - break; - case 'flashcard': - doc = this.createFlashcard(data, options); - break; - case 'deck': - doc = this.createDeck(data, options); - break; - case 'image': - doc = DocCast(Docs.Create.ImageDocument(data, options)); - break; - case 'equation': - doc = DocCast(Docs.Create.EquationDocument(data, options)); - break; - case 'noteboard': - doc = DocCast(Docs.Create.NoteTakingDocument([], options)); - break; - case 'simulation': - doc = DocCast(Docs.Create.SimulationDocument(options)); - break; - case 'collection': { - const arr = await this.createCollectionWithChildren(data, true); - options._layout_fitWidth = true; - options._freeform_backgroundGrid = true; - if (options.type_collection == 'tree') { - doc = DocCast(Docs.Create.TreeDocument(arr, options)); - } else if (options.type_collection == 'masonry') { - doc = DocCast(Docs.Create.MasonryDocument(arr, options)); - } else if (options.type_collection == 'card') { - doc = DocCast(Docs.Create.CardDeckDocument(arr, options)); - } else if (options.type_collection == 'carousel') { - doc = DocCast(Docs.Create.CarouselDocument(arr, options)); - } else if (options.type_collection == '3d-carousel') { - doc = DocCast(Docs.Create.Carousel3DDocument(arr, options)); - } else if (options.type_collection == 'multicolumn') { - doc = DocCast(Docs.Create.CarouselDocument(arr, options)); - } else { - doc = DocCast(Docs.Create.FreeformDocument(arr, options)); - } - break; + whichDoc = (doc_type: string, data: string, options: DocumentOptions, id: string, insideCol: boolean): Promise<Opt<Doc>> => + (async () => { + switch (doc_type) { + case 'text': return Docs.Create.TextDocument(data, options); + case 'flashcard': return this.createFlashcard(data, options); + case 'deck': return this.createDeck(data, options); + case 'image': return Docs.Create.ImageDocument(data, options); + case 'equation': return Docs.Create.EquationDocument(data, options); + case 'noteboard': return Docs.Create.NoteTakingDocument([], options); + case 'simulation': return Docs.Create.SimulationDocument(options); + case 'collection': return this.createCollectionWithChildren(data as any, true). + then((arr, collOpts = { ...options, _layout_fitWidth: true, _freeform_backgroundGrid: true }) => + (() => { + switch (options.type_collection) { + case CollectionViewType.Tree: return Docs.Create.TreeDocument(arr, collOpts); + case CollectionViewType.Masonry: return Docs.Create.MasonryDocument(arr, collOpts); + case CollectionViewType.Card: return Docs.Create.CardDeckDocument(arr, collOpts); + case CollectionViewType.Carousel: return Docs.Create.CarouselDocument(arr, collOpts); + case CollectionViewType.Carousel3D: return Docs.Create.Carousel3DDocument(arr, collOpts); + case CollectionViewType.Multicolumn: return Docs.Create.CarouselDocument(arr, collOpts); + default: return Docs.Create.FreeformDocument(arr, collOpts); + } + })() + ); + case 'web': return Docs.Create.WebDocument(data, { ...options, data_useCors: true }); + case 'comparison': return this.createComparison(data, options); + case 'diagram': return Docs.Create.DiagramDocument(options); + case 'audio': return Docs.Create.AudioDocument(data, options); + case 'map': return Docs.Create.MapDocument([], options); + case 'screengrab': return Docs.Create.ScreenshotDocument(options); + case 'webcam': return Docs.Create.WebCamDocument('', options); + case 'button': return Docs.Create.ButtonDocument(options); + case 'script': return Docs.Create.ScriptingDocument(null, options); + case 'dataviz': return Docs.Create.DataVizDocument('/users/rz/Downloads/addresses.csv', options); + case 'chat': return Docs.Create.ChatDocument(options); + case 'trail': return Docs.Create.PresDocument(options); + case 'tab': return Docs.Create.FreeformDocument([], options); + case 'slide': return Docs.Create.TreeDocument([], options); + default: return Docs.Create.TextDocument(data, options); + } // prettier-ignore + })().then(doc => { + if (doc) { + doc.x = NumCast((options.x as number) ?? 0) + (insideCol ? 0 : NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc.width)) + 100; + doc.y = NumCast(options.y as number) + (insideCol ? 0 : NumCast(this.layoutDoc.y)); } - case 'web': - options.data_useCors = true; - doc = DocCast(Docs.Create.WebDocument(data, options)); - break; - case 'comparison': - doc = this.createComparison(data, options); - break; - case 'diagram': - doc = Docs.Create.DiagramDocument(options); - break; - case 'audio': - doc = Docs.Create.AudioDocument(data, options); - break; - case 'map': - doc = Docs.Create.MapDocument([], options); - break; - case 'screengrab': - doc = Docs.Create.ScreenshotDocument(options); - break; - case 'webcam': - doc = Docs.Create.WebCamDocument('', options); - break; - case 'button': - doc = Docs.Create.ButtonDocument(options); - break; - case 'script': - doc = Docs.Create.ScriptingDocument(null, options); - break; - case 'dataviz': - doc = Docs.Create.DataVizDocument('/users/rz/Downloads/addresses.csv', options); - break; - case 'chat': - doc = Docs.Create.ChatDocument(options); - break; - case 'trail': - doc = Docs.Create.PresDocument(options); - break; - case 'tab': - doc = Docs.Create.FreeformDocument([], options); - break; - case 'slide': - doc = Docs.Create.TreeDocument([], options); - break; - default: - doc = DocCast(Docs.Create.TextDocument(data, options)); - } - doc!.x = NumCast(options.x ?? 0) + (insideCol ? 0 : NumCast(this.layoutDoc.x) + NumCast(this.layoutDoc.width)) + 100; - doc!.y = NumCast(options.y) + (insideCol ? 0 : NumCast(this.layoutDoc.y)); - return doc; - }; + return doc; + }); /** * Creates a document in the dashboard. @@ -548,57 +491,42 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * @returns {Promise<void>} A promise that resolves once the document is created and displayed. */ @action - createDocInDash = async (doc_type: string, data: string | undefined, options: DocumentOptions, id: string) => { - let doc; - - switch (doc_type.toLowerCase()) { - case 'text': - doc = Docs.Create.TextDocument(data || '', options); - break; - case 'image': - doc = Docs.Create.ImageDocument(data || '', options); - break; - case 'pdf': - doc = Docs.Create.PdfDocument(data || '', options); - break; - case 'video': - doc = Docs.Create.VideoDocument(data || '', options); - break; - case 'audio': - doc = Docs.Create.AudioDocument(data || '', options); - break; - case 'web': - doc = Docs.Create.WebDocument(data || '', options); - break; - case 'equation': - doc = Docs.Create.EquationDocument(data || '', options); - break; - case 'functionplot': - case 'function_plot': - doc = Docs.Create.FunctionPlotDocument([], options); - break; - case 'dataviz': - case 'data_viz': { - const { fileUrl, id } = await Networking.PostToServer('/createCSV', { - filename: (options.title as string).replace(/\s+/g, '') + '.csv', - data: data, - }); - doc = Docs.Create.DataVizDocument(fileUrl, { ...options, text: RTFCast(data) }); - this.addCSVForAnalysis(doc, id); - break; + createDocInDash = (doc_type: string, data: string | undefined, options: DocumentOptions, id: string) => { + const linkAndShowDoc = (doc: Opt<Doc>) => { + if (doc) { + LinkManager.Instance.addLink(Docs.Create.LinkDocument(this.Document, doc)); + this._props.addDocument?.(doc); + DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, () => {}); } - case 'chat': - doc = Docs.Create.ChatDocument(options); - break; - // Add more cases for other document types - default: - console.error('Unknown or unsupported document type:', doc_type); - return; - } - const linkDoc = Docs.Create.LinkDocument(this.Document, doc); - LinkManager.Instance.addLink(linkDoc); - doc && this._props.addDocument?.(doc); - await DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, () => {}); + }; + const doc = (() => { + switch (doc_type.toLowerCase()) { + case 'text': return Docs.Create.TextDocument(data || '', options); + case 'image': return Docs.Create.ImageDocument(data || '', options); + case 'pdf': return Docs.Create.PdfDocument(data || '', options); + case 'video': return Docs.Create.VideoDocument(data || '', options); + case 'audio': return Docs.Create.AudioDocument(data || '', options); + case 'web': return Docs.Create.WebDocument(data || '', options); + case 'equation': return Docs.Create.EquationDocument(data || '', options); + case 'chat': return Docs.Create.ChatDocument(options); + case 'functionplot': + case 'function_plot': return Docs.Create.FunctionPlotDocument([], options); + case 'dataviz': + case 'data_viz': Networking.PostToServer('/createCSV', { + filename: (options.title as string).replace(/\s+/g, '') + '.csv', + data: data, + })?.then(({ fileUrl, id }) => { + const vdoc = Docs.Create.DataVizDocument(fileUrl, { ...options, text: RTFCast(data) }); + this.addCSVForAnalysis(vdoc, id); + linkAndShowDoc(vdoc); + }); + return undefined; + // Add more cases for other document types + default: console.error('Unknown or unsupported document type:', doc_type); + return undefined; + } // prettier-ignore + })(); + if (doc) linkAndShowDoc(doc); }; /** @@ -625,16 +553,13 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } // Create a carousel to contain the flashcard deck - const carouselDoc = DocCast( - Docs.Create.CarouselDocument(flashcardDeck, { - title: options.title || 'Flashcard Deck', - _width: options._width || 300, - _height: options._height || 300, - _layout_fitWidth: false, - _layout_autoHeight: true, - }) - ); - return carouselDoc; + return Docs.Create.CarouselDocument(flashcardDeck, { + title: options.title || 'Flashcard Deck', + _width: options._width || 300, + _height: options._height || 300, + _layout_fitWidth: false, + _layout_autoHeight: true, + }); }; /** @@ -662,8 +587,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const side2 = Docs.Create.CenteredTextCreator(back.title, back.data, sideOptions); // Create the flashcard document with both sides - const flashcardDoc = DocCast(Docs.Create.FlashcardDocument(data.title, side1, side2, sideOptions)); - return flashcardDoc; + return Docs.Create.FlashcardDocument(data.title, side1, side2, sideOptions); } }; @@ -675,15 +599,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * @returns {Doc} The created comparison document. */ @action - createComparison = (doc: any, options: any) => { - const comp = Docs.Create.ComparisonDocument(options.title, { _width: options.width, _height: options.height | 300, backgroundColor: options.backgroundColor }); - const [left, right] = doc; - const docLeft = DocCast(Docs.Create.TextDocument(left.data, { backgroundColor: left.backgroundColor, _width: left.width, _height: left.height })); - const docRight = DocCast(Docs.Create.TextDocument(right.data, { backgroundColor: right.backgroundColor, _width: right.width, _height: right.height })); - comp[DocData].data_back = docLeft; - comp[DocData].data_front = docRight; - return comp; - }; + createComparison = (doc: { left: any; right: any }, options: any) => + Docs.Create.ComparisonDocument(options.title, { + data_back: Docs.Create.TextDocument(doc.left.data, { backgroundColor: doc.left.backgroundColor, _width: doc.left.width, _height: doc.left.height }), + data_front: Docs.Create.TextDocument(doc.right.data, { backgroundColor: doc.right.backgroundColor, _width: doc.right.width, _height: doc.right.height }), + _width: options.width, + _height: options.height | 300, + backgroundColor: options.backgroundColor, + }); /** * Event handler to manage citations click in the message components. @@ -692,7 +615,6 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @action handleCitationClick = (citation: Citation) => { const currentLinkedDocs: Doc[] = this.linkedDocs; - const chunkId = citation.chunk_id; // Loop through the linked documents to find the matching chunk and handle its display @@ -727,8 +649,8 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } break; case CHUNK_TYPE.TEXT: - this.citationPopup = { text: citation.direct_text ?? 'No text available', visible: true }; - setTimeout(() => (this.citationPopup.visible = false), 3000); // Hide after 3 seconds + this._citationPopup = { text: citation.direct_text ?? 'No text available', visible: true }; + setTimeout(() => (this._citationPopup.visible = false), 3000); // Hide after 3 seconds DocumentManager.Instance.showDocument(doc, { willZoomCentered: true }, () => { const firstView = Array.from(doc[DocViews])[0] as DocumentView; @@ -796,7 +718,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { try { const storedHistory = JSON.parse(StrCast(this.dataDoc.data)); runInAction(() => { - this.history.push( + this._history.push( ...storedHistory.map((msg: AssistantMessage) => ({ role: msg.role, content: msg.content, @@ -811,7 +733,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } else { // Default welcome message runInAction(() => { - this.history.push({ + this._history.push({ role: ASSISTANT_ROLE.ASSISTANT, content: [ { @@ -835,11 +757,11 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { .filter(d => d); return linkedDocs; }, - linked => linked.forEach(doc => this.linked_docs_to_add.add(doc)) + linked => linked.forEach(doc => this._linked_docs_to_add.add(doc)) ); // Observe changes to linked documents and handle document addition - observe(this.linked_docs_to_add, change => { + observe(this._linked_docs_to_add, change => { if (change.type === 'add') { if (PDFCast(change.newValue.data)) { this.addDocToVectorstore(change.newValue); @@ -913,7 +835,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * Getter that retrieves all linked CSV files for analysis. */ @computed get linkedCSVs(): { filename: string; id: string; text: string }[] { - return this.linked_csv_files; + return this._linked_csv_files; } /** @@ -921,7 +843,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @computed get formattedHistory(): string { let history = '<chat_history>\n'; - for (const message of this.history) { + for (const message of this._history) { history += `<${message.role}>${message.content.map(content => content.text).join(' ')}`; if (message.loop_summary) { history += `<loop_summary>${message.loop_summary}</loop_summary>`; @@ -957,7 +879,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { */ @action handleFollowUpClick = (question: string) => { - this.inputValue = question; + this._inputValue = question; }; /** @@ -966,11 +888,11 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { render() { return ( <div className="chat-box"> - {this.isUploadingDocs && ( + {this._isUploadingDocs && ( <div className="uploading-overlay"> <div className="progress-container"> <ProgressBar /> - <div className="step-name">{this.currentStep}</div> + <div className="step-name">{this._currentStep}</div> </div> </div> )} @@ -978,18 +900,18 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { <h2>{this.userName()}'s AI Assistant</h2> </div> <div className="chat-messages" ref={this.messagesRef}> - {this.history.map((message, index) => ( + {this._history.map((message, index) => ( <MessageComponentBox key={index} message={message} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} /> ))} - {this.current_message && ( - <MessageComponentBox key={this.history.length} message={this.current_message} onFollowUpClick={this.handleFollowUpClick} onCitationClick={this.handleCitationClick} updateMessageCitations={this.updateMessageCitations} /> + {this._current_message && ( + <MessageComponentBox key={this._history.length} message={this._current_message} 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)} disabled={this.isLoading} /> - <button className="submit-button" type="submit" disabled={this.isLoading || !this.inputValue.trim()}> - {this.isLoading ? ( + <input type="text" name="messageInput" autoComplete="off" placeholder="Type your message here..." value={this._inputValue} onChange={e => (this._inputValue = e.target.value)} disabled={this._isLoading} /> + <button className="submit-button" type="submit" disabled={this._isLoading || !this._inputValue.trim()}> + {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"> @@ -1000,10 +922,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { </button> </form> {/* Popup for citation */} - {this.citationPopup.visible && ( + {this._citationPopup.visible && ( <div className="citation-popup"> <p> - <strong>Text from your document: </strong> {this.citationPopup.text} + <strong>Text from your document: </strong> {this._citationPopup.text} </p> </div> )} |