aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts')
-rw-r--r--src/client/views/nodes/chatbot/tools/CreateDocumentTool.ts497
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 }];
+ }
+ }
+}