Files
Flowise/packages/server/src/Interface.DocumentStore.ts
T
Vinod Kiran bf05f25f7e New Feature Pagination (#4704)
* common pagination component

* Pagination for Doc Store Dashboard

* Pagination for Executions Dashboard

* Pagination Support for Tables

* lint fixes

* update view message dialog UI

* initial loading was ignoring the pagination counts

* 1) default page size change
2) ensure page limits are passed on load
3) co-pilot review comments (n+1 query)
4)

* 1) default page size change
2) ensure page limits are passed on load
3) co-pilot review comments (n+1 query)
4) refresh lists after insert/delete.

* Enhancement: Improve handling of empty responses in DocumentStore and API key services

- Added check for empty entities in DocumentStoreDTO.fromEntities to return an empty array.
- Updated condition in getAllDocumentStores to handle total count correctly, allowing for zero total.
- Refined logic in getAllApiKeys to check for empty keys and ensure correct API key retrieval.
- Adjusted UI components to safely handle potential undefined apiKeys array.

* Refresh API key list on pagination change

* Enhancement: Update pagination and filter handling across components
- Increased default items per page in AgentExecutions from 10 to 12.
- Improved JSON parsing for chat type and feedback type filters in ViewMessagesDialog.
- Enhanced execution filtering logic in AgentExecutions to ensure proper pagination and state management.
- Refactored filter section in AgentExecutions for better readability and functionality.
- Updated refresh logic in Agentflows to use the correct agentflow version.

* add workspaceId to removeAllChatMessages

* Refactor chat message retrieval logic for improved efficiency and maintainability

- Introduced a new `handleFeedbackQuery` function to streamline feedback-related queries.
- Enhanced pagination handling for session-based queries in `getMessagesWithFeedback`.
- Updated `ViewMessagesDialog` to sort messages in descending order by default.
- Simplified image rendering logic in `DocumentStoreTable` for better readability.

* - Update  `validateChatflowAPIKey` and `validateAPIKey` functions to get the correct keys array
- Enhanced error handling in the `sanitizeExecution` function to ensure safe access to nested properties

* Refactor API key validation logic for improved accuracy and error handling

- Consolidated API key validation in `validateAPIKey` to return detailed validation results.
- Updated `validateFlowAPIKey` to streamline flow API key validation.
- Introduced `getApiKeyById` function in the API key service for better key retrieval.
- Removed unused function `getAllChatSessionsFromChatflow` from the chat message API.

---------

Co-authored-by: Henry <hzj94@hotmail.com>
2025-07-10 15:59:24 +01:00

309 lines
8.7 KiB
TypeScript

