diff options
author | A.J. Shulman <Shulman.aj@gmail.com> | 2024-05-30 13:58:40 -0400 |
---|---|---|
committer | A.J. Shulman <Shulman.aj@gmail.com> | 2024-05-30 13:58:40 -0400 |
commit | 7ff649c6582b7e00dcf2d7fe607699f850310ba0 (patch) | |
tree | 681ca2195a948ee86b556e6a4ba49b833f298ada | |
parent | f07a80b23080d01411f47f331854adb3cc89e92f (diff) |
fixing chatbox features
still messages appear weird when using code interpreter and now doesn't detect file links
-rw-r--r-- | src/client/views/collections/CollectionNoteTakingViewColumn.tsx | 12 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/ChatBox.tsx | 101 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/MessageComponent.tsx | 37 | ||||
-rw-r--r-- | src/client/views/nodes/ChatBox/types.ts | 1 | ||||
-rw-r--r-- | src/server/ApiManagers/AssistantManager.ts | 7 |
5 files changed, 70 insertions, 88 deletions
diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index 44ab1968d..2c6257cf2 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -1,6 +1,6 @@ /* eslint-disable jsx-a11y/control-has-associated-label */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, makeObservable, observable } from 'mobx'; +import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { lightOrDark, returnEmptyString } from '../../../ClientUtils'; @@ -88,12 +88,16 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV }; componentDidMount(): void { - this._ele && this.props.refList.push(this._ele); + runInAction(() => { + this._ele && this.props.refList.push(this._ele); + }); } componentWillUnmount() { - this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1); - this._ele = null; + runInAction(() => { + this._ele && this.props.refList.splice(this._props.refList.indexOf(this._ele), 1); + this._ele = null; + }); } @undoBatch diff --git a/src/client/views/nodes/ChatBox/ChatBox.tsx b/src/client/views/nodes/ChatBox/ChatBox.tsx index 880c332ac..4c1550321 100644 --- a/src/client/views/nodes/ChatBox/ChatBox.tsx +++ b/src/client/views/nodes/ChatBox/ChatBox.tsx @@ -34,7 +34,6 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { @observable linked_docs_to_add: Doc[] = []; private openai: OpenAI; - private interim_history: string = ''; private assistantID: string = ''; private threadID: string = ''; private _oldWheel: any; @@ -74,13 +73,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { }, }; reaction( - () => this.history.map((msg: AssistantMessage) => ({ role: msg.role, text: msg.text, image: msg.image, tool_logs: msg.tool_logs, links: msg.links })), + () => this.history.map((msg: AssistantMessage) => ({ role: msg.role, text: msg.text, image: msg.image, tool_logs: msg.tool_logs })), serializableHistory => { this.dataDoc.data = JSON.stringify(serializableHistory); } ); } + @action toggleToolLogs = (index: number) => { this.expandedLogIndex = this.expandedLogIndex === index ? null : index; }; @@ -101,6 +101,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } initializeOpenAI() { + //console.log(process.env._CLIENT_OPENAI_KEY); const configuration: ClientOptions = { apiKey: process.env.OPENAI_KEY, dangerouslyAllowBrowser: true, @@ -114,11 +115,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } }; - createLink = (linkInfo: string, startIndex: number, endIndex: number, linkType: ANNOTATION_LINK_TYPE, annotationIndex: number = 0) => { - const text = this.interim_history; - const subString = this.current_message?.text.substring(startIndex, endIndex) ?? ''; + createLink = (linkInfo: string, annotationText: string, linkType: ANNOTATION_LINK_TYPE) => { + console.log(this.current_message); + const text = this.current_message?.text; + console.log(text); + + const subString = annotationText; if (!text) return; - const textToDisplay = `${annotationIndex}`; + const textToDisplay = `DASHLINK`; let fileInfo = linkInfo; const fileName = subString.split('/')[subString.split('/').length - 1]; if (linkType === ANNOTATION_LINK_TYPE.DOWNLOAD_FILE) { @@ -127,17 +131,9 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const formattedLink = `[${textToDisplay}](${fileInfo}~~~${linkType})`; console.log(formattedLink); - const newText = text.replace(subString, formattedLink); + const newText = text.split(subString).join(formattedLink); runInAction(() => { - this.interim_history = newText; - console.log(newText); - this.current_message?.links?.push({ - start: startIndex, - end: endIndex, - url: linkType === ANNOTATION_LINK_TYPE.DOWNLOAD_FILE ? fileName : linkInfo, - id: linkType === ANNOTATION_LINK_TYPE.DOWNLOAD_FILE ? linkInfo : undefined, - link_type: linkType, - }); + if (this.current_message) this.current_message.text = newText; }); }; @@ -192,8 +188,10 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { await this.createAssistant(); console.log('Assistant and thread created:', this.assistantID, this.threadID); } + let currentText: string = ''; let currentToolCallMessage: string = ''; + let current_message_id: string | null = null; // Send the user's input to the assistant await this.openai.beta.threads.messages.create(this.threadID, { @@ -207,14 +205,14 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { assistant_id: this.assistantID, }) .on('runStepCreated', (runStep: RunStep) => { - currentText = ''; runInAction(() => { - this.current_message = { role: ASSISTANT_ROLE.ASSISTANT, text: currentText, tool_logs: '', links: [] }; + this.isLoading = true; + //intentionally don't merge run steps' messages and keep them as seperate messages on the interface + this.current_message = { role: ASSISTANT_ROLE.ASSISTANT, text: '', tool_logs: '' }; }); - this.isLoading = true; }) .on('toolCallDelta', (toolCallDelta, snapshot) => { - this.isLoading = false; + runInAction(() => (this.isLoading = false)); if (toolCallDelta.type === 'code_interpreter') { if (toolCallDelta.code_interpreter?.input) { currentToolCallMessage += toolCallDelta.code_interpreter.input; @@ -243,31 +241,44 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { currentText += textDelta.value; runInAction(() => { if (this.current_message) { - // this.current_message = {...this.current_message, text: current_text}; this.current_message.text = currentText; } }); }) - .on('messageDone', async event => { - console.log(event); - const textItem = event.content.find(item => item.type === 'text'); + .on('messageDone', async message => { + console.log(this.current_message); + const textItem = message.content.find(item => item.type === 'text'); if (textItem && textItem.type === 'text') { const { text } = textItem; console.log(text.value); try { runInAction(() => { - this.interim_history = text.value; + if (this.current_message) { + this.current_message.text = text.value; + } }); } catch (e) { console.error('Error parsing JSON response:', e); } + console.log(this.current_message); const { annotations } = text; console.log('Annotations: ' + annotations); - let index = 0; - annotations.forEach(async annotation => { - console.log(' ' + annotation); - console.log(' ' + annotation.text); + const uniqueAnnotations = annotations.filter( + (annotation => { + const seenAnnotationTexts = new Set<string>(); + return annotation => { + if (seenAnnotationTexts.has(annotation.text)) { + return false; + } else { + seenAnnotationTexts.add(annotation.text); + return true; + } + }; + })() + ); + + uniqueAnnotations.forEach(async annotation => { if (annotation.type === 'file_path') { const { file_path: filePath } = annotation; const fileToDownload = filePath.file_id; @@ -275,40 +286,38 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { if (filePath) { console.log(filePath); console.log(fileToDownload); - this.createLink(fileToDownload, annotation.start_index, annotation.end_index, ANNOTATION_LINK_TYPE.DOWNLOAD_FILE); + console.log(annotation.text); + this.createLink(fileToDownload, annotation.text, ANNOTATION_LINK_TYPE.DOWNLOAD_FILE); } } else { const { file_citation: fileCitation } = annotation; if (fileCitation) { const citedFile = await this.openai.files.retrieve(fileCitation.file_id); const citationUrl = citedFile.filename; - this.createLink(citationUrl, annotation.start_index, annotation.end_index, ANNOTATION_LINK_TYPE.DASH_DOC, index); - index++; + console.log(annotation.text); + console.log(this.current_message + 'fewjfjec'); + this.createLink(citationUrl, annotation.text, ANNOTATION_LINK_TYPE.DASH_DOC); } } }); - runInAction(() => { - if (this.current_message) { - console.log('current message: ' + this.current_message.text); - this.current_message.text = this.interim_history; - this.history.push({ ...this.current_message }); - this.current_message = undefined; - } - }); } + runInAction(() => { + if (this.current_message?.text) { + this.history.push({ ...this.current_message }); + //this.current_message = undefined; + } + }); }) - .on('toolCallDone', toolCall => { + .on('toolCallDone', async toolCall => { runInAction(() => { - if (this.current_message && currentToolCallMessage) { - this.current_message.tool_logs = currentToolCallMessage; + if (this.current_message?.tool_logs) { + this.history.push({ ...this.current_message }); + //this.current_message = undefined; } }); }) .on('imageFileDone', (content: ImageFile, snapshot: Message) => { console.log('Image file done:', content); - }) - .on('end', () => { - console.log('Streaming done'); }); }; diff --git a/src/client/views/nodes/ChatBox/MessageComponent.tsx b/src/client/views/nodes/ChatBox/MessageComponent.tsx index fced0b4d5..ef6ce83b5 100644 --- a/src/client/views/nodes/ChatBox/MessageComponent.tsx +++ b/src/client/views/nodes/ChatBox/MessageComponent.tsx @@ -3,8 +3,8 @@ import React from 'react'; import { observer } from 'mobx-react'; import { MathJax, MathJaxContext } from 'better-react-mathjax'; import ReactMarkdown from 'react-markdown'; -import { TbCircle0Filled, TbCircle1Filled, TbCircle2Filled, TbCircle3Filled, TbCircle4Filled, TbCircle5Filled, TbCircle6Filled, TbCircle7Filled, TbCircle8Filled, TbCircle9Filled } from 'react-icons/tb'; import { AssistantMessage } from './types'; +import { TbInfoCircleFilled } from 'react-icons/tb'; interface MessageComponentProps { message: AssistantMessage; @@ -29,40 +29,7 @@ const MessageComponent: React.FC<MessageComponentProps> = function ({ message, t const url = matches ? matches[1] : href; const linkType = matches ? matches[2] : null; if (linkType === 'citation') { - switch (children) { - case '0': - children = <TbCircle0Filled />; - break; - case '1': - children = <TbCircle1Filled />; - break; - case '2': - children = <TbCircle2Filled />; - break; - case '3': - children = <TbCircle3Filled />; - break; - case '4': - children = <TbCircle4Filled />; - break; - case '5': - children = <TbCircle5Filled />; - break; - case '6': - children = <TbCircle6Filled />; - break; - case '7': - children = <TbCircle7Filled />; - break; - case '8': - children = <TbCircle8Filled />; - break; - case '9': - children = <TbCircle9Filled />; - break; - default: - break; - } + children = <TbInfoCircleFilled />; } // console.log(linkType) const style = { diff --git a/src/client/views/nodes/ChatBox/types.ts b/src/client/views/nodes/ChatBox/types.ts index 8212a7050..cfda0d40e 100644 --- a/src/client/views/nodes/ChatBox/types.ts +++ b/src/client/views/nodes/ChatBox/types.ts @@ -19,5 +19,4 @@ export interface AssistantMessage { quote?: string; image?: string; tool_logs?: string; - links?: { start: number; end: number; url: string; id?: string; link_type: ANNOTATION_LINK_TYPE }[]; } diff --git a/src/server/ApiManagers/AssistantManager.ts b/src/server/ApiManagers/AssistantManager.ts index 82e48167a..f2ea83310 100644 --- a/src/server/ApiManagers/AssistantManager.ts +++ b/src/server/ApiManagers/AssistantManager.ts @@ -4,7 +4,7 @@ import OpenAI from 'openai'; import * as path from 'path'; import { promisify } from 'util'; import * as uuid from 'uuid'; -import { filesDirectory, publicDirectory } from '..'; +import { filesDirectory, publicDirectory } from '../SocketData'; import { Method } from '../RouteManager'; import ApiManager, { Registration } from './ApiManager'; @@ -36,7 +36,10 @@ const readFileAsync = promisify(fs.readFile); export default class AssistantManager extends ApiManager { protected initialize(register: Registration): void { - const openai = new OpenAI({ apiKey: process.env.OPENAI_KEY, dangerouslyAllowBrowser: true }); + const openai = new OpenAI({ + apiKey: process.env._CLIENT_OPENAI_KEY, // Use client key so don't have to set key seperately for client and server. + dangerouslyAllowBrowser: true, + }); register({ method: Method.POST, |