diff options
Diffstat (limited to 'src')
26 files changed, 214 insertions, 271 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index e0a9918f4..d77f76b81 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,5 +1,3 @@ -/* eslint-disable prefer-destructuring */ -/* eslint-disable default-param-last */ /* eslint-disable no-use-before-define */ import { reaction } from 'mobx'; import { basename } from 'path'; @@ -671,7 +669,6 @@ export namespace Docs { * only when creating a DockDocument from the current user's already existing * main document. */ - // eslint-disable-next-line default-param-last function InstanceFromProto(proto: Doc, data: FieldType | undefined, options: DocumentOptions, delegId?: string, fieldKey: string = 'data', protoId?: string, placeholderDocIn?: Doc, noView?: boolean) { const placeholderDoc = placeholderDocIn; const viewKeys = ['x', 'y', 'isSystem']; // keys that should be addded to the view document even though they don't begin with an "_" @@ -732,7 +729,6 @@ export namespace Docs { return dataDoc; } - // eslint-disable-next-line default-param-last export function ImageDocument(url: string | ImageField, options: DocumentOptions = {}, overwriteDoc?: Doc) { const imgField = url instanceof ImageField ? url : url ? new ImageField(url) : undefined; return InstanceFromProto(Prototypes.get(DocumentType.IMG), imgField, { title: basename(imgField?.url.href ?? '-no image-'), ...options }, undefined, undefined, undefined, overwriteDoc); @@ -751,7 +747,6 @@ export namespace Docs { * @param fieldKey the field that the compiled script is written into. * @returns the Scripting Doc */ - // eslint-disable-next-line default-param-last export function ScriptingDocument(script: Opt<ScriptField> | null, options: DocumentOptions = {}, fieldKey?: string) { return InstanceFromProto(Prototypes.get(DocumentType.SCRIPTING), script || undefined, { ...options, layout: fieldKey ? `<ScriptingBox {...props} fieldKey={'${fieldKey}'}/>` /* ScriptingBox.LayoutString(fieldKey) */ : undefined }); } @@ -759,7 +754,6 @@ export namespace Docs { export function ChatDocument(options?: DocumentOptions) { return InstanceFromProto(Prototypes.get(DocumentType.CHAT), undefined, { ...(options || {}) }); } - // eslint-disable-next-line default-param-last export function VideoDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) { return InstanceFromProto(Prototypes.get(DocumentType.VID), new VideoField(url), options, undefined, undefined, undefined, overwriteDoc); } @@ -779,7 +773,6 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.DIAGRAM), undefined, options); } - // eslint-disable-next-line default-param-last export function AudioDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) { return InstanceFromProto(Prototypes.get(DocumentType.AUDIO), new AudioField(url), options, undefined, undefined, undefined, overwriteDoc); } @@ -839,7 +832,6 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey); } - // eslint-disable-next-line default-param-last export function LinkDocument(source: Doc, target: Doc, options: DocumentOptions = {}, id?: string) { const linkDoc = InstanceFromProto( Prototypes.get(DocumentType.LINK), @@ -883,7 +875,6 @@ export namespace Docs { return ink; } - // eslint-disable-next-line default-param-last export function PdfDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) { const width = options._width || undefined; const height = options._height || undefined; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 96b30c429..09adf70f5 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -2,7 +2,7 @@ import { reaction, runInAction } from "mobx"; import * as rp from 'request-promise'; import { ClientUtils, OmitKeys } from "../../ClientUtils"; -import { Doc, DocListCast, DocListCastAsync, FieldType, Opt, StrListCast } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, FieldType, Opt } from "../../fields/Doc"; import { DocData } from "../../fields/DocSymbols"; import { InkTool } from "../../fields/InkField"; import { List } from "../../fields/List"; @@ -366,11 +366,11 @@ pie title Minerals in my tap water {key: "Button", creator: Docs.Create.ButtonDocument, opts: { _width: 150, _height: 50, _xPadding: 10, _yPadding: 10, title_custom: true, waitForDoubleClickToClick: 'never'}, scripts: {onClick: FollowLinkScript()?.script.originalScript ?? ""}}, {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, - {key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 500, _height: 500, }}, + {key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 500, _height: 500, }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, _layout_dontCenter:'xy', dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, - {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, + {key: "Tab", creator: opts => Docs.Create.FreeformDocument([], opts), opts: { _width: 500, _height: 800, _layout_fitWidth: true, _freeform_backgroundGrid: true, }}, {key: "Slide", creator: opts => Docs.Create.TreeDocument([], opts), opts: { _width: 300, _height: 200, _type_collection: CollectionViewType.Tree, treeView_HasOverlay: true, _text_fontSize: "20px", _layout_autoHeight: true, dropAction:dropActionType.move, treeView_Type: TreeViewType.outline, @@ -801,7 +801,7 @@ pie title Minerals in my tap water { title: "Num", icon:"", toolTip: "Frame # (click to toggle edit mode)",btnType: ButtonType.TextButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)', buttonText: 'selectedDocs()?.lastElement()?.currentFrame?.toString()'}, width: 20, scripts: { onClick: '{ return curKeyFrame(_readOnly_);}'}}, { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, expertMode: true, toolType:CollectionViewType.Freeform, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, width: 30, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, - { title: "Filter", icon: "=", toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.tagGroupTools(),ignoreClick:true, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor}, + { title: "Filter", icon: "=", toolTip: "Filter cards by tags", subMenu: CurrentUserUtils.tagGroupTools(),ignoreClick:true, toolType:DocumentType.COL, funcs: {hidden: '!SelectedDocType(this.toolType, this.expertMode)'}, btnType: ButtonType.MultiToggleButton, width: 30, backgroundColor: doc.userVariantColor as string}, { title: "Text", icon: "Text", toolTip: "Text functions", subMenu: CurrentUserUtils.textTools(), expertMode: false, toolType:DocumentType.RTF, funcs: { linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available { title: "Ink", icon: "Ink", toolTip: "Ink functions", subMenu: CurrentUserUtils.inkTools(), expertMode: false, toolType:DocumentType.INK, funcs: {hidden: `IsExploreMode()`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`}, scripts: { onClick: 'setInkToolDefaults()'} }, // Always available { title: "Doc", icon: "Doc", toolTip: "Freeform Doc tools", subMenu: CurrentUserUtils.freeTools(), expertMode: false, toolType:CollectionViewType.Freeform, funcs: {hidden: `!SelectedDocType(this.toolType, this.expertMode, true)`, linearView_IsOpen: `SelectedDocType(this.toolType, this.expertMode)`} }, // Always available diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 3e7a2df02..c7b86815a 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -1,7 +1,7 @@ // export const ts = (window as any).ts; // import * as typescriptlib from '!!raw-loader!../../../node_modules/typescript/lib/lib.d.ts' // import * as typescriptes5 from '!!raw-loader!../../../node_modules/typescript/lib/lib.es5.d.ts' -// import typescriptlib from 'type_decls.d'; +import typescriptlib from 'type_decls.d'; import * as ts from 'typescript'; import { Doc, FieldType } from '../../fields/Doc'; import { RefField } from '../../fields/RefField'; @@ -29,7 +29,7 @@ export interface CompiledScript { readonly compiled: true; readonly originalScript: string; // eslint-disable-next-line no-use-before-define - readonly options: Readonly; + readonly options: Readonly<ScriptOptions>; run(args?: { [name: string]: unknown }, onError?: (res: string) => void, errorVal?: unknown): ScriptResult; } @@ -60,7 +60,6 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts // let params: any[] = [Docs, ...fieldTypes]; const compiledFunction = (() => { try { - // eslint-disable-next-line no-new-func return new Function(...paramNames, `return ${script}`); } catch (e) { console.log(e); @@ -69,10 +68,8 @@ function Run(script: string | undefined, customParams: string[], diagnostics: ts })(); if (!compiledFunction) return { compiled: false, errors }; const { capturedVariables = {} } = options; - // eslint-disable-next-line default-param-last const run = (args: { [name: string]: unknown } = {}, onError?: (e: string) => void, errorVal?: ts.Diagnostic): ScriptResult => { const argsArray: unknown[] = []; - // eslint-disable-next-line no-restricted-syntax for (const name of customParams) { if (name !== 'this') { argsArray.push(name in args ? args[name] : capturedVariables[name]); @@ -154,7 +151,7 @@ class ScriptingCompilerHost { export type Traverser = (node: ts.Node, indentation: string) => boolean | void; export type TraverserParam = Traverser | { onEnter: Traverser; onLeave: Traverser }; export type Transformer = { - transformer: ts.TransformerFactory; + transformer: ts.TransformerFactory<ts.Node>; getVars?: () => { [name: string]: FieldType }; }; export interface ScriptOptions { @@ -224,7 +221,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp if ('this' in params || 'this' in capturedVariables) { paramNames.push('this'); } - // eslint-disable-next-line no-restricted-syntax for (const key in params) { if (key !== 'this') { paramNames.push(key); @@ -234,7 +230,6 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp const val = params[key]; return `${key}: ${val}`; }); - // eslint-disable-next-line no-restricted-syntax for (const key in capturedVariables) { if (key !== 'this') { const val = capturedVariables[key]; @@ -248,7 +243,7 @@ export function CompileScript(script: string, options: ScriptOptions = {}): Comp const funcScript = `(function(${paramString})${reqTypes} { ${body} })`; host.writeFile('file.ts', funcScript); - // if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib); + if (typecheck) host.writeFile('node_modules/typescript/lib/lib.d.ts', typescriptlib); const program = ts.createProgram(['file.ts'], {}, host); const testResult = program.emit(); const outputText = host.readFile('file.js'); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8b8f85dfb..abe154de4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -75,7 +75,7 @@ import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports +// eslint-disable-next-line @typescript-eslint/no-require-imports const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore @observer @@ -1059,10 +1059,7 @@ export class MainView extends ObservableReactComponent<object> { docView={DocButtonState.Instance.LinkEditorDocView} /> ) : null} - {LinkInfo.Instance?.LinkInfo ? ( - // eslint-disable-next-line react/jsx-props-no-spreading - <LinkDocPreview {...LinkInfo.Instance.LinkInfo} /> - ) : null} + {LinkInfo.Instance?.LinkInfo ? <LinkDocPreview {...LinkInfo.Instance.LinkInfo} /> : null} {((page: string) => { // prettier-ignore switch (page) { diff --git a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx index fc5f5cb71..226d06f37 100644 --- a/src/client/views/collections/CollectionNoteTakingViewColumn.tsx +++ b/src/client/views/collections/CollectionNoteTakingViewColumn.tsx @@ -252,10 +252,7 @@ export class CollectionNoteTakingViewColumn extends ObservableReactComponent<CSV <EditableView GetValue={returnEmptyString} SetValue={this.addNewTextDoc} textCallback={this.addTextNote} placeholder={"Type ':' for commands"} contents="+ Node" menuCallback={this.menuCallback} /> </div> <div className="collectionNoteTakingView-addDocumentButton" style={{ color: lightOrDark(this._props.backgroundColor?.()) }}> - { - // eslint-disable-next-line react/jsx-props-no-spreading - <EditableView {...this._props.editableViewProps()} /> - } + <EditableView {...this._props.editableViewProps()} /> </div> </div> ) : null} diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 4616ec057..596975062 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -10,7 +10,7 @@ import { DocData } from '../../../fields/DocSymbols'; import { Id } from '../../../fields/FieldSymbols'; import { InkTool } from '../../../fields/InkField'; import { ComputedField } from '../../../fields/ScriptField'; -import { Cast, FieldValue, ImageCast, NumCast, StrCast, toList } from '../../../fields/Types'; +import { Cast, FieldValue, NumCast, StrCast, toList } from '../../../fields/Types'; import { ImageField, PdfField } from '../../../fields/URLField'; import { TraceMobx } from '../../../fields/util'; import { emptyFunction } from '../../../Utils'; @@ -43,14 +43,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { public static openSidebarWidth = 250; public static sidebarResizerWidth = 5; private _searchString: string = ''; - private _initialScrollTarget: Opt; + private _initialScrollTarget: Opt<Doc>; private _pdfViewer: PDFViewer | undefined; private _searchRef = React.createRef<HTMLInputElement>(); private _disposers: { [name: string]: IReactionDisposer } = {}; private _sidebarRef = React.createRef<SidebarAnnos>(); @observable private _searching: boolean = false; - @observable private _pdf: Opt = undefined; + @observable private _pdf: Opt<Pdfjs.PDFDocumentProxy> = undefined; @observable private _pageControls = false; @computed get pdfUrl() { @@ -242,13 +242,13 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { options.didMove = true; this.toggleSidebar(false); } - return new Promise<Opt>(res => { + return new Promise<Opt<DocumentView>>(res => { DocumentView.addViewRenderedCb(doc, dv => res(dv)); }); }; getAnchor = (addAsAnnotation: boolean, pinProps?: PinProps) => { - let ele: Opt; + let ele: Opt<HTMLDivElement>; if (this._pdfViewer?.selectionContent()) { ele = document.createElement('div'); ele.append(this._pdfViewer.selectionContent()!); @@ -327,7 +327,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { this._initialScrollTarget = undefined; } }; - searchStringChanged = (e: React.ChangeEvent) => { + searchStringChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this._searchString = e.currentTarget.value; }; @@ -365,8 +365,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } ); }; - @observable _previewNativeWidth: Opt = undefined; - @observable _previewWidth: Opt = undefined; + @observable _previewNativeWidth: Opt<number> = undefined; + @observable _previewWidth: Opt<number> = undefined; toggleSidebar = action((preview: boolean = false) => { const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']); const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth; @@ -540,7 +540,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { return ComponentTag === CollectionStackingView ? ( <SidebarAnnos ref={this._sidebarRef} - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} Document={this.Document} layoutDoc={this.layoutDoc} @@ -556,7 +555,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { ) : ( <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => this._props.select(false), true)}> <ComponentTag - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} setContentViewBox={emptyFunction} // override setContentView to do nothing NativeWidth={this.sidebarNativeWidthFunc} @@ -610,7 +608,6 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { top: 0, }}> <PDFViewer - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} pdfBox={this} sidebarAddDoc={this.sidebarAddDocument} @@ -637,7 +634,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { } static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>(); - static pdfpromise = new Map<string, Promise>(); + static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>(); render() { TraceMobx(); const pdfView = !this._pdf ? null : this.renderPdfView; diff --git a/src/client/views/nodes/RecordingBox/ProgressBar.tsx b/src/client/views/nodes/RecordingBox/ProgressBar.tsx index 62798bc2f..7e91df7ab 100644 --- a/src/client/views/nodes/RecordingBox/ProgressBar.tsx +++ b/src/client/views/nodes/RecordingBox/ProgressBar.tsx @@ -1,5 +1,3 @@ -/* eslint-disable react/no-array-index-key */ -/* eslint-disable react/require-default-props */ import * as React from 'react'; import { useEffect, useState, useRef } from 'react'; import './ProgressBar.scss'; diff --git a/src/client/views/nodes/chatbot/agentsystem/Agent.ts b/src/client/views/nodes/chatbot/agentsystem/Agent.ts index 180d05cf3..ccf9caf15 100644 --- a/src/client/views/nodes/chatbot/agentsystem/Agent.ts +++ b/src/client/views/nodes/chatbot/agentsystem/Agent.ts @@ -1,20 +1,19 @@ +import dotenv from 'dotenv'; +import { XMLBuilder, XMLParser } from 'fast-xml-parser'; import OpenAI from 'openai'; -import { Tool, AgentMessage, AssistantMessage, TEXT_TYPE, CHUNK_TYPE, ASSISTANT_ROLE, ProcessingInfo, PROCESSING_TYPE } from '../types/types'; -import { getReactPrompt } from './prompts'; -import { XMLParser, XMLBuilder } from 'fast-xml-parser'; -import { Vectorstore } from '../vectorstore/Vectorstore'; import { ChatCompletionMessageParam } from 'openai/resources'; -import dotenv from 'dotenv'; -import { CalculateTool } from '../tools/CalculateTool'; -import { RAGTool } from '../tools/RAGTool'; -import { DataAnalysisTool } from '../tools/DataAnalysisTool'; -import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool'; -import { SearchTool } from '../tools/SearchTool'; -import { NoTool } from '../tools/NoTool'; -import { v4 as uuidv4 } from 'uuid'; import { AnswerParser } from '../response_parsers/AnswerParser'; import { StreamedAnswerParser } from '../response_parsers/StreamedAnswerParser'; +import { CalculateTool } from '../tools/CalculateTool'; import { CreateCSVTool } from '../tools/CreateCSVTool'; +import { DataAnalysisTool } from '../tools/DataAnalysisTool'; +import { NoTool } from '../tools/NoTool'; +import { RAGTool } from '../tools/RAGTool'; +import { SearchTool } from '../tools/SearchTool'; +import { WebsiteInfoScraperTool } from '../tools/WebsiteInfoScraperTool'; +import { AgentMessage, AssistantMessage, PROCESSING_TYPE, ProcessingInfo, Tool } from '../types/types'; +import { Vectorstore } from '../vectorstore/Vectorstore'; +import { getReactPrompt } from './prompts'; dotenv.config(); @@ -25,7 +24,7 @@ dotenv.config(); export class Agent { // Private properties private client: OpenAI; - private tools: Record<string, Tool<any>>; + private tools: Record<string, Tool<any>>; // bcz: need a real type here private messages: AgentMessage[] = []; private interMessages: AgentMessage[] = []; private vectorstore: Vectorstore; @@ -102,7 +101,7 @@ export class Agent { ignoreAttributes: false, attributeNamePrefix: '@_', textNodeName: '_text', - isArray: (name, jpath, isLeafNode, isAttribute) => ['query', 'url'].indexOf(name) !== -1, + isArray: (name /* , jpath, isLeafNode, isAttribute */) => ['query', 'url'].indexOf(name) !== -1, }); const builder = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_' }); @@ -167,7 +166,7 @@ export class Agent { if (currentAction) { try { // Process the action with its input - const observation = await this.processAction(currentAction, actionInput.inputs); + const observation = (await this.processAction(currentAction, actionInput.inputs)) as any; // bcz: really need a type here const nextPrompt = [{ type: 'text', text: `<stage number="${i + 1}" role="user"> <observation>` }, ...observation, { type: 'text', text: '</observation></stage>' }]; console.log(observation); this.interMessages.push({ role: 'user', content: nextPrompt }); @@ -214,7 +213,7 @@ export class Agent { // Process each chunk of the streamed response for await (const chunk of stream) { - let content = chunk.choices[0]?.delta?.content || ''; + const content = chunk.choices[0]?.delta?.content || ''; fullResponse += content; // Parse the streamed content character by character @@ -267,7 +266,7 @@ export class Agent { * @param actionInput The inputs for the action. * @returns The result of the action. */ - private async processAction(action: string, actionInput: any): Promise<any> { + private async processAction(action: string, actionInput: unknown): Promise<unknown> { if (!(action in this.tools)) { throw new Error(`Unknown action: ${action}`); } diff --git a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx index d4deff78b..613cb7078 100644 --- a/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx +++ b/src/client/views/nodes/chatbot/chatboxcomponents/ChatBox.tsx @@ -1,30 +1,29 @@ -import { action, computed, makeObservable, observable, observe, reaction, runInAction, ObservableSet } from 'mobx'; +import dotenv from 'dotenv'; +import { ObservableSet, action, computed, makeObservable, observable, observe, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import OpenAI, { ClientOptions } from 'openai'; import * as React from 'react'; +import { v4 as uuidv4 } from 'uuid'; +import { ClientUtils } from '../../../../../ClientUtils'; import { Doc, DocListCast } from '../../../../../fields/Doc'; +import { DocData, DocViews } from '../../../../../fields/DocSymbols'; import { CsvCast, DocCast, PDFCast, RTFCast, StrCast } from '../../../../../fields/Types'; +import { Networking } from '../../../../Network'; +import { DocUtils } from '../../../../documents/DocUtils'; import { DocumentType } from '../../../../documents/DocumentTypes'; import { Docs } from '../../../../documents/Documents'; +import { DocumentManager } from '../../../../util/DocumentManager'; import { LinkManager } from '../../../../util/LinkManager'; import { ViewBoxAnnotatableComponent } from '../../../DocComponent'; +import { DocumentView } from '../../DocumentView'; import { FieldView, FieldViewProps } from '../../FieldView'; +import { PDFBox } from '../../PDFBox'; +import { Agent } from '../agentsystem/Agent'; +import { ASSISTANT_ROLE, AssistantMessage, CHUNK_TYPE, Citation, ProcessingInfo, SimplifiedChunk, TEXT_TYPE } from '../types/types'; +import { Vectorstore } from '../vectorstore/Vectorstore'; import './ChatBox.scss'; import MessageComponentBox from './MessageComponent'; -import { ASSISTANT_ROLE, AssistantMessage, Citation, CHUNK_TYPE, TEXT_TYPE, SimplifiedChunk, ProcessingInfo } from '../types/types'; -import { Vectorstore } from '../vectorstore/Vectorstore'; -import { Agent } from '../agentsystem/Agent'; -import dotenv from 'dotenv'; -import { DocData, DocViews } from '../../../../../fields/DocSymbols'; -import { DocumentManager } from '../../../../util/DocumentManager'; -import { v4 as uuidv4 } from 'uuid'; -import { DocUtils } from '../../../../documents/DocUtils'; -import { ClientUtils } from '../../../../../ClientUtils'; import { ProgressBar } from './ProgressBar'; -import { DocumentView } from '../../DocumentView'; -import { Networking } from '../../../../Network'; -import { PDFViewer } from '../../../pdf/PDFViewer'; -import { PDFBox } from '../../PDFBox'; dotenv.config(); @@ -247,7 +246,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { * @param event The form submission event. */ @action - askGPT = async (event: React.FormEvent): Promise<any> => { + askGPT = async (event: React.FormEvent): Promise<void> => { event.preventDefault(); this.inputValue = ''; @@ -413,7 +412,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { const chunkId = citation.chunk_id; // Loop through the linked documents to find the matching chunk and handle its display - for (let doc of currentLinkedDocs) { + for (const doc of currentLinkedDocs) { if (doc.chunk_simpl) { const docChunkSimpl = JSON.parse(StrCast(doc.chunk_simpl)) as { chunks: SimplifiedChunk[] }; const foundChunk = docChunkSimpl.chunks.find(chunk => chunk.chunkId === chunkId); @@ -422,24 +421,26 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { switch (foundChunk.chunkType) { case CHUNK_TYPE.IMAGE: case CHUNK_TYPE.TABLE: - const values = foundChunk.location?.replace(/[\[\]]/g, '').split(','); + { + const values = foundChunk.location?.replace(/[[\]]/g, '').split(','); - if (values?.length !== 4) { - console.error('Location string must contain exactly 4 numbers'); - return; - } + if (values?.length !== 4) { + console.error('Location string must contain exactly 4 numbers'); + return; + } - const x1 = parseFloat(values[0]) * Doc.NativeWidth(doc); - const y1 = parseFloat(values[1]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc); - const x2 = parseFloat(values[2]) * Doc.NativeWidth(doc); - const y2 = parseFloat(values[3]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc); + const x1 = parseFloat(values[0]) * Doc.NativeWidth(doc); + const y1 = parseFloat(values[1]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc); + const x2 = parseFloat(values[2]) * Doc.NativeWidth(doc); + const y2 = parseFloat(values[3]) * Doc.NativeHeight(doc) + foundChunk.startPage * Doc.NativeHeight(doc); - const annotationKey = Doc.LayoutFieldKey(doc) + '_annotations'; + const annotationKey = Doc.LayoutFieldKey(doc) + '_annotations'; - const existingDoc = DocListCast(doc[DocData][annotationKey]).find(d => d.citation_id === citation.citation_id); - const highlightDoc = existingDoc ?? this.createImageCitationHighlight(x1, y1, x2, y2, citation, annotationKey, doc); + const existingDoc = DocListCast(doc[DocData][annotationKey]).find(d => d.citation_id === citation.citation_id); + const highlightDoc = existingDoc ?? this.createImageCitationHighlight(x1, y1, x2, y2, citation, annotationKey, doc); - DocumentManager.Instance.showDocument(highlightDoc, { willZoomCentered: true }, () => {}); + DocumentManager.Instance.showDocument(highlightDoc, { willZoomCentered: true }, () => {}); + } break; case CHUNK_TYPE.TEXT: this.citationPopup = { text: citation.direct_text ?? 'No text available', visible: true }; @@ -695,7 +696,7 @@ export class ChatBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { </div> )} <div className="chat-header"> - <h2>{this.userName()}'s AI Assistant</h2> + <h2>{this.userName()}'s AI Assistant</h2> </div> <div className="chat-messages" ref={this.messagesRef}> {this.history.map((message, index) => ( diff --git a/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts b/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts index 3b4fdb6f5..1ac753790 100644 --- a/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts +++ b/src/client/views/nodes/chatbot/response_parsers/AnswerParser.ts @@ -1,5 +1,5 @@ -import { ASSISTANT_ROLE, AssistantMessage, Citation, CHUNK_TYPE, TEXT_TYPE, getChunkType, ProcessingInfo } from '../types/types'; import { v4 as uuid } from 'uuid'; +import { ASSISTANT_ROLE, AssistantMessage, Citation, ProcessingInfo, TEXT_TYPE, getChunkType } from '../types/types'; export class AnswerParser { static parse(xml: string, processingInfo: ProcessingInfo[]): AssistantMessage { @@ -22,8 +22,8 @@ export class AnswerParser { } let rawTextContent = answerMatch[1].trim(); - let content: AssistantMessage['content'] = []; - let citations: Citation[] = []; + const content: AssistantMessage['content'] = []; + const citations: Citation[] = []; let contentIndex = 0; // Remove citations and follow-up questions from rawTextContent @@ -43,6 +43,7 @@ export class AnswerParser { if (citationsMatch) { const citationsContent = citationsMatch[1]; while ((citationMatch = citationRegex.exec(citationsContent)) !== null) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [_, index, chunk_id, type, direct_text] = citationMatch; const citation_id = uuid(); citationMap.set(index, citation_id); @@ -102,7 +103,7 @@ export class AnswerParser { } } - let followUpQuestions: string[] = []; + const followUpQuestions: string[] = []; if (followUpQuestionsMatch) { const questionsText = followUpQuestionsMatch[1]; let questionMatch; diff --git a/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts b/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts index 3585cab4a..4149f3da9 100644 --- a/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts +++ b/src/client/views/nodes/chatbot/response_parsers/StreamedAnswerParser.ts @@ -1,5 +1,3 @@ -import { threadId } from 'worker_threads'; - enum ParserState { Outside, InGroundedText, diff --git a/src/client/views/nodes/chatbot/tools/BaseTool.ts b/src/client/views/nodes/chatbot/tools/BaseTool.ts index b57f1c8e4..10780617b 100644 --- a/src/client/views/nodes/chatbot/tools/BaseTool.ts +++ b/src/client/views/nodes/chatbot/tools/BaseTool.ts @@ -1,17 +1,17 @@ import { Tool } from '../types/types'; -export abstract class BaseTool<T extends Record<string, any> = Record<string, any>> implements Tool<T> { +export abstract class BaseTool<T extends Record<string, unknown> = Record<string, unknown>> implements Tool<T> { constructor( public name: string, public description: string, - public parameters: Record<string, any>, + public parameters: Record<string, unknown>, public citationRules: string, public briefSummary: string ) {} - abstract execute(args: T): Promise<any>; + abstract execute(args: T): Promise<unknown>; - getActionRule(): Record<string, any> { + getActionRule(): Record<string, unknown> { return { [this.name]: { name: this.name, diff --git a/src/client/views/nodes/chatbot/tools/CalculateTool.ts b/src/client/views/nodes/chatbot/tools/CalculateTool.ts index 74b7ca27b..77ab1b39b 100644 --- a/src/client/views/nodes/chatbot/tools/CalculateTool.ts +++ b/src/client/views/nodes/chatbot/tools/CalculateTool.ts @@ -18,7 +18,7 @@ export class CalculateTool extends BaseTool<{ expression: string }> { ); } - async execute(args: { expression: string }): Promise<any> { + async execute(args: { expression: string }): Promise<unknown> { // Note: Using eval() can be dangerous. Consider using a safer alternative. const result = eval(args.expression); return [{ type: 'text', text: result.toString() }]; diff --git a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts index 55015846b..d3ded0de0 100644 --- a/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts +++ b/src/client/views/nodes/chatbot/tools/CreateCSVTool.ts @@ -28,7 +28,7 @@ export class CreateCSVTool extends BaseTool<{ csvData: string; filename: string this._handleCSVResult = handleCSVResult; } - async execute(args: { csvData: string; filename: string }): Promise<any> { + async execute(args: { csvData: string; filename: string }): Promise<unknown> { try { console.log('Creating CSV file:', args.filename, ' with data:', args.csvData); // Post the raw CSV data to the createCSV endpoint on the server diff --git a/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts b/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts index 573428179..1e479a62c 100644 --- a/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts +++ b/src/client/views/nodes/chatbot/tools/CreateCollectionTool.ts @@ -25,7 +25,7 @@ export class GetDocsContentTool extends BaseTool<{ title: string; document_ids: this._docView = docView; } - async execute(args: { title: string; document_ids: string[] }): Promise<any> { + async execute(args: { title: string; document_ids: string[] }): Promise<unknown> { // Note: Using eval() can be dangerous. Consider using a safer alternative. const docs = args.document_ids.map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id))); const collection = Docs.Create.FreeformDocument(docs, { title: args.title }); diff --git a/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts b/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts index a12ee46e5..2e663fed1 100644 --- a/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts +++ b/src/client/views/nodes/chatbot/tools/DataAnalysisTool.ts @@ -33,7 +33,7 @@ export class DataAnalysisTool extends BaseTool<{ csv_file_name: string | string[ return file?.id; } - async execute(args: { csv_file_name: string | string[] }): Promise<any> { + async execute(args: { csv_file_name: string | string[] }): Promise<unknown> { const filenames = Array.isArray(args.csv_file_name) ? args.csv_file_name : [args.csv_file_name]; const results = []; diff --git a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts index f970ca8ee..903f3f69c 100644 --- a/src/client/views/nodes/chatbot/tools/GetDocsTool.ts +++ b/src/client/views/nodes/chatbot/tools/GetDocsTool.ts @@ -18,7 +18,7 @@ export class GetDocsTool extends BaseTool<{ title: string; document_ids: string[ this._docView = docView; } - async execute(args: { title: string; document_ids: string[] }): Promise<any> { + async execute(args: { title: string; document_ids: string[] }): Promise<unknown> { // Note: Using eval() can be dangerous. Consider using a safer alternative. const docs = args.document_ids.map(doc_id => DocCast(DocServer.GetCachedRefField(doc_id))); const collection = Docs.Create.FreeformDocument(docs, { title: args.title }); diff --git a/src/client/views/nodes/chatbot/tools/NoTool.ts b/src/client/views/nodes/chatbot/tools/NoTool.ts index 1f0830a77..edd3160ec 100644 --- a/src/client/views/nodes/chatbot/tools/NoTool.ts +++ b/src/client/views/nodes/chatbot/tools/NoTool.ts @@ -1,7 +1,7 @@ // tools/NoTool.ts import { BaseTool } from './BaseTool'; -export class NoTool extends BaseTool<{}> { +export class NoTool extends BaseTool<Record<string, unknown>> { constructor() { super( 'no_tool', @@ -12,7 +12,8 @@ export class NoTool extends BaseTool<{}> { ); } - async execute(args: {}): Promise<any> { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + async execute(args: object): Promise<unknown> { return [{ type: 'text', text: 'No tool used. Proceed with answering the question.' }]; } } diff --git a/src/client/views/nodes/chatbot/tools/RAGTool.ts b/src/client/views/nodes/chatbot/tools/RAGTool.ts index f4b7b42ea..4cc2f26ff 100644 --- a/src/client/views/nodes/chatbot/tools/RAGTool.ts +++ b/src/client/views/nodes/chatbot/tools/RAGTool.ts @@ -1,10 +1,7 @@ -import { BaseTool } from './BaseTool'; -import { Vectorstore } from '../vectorstore/Vectorstore'; -import { RAGChunk } from '../types/types'; -import * as fs from 'fs'; import { Networking } from '../../../../Network'; -import { file } from 'jszip'; -import { ChatCompletion, ChatCompletionContentPart, ChatCompletionMessageParam } from 'openai/resources'; +import { RAGChunk } from '../types/types'; +import { Vectorstore } from '../vectorstore/Vectorstore'; +import { BaseTool } from './BaseTool'; export class RAGTool extends BaseTool { constructor(private vectorstore: Vectorstore) { @@ -59,13 +56,13 @@ export class RAGTool extends BaseTool { ); } - async execute(args: { hypothetical_document_chunk: string }): Promise<any> { + async execute(args: { hypothetical_document_chunk: string }): Promise<unknown> { const relevantChunks = await this.vectorstore.retrieve(args.hypothetical_document_chunk); const formatted_chunks = await this.getFormattedChunks(relevantChunks); return formatted_chunks; } - async getFormattedChunks(relevantChunks: RAGChunk[]): Promise<any> { + async getFormattedChunks(relevantChunks: RAGChunk[]): Promise<unknown> { try { const { formattedChunks } = await Networking.PostToServer('/formatChunks', { relevantChunks }); diff --git a/src/client/views/nodes/chatbot/tools/SearchTool.ts b/src/client/views/nodes/chatbot/tools/SearchTool.ts index b926cbadc..3a4668422 100644 --- a/src/client/views/nodes/chatbot/tools/SearchTool.ts +++ b/src/client/views/nodes/chatbot/tools/SearchTool.ts @@ -1,7 +1,6 @@ -import { max } from 'lodash'; +import { v4 as uuidv4 } from 'uuid'; import { Networking } from '../../../../Network'; import { BaseTool } from './BaseTool'; -import { v4 as uuidv4 } from 'uuid'; export class SearchTool extends BaseTool<{ query: string | string[] }> { private _addLinkedUrlDoc: (url: string, id: string) => void; @@ -25,7 +24,7 @@ export class SearchTool extends BaseTool<{ query: string | string[] }> { this._max_results = max_results; } - async execute(args: { query: string | string[] }): Promise<any> { + async execute(args: { query: string | string[] }): Promise<unknown> { const queries = Array.isArray(args.query) ? args.query : [args.query]; const allResults = []; diff --git a/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts b/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts index 2118218f6..1efb389b8 100644 --- a/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts +++ b/src/client/views/nodes/chatbot/tools/WebsiteInfoScraperTool.ts @@ -1,6 +1,6 @@ +import { v4 as uuidv4 } from 'uuid'; import { Networking } from '../../../../Network'; import { BaseTool } from './BaseTool'; -import { v4 as uuidv4 } from 'uuid'; export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }> { private _addLinkedUrlDoc: (url: string, id: string) => void; @@ -63,7 +63,7 @@ export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }> this._addLinkedUrlDoc = addLinkedUrlDoc; } - async execute(args: { url: string | string[] }): Promise<any> { + async execute(args: { url: string | string[] }): Promise<unknown> { const urls = Array.isArray(args.url) ? args.url : [args.url]; const results = []; @@ -74,6 +74,7 @@ export class WebsiteInfoScraperTool extends BaseTool<{ url: string | string[] }> this._addLinkedUrlDoc(url, id); results.push({ type: 'text', text: `<chunk chunk_id=${id} chunk_type=url>\n${website_plain_text}\n</chunk>\n` }); } catch (error) { + console.log(error); results.push({ type: 'text', text: `An error occurred while scraping the website: ${url}` }); } } diff --git a/src/client/views/nodes/chatbot/tools/WikipediaTool.ts b/src/client/views/nodes/chatbot/tools/WikipediaTool.ts index 143d91d80..692dff749 100644 --- a/src/client/views/nodes/chatbot/tools/WikipediaTool.ts +++ b/src/client/views/nodes/chatbot/tools/WikipediaTool.ts @@ -1,8 +1,6 @@ -import { title } from 'process'; +import { v4 as uuidv4 } from 'uuid'; import { Networking } from '../../../../Network'; import { BaseTool } from './BaseTool'; -import axios from 'axios'; -import { v4 as uuidv4 } from 'uuid'; export class WikipediaTool extends BaseTool<{ title: string }> { private _addLinkedUrlDoc: (url: string, id: string) => void; @@ -23,7 +21,7 @@ export class WikipediaTool extends BaseTool<{ title: string }> { this._addLinkedUrlDoc = addLinkedUrlDoc; } - async execute(args: { title: string }): Promise<any> { + async execute(args: { title: string }): Promise<unknown> { try { const { text } = await Networking.PostToServer('/getWikipediaSummary', { title: args.title }); const id = uuidv4(); @@ -31,6 +29,7 @@ export class WikipediaTool extends BaseTool<{ title: string }> { this._addLinkedUrlDoc(url, id); return [{ type: 'text', text: `<chunk chunk_id=${id} chunk_type=csv}> ${text} </chunk>` }]; } catch (error) { + console.log(error); return [{ type: 'text', text: 'An error occurred while fetching the article.' }]; } } diff --git a/src/client/views/nodes/chatbot/types/types.ts b/src/client/views/nodes/chatbot/types/types.ts index f5d14ad6a..2bc7f4952 100644 --- a/src/client/views/nodes/chatbot/types/types.ts +++ b/src/client/views/nodes/chatbot/types/types.ts @@ -52,15 +52,6 @@ export interface ProcessingInfo { content: string; } -export interface AssistantMessage { - role: ASSISTANT_ROLE; - content: MessageContent[]; - follow_up_questions?: string[]; - citations?: Citation[]; - processing_info: ProcessingInfo[]; - loop_summary?: string; -} - export interface MessageContent { index: number; type: TEXT_TYPE; @@ -75,6 +66,14 @@ export interface Citation { citation_id: string; url?: string; } +export interface AssistantMessage { + role: ASSISTANT_ROLE; + content: MessageContent[]; + follow_up_questions?: string[]; + citations?: Citation[]; + processing_info: ProcessingInfo[]; + loop_summary?: string; +} export interface RAGChunk { id: string; @@ -113,14 +112,14 @@ export interface AI_Document { type: string; } -export interface Tool<T extends Record<string, any> = Record<string, any>> { +export interface Tool<T extends Record<string, unknown> = Record<string, unknown>> { name: string; description: string; - parameters: Record<string, any>; + parameters: Record<string, unknown>; citationRules: string; briefSummary: string; - execute: (args: T) => Promise<any>; - getActionRule: () => Record<string, any>; + execute: (args: T) => Promise<unknown>; + getActionRule: () => Record<string, unknown>; } export interface AgentMessage { diff --git a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts index 07a2b73bc..9575277f7 100644 --- a/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts +++ b/src/client/views/nodes/chatbot/vectorstore/Vectorstore.ts @@ -1,11 +1,11 @@ -import { Pinecone, Index, IndexList, PineconeRecord, RecordMetadata, QueryResponse } from '@pinecone-database/pinecone'; +import { Index, IndexList, Pinecone, PineconeRecord, QueryResponse, RecordMetadata } from '@pinecone-database/pinecone'; import { CohereClient } from 'cohere-ai'; import { EmbedResponse } from 'cohere-ai/api'; import dotenv from 'dotenv'; -import { RAGChunk, AI_Document, CHUNK_TYPE } from '../types/types'; import { Doc } from '../../../../../fields/Doc'; import { CsvCast, PDFCast, StrCast } from '../../../../../fields/Types'; import { Networking } from '../../../../Network'; +import { AI_Document, CHUNK_TYPE, RAGChunk } from '../types/types'; dotenv.config(); @@ -103,8 +103,8 @@ export class Vectorstore { const { jobId } = await Networking.PostToServer('/createDocument', { file_path: local_file_path }); // Poll the server for progress updates. - let inProgress: boolean = true; - let result: any = null; + const inProgress = true; + let result: (AI_Document & { doc_id: string }) | null = null; // bcz: is this the correct type?? while (inProgress) { // Polling interval for status updates. await new Promise(resolve => setTimeout(resolve, 2000)); @@ -127,6 +127,9 @@ export class Vectorstore { progressCallback(progress, step); } } + if (!result) { + throw new Error('no result received...'); // bcz: is this an Error? + } // Once completed, process the document and add it to the vectorstore. console.log('Document JSON:', result); @@ -175,7 +178,7 @@ export class Vectorstore { * Indexes the processed document by uploading the document's vector chunks to the Pinecone index. * @param document The processed document containing its chunks and metadata. */ - private async indexDocument(document: any) { + private async indexDocument(document: AI_Document) { console.log('Uploading vectors to content namespace...'); // Prepare Pinecone records for each chunk in the document. diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index 7543b3fb1..b5c69bff0 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -51,7 +51,7 @@ interface IViewerProps extends FieldViewProps { * Handles rendering and virtualization of the pdf */ @observer -export class PDFViewer extends ObservableReactComponent { +export class PDFViewer extends ObservableReactComponent<IViewerProps> { static _annotationStyle = addStyleSheet(); constructor(props: IViewerProps) { @@ -68,12 +68,12 @@ export class PDFViewer extends ObservableReactComponent { private _pdfViewer!: PDFJSViewer.PDFViewer; private _styleRule: number | undefined; // stylesheet rule for making hyperlinks clickable private _retries = 0; // number of times tried to create the PDF viewer - private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void); + private _setPreviewCursor: undefined | ((x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void); private _marqueeref = React.createRef<MarqueeAnnotator>(); - private _annotationLayer: React.RefObject = React.createRef(); + private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef(); private _disposers: { [name: string]: IReactionDisposer } = {}; - private _viewer: React.RefObject = React.createRef(); - _mainCont: React.RefObject = React.createRef(); + private _viewer: React.RefObject<HTMLDivElement> = React.createRef(); + _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); private _selectionText: string = ''; private _selectionContent: DocumentFragment | undefined; private _downX: number = 0; @@ -81,9 +81,9 @@ export class PDFViewer extends ObservableReactComponent { private _lastSearch = false; private _viewerIsSetup = false; private _ignoreScroll = false; - private _initialScroll: { loc: Opt; easeFunc: 'linear' | 'ease' | undefined } | undefined; + private _initialScroll: { loc: Opt<number>; easeFunc: 'linear' | 'ease' | undefined } | undefined; private _forcedScroll = true; - _getAnchor: (savedAnnotations: Opt, addAsAnnotation: boolean) => Opt = () => undefined; + _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined; selectionText = () => this._selectionText; selectionContent = () => this._selectionContent; @@ -179,7 +179,7 @@ export class PDFViewer extends ObservableReactComponent { // otherwise it will scroll smoothly. scrollFocus = (doc: Doc, scrollTop: number, options: FocusViewOptions) => { const mainCont = this._mainCont.current; - let focusSpeed: Opt; + let focusSpeed: Opt<number>; if (doc !== this._props.Document && mainCont) { const windowHeight = this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); const scrollTo = ClientUtils.scrollIntoView(scrollTop, doc[Height](), NumCast(this._props.layoutDoc._layout_scrollTop), windowHeight, windowHeight * 0.1, this._scrollHeight); @@ -394,30 +394,6 @@ export class PDFViewer extends ObservableReactComponent { } }; - // @action - // createMarquee = (coords: [x1: number, x2: number, y1: number, y2: number]): void => { - // // const hit = document.elementFromPoint(e.clientX, e.clientY); - // // bcz: Change. drag selecting requires that preventDefault is NOT called. This used to happen in DocumentView, - // // but that's changed, so this shouldn't be needed. - // // if (hit && hit.localName === "span" && this.annotationsActive(true)) { // drag selecting text stops propagation - // // e.button === 0 && e.stopPropagation(); - // // } - // // if alt+left click, drag and annotate - // this._downX = coords[0]; - // this._downY = coords[2]; - - // if ((this._props.Document._freeform_scale || 1) !== 1) return; - // this._props.select(false); - // MarqueeAnnotator.clearAnnotations(this._savedAnnotations); - // this.isAnnotating = true; - // this._textSelecting = false; - // // if textLayer is hit, then we select text instead of using a marquee so clear out the marquee. - // this._styleRule = addStyleSheetRule(PDFViewer._annotationStyle, 'htmlAnnotation', { 'pointer-events': 'none' }); - - // this._marqueeref.current?.onInitiateSelection([coords[0], coords[2]]); - // this._marqueeref.current?.onTerminateSelection(); - // }; - @action finishMarquee = (/* x?: number, y?: number */) => { this._getAnchor = AnchorMenu.Instance?.GetAnchor; @@ -495,7 +471,7 @@ export class PDFViewer extends ObservableReactComponent { // e.stopPropagation(); // bcz: not sure why this was here. We need to allow the DocumentView to get clicks to process doubleClicks }; - setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt) => void) => { + setPreviewCursor = (func?: (x: number, y: number, drag: boolean, hide: boolean, doc: Opt<Doc>) => void) => { this._setPreviewCursor = func; }; @@ -520,7 +496,6 @@ export class PDFViewer extends ObservableReactComponent { return ( <div className="pdfViewerDash-annotationLayer" style={{ height: Doc.NativeHeight(this._props.Document), transform: `scale(${NumCast(this._props.layoutDoc._freeform_scale, 1)})` }} ref={this._annotationLayer}> {inlineAnnos.map(anno => ( - // eslint-disable-next-line react/jsx-props-no-spreading <Annotation {...this._props} fieldKey={this._props.fieldKey + '_annotations'} pointerEvents={this.pointerEvents} containerDataDoc={this._props.dataDoc} annoDoc={anno} key={`${anno[Id]}-annotation`} /> ))} </div> @@ -534,7 +509,7 @@ export class PDFViewer extends ObservableReactComponent { panelHeight = () => this._props.PanelHeight() / (this._props.NativeDimScaling?.() || 1); transparentFilter = () => [...this._props.childFilters(), ClientUtils.TransparentBackgroundFilter]; opaqueFilter = () => [...this._props.childFilters(), ClientUtils.noDragDocsFilter, ...(SnappingManager.CanEmbed && this._props.isContentActive() ? [] : [ClientUtils.OpaqueBackgroundFilter])]; - childStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + childStyleProvider = (doc: Doc | undefined, props: Opt<FieldViewProps>, property: string) => { if (doc instanceof Doc && property === StyleProp.PointerEvents) { if (this.inlineTextAnnotations.includes(doc) || this._props.isContentActive() === false) return 'none'; const isInk = doc.layout_isSvg && !props?.LayoutTemplateString; @@ -554,7 +529,6 @@ export class PDFViewer extends ObservableReactComponent { pointerEvents: Doc.ActiveTool !== InkTool.None ? 'all' : undefined, }}> <CollectionFreeFormView - // eslint-disable-next-line react/jsx-props-no-spreading {...this._props} NativeWidth={returnZero} NativeHeight={returnZero} diff --git a/src/server/ApiManagers/AssistantManager.ts b/src/server/ApiManagers/AssistantManager.ts index e940fb121..b4ebb1eae 100644 --- a/src/server/ApiManagers/AssistantManager.ts +++ b/src/server/ApiManagers/AssistantManager.ts @@ -1,23 +1,19 @@ +import { Readability } from '@mozilla/readability'; +import axios from 'axios'; +import { spawn } from 'child_process'; import * as fs from 'fs'; -import { createReadStream, writeFile } from 'fs'; +import { writeFile } from 'fs'; +import { google } from 'googleapis'; +import { JSDOM } from 'jsdom'; import OpenAI from 'openai'; import * as path from 'path'; +import * as puppeteer from 'puppeteer'; import { promisify } from 'util'; import * as uuid from 'uuid'; -import { filesDirectory, publicDirectory } from '../SocketData'; +import { AI_Document } from '../../client/views/nodes/chatbot/types/types'; import { Method } from '../RouteManager'; +import { filesDirectory, publicDirectory } from '../SocketData'; import ApiManager, { Registration } from './ApiManager'; -import axios from 'axios'; -import { RAGChunk } from '../../client/views/nodes/chatbot/types/types'; -import { UnstructuredClient } from 'unstructured-client'; -import { PartitionResponse } from 'unstructured-client/sdk/models/operations'; -import { ChunkingStrategy, Strategy } from 'unstructured-client/sdk/models/shared'; -import * as cheerio from 'cheerio'; -import { google } from 'googleapis'; -import * as puppeteer from 'puppeteer'; -import { JSDOM } from 'jsdom'; -import { Readability } from '@mozilla/readability'; -import { spawn } from 'child_process'; // Enumeration of directories where different file types are stored export enum Directory { @@ -34,8 +30,8 @@ export enum Directory { } // In-memory job tracking -let jobResults: { [key: string]: any } = {}; -let jobProgress: { [key: string]: any } = {}; +const jobResults: { [key: string]: unknown } = {}; +const jobProgress: { [key: string]: unknown } = {}; /** * Constructs a normalized path to a file in the server's file system. @@ -81,10 +77,10 @@ export default class AssistantManager extends ApiManager { */ protected initialize(register: Registration): void { // Initialize OpenAI API with client key - const openai = new OpenAI({ + const openai = new OpenAI({ // bcz: is this needed? variable is never used... apiKey: process.env._CLIENT_OPENAI_KEY, dangerouslyAllowBrowser: true, - }); + }); // prettier-ignore // Initialize Google Custom Search API const customsearch = google.customsearch('v1'); @@ -107,11 +103,11 @@ export default class AssistantManager extends ApiManager { }); const summary = response.data.query.search[0]?.snippet || 'No article found with that title.'; res.send({ text: summary }); - } catch (error: any) { + } catch (error) { console.error('Error retrieving Wikipedia summary:', error); res.status(500).send({ error: 'Error retrieving article summary from Wikipedia.', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know what the error type contains... }); } }, @@ -134,17 +130,17 @@ export default class AssistantManager extends ApiManager { }); const results = - response.data.items?.map((item: any) => ({ + response.data.items?.map(item => ({ url: item.link, snippet: item.snippet, })) || []; res.send({ results }); - } catch (error: any) { + } catch (error) { console.error('Error performing web search:', error); res.status(500).send({ error: 'Failed to perform web search', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains... }); } }, @@ -170,16 +166,16 @@ export default class AssistantManager extends ApiManager { * @param retries The number of retry attempts. * @param backoff Initial backoff time in milliseconds. */ - const fetchWithRetry = async (url: string, retries = 3, backoff = 300) => { + const fetchWithRetry = async (url: string, retries = 3, backoff = 300): Promise<unknown> => { try { const response = await axiosInstance.get(url); return response.data; - } catch (error: any) { - if (retries > 0 && error.response?.status === 429) { + } catch (error) { + if (retries > 0 && (error as { response: { status: number } }).response?.status === 429) { // bcz: don't know the error type console.log(`Rate limited. Retrying in ${backoff}ms...`); await delay(backoff); return fetchWithRetry(url, retries - 1, backoff * 2); - } + } // prettier-ignore throw error; } }; @@ -199,11 +195,11 @@ export default class AssistantManager extends ApiManager { try { const data = await fetchWithRetry(url); res.send({ data }); - } catch (error: any) { + } catch (error) { console.error('Error fetching the URL:', error); res.status(500).send({ error: 'Failed to fetch the URL', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains... }); } }, @@ -241,11 +237,11 @@ export default class AssistantManager extends ApiManager { } else { res.status(500).send({ error: 'Failed to extract readable content' }); } - } catch (error: any) { + } catch (error) { console.error('Error scraping website:', error); res.status(500).send({ error: 'Failed to scrape website', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains... }); } }, @@ -267,15 +263,16 @@ export default class AssistantManager extends ApiManager { const jobId = uuid.v4(); // Spawn the Python process and track its progress/output + // eslint-disable-next-line no-use-before-define spawnPythonProcess(jobId, file_name, file_data); // Send the job ID back to the client for tracking res.send({ jobId }); - } catch (error: any) { + } catch (error) { console.error('Error initiating document creation:', error); res.status(500).send({ error: 'Failed to initiate document creation', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know wha tthe error type contains... }); } }, @@ -307,13 +304,13 @@ export default class AssistantManager extends ApiManager { const { jobId } = req.params; // Get the job ID from the URL parameters // Check if the job result is available if (jobResults[jobId]) { - const result = jobResults[jobId]; + const result = jobResults[jobId] as AI_Document & { status: string }; // If the result contains image or table chunks, save the base64 data as image files if (result.chunks && Array.isArray(result.chunks)) { for (const chunk of result.chunks) { if (chunk.metadata && (chunk.metadata.type === 'image' || chunk.metadata.type === 'table')) { - let files_directory = '/files/chunk_images/'; + const files_directory = '/files/chunk_images/'; const directory = path.join(publicDirectory, files_directory); // Ensure the directory exists or create it @@ -338,7 +335,7 @@ export default class AssistantManager extends ApiManager { } } } - result['status'] = 'completed'; + result.status = 'completed'; } else { result.status = 'pending'; } @@ -429,11 +426,11 @@ export default class AssistantManager extends ApiManager { // Send the file URL and UUID back to the client res.send({ fileUrl, id: uuidv4 }); - } catch (error: any) { + } catch (error) { console.error('Error creating CSV file:', error); res.status(500).send({ error: 'Failed to create CSV file.', - details: error.message, + details: (error as { message: string }).message ?? error, // bcz: don't know what the error type contains... }); } }, @@ -446,59 +443,6 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string) const requirementsPath = path.join(__dirname, '../chunker/requirements.txt'); const pythonScriptPath = path.join(__dirname, '../chunker/pdf_chunker.py'); - // Check if venv exists - if (!fs.existsSync(venvPath)) { - console.log('Virtual environment not found. Creating and setting up...'); - - // Create venv - const createVenvProcess = spawn('python', ['-m', 'venv', venvPath]); - - createVenvProcess.on('close', code => { - if (code !== 0) { - console.error(`Failed to create virtual environment. Exit code: ${code}`); - return; - } - - console.log('Virtual environment created. Installing requirements...'); - - // Determine the pip path based on the OS - const pipPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'pip.exe') : path.join(venvPath, 'bin', 'pip3'); // Try 'pip3' for Unix-like systems - - if (!fs.existsSync(pipPath)) { - console.error(`pip executable not found at ${pipPath}`); - return; - } - - // Install requirements - const installRequirementsProcess = spawn(pipPath, ['install', '-r', requirementsPath]); - - installRequirementsProcess.stdout.on('data', data => { - console.log(`pip stdout: ${data}`); - }); - - installRequirementsProcess.stderr.on('data', data => { - console.error(`pip stderr: ${data}`); - }); - - installRequirementsProcess.on('error', error => { - console.error(`Error starting pip process: ${error}`); - }); - - installRequirementsProcess.on('close', code => { - if (code !== 0) { - console.error(`Failed to install requirements. Exit code: ${code}`); - return; - } - - console.log('Requirements installed. Running Python script...'); - runPythonScript(); - }); - }); - } else { - console.log('Virtual environment found. Running Python script...'); - runPythonScript(); - } - function runPythonScript() { const pythonPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'python') : path.join(venvPath, 'bin', 'python3'); @@ -530,7 +474,7 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string) }; } } catch (err) { - console.error('Progress log from Python:', line); + console.error('Progress log from Python:', line, err); } } }); @@ -551,4 +495,56 @@ function spawnPythonProcess(jobId: string, file_name: string, file_data: string) } }); } + // Check if venv exists + if (!fs.existsSync(venvPath)) { + console.log('Virtual environment not found. Creating and setting up...'); + + // Create venv + const createVenvProcess = spawn('python', ['-m', 'venv', venvPath]); + + createVenvProcess.on('close', code => { + if (code !== 0) { + console.error(`Failed to create virtual environment. Exit code: ${code}`); + return; + } + + console.log('Virtual environment created. Installing requirements...'); + + // Determine the pip path based on the OS + const pipPath = process.platform === 'win32' ? path.join(venvPath, 'Scripts', 'pip.exe') : path.join(venvPath, 'bin', 'pip3'); // Try 'pip3' for Unix-like systems + + if (!fs.existsSync(pipPath)) { + console.error(`pip executable not found at ${pipPath}`); + return; + } + + // Install requirements + const installRequirementsProcess = spawn(pipPath, ['install', '-r', requirementsPath]); + + installRequirementsProcess.stdout.on('data', data => { + console.log(`pip stdout: ${data}`); + }); + + installRequirementsProcess.stderr.on('data', data => { + console.error(`pip stderr: ${data}`); + }); + + installRequirementsProcess.on('error', error => { + console.error(`Error starting pip process: ${error}`); + }); + + installRequirementsProcess.on('close', closecode => { + if (closecode !== 0) { + console.error(`Failed to install requirements. Exit code: ${closecode}`); + return; + } + + console.log('Requirements installed. Running Python script...'); + runPythonScript(); + }); + }); + } else { + console.log('Virtual environment found. Running Python script...'); + runPythonScript(); + } } |