From d72977ad8b67f2575cad8aea988fcfa7c04f794a Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 21 Jan 2025 18:13:39 -0500 Subject: more attempts to cleanup typing, etc in chat box --- src/client/documents/DocumentTypes.ts | 2 +- src/client/documents/Documents.ts | 1 - .../views/nodes/chatbot/agentsystem/Agent.ts | 13 +- .../nodes/chatbot/chatboxcomponents/ChatBox.tsx | 114 ++++++++-------- .../views/nodes/chatbot/tools/CreateAnyDocTool.ts | 145 +++++++++------------ .../nodes/chatbot/tools/CreateDocumentTool.ts | 33 ++--- 6 files changed, 145 insertions(+), 163 deletions(-) (limited to 'src') diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts index efe73fbbe..8aa844c0b 100644 --- a/src/client/documents/DocumentTypes.ts +++ b/src/client/documents/DocumentTypes.ts @@ -26,7 +26,7 @@ export enum DocumentType { SCRIPTING = 'script', // script editor CHAT = 'chat', // chat with GPT about files EQUATION = 'equation', // equation editor - FUNCPLOT = 'funcplot', // function plotter + FUNCPLOT = 'function plot', // function plotter MAP = 'map', DATAVIZ = 'dataviz', ANNOPALETTE = 'annopalette', diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 0bff74ac1..7f1387ff8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -19,7 +19,6 @@ import { DocServer } from '../DocServer'; import { dropActionType } from '../util/DropActionTypes'; import { CollectionViewType, DocumentType } from './DocumentTypes'; import { Id } from '../../fields/FieldSymbols'; -import { FireflyImageData } from '../views/smartdraw/FireflyConstants'; class EmptyBox { public static LayoutString() { diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts index 4d3f1e4e7..ee91ccb92 100644 --- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts +++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts @@ -8,7 +8,7 @@ import { AnswerParser } from '../response_parsers/AnswerParser'; import { StreamedAnswerParser } from '../response_parsers/StreamedAnswerParser'; import { BaseTool } from '../tools/BaseTool'; import { CalculateTool } from '../tools/CalculateTool'; -import { CreateAnyDocumentTool } from '../tools/CreateAnyDocTool'; +import { CreateAnyDocumentTool, supportedDocumentTypes } from '../tools/CreateAnyDocTool'; import { CreateDocTool } from '../tools/CreateDocumentTool'; import { DataAnalysisTool } from '../tools/DataAnalysisTool'; import { NoTool } from '../tools/NoTool'; @@ -55,7 +55,8 @@ export class Agent { history: () => string, csvData: () => { filename: string; id: string; text: string }[], addLinkedUrlDoc: (url: string, id: string) => void, - addLinkedDoc: (doc_type: string, data: string | undefined, options: DocumentOptions, id: string) => void, + addLinkedDoc: (doc_type: supportedDocumentTypes, data: unknown, options: DocumentOptions, id: string) => void, + // eslint-disable-next-line @typescript-eslint/no-unused-vars createCSVInDash: (url: string, title: string, id: string, data: string) => void ) { // Initialize OpenAI client with API key from environment @@ -134,6 +135,7 @@ export class Agent { console.log(this.interMessages); console.log(`Turn ${i}/${maxTurns}`); + // eslint-disable-next-line no-await-in-loop const result = await this.execute(onProcessingUpdate, onAnswerUpdate); this.interMessages.push({ role: 'assistant', content: result }); @@ -195,6 +197,7 @@ export class Agent { if (currentAction) { try { // Process the action with its input + // eslint-disable-next-line no-await-in-loop const observation = (await this.processAction(currentAction, actionInput.inputs)) as Observation[]; const nextPrompt = [{ type: 'text', text: ` ` }, ...observation, { type: 'text', text: '' }] as Observation[]; console.log(observation); @@ -299,7 +302,7 @@ export class Agent { * @param response The parsed XML response from the assistant. * @throws An error if the response does not meet the expected structure. */ - private validateAssistantResponse(response: any) { + private validateAssistantResponse(response: { stage: { [key: string]: object | string } }) { if (!response.stage) { throw new Error('Response does not contain a element'); } @@ -342,7 +345,7 @@ export class Agent { // If 'action_input' is present, validate its structure if ('action_input' in stage) { - const actionInput = stage.action_input; + const actionInput = stage.action_input as object; if (!('action_input_description' in actionInput) || typeof actionInput.action_input_description !== 'string') { throw new Error('action_input must contain an action_input_description string'); @@ -357,7 +360,7 @@ export class Agent { // If 'answer' is present, validate its structure if ('answer' in stage) { - const answer = stage.answer; + const answer = stage.answer as object; // Ensure answer contains at least one of the required elements if (!('grounded_text' in answer || 'normal_text' in answer)) { diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx index 83b50c8c6..076f49831 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx @@ -14,7 +14,7 @@ import OpenAI, { ClientOptions } from 'openai'; import * as React from 'react'; import { v4 as uuidv4 } from 'uuid'; import { ClientUtils } from '../../../../../ClientUtils'; -import { Doc, DocListCast, Opt } from '../../../../../fields/Doc'; +import { Doc, DocListCast, FieldType, Opt } from '../../../../../fields/Doc'; import { DocData, DocViews } from '../../../../../fields/DocSymbols'; import { CsvCast, DocCast, NumCast, PDFCast, RTFCast, StrCast } from '../../../../../fields/Types'; import { Networking } from '../../../../Network'; @@ -324,7 +324,9 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { processing_info: [], }); } finally { - this._isLoading = false; + runInAction(() => { + this._isLoading = false; + }); this.scrollToBottom(); } } @@ -402,19 +404,17 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { 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 + : 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, + }) + ) + ) // prettier-ignore ).then(childDocs => childDocs.filter(doc => doc).map(doc => doc!)); // .then(nestedResults => { // // Flatten any nested arrays from recursive collection calls @@ -427,23 +427,18 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { // return childDocs; // }); - // @action - // createSingleFlashcard = (data: any, options: DocumentOptions) => { - - // } - @action - whichDoc = (doc_type: string, data: string, options: DocumentOptions, id: string, insideCol: boolean): Promise> => + whichDoc = (doc_type: string, data: unknown, options: DocumentOptions, id: string, insideCol: boolean): Promise> => (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 'text': return Docs.Create.TextDocument(data as string, options); + case 'flashcard': return this.createFlashcard(data as string[], options); + case 'deck': return this.createDeck(data as string, options); + case 'image': return Docs.Create.ImageDocument(data as string, options); + case 'equation': return Docs.Create.EquationDocument(data as string, options); case 'noteboard': return Docs.Create.NoteTakingDocument([], options); case 'simulation': return Docs.Create.SimulationDocument(options); - case 'collection': return this.createCollectionWithChildren(data as any, true). + case 'collection': return this.createCollectionWithChildren(data as { doc_type: string; id: string; data: any; title: string; width: number; height: number; backgroundColor: string }[] , true). then((arr, collOpts = { ...options, _layout_fitWidth: true, _freeform_backgroundGrid: true }) => (() => { switch (options.type_collection) { @@ -457,10 +452,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { } })() ); - case 'web': return Docs.Create.WebDocument(data, { ...options, data_useCors: true }); - case 'comparison': return this.createComparison(data, options); + case 'web': return Docs.Create.WebDocument(data as string, { ...options, data_useCors: true }); + case 'comparison': return this.createComparison(data as {left: {width:number ,height: number, backgroundColor: string, data: string}, right: {width:number ,height: number, backgroundColor: string, data: string}}, options); case 'diagram': return Docs.Create.DiagramDocument(options); - case 'audio': return Docs.Create.AudioDocument(data, options); + case 'audio': return Docs.Create.AudioDocument(data as string, options); case 'map': return Docs.Create.MapDocument([], options); case 'screengrab': return Docs.Create.ScreenshotDocument(options); case 'webcam': return Docs.Create.WebCamDocument('', options); @@ -471,7 +466,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { 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); + default: return Docs.Create.TextDocument(data as string, options); } // prettier-ignore })().then(doc => { if (doc) { @@ -491,7 +486,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { * @returns {Promise} A promise that resolves once the document is created and displayed. */ @action - createDocInDash = (doc_type: string, data: string | undefined, options: DocumentOptions, id: string) => { + createDocInDash = (doc_type: string, data: unknown, options: DocumentOptions /*, id: string */) => { const linkAndShowDoc = (doc: Opt) => { if (doc) { LinkManager.Instance.addLink(Docs.Create.LinkDocument(this.Document, doc)); @@ -501,22 +496,21 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { }; 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 'flashcard': return this.createFlashcard(data as string[], options); + case 'text': return Docs.Create.TextDocument(data as string || '', options); + case 'image': return Docs.Create.ImageDocument(data as string || '', options); + case 'pdf': return Docs.Create.PdfDocument(data as string || '', options); + case 'video': return Docs.Create.VideoDocument(data as string || '', options); + case 'audio': return Docs.Create.AudioDocument(data as string || '', options); + case 'web': return Docs.Create.WebDocument(data as string || '', options); + case 'equation': return Docs.Create.EquationDocument(data as string || '', 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', { + case 'functionplot': return Docs.Create.FunctionPlotDocument([], options); + case 'dataviz': 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) }); + const vdoc = Docs.Create.DataVizDocument(fileUrl, { ...options, text: RTFCast(data as FieldType) }); this.addCSVForAnalysis(vdoc, id); linkAndShowDoc(vdoc); }); @@ -537,14 +531,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { * @returns {Doc} A carousel document containing the flashcard deck. */ @action - createDeck = (data: any, options: DocumentOptions) => { + createDeck = (data: string | unknown[], options: DocumentOptions) => { const flashcardDeck: Doc[] = []; // Parse `data` only if it’s a string - const deckData = typeof data === 'string' ? JSON.parse(data) : data; - const flashcardArray = Array.isArray(deckData) ? deckData : Object.values(deckData); + const deckData = typeof data === 'string' ? (JSON.parse(data) as unknown) : data; + const flashcardArray = Array.isArray(deckData) ? deckData : Object.values(deckData as object); // Process each flashcard document in the `deckData` array if (flashcardArray.length == 2 && flashcardArray[0].doc_type == 'text' && flashcardArray[1].doc_type == 'text') { - this.createFlashcard(flashcardArray, options); + this.createFlashcard(flashcardArray as string[], options); } else { flashcardArray.forEach(doc => { const flashcardDoc = this.createFlashcard(doc, options); @@ -570,24 +564,24 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { * @returns {Doc | undefined} The created flashcard document, or undefined if the flashcard cannot be created. */ @action - createFlashcard = (data: any, options: any) => { + createFlashcard = (data: string[], options: DocumentOptions) => { const deckData = typeof data === 'string' ? JSON.parse(data) : data; - const flashcardArray = Array.isArray(deckData) ? deckData : Object.values(deckData)[2]; + const flashcardArray = Array.isArray(deckData) ? deckData : (Object.values(deckData)[2] as string[]); const [front, back] = flashcardArray; - if (front.doc_type === 'text' && back.doc_type === 'text') { + if (typeof front === 'string' && typeof back === 'string') { const sideOptions: DocumentOptions = { backgroundColor: options.backgroundColor, _width: options._width, - _height: options._height, + _height: options._height || 300, }; // Create front and back text documents - const side1 = Docs.Create.CenteredTextCreator(front.title, front.data, sideOptions); - const side2 = Docs.Create.CenteredTextCreator(back.title, back.data, sideOptions); + const side1 = Docs.Create.CenteredTextCreator('question', front, sideOptions); + const side2 = Docs.Create.CenteredTextCreator('answer', back, sideOptions); // Create the flashcard document with both sides - return Docs.Create.FlashcardDocument(data.title, side1, side2, sideOptions); + return Docs.Create.FlashcardDocument('flashcard', side1, side2, sideOptions); } }; @@ -599,12 +593,12 @@ export class ChatBox extends ViewBoxAnnotatableComponent() { * @returns {Doc} The created comparison document. */ @action - createComparison = (doc: { left: any; right: any }, options: any) => - Docs.Create.ComparisonDocument(options.title, { + createComparison = (doc: { left: { width: number; height: number; backgroundColor: string; data: string }; right: { width: number; height: number; backgroundColor: string; data: string } }, options: DocumentOptions) => + Docs.Create.ComparisonDocument(options.title as string, { 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, + _width: options._width, + _height: options._height || 300, backgroundColor: options.backgroundColor, }); @@ -909,7 +903,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent() {
- (this._inputValue = e.target.value)} disabled={this._isLoading} /> + (this._inputValue = e.target.value))} disabled={this._isLoading} />