diff options
Diffstat (limited to 'src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts')
-rw-r--r-- | src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts new file mode 100644 index 000000000..284879a4a --- /dev/null +++ b/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts @@ -0,0 +1,497 @@ +import { BaseTool } from './BaseTool'; +import { Observation } from '../types/types'; +import { Parameter, ParametersType, ToolInfo } from '../types/tool_types'; +import { parsedDoc } from '../chatboxcomponents/ChatBox'; +import { CollectionViewType } from '../../../../documents/DocumentTypes'; + +/** + * List of supported document types that can be created via text LLM. + */ +export enum supportedDocTypes { + flashcard = 'flashcard', + text = 'text', + html = 'html', + equation = 'equation', + functionplot = 'functionplot', + dataviz = 'dataviz', + notetaking = 'notetaking', + audio = 'audio', + video = 'video', + pdf = 'pdf', + rtf = 'rtf', + message = 'message', + collection = 'collection', + image = 'image', + deck = 'deck', + web = 'web', + comparison = 'comparison', + diagram = 'diagram', + script = 'script', +} +/** + * Tthe CreateDocTool class is responsible for creating + * documents of various types (e.g., text, flashcards, collections) and organizing them in a + * structured manner. The tool supports creating dashboards with diverse document types and + * ensures proper placement of documents without overlap. + */ + +// Example document structure for various document types +const example = [ + { + doc_type: supportedDocTypes.equation, + title: 'quadratic', + data: 'x^2 + y^2 = 3', + _width: 300, + _height: 300, + x: 0, + y: 0, + }, + { + doc_type: supportedDocTypes.collection, + title: 'Advanced Biology', + data: [ + { + doc_type: supportedDocTypes.text, + title: 'Cell Structure', + data: 'Cells are the basic building blocks of all living organisms.', + _width: 300, + _height: 300, + x: 500, + y: 0, + }, + ], + backgroundColor: '#00ff00', + _width: 600, + _height: 600, + x: 600, + y: 0, + type_collection: 'tree', + }, + { + doc_type: supportedDocTypes.image, + title: 'experiment', + data: 'https://plus.unsplash.com/premium_photo-1694819488591-a43907d1c5cc?q=80&w=2628&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D', + _width: 300, + _height: 300, + x: 600, + y: 300, + }, + { + doc_type: supportedDocTypes.deck, + title: 'Chemistry', + data: [ + { + doc_type: supportedDocTypes.flashcard, + title: 'Photosynthesis', + data: [ + { + doc_type: supportedDocTypes.text, + title: 'front_Photosynthesis', + data: 'What is photosynthesis?', + _width: 300, + _height: 300, + x: 100, + y: 600, + }, + { + doc_type: supportedDocTypes.text, + title: 'back_photosynthesis', + data: 'The process by which plants make food.', + _width: 300, + _height: 300, + x: 100, + y: 700, + }, + ], + backgroundColor: '#00ff00', + _width: 300, + _height: 300, + x: 300, + y: 1000, + }, + { + doc_type: supportedDocTypes.flashcard, + title: 'Photosynthesis', + data: [ + { + doc_type: supportedDocTypes.text, + title: 'front_Photosynthesis', + data: 'What is photosynthesis?', + _width: 300, + _height: 300, + x: 200, + y: 800, + }, + { + doc_type: supportedDocTypes.text, + title: 'back_photosynthesis', + data: 'The process by which plants make food.', + _width: 300, + _height: 300, + x: 100, + y: -100, + }, + ], + backgroundColor: '#00ff00', + _width: 300, + _height: 300, + x: 10, + y: 70, + }, + ], + backgroundColor: '#00ff00', + _width: 600, + _height: 600, + x: 200, + y: 800, + }, + { + doc_type: supportedDocTypes.web, + title: 'Brown University Wikipedia', + data: 'https://en.wikipedia.org/wiki/Brown_University', + _width: 300, + _height: 300, + x: 1000, + y: 2000, + }, + { + doc_type: supportedDocTypes.comparison, + title: 'WWI vs. WWII', + data: [ + { + doc_type: supportedDocTypes.text, + title: 'WWI', + data: 'From 1914 to 1918, fighting took place across several continents, at sea and, for the first time, in the air.', + _width: 300, + _height: 300, + x: 100, + y: 100, + }, + { + doc_type: supportedDocTypes.text, + title: 'WWII', + data: 'A devastating global conflict spanning from 1939 to 1945, saw the Allied powers fight against the Axis powers.', + _width: 300, + _height: 300, + x: 100, + y: 100, + }, + ], + _width: 300, + _height: 300, + x: 100, + y: 100, + }, + { + doc_type: supportedDocTypes.collection, + title: 'Science Collection', + data: [ + { + doc_type: supportedDocTypes.flashcard, + title: 'Photosynthesis', + data: [ + { + doc_type: supportedDocTypes.text, + title: 'front_Photosynthesis', + data: 'What is photosynthesis?', + _width: 300, + _height: 300, + }, + { + doc_type: supportedDocTypes.text, + title: 'back_photosynthesis', + data: 'The process by which plants make food.', + _width: 300, + _height: 300, + }, + ], + backgroundColor: '#00ff00', + _width: 300, + _height: 300, + }, + { + doc_type: supportedDocTypes.web, + title: 'Brown University Wikipedia', + data: 'https://en.wikipedia.org/wiki/Brown_University', + _width: 300, + _height: 300, + x: 1100, + y: 1100, + }, + { + doc_type: supportedDocTypes.text, + title: 'Water Cycle', + data: 'The continuous movement of water on, above, and below the Earth’s surface.', + _width: 300, + _height: 300, + x: 1500, + y: 500, + }, + { + doc_type: supportedDocTypes.collection, + title: 'Advanced Biology', + data: [ + { + doc_type: 'text', + title: 'Cell Structure', + data: 'Cells are the basic building blocks of all living organisms.', + _width: 300, + _height: 300, + }, + ], + backgroundColor: '#00ff00', + _width: 600, + _height: 600, + x: 1100, + y: 500, + type_collection: 'stacking', + }, + ], + _width: 600, + _height: 600, + x: 500, + y: 500, + type_collection: 'carousel', + }, +]; + +// Stringify the entire structure for transmission if needed +const finalJsonString = JSON.stringify(example); + +const standardOptions = ['title', 'backgroundColor']; +/** + * Description of document options and data field for each type. + */ +const documentTypesInfo: { [key in supportedDocTypes]: { options: string[]; dataDescription: string } } = { + comparison: { + options: [...standardOptions, 'fontColor', 'text_align'], + dataDescription: 'an array of two documents of any kind that can be compared.', + }, + deck: { + options: [...standardOptions, 'fontColor', 'text_align'], + dataDescription: 'an array of flashcard docs', + }, + flashcard: { + options: [...standardOptions, 'fontColor', 'text_align'], + dataDescription: 'an array of two strings. the first string contains a question, and the second string contains an answer', + }, + text: { + options: [...standardOptions, 'fontColor', 'text_align'], + dataDescription: 'The text content of the document.', + }, + web: { + options: [], + dataDescription: 'A URL to a webpage. Example: https://en.wikipedia.org/wiki/Brown_University', + }, + html: { + options: [], + dataDescription: 'The HTML-formatted text content of the document.', + }, + equation: { + options: [...standardOptions, 'fontColor'], + dataDescription: 'The equation content represented as a MathML string.', + }, + functionplot: { + options: [...standardOptions, 'function_definition'], + dataDescription: 'The function definition(s) for plotting. Provide as a string or array of function definitions.', + }, + dataviz: { + options: [...standardOptions, 'chartType'], + dataDescription: 'A string of comma-separated values representing the CSV data.', + }, + notetaking: { + options: standardOptions, + dataDescription: 'An array of related text documents with small amounts of text.', + }, + rtf: { + options: standardOptions, + dataDescription: 'The rich text content in RTF format.', + }, + image: { + options: standardOptions, + dataDescription: `A url string that must end with '.png', '.jpeg', '.gif', or '.jpg'`, + }, + pdf: { + options: standardOptions, + dataDescription: 'the pdf content as a PDF file url.', + }, + audio: { + options: standardOptions, + dataDescription: 'The audio content as a file url.', + }, + video: { + options: standardOptions, + dataDescription: 'The video content as a file url.', + }, + message: { + options: standardOptions, + dataDescription: 'The message content of the document.', + }, + diagram: { + options: standardOptions, + dataDescription: 'diagram content as a text string in Mermaid format.', + }, + script: { + options: standardOptions, + dataDescription: 'The compilable JavaScript code. Use this for creating scripts.', + }, + collection: { + options: [...standardOptions, 'type_collection'], + dataDescription: 'A collection of Docs represented as an array.', + }, +}; + +// Parameters for creating individual documents +const createDocToolParams: { name: string; type: 'string' | 'number' | 'boolean' | 'string[]' | 'number[]'; description: string; required: boolean }[] = [ + { + name: 'data', + type: 'string', // Accepts either string or array, supporting individual and nested data + description: + 'the data that describes the Document contents. For collections this is an' + + `Array of documents in stringified JSON format. Each item in the array should be an individual stringified JSON object. ` + + `Creates any type of document with the provided options and data. Supported document types are: ${Object.keys(documentTypesInfo).join(', ')}. + dataviz is a csv table tool, so for CSVs, use dataviz. Here are the options for each type: + <supported_document_types>` + + Object.entries(documentTypesInfo) + .map( + ([doc_type, info]) => + `<document_type name="${doc_type}"> + <data_description>${info.dataDescription}</data_description> + <options>` + + info.options.map(option => `<option>${option}</option>`).join('\n') + + ` + </options> + </document_type>` + ) + .join('\n') + + `</supported_document_types> An example of the structure of a collection is:` + + finalJsonString, // prettier-ignore, + required: true, + }, + { + name: 'doc_type', + type: 'string', + description: `The type of the document. Options: ${Object.keys(documentTypesInfo).join(',')}.`, + required: true, + }, + { + name: 'title', + type: 'string', + description: 'The title of the document.', + required: true, + }, + { + name: 'x', + type: 'number', + description: 'The x location of the document; 0 <= x.', + required: true, + }, + { + name: 'y', + type: 'number', + description: 'The y location of the document; 0 <= y.', + required: true, + }, + { + name: 'backgroundColor', + type: 'string', + description: 'The background color of the document as a hex string.', + required: false, + }, + { + name: 'fontColor', + type: 'string', + description: 'The font color of the document as a hex string.', + required: false, + }, + { + name: '_width', + type: 'number', + description: 'The width of the document in pixels.', + required: true, + }, + { + name: '_height', + type: 'number', + description: 'The height of the document in pixels.', + required: true, + }, + { + name: 'type_collection', + type: 'string', + description: `the visual style for a collection doc. Options include: ${Object.values(CollectionViewType).join(',')}.`, + required: false, + }, +] as const; + +type CreateDocToolParamsType = typeof createDocToolParams; + +const createDocToolInfo: ToolInfo<CreateDocToolParamsType> = { + name: 'createDoc', + description: `Creates one or more documents that best fit the user’s request. + If the user requests a "dashboard," first call the search tool and then generate a variety of document types individually, with absolutely a minimum of 20 documents + with two stacks of flashcards that are small and it should have a couple nested freeform collections of things, each with different content and color schemes. + For example, create multiple individual documents, including ${Object.keys(documentTypesInfo) + .map(t => '"' + t + '"') + .join(',')} + If the "doc_type" parameter is missing, set it to an empty string (""). + Use Decks instead of Flashcards for dashboards. Decks should have at least three flashcards. + Really think about what documents are useful to the user. If they ask for a dashboard about the skeletal system, include flashcards, as they would be helpful. + Arrange the documents in a grid layout, ensuring that the x and y coordinates are calculated so no documents overlap but they should be directly next to each other with 20 padding in between. + Take into account the width and height of each document, spacing them appropriately to prevent collisions. + Use a systematic approach, such as placing each document in a grid cell based on its order, where cell dimensions match the document dimensions plus a fixed margin for spacing. + Do not nest all documents within a single collection unless explicitly requested by the user. + Instead, create a set of independent documents with diverse document types. Each type should appear separately unless specified otherwise. + Use the "data" parameter for document content and include title, color, and document dimensions. + Ensure web documents use URLs from the search tool if relevant. Each document in a dashboard should be unique and well-differentiated in type and content, + without repetition of similar types in any single collection. + When creating a dashboard, ensure that it consists of a broad range of document types. + Include a variety of documents, such as text, web, deck, comparison, image, and equation documents, + each with distinct titles and colors, following the user’s preferences. + Do not overuse collections or nest all document types within a single collection; instead, represent document types individually. Use this example for reference: + ${finalJsonString} . + Which documents are created should be random with different numbers of each document type and different for each dashboard. + Must use search tool before creating a dashboard.`, + parameterRules: createDocToolParams, + citationRules: 'No citation needed.', +}; + +// Tool class for creating documents +export class CreateDocTool extends BaseTool< + { + name: string; + type: 'string' | 'number' | 'boolean' | 'string[]' | 'number[]'; + description: string; + required: boolean; + }[] +> { + private _addLinkedDoc: (doc: parsedDoc) => void; + + constructor(addLinkedDoc: (doc: parsedDoc) => void) { + super(createDocToolInfo); + this._addLinkedDoc = addLinkedDoc; + } + + override inputValidator(inputParam: ParametersType<readonly Parameter[]>) { + return !!inputParam.data; + } + // Executes the tool logic for creating documents + async execute( + args: ParametersType< + { + name: 'string'; + type: 'string' | 'number' | 'boolean' | 'string[]' | 'number[]'; + description: 'string'; + required: boolean; + }[] + > + ): Promise<Observation[]> { + try { + const parsedDocs = args instanceof Array ? args : Object.keys(args).length === 1 && 'data' in args ? JSON.parse(args.data as string) : [args]; + parsedDocs.forEach((pdoc: parsedDoc) => this._addLinkedDoc({ ...pdoc, _layout_fitWidth: false, _layout_autoHeight: true })); + return [{ type: 'text', text: 'Created document.' }]; + } catch (error) { + return [{ type: 'text', text: 'Error creating text document, ' + error }]; + } + } +} |