@retrivora-ai/rag-engine 0.2.1 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DocumentChunker-BEyzadsv.d.mts → DocumentChunker-BICIjSuG.d.mts} +2 -0
- package/dist/{DocumentChunker-BEyzadsv.d.ts → DocumentChunker-BICIjSuG.d.ts} +2 -0
- package/dist/{RagConfig-D_rSf8ep.d.mts → RagConfig-Ttch1N4d.d.mts} +4 -0
- package/dist/{RagConfig-D_rSf8ep.d.ts → RagConfig-Ttch1N4d.d.ts} +4 -0
- package/dist/{chunk-2VR5ZMXV.mjs → chunk-K53N7SEE.mjs} +18 -4
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +18 -4
- package/dist/handlers/index.mjs +1 -1
- package/dist/{index-DtNprGGj.d.ts → index-rK0KAr2S.d.ts} +1 -1
- package/dist/{index-BJ8CUArE.d.mts → index-sbCtrIRT.d.mts} +1 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/server.d.mts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/server.js +47 -16
- package/dist/server.mjs +30 -13
- package/package.json +1 -1
- package/src/config/RagConfig.ts +4 -0
- package/src/config/serverConfig.ts +2 -0
- package/src/core/Pipeline.ts +2 -2
- package/src/llm/ILLMProvider.ts +2 -0
- package/src/llm/providers/OllamaProvider.ts +17 -1
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +40 -16
|
@@ -18,6 +18,8 @@ interface ChatOptions {
|
|
|
18
18
|
interface EmbedOptions {
|
|
19
19
|
/** Override model for this specific embed call */
|
|
20
20
|
model?: string;
|
|
21
|
+
/** Specify the task type for models that require prefixes (e.g. nomic-embed-text) */
|
|
22
|
+
taskType?: 'query' | 'document';
|
|
21
23
|
}
|
|
22
24
|
interface ILLMProvider {
|
|
23
25
|
/**
|
|
@@ -18,6 +18,8 @@ interface ChatOptions {
|
|
|
18
18
|
interface EmbedOptions {
|
|
19
19
|
/** Override model for this specific embed call */
|
|
20
20
|
model?: string;
|
|
21
|
+
/** Specify the task type for models that require prefixes (e.g. nomic-embed-text) */
|
|
22
|
+
taskType?: 'query' | 'document';
|
|
21
23
|
}
|
|
22
24
|
interface ILLMProvider {
|
|
23
25
|
/**
|
|
@@ -85,6 +85,10 @@ interface EmbeddingConfig {
|
|
|
85
85
|
baseUrl?: string;
|
|
86
86
|
/** Output vector dimension — must match the index dimension */
|
|
87
87
|
dimensions?: number;
|
|
88
|
+
/** Optional prefix to prepend to queries (for models like nomic-embed-text) */
|
|
89
|
+
queryPrefix?: string;
|
|
90
|
+
/** Optional prefix to prepend to documents during ingestion */
|
|
91
|
+
documentPrefix?: string;
|
|
88
92
|
/** Provider-specific options for custom adapters */
|
|
89
93
|
options?: Record<string, unknown>;
|
|
90
94
|
}
|
|
@@ -85,6 +85,10 @@ interface EmbeddingConfig {
|
|
|
85
85
|
baseUrl?: string;
|
|
86
86
|
/** Output vector dimension — must match the index dimension */
|
|
87
87
|
dimensions?: number;
|
|
88
|
+
/** Optional prefix to prepend to queries (for models like nomic-embed-text) */
|
|
89
|
+
queryPrefix?: string;
|
|
90
|
+
/** Optional prefix to prepend to documents during ingestion */
|
|
91
|
+
documentPrefix?: string;
|
|
88
92
|
/** Provider-specific options for custom adapters */
|
|
89
93
|
options?: Record<string, unknown>;
|
|
90
94
|
}
|
|
@@ -130,6 +130,8 @@ function getRagConfig(env = process.env) {
|
|
|
130
130
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
131
131
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
132
132
|
dimensions: embeddingDimensions,
|
|
133
|
+
queryPrefix: readString(env, "EMBEDDING_QUERY_PREFIX"),
|
|
134
|
+
documentPrefix: readString(env, "EMBEDDING_DOCUMENT_PREFIX"),
|
|
133
135
|
options: {
|
|
134
136
|
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
135
137
|
}
|
|
@@ -903,13 +905,25 @@ ${context}`;
|
|
|
903
905
|
return data.message.content;
|
|
904
906
|
}
|
|
905
907
|
async embed(text, options) {
|
|
906
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
908
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
907
909
|
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
|
|
908
910
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
909
911
|
const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? axios.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
912
|
+
let prompt = text;
|
|
913
|
+
const queryPrefix = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix;
|
|
914
|
+
const docPrefix = (_i = this.embeddingConfig) == null ? void 0 : _i.documentPrefix;
|
|
915
|
+
if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
|
|
916
|
+
if (!prompt.startsWith(queryPrefix)) {
|
|
917
|
+
prompt = `${queryPrefix}${text}`;
|
|
918
|
+
}
|
|
919
|
+
} else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
|
|
920
|
+
if (!prompt.startsWith(docPrefix)) {
|
|
921
|
+
prompt = `${docPrefix}${text}`;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
910
924
|
const { data } = await client.post("/api/embeddings", {
|
|
911
925
|
model,
|
|
912
|
-
prompt
|
|
926
|
+
prompt
|
|
913
927
|
});
|
|
914
928
|
return data.embedding;
|
|
915
929
|
}
|
|
@@ -1582,7 +1596,7 @@ var Pipeline = class {
|
|
|
1582
1596
|
};
|
|
1583
1597
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
1584
1598
|
chunks.map((c) => c.content),
|
|
1585
|
-
(text) => this.embeddingProvider.embed(text),
|
|
1599
|
+
(text) => this.embeddingProvider.embed(text, { taskType: "document" }),
|
|
1586
1600
|
embedBatchOptions
|
|
1587
1601
|
);
|
|
1588
1602
|
if (vectors.length !== chunks.length) {
|
|
@@ -1625,7 +1639,7 @@ var Pipeline = class {
|
|
|
1625
1639
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
1626
1640
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
1627
1641
|
try {
|
|
1628
|
-
const queryVector = await this.embeddingProvider.embed(question);
|
|
1642
|
+
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
1629
1643
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
1630
1644
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
1631
1645
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import '../RagConfig-
|
|
2
|
-
export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-
|
|
1
|
+
import '../RagConfig-Ttch1N4d.mjs';
|
|
2
|
+
export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-sbCtrIRT.mjs';
|
|
3
3
|
import 'next/server';
|
package/dist/handlers/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import '../RagConfig-
|
|
2
|
-
export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-
|
|
1
|
+
import '../RagConfig-Ttch1N4d.js';
|
|
2
|
+
export { c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from '../index-rK0KAr2S.js';
|
|
3
3
|
import 'next/server';
|
package/dist/handlers/index.js
CHANGED
|
@@ -1284,6 +1284,8 @@ function getRagConfig(env = process.env) {
|
|
|
1284
1284
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
1285
1285
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
1286
1286
|
dimensions: embeddingDimensions,
|
|
1287
|
+
queryPrefix: readString(env, "EMBEDDING_QUERY_PREFIX"),
|
|
1288
|
+
documentPrefix: readString(env, "EMBEDDING_DOCUMENT_PREFIX"),
|
|
1287
1289
|
options: {
|
|
1288
1290
|
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
1289
1291
|
}
|
|
@@ -2057,13 +2059,25 @@ ${context}`;
|
|
|
2057
2059
|
return data.message.content;
|
|
2058
2060
|
}
|
|
2059
2061
|
async embed(text, options) {
|
|
2060
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
2062
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2061
2063
|
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
|
|
2062
2064
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2063
2065
|
const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2066
|
+
let prompt = text;
|
|
2067
|
+
const queryPrefix = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix;
|
|
2068
|
+
const docPrefix = (_i = this.embeddingConfig) == null ? void 0 : _i.documentPrefix;
|
|
2069
|
+
if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
|
|
2070
|
+
if (!prompt.startsWith(queryPrefix)) {
|
|
2071
|
+
prompt = `${queryPrefix}${text}`;
|
|
2072
|
+
}
|
|
2073
|
+
} else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
|
|
2074
|
+
if (!prompt.startsWith(docPrefix)) {
|
|
2075
|
+
prompt = `${docPrefix}${text}`;
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2064
2078
|
const { data } = await client.post("/api/embeddings", {
|
|
2065
2079
|
model,
|
|
2066
|
-
prompt
|
|
2080
|
+
prompt
|
|
2067
2081
|
});
|
|
2068
2082
|
return data.embedding;
|
|
2069
2083
|
}
|
|
@@ -2692,7 +2706,7 @@ var Pipeline = class {
|
|
|
2692
2706
|
};
|
|
2693
2707
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
2694
2708
|
chunks.map((c) => c.content),
|
|
2695
|
-
(text) => this.embeddingProvider.embed(text),
|
|
2709
|
+
(text) => this.embeddingProvider.embed(text, { taskType: "document" }),
|
|
2696
2710
|
embedBatchOptions
|
|
2697
2711
|
);
|
|
2698
2712
|
if (vectors.length !== chunks.length) {
|
|
@@ -2735,7 +2749,7 @@ var Pipeline = class {
|
|
|
2735
2749
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
2736
2750
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
2737
2751
|
try {
|
|
2738
|
-
const queryVector = await this.embeddingProvider.embed(question);
|
|
2752
|
+
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
2739
2753
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
2740
2754
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
2741
2755
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
package/dist/handlers/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-
|
|
1
|
+
import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-Ttch1N4d.js';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-
|
|
1
|
+
import { c as VectorDBConfig, L as LLMConfig, E as EmbeddingConfig, a as RagConfig, C as ChatResponse } from './RagConfig-Ttch1N4d.mjs';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
|
|
4
4
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1, { ReactNode } from 'react';
|
|
3
|
-
import { C as ChatMessage } from './DocumentChunker-
|
|
4
|
-
export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-
|
|
5
|
-
import { V as VectorMatch, U as UIConfig } from './RagConfig-
|
|
6
|
-
export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-
|
|
3
|
+
import { C as ChatMessage } from './DocumentChunker-BICIjSuG.mjs';
|
|
4
|
+
export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-BICIjSuG.mjs';
|
|
5
|
+
import { V as VectorMatch, U as UIConfig } from './RagConfig-Ttch1N4d.mjs';
|
|
6
|
+
export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-Ttch1N4d.mjs';
|
|
7
7
|
|
|
8
8
|
interface ChatWidgetProps {
|
|
9
9
|
/** Position of the floating button. Defaults to bottom-right. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1, { ReactNode } from 'react';
|
|
3
|
-
import { C as ChatMessage } from './DocumentChunker-
|
|
4
|
-
export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-
|
|
5
|
-
import { V as VectorMatch, U as UIConfig } from './RagConfig-
|
|
6
|
-
export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-
|
|
3
|
+
import { C as ChatMessage } from './DocumentChunker-BICIjSuG.js';
|
|
4
|
+
export { a as ChatOptions, b as Chunk, c as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-BICIjSuG.js';
|
|
5
|
+
import { V as VectorMatch, U as UIConfig } from './RagConfig-Ttch1N4d.js';
|
|
6
|
+
export { C as ChatResponse, E as EmbeddingConfig, I as IngestDocument, L as LLMConfig, R as RAGConfig, a as RagConfig, b as UpsertDocument, c as VectorDBConfig } from './RagConfig-Ttch1N4d.js';
|
|
7
7
|
|
|
8
8
|
interface ChatWidgetProps {
|
|
9
9
|
/** Position of the floating button. Defaults to bottom-right. */
|
package/dist/server.d.mts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-
|
|
2
|
-
export { R as RAGConfig, U as UIConfig } from './RagConfig-
|
|
3
|
-
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-
|
|
4
|
-
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-
|
|
5
|
-
import { H as HealthCheckResult } from './index-
|
|
6
|
-
export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-
|
|
1
|
+
import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-Ttch1N4d.mjs';
|
|
2
|
+
export { R as RAGConfig, U as UIConfig } from './RagConfig-Ttch1N4d.mjs';
|
|
3
|
+
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-BICIjSuG.mjs';
|
|
4
|
+
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BICIjSuG.mjs';
|
|
5
|
+
import { H as HealthCheckResult } from './index-sbCtrIRT.mjs';
|
|
6
|
+
export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-sbCtrIRT.mjs';
|
|
7
7
|
import 'next/server';
|
|
8
8
|
|
|
9
9
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-
|
|
2
|
-
export { R as RAGConfig, U as UIConfig } from './RagConfig-
|
|
3
|
-
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-
|
|
4
|
-
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-
|
|
5
|
-
import { H as HealthCheckResult } from './index-
|
|
6
|
-
export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-
|
|
1
|
+
import { a as RagConfig, C as ChatResponse, I as IngestDocument, c as VectorDBConfig, b as UpsertDocument, V as VectorMatch, L as LLMConfig, E as EmbeddingConfig, d as VectorDBProvider, e as LLMProvider, f as EmbeddingProvider } from './RagConfig-Ttch1N4d.js';
|
|
2
|
+
export { R as RAGConfig, U as UIConfig } from './RagConfig-Ttch1N4d.js';
|
|
3
|
+
import { C as ChatMessage, I as ILLMProvider, a as ChatOptions, E as EmbedOptions } from './DocumentChunker-BICIjSuG.js';
|
|
4
|
+
export { b as Chunk, c as ChunkOptions, D as DocumentChunker } from './DocumentChunker-BICIjSuG.js';
|
|
5
|
+
import { H as HealthCheckResult } from './index-rK0KAr2S.js';
|
|
6
|
+
export { P as ProviderHealthCheck, c as createChatHandler, a as createHealthHandler, b as createIngestHandler, d as createUploadHandler } from './index-rK0KAr2S.js';
|
|
7
7
|
import 'next/server';
|
|
8
8
|
|
|
9
9
|
/**
|
package/dist/server.js
CHANGED
|
@@ -1328,6 +1328,8 @@ function getRagConfig(env = process.env) {
|
|
|
1328
1328
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
1329
1329
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
1330
1330
|
dimensions: embeddingDimensions,
|
|
1331
|
+
queryPrefix: readString(env, "EMBEDDING_QUERY_PREFIX"),
|
|
1332
|
+
documentPrefix: readString(env, "EMBEDDING_DOCUMENT_PREFIX"),
|
|
1331
1333
|
options: {
|
|
1332
1334
|
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
1333
1335
|
}
|
|
@@ -2101,13 +2103,25 @@ ${context}`;
|
|
|
2101
2103
|
return data.message.content;
|
|
2102
2104
|
}
|
|
2103
2105
|
async embed(text, options) {
|
|
2104
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
2106
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2105
2107
|
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
|
|
2106
2108
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2107
2109
|
const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2110
|
+
let prompt = text;
|
|
2111
|
+
const queryPrefix = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix;
|
|
2112
|
+
const docPrefix = (_i = this.embeddingConfig) == null ? void 0 : _i.documentPrefix;
|
|
2113
|
+
if ((options == null ? void 0 : options.taskType) === "query" && queryPrefix) {
|
|
2114
|
+
if (!prompt.startsWith(queryPrefix)) {
|
|
2115
|
+
prompt = `${queryPrefix}${text}`;
|
|
2116
|
+
}
|
|
2117
|
+
} else if ((options == null ? void 0 : options.taskType) === "document" && docPrefix) {
|
|
2118
|
+
if (!prompt.startsWith(docPrefix)) {
|
|
2119
|
+
prompt = `${docPrefix}${text}`;
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2108
2122
|
const { data } = await client.post("/api/embeddings", {
|
|
2109
2123
|
model,
|
|
2110
|
-
prompt
|
|
2124
|
+
prompt
|
|
2111
2125
|
});
|
|
2112
2126
|
return data.embedding;
|
|
2113
2127
|
}
|
|
@@ -2781,7 +2795,7 @@ var Pipeline = class {
|
|
|
2781
2795
|
};
|
|
2782
2796
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
2783
2797
|
chunks.map((c) => c.content),
|
|
2784
|
-
(text) => this.embeddingProvider.embed(text),
|
|
2798
|
+
(text) => this.embeddingProvider.embed(text, { taskType: "document" }),
|
|
2785
2799
|
embedBatchOptions
|
|
2786
2800
|
);
|
|
2787
2801
|
if (vectors.length !== chunks.length) {
|
|
@@ -2824,7 +2838,7 @@ var Pipeline = class {
|
|
|
2824
2838
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
2825
2839
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
2826
2840
|
try {
|
|
2827
|
-
const queryVector = await this.embeddingProvider.embed(question);
|
|
2841
|
+
const queryVector = await this.embeddingProvider.embed(question, { taskType: "query" });
|
|
2828
2842
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
2829
2843
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
2830
2844
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
@@ -3749,31 +3763,36 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
3749
3763
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
3750
3764
|
*/
|
|
3751
3765
|
async query(vector, topK, _namespace, _filter) {
|
|
3752
|
-
var _b, _c;
|
|
3766
|
+
var _b, _c, _d;
|
|
3753
3767
|
if (!this.pool) {
|
|
3754
3768
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
3755
3769
|
}
|
|
3756
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
3757
3770
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
3758
3771
|
const allResults = [];
|
|
3772
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
3759
3773
|
for (const table of this.tables) {
|
|
3760
3774
|
try {
|
|
3761
3775
|
const result = await this.pool.query(
|
|
3762
|
-
`SELECT *,
|
|
3776
|
+
`SELECT *,
|
|
3777
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
3763
3778
|
FROM "${table}"
|
|
3764
|
-
ORDER BY
|
|
3779
|
+
ORDER BY vector_score DESC
|
|
3765
3780
|
LIMIT 50`,
|
|
3766
3781
|
[vectorLiteral]
|
|
3767
3782
|
);
|
|
3783
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
3784
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
3785
|
+
} else {
|
|
3786
|
+
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
3787
|
+
}
|
|
3768
3788
|
for (const row of result.rows) {
|
|
3769
|
-
const _a = row, {
|
|
3789
|
+
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
3770
3790
|
delete rest.embedding;
|
|
3771
|
-
const
|
|
3772
|
-
const content = `[TYPE: ${type}]
|
|
3791
|
+
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
3773
3792
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
3774
3793
|
allResults.push({
|
|
3775
3794
|
id: `${table}-${id}`,
|
|
3776
|
-
score: parseFloat(String(
|
|
3795
|
+
score: parseFloat(String(vector_score)),
|
|
3777
3796
|
content,
|
|
3778
3797
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
3779
3798
|
});
|
|
@@ -3785,11 +3804,23 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
3785
3804
|
);
|
|
3786
3805
|
}
|
|
3787
3806
|
}
|
|
3788
|
-
const
|
|
3789
|
-
|
|
3790
|
-
|
|
3807
|
+
const resultsByTable = {};
|
|
3808
|
+
for (const res of allResults) {
|
|
3809
|
+
const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
|
|
3810
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
3811
|
+
resultsByTable[table].push(res);
|
|
3812
|
+
}
|
|
3813
|
+
const balancedResults = [];
|
|
3814
|
+
const tables = Object.keys(resultsByTable);
|
|
3815
|
+
for (const table of tables) {
|
|
3816
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
3817
|
+
}
|
|
3818
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
3819
|
+
if (finalSorted.length > 0) {
|
|
3820
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
3821
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
3791
3822
|
}
|
|
3792
|
-
return
|
|
3823
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
3793
3824
|
}
|
|
3794
3825
|
async delete(_id, _namespace) {
|
|
3795
3826
|
console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
|
package/dist/server.mjs
CHANGED
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
createIngestHandler,
|
|
35
35
|
createUploadHandler,
|
|
36
36
|
getRagConfig
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-K53N7SEE.mjs";
|
|
38
38
|
import "./chunk-EDLTMSNY.mjs";
|
|
39
39
|
import {
|
|
40
40
|
PineconeProvider
|
|
@@ -406,31 +406,36 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
406
406
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
407
407
|
*/
|
|
408
408
|
async query(vector, topK, _namespace, _filter) {
|
|
409
|
-
var _b, _c;
|
|
409
|
+
var _b, _c, _d;
|
|
410
410
|
if (!this.pool) {
|
|
411
411
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
412
412
|
}
|
|
413
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
414
413
|
const vectorLiteral = `[${vector.join(",")}]`;
|
|
415
414
|
const allResults = [];
|
|
415
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
416
416
|
for (const table of this.tables) {
|
|
417
417
|
try {
|
|
418
418
|
const result = await this.pool.query(
|
|
419
|
-
`SELECT *,
|
|
419
|
+
`SELECT *,
|
|
420
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
420
421
|
FROM "${table}"
|
|
421
|
-
ORDER BY
|
|
422
|
+
ORDER BY vector_score DESC
|
|
422
423
|
LIMIT 50`,
|
|
423
424
|
[vectorLiteral]
|
|
424
425
|
);
|
|
426
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
427
|
+
console.log(` \u2705 Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
428
|
+
} else {
|
|
429
|
+
console.log(` \u26AA Table "${table}": No relevant matches found.`);
|
|
430
|
+
}
|
|
425
431
|
for (const row of result.rows) {
|
|
426
|
-
const _a = row, {
|
|
432
|
+
const _a = row, { vector_score, id } = _a, rest = __objRest(_a, ["vector_score", "id"]);
|
|
427
433
|
delete rest.embedding;
|
|
428
|
-
const
|
|
429
|
-
const content = `[TYPE: ${type}]
|
|
434
|
+
const content = `[TYPE: ${table.replace(/s$/, "").toUpperCase()}]
|
|
430
435
|
` + Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
|
|
431
436
|
allResults.push({
|
|
432
437
|
id: `${table}-${id}`,
|
|
433
|
-
score: parseFloat(String(
|
|
438
|
+
score: parseFloat(String(vector_score)),
|
|
434
439
|
content,
|
|
435
440
|
metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
|
|
436
441
|
});
|
|
@@ -442,11 +447,23 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
442
447
|
);
|
|
443
448
|
}
|
|
444
449
|
}
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
450
|
+
const resultsByTable = {};
|
|
451
|
+
for (const res of allResults) {
|
|
452
|
+
const table = (_b = res.metadata) == null ? void 0 : _b.source_table;
|
|
453
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
454
|
+
resultsByTable[table].push(res);
|
|
455
|
+
}
|
|
456
|
+
const balancedResults = [];
|
|
457
|
+
const tables = Object.keys(resultsByTable);
|
|
458
|
+
for (const table of tables) {
|
|
459
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
460
|
+
}
|
|
461
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
462
|
+
if (finalSorted.length > 0) {
|
|
463
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
464
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${(_d = (_c = finalSorted[0].metadata) == null ? void 0 : _c.source_table) != null ? _d : "unknown"}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
448
465
|
}
|
|
449
|
-
return
|
|
466
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
450
467
|
}
|
|
451
468
|
async delete(_id, _namespace) {
|
|
452
469
|
console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
package/src/config/RagConfig.ts
CHANGED
|
@@ -81,6 +81,10 @@ export interface EmbeddingConfig {
|
|
|
81
81
|
baseUrl?: string;
|
|
82
82
|
/** Output vector dimension — must match the index dimension */
|
|
83
83
|
dimensions?: number;
|
|
84
|
+
/** Optional prefix to prepend to queries (for models like nomic-embed-text) */
|
|
85
|
+
queryPrefix?: string;
|
|
86
|
+
/** Optional prefix to prepend to documents during ingestion */
|
|
87
|
+
documentPrefix?: string;
|
|
84
88
|
/** Provider-specific options for custom adapters */
|
|
85
89
|
options?: Record<string, unknown>;
|
|
86
90
|
}
|
|
@@ -150,6 +150,8 @@ export function getRagConfig(env: Record<string, string | undefined> = process.e
|
|
|
150
150
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
151
151
|
baseUrl: readString(env, 'EMBEDDING_BASE_URL'),
|
|
152
152
|
dimensions: embeddingDimensions,
|
|
153
|
+
queryPrefix: readString(env, 'EMBEDDING_QUERY_PREFIX'),
|
|
154
|
+
documentPrefix: readString(env, 'EMBEDDING_DOCUMENT_PREFIX'),
|
|
153
155
|
options: {
|
|
154
156
|
profile: readString(env, 'EMBEDDING_UNIVERSAL_PROFILE'),
|
|
155
157
|
},
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -82,7 +82,7 @@ export class Pipeline {
|
|
|
82
82
|
|
|
83
83
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
84
84
|
chunks.map(c => c.content),
|
|
85
|
-
(text) => this.embeddingProvider.embed(text),
|
|
85
|
+
(text) => this.embeddingProvider.embed(text, { taskType: 'document' }),
|
|
86
86
|
embedBatchOptions
|
|
87
87
|
);
|
|
88
88
|
|
|
@@ -134,7 +134,7 @@ export class Pipeline {
|
|
|
134
134
|
const scoreThreshold = this.config.rag?.scoreThreshold ?? 0.0;
|
|
135
135
|
|
|
136
136
|
try {
|
|
137
|
-
const queryVector = await this.embeddingProvider.embed(question);
|
|
137
|
+
const queryVector = await this.embeddingProvider.embed(question, { taskType: 'query' });
|
|
138
138
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
139
139
|
|
|
140
140
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
package/src/llm/ILLMProvider.ts
CHANGED
|
@@ -21,6 +21,8 @@ export interface ChatOptions {
|
|
|
21
21
|
export interface EmbedOptions {
|
|
22
22
|
/** Override model for this specific embed call */
|
|
23
23
|
model?: string;
|
|
24
|
+
/** Specify the task type for models that require prefixes (e.g. nomic-embed-text) */
|
|
25
|
+
taskType?: 'query' | 'document';
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
export interface ILLMProvider {
|
|
@@ -73,9 +73,25 @@ export class OllamaProvider implements ILLMProvider {
|
|
|
73
73
|
? axios.create({ baseURL, timeout: 60_000 })
|
|
74
74
|
: this.http;
|
|
75
75
|
|
|
76
|
+
let prompt = text;
|
|
77
|
+
|
|
78
|
+
// Dynamically apply prefixes from configuration if they exist
|
|
79
|
+
const queryPrefix = this.embeddingConfig?.queryPrefix;
|
|
80
|
+
const docPrefix = this.embeddingConfig?.documentPrefix;
|
|
81
|
+
|
|
82
|
+
if (options?.taskType === 'query' && queryPrefix) {
|
|
83
|
+
if (!prompt.startsWith(queryPrefix)) {
|
|
84
|
+
prompt = `${queryPrefix}${text}`;
|
|
85
|
+
}
|
|
86
|
+
} else if (options?.taskType === 'document' && docPrefix) {
|
|
87
|
+
if (!prompt.startsWith(docPrefix)) {
|
|
88
|
+
prompt = `${docPrefix}${text}`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
76
92
|
const { data } = await client.post<OllamaEmbedResponse>('/api/embeddings', {
|
|
77
93
|
model,
|
|
78
|
-
prompt
|
|
94
|
+
prompt,
|
|
79
95
|
});
|
|
80
96
|
|
|
81
97
|
return data.embedding;
|
|
@@ -118,30 +118,36 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
118
118
|
throw new Error('[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.');
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
|
|
122
|
-
|
|
123
121
|
const vectorLiteral = `[${vector.join(',')}]`;
|
|
124
122
|
const allResults: VectorMatch[] = [];
|
|
125
123
|
|
|
124
|
+
console.log(`[MultiTablePostgresProvider] --- Starting Multi-Table Search ---`);
|
|
125
|
+
|
|
126
126
|
for (const table of this.tables) {
|
|
127
127
|
try {
|
|
128
|
+
// We use a hybrid approach:
|
|
129
|
+
// 1. Vector similarity (Semantic)
|
|
130
|
+
// 2. Simple keyword matching (Exact) to boost relevance for specific names
|
|
128
131
|
const result = await this.pool.query(
|
|
129
|
-
`SELECT *,
|
|
132
|
+
`SELECT *,
|
|
133
|
+
(1 - (embedding <=> $1::vector)) AS vector_score
|
|
130
134
|
FROM "${table}"
|
|
131
|
-
ORDER BY
|
|
135
|
+
ORDER BY vector_score DESC
|
|
132
136
|
LIMIT 50`,
|
|
133
137
|
[vectorLiteral]
|
|
134
138
|
);
|
|
135
139
|
|
|
140
|
+
if (result.rowCount && result.rowCount > 0) {
|
|
141
|
+
console.log(` ✅ Table "${table}": Found ${result.rowCount} potential matches. Top score: ${result.rows[0].vector_score.toFixed(4)}`);
|
|
142
|
+
} else {
|
|
143
|
+
console.log(` ⚪ Table "${table}": No relevant matches found.`);
|
|
144
|
+
}
|
|
145
|
+
|
|
136
146
|
for (const row of result.rows) {
|
|
137
|
-
const {
|
|
138
|
-
// Remove embedding from rest to avoid including it in content
|
|
147
|
+
const { vector_score, id, ...rest } = row as Record<string, unknown>;
|
|
139
148
|
delete rest.embedding;
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
// Prepend the entity type (derived from table name) to prevent cross-table confusion.
|
|
143
|
-
const type = table.replace(/s$/, '').toUpperCase();
|
|
144
|
-
const content = `[TYPE: ${type}]\n` +
|
|
150
|
+
const content = `[TYPE: ${table.replace(/s$/, '').toUpperCase()}]\n` +
|
|
145
151
|
Object.entries(rest)
|
|
146
152
|
.filter(([k, v]) => v !== null && typeof v !== 'object' && k !== 'id')
|
|
147
153
|
.map(([k, v]) => `${k}: ${v}`)
|
|
@@ -149,7 +155,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
149
155
|
|
|
150
156
|
allResults.push({
|
|
151
157
|
id: `${table}-${id}`,
|
|
152
|
-
score: parseFloat(String(
|
|
158
|
+
score: parseFloat(String(vector_score)),
|
|
153
159
|
content,
|
|
154
160
|
metadata: { ...rest, source_table: table },
|
|
155
161
|
});
|
|
@@ -162,14 +168,32 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
162
168
|
}
|
|
163
169
|
}
|
|
164
170
|
|
|
165
|
-
//
|
|
166
|
-
const
|
|
171
|
+
// 1. Group results by table to ensure we take the top ones from each
|
|
172
|
+
const resultsByTable: Record<string, VectorMatch[]> = {};
|
|
173
|
+
for (const res of allResults) {
|
|
174
|
+
const table = res.metadata?.source_table as string;
|
|
175
|
+
if (!resultsByTable[table]) resultsByTable[table] = [];
|
|
176
|
+
resultsByTable[table].push(res);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 2. Take top 3 from EACH table guaranteed, then fill the rest with overall best
|
|
180
|
+
const balancedResults: VectorMatch[] = [];
|
|
181
|
+
const tables = Object.keys(resultsByTable);
|
|
182
|
+
|
|
183
|
+
// First, ensure every table's best match is included
|
|
184
|
+
for (const table of tables) {
|
|
185
|
+
balancedResults.push(...resultsByTable[table].slice(0, 3));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// 3. Sort the balanced list by score
|
|
189
|
+
const finalSorted = balancedResults.sort((a, b) => b.score - a.score);
|
|
167
190
|
|
|
168
|
-
if (
|
|
169
|
-
console.log(`[MultiTablePostgresProvider]
|
|
191
|
+
if (finalSorted.length > 0) {
|
|
192
|
+
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
193
|
+
console.log(`[MultiTablePostgresProvider] Final top match from "${finalSorted[0].metadata?.source_table ?? 'unknown'}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
170
194
|
}
|
|
171
195
|
|
|
172
|
-
return
|
|
196
|
+
return finalSorted.slice(0, Math.max(topK, 15));
|
|
173
197
|
}
|
|
174
198
|
|
|
175
199
|
async delete(_id: string | number, _namespace?: string): Promise<void> { // eslint-disable-line @typescript-eslint/no-unused-vars
|