import { ICommonObject } from 'flowise-components'
import { DocumentStore } from './database/entities/DocumentStore'
import { DataSource } from 'typeorm'
import { IComponentNodes } from './Interface'
import { Telemetry } from './utils/telemetry'
import { CachePool } from './CachePool'
import { UsageCacheManager } from './UsageCacheManager'
export enum DocumentStoreStatus {
EMPTY_SYNC = 'EMPTY',
SYNC = 'SYNC',
SYNCING = 'SYNCING',
STALE = 'STALE',
NEW = 'NEW',
UPSERTING = 'UPSERTING',
UPSERTED = 'UPSERTED'
}
export interface IDocumentStore {
id: string
name: string
description: string
loaders: string // JSON string
whereUsed: string // JSON string
updatedDate: Date
createdDate: Date
status: DocumentStoreStatus
vectorStoreConfig: string | null // JSON string
embeddingConfig: string | null // JSON string
recordManagerConfig: string | null // JSON string
workspaceId?: string
}
export interface IDocumentStoreFileChunk {
id: string
chunkNo: number
docId: string
storeId: string
pageContent: string
metadata: string
}
export interface IDocumentStoreFileChunkPagedResponse {
chunks: IDocumentStoreFileChunk[]
count: number
characters: number
file?: IDocumentStoreLoader
currentPage: number
storeName: string
description: string
docId: string
workspaceId?: string
}
export interface IDocumentStoreLoader {
id?: string
loaderId?: string
loaderName?: string
loaderConfig?: any // JSON string
splitterId?: string
splitterName?: string
splitterConfig?: any // JSON string
totalChunks?: number
totalChars?: number
status?: DocumentStoreStatus
storeId?: string
files?: IDocumentStoreLoaderFile[]
source?: string
credential?: string
}
export interface IDocumentStoreLoaderForPreview extends IDocumentStoreLoader {
rehydrated?: boolean
preview?: boolean
previewChunkCount?: number
}
export interface IDocumentStoreUpsertData {
docId: string
metadata?: string | object
replaceExisting?: boolean
createNewDocStore?: boolean
docStore?: IDocumentStore
loader?: {
name: string
config: ICommonObject
}
splitter?: {
name: string
config: ICommonObject
}
vectorStore?: {
name: string
config: ICommonObject
}
embedding?: {
name: string
config: ICommonObject
}
recordManager?: {
name: string
config: ICommonObject
}
}
export interface IDocumentStoreRefreshData {
items: IDocumentStoreUpsertData[]
}
export interface IDocumentStoreLoaderFile {
id: string
name: string
mimePrefix: string
size: number
status: DocumentStoreStatus
uploaded: Date
}
export interface IDocumentStoreWhereUsed {
id: string
name: string
}
export interface IUpsertQueueAppServer {
orgId: string
workspaceId: string
subscriptionId: string
appDataSource: DataSource
componentNodes: IComponentNodes
telemetry: Telemetry
usageCacheManager: UsageCacheManager
cachePool?: CachePool
}
export interface IExecuteDocStoreUpsert extends IUpsertQueueAppServer {
storeId: string
totalItems: IDocumentStoreUpsertData[]
files: Express.Multer.File[]
isRefreshAPI: boolean
}
export interface IExecutePreviewLoader extends Omit<IUpsertQueueAppServer, 'telemetry'> {
data: IDocumentStoreLoaderForPreview
isPreviewOnly: boolean
telemetry?: Telemetry
}
export interface IExecuteProcessLoader extends IUpsertQueueAppServer {
data: IDocumentStoreLoaderForPreview
docLoaderId: string
isProcessWithoutUpsert: boolean
}
export interface IExecuteVectorStoreInsert extends IUpsertQueueAppServer {
data: ICommonObject
isStrictSave: boolean
isVectorStoreInsert: boolean
}
const getFileName = (fileBase64: string) => {
let fileNames = []
if (fileBase64.startsWith('FILE-STORAGE::')) {
const names = fileBase64.substring(14)
if (names.includes('[') && names.includes(']')) {
const files = JSON.parse(names)
return files.join(', ')
} else {
return fileBase64.substring(14)
}
}
if (fileBase64.startsWith('[') && fileBase64.endsWith(']')) {
const files = JSON.parse(fileBase64)
for (const file of files) {
const splitDataURI = file.split(',')
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1]
fileNames.push(filename)
}
return fileNames.join(', ')
} else {
const splitDataURI = fileBase64.split(',')
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1]
return filename
}
}
export const addLoaderSource = (loader: IDocumentStoreLoader, isGetFileNameOnly = false) => {
let source = 'None'
const handleUnstructuredFileLoader = (config: any, isGetFileNameOnly: boolean): string => {
if (config.fileObject) {
return isGetFileNameOnly ? getFileName(config.fileObject) : config.fileObject.replace('FILE-STORAGE::', '')
}
return config.filePath || 'None'
}
switch (loader.loaderId) {
case 'pdfFile':
case 'docxFile':
case 'jsonFile':
case 'csvFile':
case 'file':
case 'jsonlinesFile':
case 'txtFile':
source = isGetFileNameOnly
? getFileName(loader.loaderConfig?.[loader.loaderId])
: loader.loaderConfig?.[loader.loaderId]?.replace('FILE-STORAGE::', '') || 'None'
break
case 'apiLoader':
source = loader.loaderConfig?.url + ' (' + loader.loaderConfig?.method + ')'
break
case 'cheerioWebScraper':
case 'playwrightWebScraper':
case 'puppeteerWebScraper':
source = loader.loaderConfig?.url || 'None'
break
case 'unstructuredFileLoader':
source = handleUnstructuredFileLoader(loader.loaderConfig || {}, isGetFileNameOnly)
break
default:
source = 'None'
break
}
return source
}
export class DocumentStoreDTO {
id: string
name: string
description: string
files: IDocumentStoreLoaderFile[]
whereUsed: IDocumentStoreWhereUsed[]
createdDate: Date
updatedDate: Date
status: DocumentStoreStatus
chunkOverlap: number
splitter: string
totalChunks: number
totalChars: number
chunkSize: number
workspaceId?: string
loaders: IDocumentStoreLoader[]
vectorStoreConfig: any
embeddingConfig: any
recordManagerConfig: any
constructor() {}
static fromEntity(entity: DocumentStore): DocumentStoreDTO {
let documentStoreDTO = new DocumentStoreDTO()
Object.assign(documentStoreDTO, entity)
documentStoreDTO.id = entity.id
documentStoreDTO.name = entity.name
documentStoreDTO.description = entity.description
documentStoreDTO.status = entity.status
documentStoreDTO.workspaceId = entity.workspaceId
documentStoreDTO.totalChars = 0
documentStoreDTO.totalChunks = 0
if (entity.whereUsed) {
documentStoreDTO.whereUsed = JSON.parse(entity.whereUsed)
} else {
documentStoreDTO.whereUsed = []
}
if (entity.vectorStoreConfig) {
documentStoreDTO.vectorStoreConfig = JSON.parse(entity.vectorStoreConfig)
}
if (entity.embeddingConfig) {
documentStoreDTO.embeddingConfig = JSON.parse(entity.embeddingConfig)
}
if (entity.recordManagerConfig) {
documentStoreDTO.recordManagerConfig = JSON.parse(entity.recordManagerConfig)
}
if (entity.loaders) {
documentStoreDTO.loaders = JSON.parse(entity.loaders)
documentStoreDTO.loaders.map((loader) => {
documentStoreDTO.totalChars += loader.totalChars || 0
documentStoreDTO.totalChunks += loader.totalChunks || 0
loader.source = addLoaderSource(loader)
if (loader.status !== 'SYNC') {
documentStoreDTO.status = DocumentStoreStatus.STALE
}
})
}
return documentStoreDTO
}
static fromEntities(entities: DocumentStore[]): DocumentStoreDTO[] {
if (entities.length === 0) {
return []
}
return entities.map((entity) => this.fromEntity(entity))
}
static toEntity(body: any): DocumentStore {
const docStore = new DocumentStore()
Object.assign(docStore, body)
docStore.loaders = '[]'
docStore.whereUsed = '[]'
// when a new document store is created, it is empty and in sync
docStore.status = DocumentStoreStatus.EMPTY_SYNC
return docStore
}
}