diff options
-rw-r--r-- | src/client/views/nodes/chatbot/tools/TutorialTool.ts | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/client/views/nodes/chatbot/tools/TutorialTool.ts b/src/client/views/nodes/chatbot/tools/TutorialTool.ts new file mode 100644 index 000000000..69ae9c618 --- /dev/null +++ b/src/client/views/nodes/chatbot/tools/TutorialTool.ts @@ -0,0 +1,166 @@ +import { BaseTool } from './BaseTool'; +import { Observation } from '../types/types'; +import { Parameter, ParametersType, ToolInfo } from '../types/tool_types'; +// import { gptAPICall } from '../../../../apis/gpt/GPT'; +import { schema } from '../../../../views/nodes/formattedText/schema_rts'; +import { RichTextField } from '../../../../../fields/RichTextField'; +import { Docs } from '../../../../documents/Documents'; +import { DocumentViewInternal } from '../../../nodes/DocumentView'; +import { v4 as uuidv4 } from 'uuid'; +import { OpenWhere } from '../../../../views/nodes/OpenWhere'; +import { gptAPICall } from '../../../../apis/gpt/GPT'; +import { parsedDoc } from '../chatboxcomponents/ChatBox'; +import { Id } from '../../../../../fields/FieldSymbols'; +import { Doc } from '../../../../../fields/Doc'; + + +const generateTutorialNodeToolParams = [ + { + name: 'query', + type: 'string', + description: 'The user\'s query about Dash functionality.', + required: true, + }, +] as const; + +const generateTutorialNodeToolInfo: ToolInfo<typeof generateTutorialNodeToolParams> = { + name: 'generateTutorialNode', + description: 'Generates a tutorial text node based on the user\'s query about Dash functionality. Use this when the user asks for help or tutorials on how to use Dash features.', + parameterRules: generateTutorialNodeToolParams, + citationRules: 'No citation needed for this tool\'s output.', +}; + +export class GPTTutorialTool extends BaseTool<typeof generateTutorialNodeToolParams> { + private _createDocInDash: (doc: parsedDoc) => Doc | undefined; + + constructor(createDocInDash: (doc: parsedDoc) => Doc | undefined) { + super(generateTutorialNodeToolInfo); + + this._createDocInDash = createDocInDash; + } + +// private applyFormatting(markdownText: string): { doc: any; plainText: string } { +// const lines = markdownText.split('\n'); +// const nodes: any[] = []; +// let plainText = ''; +// let i = 0; +// let currentListItems: any[] = []; + +// const processBoldText = (text: string) => { +// const boldRegex = /\*\*(.*?)\*\*/g; +// const parts = []; +// let lastIndex = 0; +// let match; + +// while ((match = boldRegex.exec(text)) !== null) { +// if (match.index > lastIndex) { +// parts.push(schema.text(text.substring(lastIndex, match.index))); +// } +// parts.push(schema.text(match[1], [schema.marks.strong.create()])); +// lastIndex = match.index + match[0].length; +// } +// if (lastIndex < text.length) { +// parts.push(schema.text(text.substring(lastIndex))); +// } +// return parts.length > 0 ? parts : [schema.text(text)]; +// }; + +// const flushListItems = () => { +// if (currentListItems.length > 0) { +// nodes.push(schema.nodes.ordered_list.create({ mapStyle: 'bullet' }, currentListItems)); +// currentListItems = []; +// } +// }; + +// while (i < lines.length) { +// const line = lines[i].trim(); +// if (line) { +// if (line.startsWith('## ')) { +// flushListItems(); +// const textContent = line.replace('## ', ''); +// nodes.push(schema.nodes.heading.create({ level: 1 }, processBoldText(textContent))); +// plainText += textContent + '\n'; +// } else if (line.startsWith('- ')) { +// const textContent = line.replace('- ', ''); +// currentListItems.push( +// schema.nodes.list_item.create( +// {}, +// schema.nodes.paragraph.create({}, processBoldText(textContent)) +// ) +// ); +// plainText += textContent + '\n'; +// } else { +// flushListItems(); +// nodes.push(schema.nodes.paragraph.create({}, processBoldText(line))); +// plainText += line + '\n'; +// } +// } else { +// flushListItems(); +// nodes.push(schema.nodes.paragraph.create()); +// plainText += '\n'; +// } +// i++; +// } +// flushListItems(); + +// const doc = schema.nodes.doc.create({}, nodes); +// return { doc, plainText: plainText.trim() }; +// } + + async execute(args: ParametersType<typeof generateTutorialNodeToolParams>): Promise<Observation[]> { + const chunkId = uuidv4(); + try { + console.log('Executing with args:', args); + const query = args.query; + if (typeof query !== 'string' || !query.trim()) { + return [{ + type: 'text', + text: `<chunk chunk_id="${chunkId}" chunk_type="error">Invalid input: Query must be a non-empty string.</chunk>` + }]; + } + + const markdownResponse = await gptAPICall(query); + if (!markdownResponse || typeof markdownResponse !== 'string') { + throw new Error('Invalid GPT API response'); + } + console.log('Markdown response:', markdownResponse); + + // const { doc } = this.applyFormatting(markdownResponse); + // const rtfData = { + // doc: doc.toJSON(), + // selection: { type: 'text', anchor: 1, head: 1 }, + // storedMarks: [], + // }; + // const serializedData = JSON.stringify(rtfData); + // console.log('Serialized data:', serializedData); + + const tutorialDoc: parsedDoc = { + doc_type: 'text', + data: markdownResponse, + title: 'Tutorial Node', + _width: 600, + _layout_fitWidth: true, + _layout_autoHeight: true, + text_fontSize: '16px', + }; + + const createdDoc = this._createDocInDash(tutorialDoc); + console.log('Created doc:', createdDoc); + if (!createdDoc || !createdDoc[Id]) { + throw new Error('Failed to create tutorial node'); + } + + return [{ + type: 'text', + text: `<chunk chunk_id="${chunkId}" chunk_type="tutorial_node_creation">Created tutorial node with ID ${createdDoc[Id]}.</chunk>` + }]; + } catch (error) { + console.error('Error in GPTTutorialTool:', error); + const errorMessage = error instanceof Error ? error.message : 'Unknown error'; + return [{ + type: 'text', + text: `<chunk chunk_id="${chunkId}" chunk_type="error">Error generating tutorial node: ${errorMessage}</chunk>` + }]; + } + } +}
\ No newline at end of file |