UNPKG

dtamind-components

Version:

Apps integration for Dtamind. Contain Nodes and Credentials.

128 lines (100 loc) 4.91 kB
/* * Temporary disabled due to increasing open connections without releasing them * Use TypeORM instead import { VectorStoreDriver } from './Base' import { FLOWISE_CHATID } from '../../../../src' import { DistanceStrategy, PGVectorStore, PGVectorStoreArgs } from '@langchain/community/vectorstores/pgvector' import { Document } from '@langchain/core/documents' import { PoolConfig } from 'pg' import { getContentColumnName } from '../utils' export class PGVectorDriver extends VectorStoreDriver { static CONTENT_COLUMN_NAME_DEFAULT: string = 'pageContent' protected _postgresConnectionOptions: PoolConfig protected async getPostgresConnectionOptions() { if (!this._postgresConnectionOptions) { const { user, password } = await this.getCredentials() const additionalConfig = this.nodeData.inputs?.additionalConfig as string let additionalConfiguration = {} if (additionalConfig) { try { additionalConfiguration = typeof additionalConfig === 'object' ? additionalConfig : JSON.parse(additionalConfig) } catch (exception) { throw new Error('Invalid JSON in the Additional Configuration: ' + exception) } } this._postgresConnectionOptions = { ...additionalConfiguration, host: this.getHost(), port: this.getPort(), user: user, password: password, database: this.getDatabase() } // Prevent using default MySQL port, otherwise will throw uncaught error and crashing the app if (this.getHost() === '3006') { throw new Error('Invalid port number') } } return this._postgresConnectionOptions } async getArgs(): Promise<PGVectorStoreArgs> { return { postgresConnectionOptions: await this.getPostgresConnectionOptions(), tableName: this.getTableName(), columns: { contentColumnName: getContentColumnName(this.nodeData) }, distanceStrategy: (this.nodeData.inputs?.distanceStrategy || 'cosine') as DistanceStrategy } } async instanciate(metadataFilters?: any) { return this.adaptInstance(await PGVectorStore.initialize(this.getEmbeddings(), await this.getArgs()), metadataFilters) } async fromDocuments(documents: Document[]) { const instance = await this.instanciate() await instance.addDocuments(documents) return this.adaptInstance(instance) } protected async adaptInstance(instance: PGVectorStore, metadataFilters?: any): Promise<PGVectorStore> { const { [FLOWISE_CHATID]: chatId, ...pgMetadataFilter } = metadataFilters || {} const baseSimilaritySearchVectorWithScoreFn = instance.similaritySearchVectorWithScore.bind(instance) instance.similaritySearchVectorWithScore = async (query, k, filter) => { return await baseSimilaritySearchVectorWithScoreFn(query, k, filter ?? pgMetadataFilter) } const basePoolQueryFn = instance.pool.query.bind(instance.pool) // @ts-ignore instance.pool.query = async (queryString: string, parameters: any[]) => { if (!instance.client) { instance.client = await instance.pool.connect() } const whereClauseRegex = /WHERE ([^\n]+)/ let chatflowOr = '' // Match chatflow uploaded file and keep filtering on other files: // https://github.com/DtamindAI/Dtamind/pull/3367#discussion_r1804229295 if (chatId) { parameters.push({ [FLOWISE_CHATID]: chatId }) chatflowOr = `OR metadata @> $${parameters.length}` } if (queryString.match(whereClauseRegex)) { queryString = queryString.replace(whereClauseRegex, `WHERE (($1) AND NOT (metadata ? '${FLOWISE_CHATID}')) ${chatflowOr}`) } else { const orderByClauseRegex = /ORDER BY (.*)/ // Insert WHERE clause before ORDER BY queryString = queryString.replace( orderByClauseRegex, `WHERE (metadata @> '{}' AND NOT (metadata ? '${FLOWISE_CHATID}')) ${chatflowOr} ORDER BY $1 ` ) } // Run base function const queryResult = await basePoolQueryFn(queryString, parameters) // ensure connection is released instance.client.release() instance.client = undefined return queryResult } return instance } } */