Compare commits

...

5 Commits

Author SHA1 Message Date
Alex Yang 65d834615d docs(changeset): feat: abstract @llamaindex/env package 2024-02-23 17:45:43 -06:00
Alex Yang b8be4c09e2 docs(changeset): build: use ESM as default 2024-02-23 17:45:01 -06:00
Alex Yang e5fb332538 build: leave code as-is (#560)
Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
2024-02-23 17:39:25 -06:00
Marcus Schiesser 491033d534 fix: lint errors 2024-02-23 14:55:45 +07:00
Marcus Schiesser 885fa316a5 chore: add prefer const lint 2024-02-23 14:45:17 +07:00
223 changed files with 3814 additions and 4407 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"llamaindex": patch
---
build: use ESM as default
+5
View File
@@ -0,0 +1,5 @@
---
"llamaindex": patch
---
feat: abstract `@llamaindex/env` package
+1
View File
@@ -9,6 +9,7 @@ module.exports = {
},
rules: {
"max-params": ["error", 4],
"prefer-const": "error",
},
ignorePatterns: ["dist/"],
};
+5 -2
View File
@@ -61,10 +61,13 @@ jobs:
run: pnpm run build --filter llamaindex
- name: Copy examples
run: rsync -rv --exclude=node_modules ./examples ${{ runner.temp }}
- name: Pack
- name: Pack @llamaindex/env
run: pnpm pack --pack-destination ${{ runner.temp }}
working-directory: packages/env
- name: Pack llamaindex
run: pnpm pack --pack-destination ${{ runner.temp }}
working-directory: packages/core
- name: Install llamaindex
- name: Install
run: npm add ${{ runner.temp }}/*.tgz
working-directory: ${{ runner.temp }}/examples
- name: Run Type Check
-1
View File
@@ -5,7 +5,6 @@
"[xml]": {
"editor.defaultFormatter": "redhat.vscode-xml"
},
"jest.rootPath": "./packages/core",
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter"
},
+1 -1
View File
@@ -1,4 +1,4 @@
import { Ollama } from "llamaindex";
import { Ollama } from "llamaindex/llm/ollama";
(async () => {
const llm = new Ollama({ model: "llama2", temperature: 0.75 });
-3
View File
@@ -18,15 +18,12 @@
},
"devDependencies": {
"@changesets/cli": "^2.27.1",
"@types/jest": "^29.5.12",
"eslint": "^8.56.0",
"eslint-config-custom": "workspace:*",
"husky": "^9.0.10",
"jest": "^29.7.0",
"lint-staged": "^15.2.2",
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4",
"ts-jest": "^29.1.2",
"turbo": "^1.12.3",
"typescript": "^5.3.3"
},
+11
View File
@@ -0,0 +1,11 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "esnext"
},
"module": {
"type": "commonjs"
}
}
+8
View File
@@ -0,0 +1,8 @@
{
"jsc": {
"parser": {
"syntax": "typescript"
},
"target": "esnext"
}
}
-6
View File
@@ -1,6 +0,0 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: "ts-jest",
testEnvironment: "node",
testPathIgnorePatterns: ["/lib/", "/node_modules/", "/dist/"],
};
+37 -160
View File
@@ -3,9 +3,13 @@
"private": true,
"version": "0.1.12",
"license": "MIT",
"type": "module",
"dependencies": {
"@anthropic-ai/sdk": "^0.13.0",
"@aws-crypto/sha256-js": "^5.2.0",
"@datastax/astra-db-ts": "^0.1.4",
"@llamaindex/cloud": "^0.0.1",
"@llamaindex/env": "workspace:*",
"@mistralai/mistralai": "^0.0.10",
"@notionhq/client": "^2.2.14",
"@pinecone-database/pinecone": "^2.0.1",
@@ -34,171 +38,46 @@
"wink-nlp": "^1.14.3"
},
"devDependencies": {
"@aws-crypto/sha256-js": "^5.2.0",
"@llamaindex/cloud": "^0.0.1",
"@types/edit-json-file": "^1.7.3",
"@types/jest": "^29.5.12",
"@swc/cli": "^0.3.9",
"@swc/core": "^1.4.2",
"@types/lodash": "^4.14.202",
"@types/node": "^18.19.14",
"@types/papaparse": "^5.3.14",
"@types/pg": "^8.11.0",
"bunchee": "^4.4.6",
"edit-json-file": "^1.8.0",
"concurrently": "^8.2.2",
"glob": "^10.3.10",
"madge": "^6.1.0",
"typescript": "^5.3.3"
},
"engines": {
"node": ">=18.0.0"
},
"types": "./dist/index.d.ts",
"main": "./dist/index.js",
"types": "./dist/type/index.d.ts",
"main": "./dist/cjs/index.cjs",
"exports": {
".": {
"types": "./dist/index.d.mts",
"import": "./dist/index.mjs",
"edge-light": "./dist/index.edge-light.mjs",
"require": "./dist/index.js"
"import": {
"types": "./dist/type/index.d.ts",
"default": "./dist/index.js"
},
"edge-light": {
"types": "./dist/type/index.d.ts",
"default": "./dist/index.edge-light.js"
},
"require": {
"types": "./dist/type/index.d.ts",
"default": "./dist/cjs/index.cjs"
}
},
"./env": {
"types": "./dist/env.d.mts",
"import": "./dist/env.mjs",
"edge-light": "./dist/env.edge-light.mjs",
"require": "./dist/env.js"
},
"./ChatEngine": {
"types": "./dist/ChatEngine.d.mts",
"import": "./dist/ChatEngine.mjs",
"require": "./dist/ChatEngine.js"
},
"./ChatHistory": {
"types": "./dist/ChatHistory.d.mts",
"import": "./dist/ChatHistory.mjs",
"require": "./dist/ChatHistory.js"
},
"./constants": {
"types": "./dist/constants.d.mts",
"import": "./dist/constants.mjs",
"require": "./dist/constants.js"
},
"./GlobalsHelper": {
"types": "./dist/GlobalsHelper.d.mts",
"import": "./dist/GlobalsHelper.mjs",
"require": "./dist/GlobalsHelper.js"
},
"./Node": {
"types": "./dist/Node.d.mts",
"import": "./dist/Node.mjs",
"require": "./dist/Node.js"
},
"./OutputParser": {
"types": "./dist/OutputParser.d.mts",
"import": "./dist/OutputParser.mjs",
"require": "./dist/OutputParser.js"
},
"./Prompt": {
"types": "./dist/Prompt.d.mts",
"import": "./dist/Prompt.mjs",
"require": "./dist/Prompt.js"
},
"./PromptHelper": {
"types": "./dist/PromptHelper.d.mts",
"import": "./dist/PromptHelper.mjs",
"require": "./dist/PromptHelper.js"
},
"./QueryEngine": {
"types": "./dist/QueryEngine.d.mts",
"import": "./dist/QueryEngine.mjs",
"require": "./dist/QueryEngine.js"
},
"./QuestionGenerator": {
"types": "./dist/QuestionGenerator.d.mts",
"import": "./dist/QuestionGenerator.mjs",
"require": "./dist/QuestionGenerator.js"
},
"./Response": {
"types": "./dist/Response.d.mts",
"import": "./dist/Response.mjs",
"require": "./dist/Response.js"
},
"./ServiceContext": {
"types": "./dist/ServiceContext.d.mts",
"import": "./dist/ServiceContext.mjs",
"require": "./dist/ServiceContext.js"
},
"./TextSplitter": {
"types": "./dist/TextSplitter.d.mts",
"import": "./dist/TextSplitter.mjs",
"require": "./dist/TextSplitter.js"
},
"./tools": {
"types": "./dist/tools.d.mts",
"import": "./dist/tools.mjs",
"require": "./dist/tools.js"
},
"./objects": {
"types": "./dist/objects.d.mts",
"import": "./dist/objects.mjs",
"require": "./dist/objects.js"
},
"./readers": {
"types": "./dist/readers.d.mts",
"import": "./dist/readers.mjs",
"require": "./dist/readers.js"
},
"./readers/AssemblyAIReader": {
"types": "./dist/readers/AssemblyAIReader.d.mts",
"import": "./dist/readers/AssemblyAIReader.mjs",
"require": "./dist/readers/AssemblyAIReader.js"
},
"./readers/CSVReader": {
"types": "./dist/readers/CSVReader.d.mts",
"import": "./dist/readers/CSVReader.mjs",
"require": "./dist/readers/CSVReader.js"
},
"./readers/DocxReader": {
"types": "./dist/readers/DocxReader.d.mts",
"import": "./dist/readers/DocxReader.mjs",
"require": "./dist/readers/DocxReader.js"
},
"./readers/HTMLReader": {
"types": "./dist/readers/HTMLReader.d.mts",
"import": "./dist/readers/HTMLReader.mjs",
"require": "./dist/readers/HTMLReader.js"
},
"./readers/ImageReader": {
"types": "./dist/readers/ImageReader.d.mts",
"import": "./dist/readers/ImageReader.mjs",
"require": "./dist/readers/ImageReader.js"
},
"./readers/MarkdownReader": {
"types": "./dist/readers/MarkdownReader.d.mts",
"import": "./dist/readers/MarkdownReader.mjs",
"require": "./dist/readers/MarkdownReader.js"
},
"./readers/NotionReader": {
"types": "./dist/readers/NotionReader.d.mts",
"import": "./dist/readers/NotionReader.mjs",
"require": "./dist/readers/NotionReader.js"
},
"./readers/PDFReader": {
"types": "./dist/readers/PDFReader.d.mts",
"import": "./dist/readers/PDFReader.mjs",
"require": "./dist/readers/PDFReader.js"
},
"./readers/SimpleDirectoryReader": {
"types": "./dist/readers/SimpleDirectoryReader.d.mts",
"import": "./dist/readers/SimpleDirectoryReader.mjs",
"require": "./dist/readers/SimpleDirectoryReader.js"
},
"./readers/SimpleMongoReader": {
"types": "./dist/readers/SimpleMongoReader.d.mts",
"import": "./dist/readers/SimpleMongoReader.mjs",
"require": "./dist/readers/SimpleMongoReader.js"
},
"./cloud": {
"types": "./dist/cloud.d.mts",
"import": "./dist/cloud.mjs",
"require": "./dist/cloud.js"
"./*": {
"import": {
"types": "./dist/type/*.d.ts",
"default": "./dist/*.js"
},
"require": {
"types": "./dist/type/*.d.ts",
"default": "./dist/cjs/*.cjs"
}
}
},
"files": [
@@ -211,13 +90,11 @@
},
"scripts": {
"lint": "eslint .",
"test": "jest",
"build": "rm -rf ./dist && NODE_OPTIONS=\"--max-old-space-size=12288\" bunchee",
"postbuild": "pnpm run copy && pnpm run modify-package-json",
"copy": "cp -r package.json CHANGELOG.md ../../README.md ../../LICENSE examples src dist/",
"modify-package-json": "node ./scripts/modify-package-json.mjs",
"prepublish": "pnpm run modify-package-json && echo \"please cd ./dist and run pnpm publish\" && exit 1",
"dev": "NODE_OPTIONS=\"--max-old-space-size=16384\" bunchee -w",
"circular-check": "madge -c ./src/index.ts"
"build": "rm -rf ./dist && pnpm run build:esm && pnpm run build:cjs && pnpm run build:type",
"build:esm": "swc src -d dist --strip-leading-paths --config-file .swcrc",
"build:cjs": "swc src -d dist/cjs --strip-leading-paths --config-file .cjs.swcrc --out-file-extension cjs",
"build:type": "tsc -p tsconfig.json",
"circular-check": "madge -c ./src/index.ts",
"dev": "concurrently \"pnpm run build:esm --watch\" \"pnpm run build:cjs --watch\" \"pnpm run build:type --watch\""
}
}
@@ -1,25 +0,0 @@
#!/usr/bin/env node
/**
* This script is used to modify the package.json file in the dist folder
* so that it can be published to npm.
*/
import editJsonFile from "edit-json-file";
import fs from "node:fs/promises";
{
await fs.copyFile("./package.json", "./dist/package.json");
const file = editJsonFile("./dist/package.json");
file.unset("scripts");
file.unset("private");
await new Promise((resolve) => file.save(resolve));
}
{
const packageJson = await fs.readFile("./dist/package.json", "utf8");
const modifiedPackageJson = packageJson.replaceAll("./dist/", "./");
await fs.writeFile(
"./dist/package.json",
JSON.stringify(JSON.parse(modifiedPackageJson), null, 2),
"utf8",
);
}
+3 -3
View File
@@ -1,10 +1,10 @@
import { OpenAI } from "./llm/LLM";
import { ChatMessage, LLM, MessageType } from "./llm/types";
import { OpenAI } from "./llm/LLM.js";
import { ChatMessage, LLM, MessageType } from "./llm/types.js";
import {
defaultSummaryPrompt,
messagesToHistoryStr,
SummaryPrompt,
} from "./Prompt";
} from "./Prompt.js";
/**
* A ChatHistory is used to keep the state of back and forth chat messages
+2 -2
View File
@@ -1,7 +1,7 @@
import { encodingForModel } from "js-tiktoken";
import { Event, EventTag, EventType } from "./callbacks/CallbackManager";
import { randomUUID } from "./env";
import { randomUUID } from "@llamaindex/env";
import { Event, EventTag, EventType } from "./callbacks/CallbackManager.js";
export enum Tokenizers {
CL100K_BASE = "cl100k_base",
+4 -4
View File
@@ -1,5 +1,5 @@
import { createSHA256, path, randomUUID } from "@llamaindex/env";
import _ from "lodash";
import { createSHA256, path, randomUUID } from "./env";
export enum NodeRelationship {
SOURCE = "SOURCE",
@@ -353,10 +353,10 @@ export function splitNodesByType(nodes: BaseNode[]): {
imageNodes: ImageNode[];
textNodes: TextNode[];
} {
let imageNodes: ImageNode[] = [];
let textNodes: TextNode[] = [];
const imageNodes: ImageNode[] = [];
const textNodes: TextNode[] = [];
for (let node of nodes) {
for (const node of nodes) {
if (node instanceof ImageNode) {
imageNodes.push(node);
} else if (node instanceof TextNode) {
+2 -2
View File
@@ -1,5 +1,5 @@
import { SubQuestion } from "./engines/query/types";
import { BaseOutputParser, StructuredOutput } from "./types";
import { SubQuestion } from "./engines/query/types.js";
import { BaseOutputParser, StructuredOutput } from "./types.js";
/**
* Error class for output parsing. Due to the nature of LLMs, anytime we use LLM
+3 -3
View File
@@ -1,6 +1,6 @@
import { SubQuestion } from "./engines/query/types";
import { ChatMessage } from "./llm/types";
import { ToolMetadata } from "./types";
import { SubQuestion } from "./engines/query/types.js";
import { ChatMessage } from "./llm/types.js";
import { ToolMetadata } from "./types.js";
/**
* A SimplePrompt is a function that takes a dictionary of inputs and returns a string.
+4 -4
View File
@@ -1,12 +1,12 @@
import { globalsHelper } from "./GlobalsHelper";
import { SimplePrompt } from "./Prompt";
import { SentenceSplitter } from "./TextSplitter";
import { globalsHelper } from "./GlobalsHelper.js";
import { SimplePrompt } from "./Prompt.js";
import { SentenceSplitter } from "./TextSplitter.js";
import {
DEFAULT_CHUNK_OVERLAP_RATIO,
DEFAULT_CONTEXT_WINDOW,
DEFAULT_NUM_OUTPUTS,
DEFAULT_PADDING,
} from "./constants";
} from "./constants.js";
export function getEmptyPromptTxt(prompt: SimplePrompt) {
return prompt({});
+7 -7
View File
@@ -1,14 +1,14 @@
import { SubQuestionOutputParser } from "./OutputParser";
import { SubQuestionOutputParser } from "./OutputParser.js";
import {
SubQuestionPrompt,
buildToolsText,
defaultSubQuestionPrompt,
} from "./Prompt";
import { BaseQuestionGenerator, SubQuestion } from "./engines/query/types";
import { OpenAI } from "./llm/LLM";
import { LLM } from "./llm/types";
import { PromptMixin } from "./prompts";
import { BaseOutputParser, StructuredOutput, ToolMetadata } from "./types";
} from "./Prompt.js";
import { BaseQuestionGenerator, SubQuestion } from "./engines/query/types.js";
import { OpenAI } from "./llm/LLM.js";
import { LLM } from "./llm/types.js";
import { PromptMixin } from "./prompts/index.js";
import { BaseOutputParser, StructuredOutput, ToolMetadata } from "./types.js";
/**
* LLMQuestionGenerator uses the LLM to generate new questions for the LLM using tools and a user query.
+1 -1
View File
@@ -1,4 +1,4 @@
import { BaseNode } from "./Node";
import { BaseNode } from "./Node.js";
/**
* Response is the output of a LLM
+3 -3
View File
@@ -1,6 +1,6 @@
import { Event } from "./callbacks/CallbackManager";
import { NodeWithScore } from "./Node";
import { ServiceContext } from "./ServiceContext";
import { Event } from "./callbacks/CallbackManager.js";
import { NodeWithScore } from "./Node.js";
import { ServiceContext } from "./ServiceContext.js";
/**
* Retrievers retrieve the nodes that most closely match our query in similarity.
+7 -5
View File
@@ -1,8 +1,10 @@
import { CallbackManager } from "./callbacks/CallbackManager";
import { BaseEmbedding, OpenAIEmbedding } from "./embeddings";
import { LLM, OpenAI } from "./llm";
import { NodeParser, SimpleNodeParser } from "./nodeParsers";
import { PromptHelper } from "./PromptHelper";
import { PromptHelper } from "./PromptHelper.js";
import { CallbackManager } from "./callbacks/CallbackManager.js";
import { OpenAIEmbedding } from "./embeddings/OpenAIEmbedding.js";
import { BaseEmbedding } from "./embeddings/types.js";
import { LLM, OpenAI } from "./llm/index.js";
import { SimpleNodeParser } from "./nodeParsers/SimpleNodeParser.js";
import { NodeParser } from "./nodeParsers/types.js";
/**
* The ServiceContext is a collection of components that are used in different parts of the application.
+13 -13
View File
@@ -1,7 +1,7 @@
import { EOL } from "./env";
import { EOL } from "@llamaindex/env";
// GitHub translated
import { globalsHelper } from "./GlobalsHelper";
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE } from "./constants";
import { globalsHelper } from "./GlobalsHelper.js";
import { DEFAULT_CHUNK_OVERLAP, DEFAULT_CHUNK_SIZE } from "./constants.js";
class TextSplit {
textChunk: string;
@@ -130,7 +130,7 @@ export class SentenceSplitter {
getParagraphSplits(text: string, effectiveChunkSize?: number): string[] {
// get paragraph splits
let paragraphSplits: string[] = text.split(this.paragraphSeparator);
const paragraphSplits: string[] = text.split(this.paragraphSeparator);
let idx = 0;
if (effectiveChunkSize == undefined) {
return paragraphSplits;
@@ -155,9 +155,9 @@ export class SentenceSplitter {
}
getSentenceSplits(text: string, effectiveChunkSize?: number): string[] {
let paragraphSplits = this.getParagraphSplits(text, effectiveChunkSize);
const paragraphSplits = this.getParagraphSplits(text, effectiveChunkSize);
// Next we split the text using the chunk tokenizer fn/
let splits = [];
const splits = [];
for (const parText of paragraphSplits) {
const sentenceSplits = this.chunkingTokenizerFn(parText);
@@ -194,9 +194,9 @@ export class SentenceSplitter {
}));
}
let newSplits: SplitRep[] = [];
const newSplits: SplitRep[] = [];
for (const split of sentenceSplits) {
let splitTokens = this.tokenizer(split);
const splitTokens = this.tokenizer(split);
const splitLen = splitTokens.length;
if (splitLen <= effectiveChunkSize) {
newSplits.push({ text: split, numTokens: splitLen });
@@ -219,7 +219,7 @@ export class SentenceSplitter {
// go through sentence splits, combine to chunks that are within the chunk size
// docs represents final list of text chunks
let docs: TextSplit[] = [];
const docs: TextSplit[] = [];
// curChunkSentences represents the current list of sentence splits (that)
// will be merged into a chunk
let curChunkSentences: SplitRep[] = [];
@@ -287,18 +287,18 @@ export class SentenceSplitter {
return [];
}
let effectiveChunkSize = this.getEffectiveChunkSize(extraInfoStr);
let sentenceSplits = this.getSentenceSplits(text, effectiveChunkSize);
const effectiveChunkSize = this.getEffectiveChunkSize(extraInfoStr);
const sentenceSplits = this.getSentenceSplits(text, effectiveChunkSize);
// Check if any sentences exceed the chunk size. If they don't,
// force split by tokenizer
let newSentenceSplits = this.processSentenceSplits(
const newSentenceSplits = this.processSentenceSplits(
sentenceSplits,
effectiveChunkSize,
);
// combine sentence splits into chunks of text that can then be returned
let combinedTextSplits = this.combineTextSplits(
const combinedTextSplits = this.combineTextSplits(
newSentenceSplits,
effectiveChunkSize,
);
+5 -5
View File
@@ -1,5 +1,5 @@
export * from "./openai/base";
export * from "./openai/worker";
export * from "./react/base";
export * from "./react/worker";
export * from "./types";
export * from "./openai/base.js";
export * from "./openai/worker.js";
export * from "./react/base.js";
export * from "./react/worker.js";
export * from "./types.js";
+6 -6
View File
@@ -1,9 +1,9 @@
import { CallbackManager } from "../../callbacks/CallbackManager";
import { ChatMessage, OpenAI } from "../../llm";
import { ObjectRetriever } from "../../objects/base";
import { BaseTool } from "../../types";
import { AgentRunner } from "../runner/base";
import { OpenAIAgentWorker } from "./worker";
import { CallbackManager } from "../../callbacks/CallbackManager.js";
import { ChatMessage, OpenAI } from "../../llm/index.js";
import { ObjectRetriever } from "../../objects/base.js";
import { BaseTool } from "../../types.js";
import { AgentRunner } from "../runner/base.js";
import { OpenAIAgentWorker } from "./worker.js";
type OpenAIAgentParams = {
tools?: BaseTool[];
+1 -1
View File
@@ -1,4 +1,4 @@
import { ToolMetadata } from "../../types";
import { ToolMetadata } from "../../types.js";
export type OpenAIFunction = {
type: "function";
+16 -13
View File
@@ -1,23 +1,26 @@
// Assuming that the necessary interfaces and classes (like BaseTool, OpenAI, ChatMessage, CallbackManager, etc.) are defined elsewhere
import { CallbackManager } from "../../callbacks/CallbackManager";
import { AgentChatResponse, ChatResponseMode } from "../../engines/chat";
import { randomUUID } from "../../env";
import { randomUUID } from "@llamaindex/env";
import { CallbackManager } from "../../callbacks/CallbackManager.js";
import {
AgentChatResponse,
ChatResponseMode,
} from "../../engines/chat/types.js";
import {
ChatMessage,
ChatResponse,
ChatResponseChunk,
OpenAI,
} from "../../llm";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer";
import { ObjectRetriever } from "../../objects/base";
import { ToolOutput } from "../../tools/types";
import { callToolWithErrorHandling } from "../../tools/utils";
import { BaseTool } from "../../types";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types";
import { addUserStepToMemory, getFunctionByName } from "../utils";
import { OpenAIToolCall } from "./types/chat";
import { toOpenAiTool } from "./utils";
} from "../../llm/index.js";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
import { ObjectRetriever } from "../../objects/base.js";
import { ToolOutput } from "../../tools/types.js";
import { callToolWithErrorHandling } from "../../tools/utils.js";
import { BaseTool } from "../../types.js";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
import { addUserStepToMemory, getFunctionByName } from "../utils.js";
import { OpenAIToolCall } from "./types/chat.js";
import { toOpenAiTool } from "./utils.js";
const DEFAULT_MAX_FUNCTION_CALLS = 5;
+6 -6
View File
@@ -1,9 +1,9 @@
import { CallbackManager } from "../../callbacks/CallbackManager";
import { ChatMessage, LLM } from "../../llm";
import { ObjectRetriever } from "../../objects/base";
import { BaseTool } from "../../types";
import { AgentRunner } from "../runner/base";
import { ReActAgentWorker } from "./worker";
import { CallbackManager } from "../../callbacks/CallbackManager.js";
import { ChatMessage, LLM } from "../../llm/index.js";
import { ObjectRetriever } from "../../objects/base.js";
import { BaseTool } from "../../types.js";
import { AgentRunner } from "../runner/base.js";
import { ReActAgentWorker } from "./worker.js";
type ReActAgentParams = {
tools: BaseTool[];
+4 -4
View File
@@ -1,7 +1,7 @@
import { ChatMessage } from "../../llm";
import { BaseTool } from "../../types";
import { getReactChatSystemHeader } from "./prompts";
import { BaseReasoningStep, ObservationReasoningStep } from "./types";
import { ChatMessage } from "../../llm/index.js";
import { BaseTool } from "../../types.js";
import { getReactChatSystemHeader } from "./prompts.js";
import { BaseReasoningStep, ObservationReasoningStep } from "./types.js";
function getReactToolDescriptions(tools: BaseTool[]): string[] {
const toolDescs: string[] = [];
@@ -3,7 +3,7 @@ import {
BaseOutputParser,
BaseReasoningStep,
ResponseReasoningStep,
} from "./types";
} from "./types.js";
function extractJsonStr(text: string): string {
const pattern = /\{.*\}/s;
+1 -1
View File
@@ -1,4 +1,4 @@
import { ChatMessage } from "../../llm";
import { ChatMessage } from "../../llm/index.js";
export interface BaseReasoningStep {
getContent(): string;
+11 -11
View File
@@ -1,20 +1,20 @@
import { randomUUID } from "crypto";
import { CallbackManager } from "../../callbacks/CallbackManager";
import { AgentChatResponse } from "../../engines/chat";
import { ChatResponse, LLM, OpenAI } from "../../llm";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer";
import { ObjectRetriever } from "../../objects/base";
import { ToolOutput } from "../../tools";
import { BaseTool } from "../../types";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types";
import { ReActChatFormatter } from "./formatter";
import { ReActOutputParser } from "./outputParser";
import { CallbackManager } from "../../callbacks/CallbackManager.js";
import { AgentChatResponse } from "../../engines/chat/index.js";
import { ChatResponse, LLM, OpenAI } from "../../llm/index.js";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
import { ObjectRetriever } from "../../objects/base.js";
import { ToolOutput } from "../../tools/index.js";
import { BaseTool } from "../../types.js";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
import { ReActChatFormatter } from "./formatter.js";
import { ReActOutputParser } from "./outputParser.js";
import {
ActionReasoningStep,
BaseReasoningStep,
ObservationReasoningStep,
ResponseReasoningStep,
} from "./types";
} from "./types.js";
type ReActAgentWorkerParams = {
tools: BaseTool[];
+7 -7
View File
@@ -1,15 +1,15 @@
import { randomUUID } from "crypto";
import { CallbackManager } from "../../callbacks/CallbackManager";
import { CallbackManager } from "../../callbacks/CallbackManager.js";
import {
AgentChatResponse,
ChatEngineAgentParams,
ChatResponseMode,
} from "../../engines/chat";
import { ChatMessage, LLM } from "../../llm";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer";
import { BaseMemory } from "../../memory/types";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types";
import { AgentState, BaseAgentRunner, TaskState } from "./types";
} from "../../engines/chat/index.js";
import { ChatMessage, LLM } from "../../llm/index.js";
import { ChatMemoryBuffer } from "../../memory/ChatMemoryBuffer.js";
import { BaseMemory } from "../../memory/types.js";
import { AgentWorker, Task, TaskStep, TaskStepOutput } from "../types.js";
import { AgentState, BaseAgentRunner, TaskState } from "./types.js";
const validateStepFromArgs = (
taskId: string,
+2 -2
View File
@@ -1,5 +1,5 @@
import { AgentChatResponse } from "../../engines/chat";
import { BaseAgent, Task, TaskStep, TaskStepOutput } from "../types";
import { AgentChatResponse } from "../../engines/chat/index.js";
import { BaseAgent, Task, TaskStep, TaskStepOutput } from "../types.js";
export class TaskState {
task!: Task;
+5 -2
View File
@@ -1,5 +1,8 @@
import { AgentChatResponse, ChatEngineAgentParams } from "../engines/chat";
import { QueryEngineParamsNonStreaming } from "../types";
import {
AgentChatResponse,
ChatEngineAgentParams,
} from "../engines/chat/index.js";
import { QueryEngineParamsNonStreaming } from "../types.js";
export interface AgentWorker {
initializeStep(task: Task, kwargs?: any): TaskStep;
+4 -4
View File
@@ -1,7 +1,7 @@
import { ChatMessage } from "../llm";
import { ChatMemoryBuffer } from "../memory/ChatMemoryBuffer";
import { BaseTool } from "../types";
import { TaskStep } from "./types";
import { ChatMessage } from "../llm/index.js";
import { ChatMemoryBuffer } from "../memory/ChatMemoryBuffer.js";
import { BaseTool } from "../types.js";
import { TaskStep } from "./types.js";
/**
* Adds the user's input to the memory.
@@ -1,5 +1,5 @@
import type { Anthropic } from "@anthropic-ai/sdk";
import { NodeWithScore } from "../Node";
import { NodeWithScore } from "../Node.js";
/*
An event is a wrapper that groups related operations.
+7 -7
View File
@@ -1,10 +1,10 @@
import { BaseRetriever } from "../Retriever";
import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine";
import { BaseNodePostprocessor } from "../postprocessors";
import { BaseSynthesizer } from "../synthesizers";
import { BaseQueryEngine } from "../types";
import { LlamaCloudRetriever, RetrieveParams } from "./LlamaCloudRetriever";
import { CloudConstructorParams } from "./types";
import { BaseRetriever } from "../Retriever.js";
import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine.js";
import { BaseNodePostprocessor } from "../postprocessors/types.js";
import { BaseSynthesizer } from "../synthesizers/types.js";
import { BaseQueryEngine } from "../types.js";
import { LlamaCloudRetriever, RetrieveParams } from "./LlamaCloudRetriever.js";
import { CloudConstructorParams } from "./types.js";
export class LlamaCloudIndex {
params: CloudConstructorParams;
+10 -7
View File
@@ -1,15 +1,18 @@
import { PlatformApi, PlatformApiClient } from "@llamaindex/cloud";
import { globalsHelper } from "../GlobalsHelper";
import { NodeWithScore, ObjectType, jsonToNode } from "../Node";
import { BaseRetriever } from "../Retriever";
import { ServiceContext, serviceContextFromDefaults } from "../ServiceContext";
import { Event } from "../callbacks/CallbackManager";
import { globalsHelper } from "../GlobalsHelper.js";
import { NodeWithScore, ObjectType, jsonToNode } from "../Node.js";
import { BaseRetriever } from "../Retriever.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../ServiceContext.js";
import { Event } from "../callbacks/CallbackManager.js";
import {
ClientParams,
CloudConstructorParams,
DEFAULT_PROJECT_NAME,
} from "./types";
import { getClient } from "./utils";
} from "./types.js";
import { getClient } from "./utils.js";
export type RetrieveParams = Omit<
PlatformApi.RetrievalParams,
+2 -2
View File
@@ -1,2 +1,2 @@
export * from "./LlamaCloudIndex";
export * from "./LlamaCloudRetriever";
export * from "./LlamaCloudIndex.js";
export * from "./LlamaCloudRetriever.js";
+1 -1
View File
@@ -1,4 +1,4 @@
import { ServiceContext } from "../ServiceContext";
import { ServiceContext } from "../ServiceContext.js";
export const DEFAULT_PROJECT_NAME = "default";
export const DEFAULT_BASE_URL = "https://api.cloud.llamaindex.ai";
+1 -1
View File
@@ -1,5 +1,5 @@
import { PlatformApiClient } from "@llamaindex/cloud";
import { ClientParams, DEFAULT_BASE_URL } from "./types";
import { ClientParams, DEFAULT_BASE_URL } from "./types.js";
export async function getClient({
apiKey,
@@ -1,6 +1,6 @@
import { ImageType } from "../Node";
import { MultiModalEmbedding } from "./MultiModalEmbedding";
import { readImage } from "./utils";
import { ImageType } from "../Node.js";
import { MultiModalEmbedding } from "./MultiModalEmbedding.js";
import { readImage } from "./utils.js";
export enum ClipEmbeddingModelType {
XENOVA_CLIP_VIT_BASE_PATCH32 = "Xenova/clip-vit-base-patch32",
@@ -1,4 +1,4 @@
import { BaseEmbedding } from "./types";
import { BaseEmbedding } from "./types.js";
export enum HuggingFaceEmbeddingModelType {
XENOVA_ALL_MINILM_L6_V2 = "Xenova/all-MiniLM-L6-v2",
@@ -1,5 +1,5 @@
import { MistralAISession } from "../llm/mistral";
import { BaseEmbedding } from "./types";
import { MistralAISession } from "../llm/mistral.js";
import { BaseEmbedding } from "./types.js";
export enum MistralAIEmbeddingModelType {
MISTRAL_EMBED = "mistral-embed",
@@ -1,5 +1,5 @@
import { ImageType } from "../Node";
import { BaseEmbedding } from "./types";
import { ImageType } from "../Node.js";
import { BaseEmbedding } from "./types.js";
/*
* Base class for Multi Modal embeddings.
@@ -1,5 +1,5 @@
import { Ollama } from "../llm/ollama";
import { BaseEmbedding } from "./types";
import { Ollama } from "../llm/ollama.js";
import { BaseEmbedding } from "./types.js";
/**
* OllamaEmbedding is an alias for Ollama that implements the BaseEmbedding interface.
@@ -5,9 +5,9 @@ import {
getAzureConfigFromEnv,
getAzureModel,
shouldUseAzure,
} from "../llm/azure";
import { OpenAISession, getOpenAISession } from "../llm/open_ai";
import { BaseEmbedding } from "./types";
} from "../llm/azure.js";
import { OpenAISession, getOpenAISession } from "../llm/open_ai.js";
import { BaseEmbedding } from "./types.js";
export const ALL_OPENAI_EMBEDDING_MODELS = {
"text-embedding-ada-002": {
+1 -1
View File
@@ -1,4 +1,4 @@
import { OpenAIEmbedding } from "./OpenAIEmbedding";
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
export class FireworksEmbedding extends OpenAIEmbedding {
constructor(init?: Partial<OpenAIEmbedding>) {
+10 -10
View File
@@ -1,10 +1,10 @@
export * from "./ClipEmbedding";
export * from "./HuggingFaceEmbedding";
export * from "./MistralAIEmbedding";
export * from "./MultiModalEmbedding";
export { OllamaEmbedding } from "./OllamaEmbedding";
export * from "./OpenAIEmbedding";
export { FireworksEmbedding } from "./fireworks";
export { TogetherEmbedding } from "./together";
export * from "./types";
export * from "./utils";
export * from "./ClipEmbedding.js";
export * from "./HuggingFaceEmbedding.js";
export * from "./MistralAIEmbedding.js";
export * from "./MultiModalEmbedding.js";
export { OllamaEmbedding } from "./OllamaEmbedding.js";
export * from "./OpenAIEmbedding.js";
export { FireworksEmbedding } from "./fireworks.js";
export { TogetherEmbedding } from "./together.js";
export * from "./types.js";
export * from "./utils.js";
+1 -1
View File
@@ -1,4 +1,4 @@
import { OpenAIEmbedding } from "./OpenAIEmbedding";
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
export class TogetherEmbedding extends OpenAIEmbedding {
constructor(init?: Partial<OpenAIEmbedding>) {
+3 -3
View File
@@ -1,6 +1,6 @@
import { BaseNode, MetadataMode } from "../Node";
import { TransformComponent } from "../ingestion";
import { SimilarityType, similarity } from "./utils";
import { BaseNode, MetadataMode } from "../Node.js";
import { TransformComponent } from "../ingestion/types.js";
import { SimilarityType, similarity } from "./utils.js";
const DEFAULT_EMBED_BATCH_SIZE = 10;
+22 -22
View File
@@ -1,8 +1,8 @@
import { defaultFS } from "@llamaindex/env";
import _ from "lodash";
import { ImageType } from "../Node";
import { DEFAULT_SIMILARITY_TOP_K } from "../constants";
import { defaultFS } from "../env";
import { VectorStoreQueryMode } from "../storage/vectorStore/types";
import { ImageType } from "../Node.js";
import { DEFAULT_SIMILARITY_TOP_K } from "../constants.js";
import { VectorStoreQueryMode } from "../storage/vectorStore/types.js";
/**
* Similarity type
@@ -46,7 +46,7 @@ export function similarity(
switch (mode) {
case SimilarityType.EUCLIDEAN: {
let difference = embedding1.map((x, i) => x - embedding2[i]);
const difference = embedding1.map((x, i) => x - embedding2[i]);
return -norm(difference);
}
case SimilarityType.DOT_PRODUCT: {
@@ -94,7 +94,7 @@ export function getTopKEmbeddings(
);
}
let similarities: { similarity: number; id: number }[] = [];
const similarities: { similarity: number; id: number }[] = [];
for (let i = 0; i < embeddings.length; i++) {
const sim = similarity(queryEmbedding, embeddings[i]);
@@ -105,8 +105,8 @@ export function getTopKEmbeddings(
similarities.sort((a, b) => b.similarity - a.similarity); // Reverse sort
let resultSimilarities: number[] = [];
let resultIds: any[] = [];
const resultSimilarities: number[] = [];
const resultIds: any[] = [];
for (let i = 0; i < similarityTopK; i++) {
if (i >= similarities.length) {
@@ -142,21 +142,21 @@ export function getTopKMMREmbeddings(
_similarityCutoff: number | null = null,
mmrThreshold: number | null = null,
): [number[], any[]] {
let threshold = mmrThreshold || 0.5;
const threshold = mmrThreshold || 0.5;
similarityFn = similarityFn || similarity;
if (embeddingIds === null || embeddingIds.length === 0) {
embeddingIds = Array.from({ length: embeddings.length }, (_, i) => i);
}
let fullEmbedMap = new Map(embeddingIds.map((value, i) => [value, i]));
let embedMap = new Map(fullEmbedMap);
let embedSimilarity: Map<any, number> = new Map();
const fullEmbedMap = new Map(embeddingIds.map((value, i) => [value, i]));
const embedMap = new Map(fullEmbedMap);
const embedSimilarity: Map<any, number> = new Map();
let score: number = Number.NEGATIVE_INFINITY;
let highScoreId: any | null = null;
for (let i = 0; i < embeddings.length; i++) {
let emb = embeddings[i];
let similarity = similarityFn(queryEmbedding, emb);
const emb = embeddings[i];
const similarity = similarityFn(queryEmbedding, emb);
embedSimilarity.set(embeddingIds[i], similarity);
if (similarity * threshold > score) {
highScoreId = embeddingIds[i];
@@ -164,18 +164,18 @@ export function getTopKMMREmbeddings(
}
}
let results: [number, any][] = [];
const results: [number, any][] = [];
let embeddingLength = embeddings.length;
let similarityTopKCount = similarityTopK || embeddingLength;
const embeddingLength = embeddings.length;
const similarityTopKCount = similarityTopK || embeddingLength;
while (results.length < Math.min(similarityTopKCount, embeddingLength)) {
results.push([score, highScoreId]);
embedMap.delete(highScoreId!);
let recentEmbeddingId = highScoreId;
const recentEmbeddingId = highScoreId;
score = Number.NEGATIVE_INFINITY;
for (let embedId of Array.from(embedMap.keys())) {
let overlapWithRecent = similarityFn(
for (const embedId of Array.from(embedMap.keys())) {
const overlapWithRecent = similarityFn(
embeddings[embedMap.get(embedId)!],
embeddings[fullEmbedMap.get(recentEmbeddingId!)!],
);
@@ -192,8 +192,8 @@ export function getTopKMMREmbeddings(
}
}
let resultSimilarities = results.map(([s, _]) => s);
let resultIds = results.map(([_, n]) => n);
const resultSimilarities = results.map(([s, _]) => s);
const resultIds = results.map(([_, n]) => n);
return [resultSimilarities, resultIds];
}
@@ -1,23 +1,23 @@
import { ChatHistory, getHistory } from "../../ChatHistory";
import { ChatHistory, getHistory } from "../../ChatHistory.js";
import {
CondenseQuestionPrompt,
defaultCondenseQuestionPrompt,
messagesToHistoryStr,
} from "../../Prompt";
import { Response } from "../../Response";
} from "../../Prompt.js";
import { Response } from "../../Response.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import { ChatMessage, LLM } from "../../llm";
import { extractText, streamReducer } from "../../llm/utils";
import { PromptMixin } from "../../prompts";
import { BaseQueryEngine } from "../../types";
} from "../../ServiceContext.js";
import { ChatMessage, LLM } from "../../llm/index.js";
import { extractText, streamReducer } from "../../llm/utils.js";
import { PromptMixin } from "../../prompts/index.js";
import { BaseQueryEngine } from "../../types.js";
import {
ChatEngine,
ChatEngineParamsNonStreaming,
ChatEngineParamsStreaming,
} from "./types";
} from "./types.js";
/**
* CondenseQuestionChatEngine is used in conjunction with a Index (for example VectorStoreIndex).
@@ -1,21 +1,30 @@
import { ChatHistory, getHistory } from "../../ChatHistory";
import { ContextSystemPrompt } from "../../Prompt";
import { Response } from "../../Response";
import { BaseRetriever } from "../../Retriever";
import { Event } from "../../callbacks/CallbackManager";
import { randomUUID } from "../../env";
import { ChatMessage, ChatResponseChunk, LLM, OpenAI } from "../../llm";
import { MessageContent } from "../../llm/types";
import { extractText, streamConverter, streamReducer } from "../../llm/utils";
import { BaseNodePostprocessor } from "../../postprocessors";
import { PromptMixin } from "../../prompts";
import { DefaultContextGenerator } from "./DefaultContextGenerator";
import { randomUUID } from "@llamaindex/env";
import { ChatHistory, getHistory } from "../../ChatHistory.js";
import { ContextSystemPrompt } from "../../Prompt.js";
import { Response } from "../../Response.js";
import { BaseRetriever } from "../../Retriever.js";
import { Event } from "../../callbacks/CallbackManager.js";
import {
ChatMessage,
ChatResponseChunk,
LLM,
OpenAI,
} from "../../llm/index.js";
import { MessageContent } from "../../llm/types.js";
import {
extractText,
streamConverter,
streamReducer,
} from "../../llm/utils.js";
import { BaseNodePostprocessor } from "../../postprocessors/index.js";
import { PromptMixin } from "../../prompts/Mixin.js";
import { DefaultContextGenerator } from "./DefaultContextGenerator.js";
import {
ChatEngine,
ChatEngineParamsNonStreaming,
ChatEngineParamsStreaming,
ContextGenerator,
} from "./types";
} from "./types.js";
/**
* ContextChatEngine uses the Index to get the appropriate context for each query.
@@ -1,11 +1,14 @@
import { NodeWithScore, TextNode } from "../../Node";
import { ContextSystemPrompt, defaultContextSystemPrompt } from "../../Prompt";
import { BaseRetriever } from "../../Retriever";
import { Event } from "../../callbacks/CallbackManager";
import { randomUUID } from "../../env";
import { BaseNodePostprocessor } from "../../postprocessors";
import { PromptMixin } from "../../prompts";
import { Context, ContextGenerator } from "./types";
import { randomUUID } from "@llamaindex/env";
import { NodeWithScore, TextNode } from "../../Node.js";
import {
ContextSystemPrompt,
defaultContextSystemPrompt,
} from "../../Prompt.js";
import { BaseRetriever } from "../../Retriever.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { BaseNodePostprocessor } from "../../postprocessors/index.js";
import { PromptMixin } from "../../prompts/index.js";
import { Context, ContextGenerator } from "./types.js";
export class DefaultContextGenerator
extends PromptMixin
@@ -1,12 +1,12 @@
import { ChatHistory, getHistory } from "../../ChatHistory";
import { Response } from "../../Response";
import { ChatResponseChunk, LLM, OpenAI } from "../../llm";
import { streamConverter, streamReducer } from "../../llm/utils";
import { ChatHistory, getHistory } from "../../ChatHistory.js";
import { Response } from "../../Response.js";
import { ChatResponseChunk, LLM, OpenAI } from "../../llm/index.js";
import { streamConverter, streamReducer } from "../../llm/utils.js";
import {
ChatEngine,
ChatEngineParamsNonStreaming,
ChatEngineParamsStreaming,
} from "./types";
} from "./types.js";
/**
* SimpleChatEngine is the simplest possible chat engine. Useful for using your own custom prompts.
+4 -4
View File
@@ -1,4 +1,4 @@
export { CondenseQuestionChatEngine } from "./CondenseQuestionChatEngine";
export { ContextChatEngine } from "./ContextChatEngine";
export { SimpleChatEngine } from "./SimpleChatEngine";
export * from "./types";
export { CondenseQuestionChatEngine } from "./CondenseQuestionChatEngine.js";
export { ContextChatEngine } from "./ContextChatEngine.js";
export { SimpleChatEngine } from "./SimpleChatEngine.js";
export * from "./types.js";
+7 -7
View File
@@ -1,10 +1,10 @@
import { ChatHistory } from "../../ChatHistory";
import { BaseNode, NodeWithScore } from "../../Node";
import { Response } from "../../Response";
import { Event } from "../../callbacks/CallbackManager";
import { ChatMessage } from "../../llm";
import { MessageContent } from "../../llm/types";
import { ToolOutput } from "../../tools/types";
import { ChatHistory } from "../../ChatHistory.js";
import { BaseNode, NodeWithScore } from "../../Node.js";
import { Response } from "../../Response.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { ChatMessage } from "../../llm/index.js";
import { MessageContent } from "../../llm/types.js";
import { ToolOutput } from "../../tools/types.js";
/**
* Represents the base parameters for ChatEngine.
@@ -1,17 +1,20 @@
import { NodeWithScore } from "../../Node";
import { Response } from "../../Response";
import { BaseRetriever } from "../../Retriever";
import { ServiceContext } from "../../ServiceContext";
import { Event } from "../../callbacks/CallbackManager";
import { randomUUID } from "../../env";
import { BaseNodePostprocessor } from "../../postprocessors";
import { PromptMixin } from "../../prompts";
import { BaseSynthesizer, ResponseSynthesizer } from "../../synthesizers";
import { randomUUID } from "@llamaindex/env";
import { NodeWithScore } from "../../Node.js";
import { Response } from "../../Response.js";
import { BaseRetriever } from "../../Retriever.js";
import { ServiceContext } from "../../ServiceContext.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { BaseNodePostprocessor } from "../../postprocessors/index.js";
import { PromptMixin } from "../../prompts/Mixin.js";
import {
BaseSynthesizer,
ResponseSynthesizer,
} from "../../synthesizers/index.js";
import {
BaseQueryEngine,
QueryEngineParamsNonStreaming,
QueryEngineParamsStreaming,
} from "../../types";
} from "../../types.js";
/**
* A query engine that uses a retriever to query an index and then synthesizes the response.
@@ -1,18 +1,18 @@
import { BaseNode } from "../../Node";
import { Response } from "../../Response";
import { BaseNode } from "../../Node.js";
import { Response } from "../../Response.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import { PromptMixin } from "../../prompts";
import { BaseSelector, LLMSingleSelector } from "../../selectors";
import { TreeSummarize } from "../../synthesizers";
} from "../../ServiceContext.js";
import { PromptMixin } from "../../prompts/index.js";
import { BaseSelector, LLMSingleSelector } from "../../selectors/index.js";
import { TreeSummarize } from "../../synthesizers/index.js";
import {
BaseQueryEngine,
QueryBundle,
QueryEngineParamsNonStreaming,
QueryEngineParamsStreaming,
} from "../../types";
} from "../../types.js";
type RouterQueryEngineTool = {
queryEngine: BaseQueryEngine;
@@ -1,18 +1,18 @@
import { NodeWithScore, TextNode } from "../../Node";
import { LLMQuestionGenerator } from "../../QuestionGenerator";
import { Response } from "../../Response";
import { randomUUID } from "@llamaindex/env";
import { NodeWithScore, TextNode } from "../../Node.js";
import { LLMQuestionGenerator } from "../../QuestionGenerator.js";
import { Response } from "../../Response.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import { Event } from "../../callbacks/CallbackManager";
import { randomUUID } from "../../env";
import { PromptMixin } from "../../prompts";
} from "../../ServiceContext.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { PromptMixin } from "../../prompts/Mixin.js";
import {
BaseSynthesizer,
CompactAndRefine,
ResponseSynthesizer,
} from "../../synthesizers";
} from "../../synthesizers/index.js";
import {
BaseQueryEngine,
@@ -20,9 +20,9 @@ import {
QueryEngineParamsNonStreaming,
QueryEngineParamsStreaming,
ToolMetadata,
} from "../../types";
} from "../../types.js";
import { BaseQuestionGenerator, SubQuestion } from "./types";
import { BaseQuestionGenerator, SubQuestion } from "./types.js";
/**
* SubQuestionQueryEngine decomposes a question into subquestions and then
+3 -3
View File
@@ -1,3 +1,3 @@
export * from "./RetrieverQueryEngine";
export * from "./RouterQueryEngine";
export * from "./SubQuestionQueryEngine";
export * from "./RetrieverQueryEngine.js";
export * from "./RouterQueryEngine.js";
export * from "./SubQuestionQueryEngine.js";
+1 -1
View File
@@ -1,4 +1,4 @@
import { ToolMetadata } from "../../types";
import { ToolMetadata } from "../../types.js";
/**
* QuestionGenerators generate new questions for the LLM using tools and a user query.
@@ -1,13 +1,13 @@
import { BaseNode, MetadataMode, TextNode } from "../Node";
import { LLM, OpenAI } from "../llm";
import { BaseNode, MetadataMode, TextNode } from "../Node.js";
import { LLM, OpenAI } from "../llm/index.js";
import {
defaultKeywordExtractorPromptTemplate,
defaultQuestionAnswerPromptTemplate,
defaultSummaryExtractorPromptTemplate,
defaultTitleCombinePromptTemplate,
defaultTitleExtractorPromptTemplate,
} from "./prompts";
import { BaseExtractor } from "./types";
} from "./prompts.js";
import { BaseExtractor } from "./types.js";
const STRIP_REGEX = /(\r\n|\n|\r)/gm;
@@ -172,7 +172,7 @@ export class TitleExtractor extends BaseExtractor {
if (nodesToExtractTitle.length === 0) return [];
let titlesCandidates: string[] = [];
const titlesCandidates: string[] = [];
let title: string = "";
for (let i = 0; i < nodesToExtractTitle.length; i++) {
@@ -411,7 +411,7 @@ export class SummaryExtractor extends BaseExtractor {
nodes.map((node) => this.generateNodeSummary(node)),
);
let metadataList: any[] = nodes.map(() => ({}));
const metadataList: any[] = nodes.map(() => ({}));
for (let i = 0; i < nodes.length; i++) {
if (i > 0 && this._prevSummary && nodeSummaries[i - 1]) {
+2 -2
View File
@@ -3,5 +3,5 @@ export {
QuestionsAnsweredExtractor,
SummaryExtractor,
TitleExtractor,
} from "./MetadataExtractors";
export { BaseExtractor } from "./types";
} from "./MetadataExtractors.js";
export { BaseExtractor } from "./types.js";
+6 -6
View File
@@ -1,6 +1,6 @@
import { BaseNode, MetadataMode, TextNode } from "../Node";
import { TransformComponent } from "../ingestion";
import { defaultNodeTextTemplate } from "./prompts";
import { BaseNode, MetadataMode, TextNode } from "../Node.js";
import { TransformComponent } from "../ingestion/types.js";
import { defaultNodeTextTemplate } from "./prompts.js";
/*
* Abstract class for all extractors.
@@ -43,16 +43,16 @@ export abstract class BaseExtractor implements TransformComponent {
newNodes = nodes.slice();
}
let curMetadataList = await this.extract(newNodes);
const curMetadataList = await this.extract(newNodes);
for (let idx in newNodes) {
for (const idx in newNodes) {
newNodes[idx].metadata = {
...newNodes[idx].metadata,
...curMetadataList[idx],
};
}
for (let idx in newNodes) {
for (const idx in newNodes) {
if (excludedEmbedMetadataKeys) {
newNodes[idx].excludedEmbedMetadataKeys.concat(
excludedEmbedMetadataKeys,
+31 -31
View File
@@ -1,31 +1,31 @@
export * from "./ChatHistory";
export * from "./GlobalsHelper";
export * from "./Node";
export * from "./OutputParser";
export * from "./Prompt";
export * from "./PromptHelper";
export * from "./QuestionGenerator";
export * from "./Response";
export * from "./Retriever";
export * from "./ServiceContext";
export * from "./TextSplitter";
export * from "./agent";
export * from "./callbacks/CallbackManager";
export * from "./cloud";
export * from "./constants";
export * from "./embeddings";
export * from "./engines/chat";
export * from "./engines/query";
export * from "./extractors";
export * from "./indices";
export * from "./ingestion";
export * from "./llm";
export * from "./nodeParsers";
export * from "./objects";
export * from "./postprocessors";
export * from "./prompts";
export * from "./readers";
export * from "./selectors";
export * from "./storage";
export * from "./synthesizers";
export * from "./tools";
export * from "./ChatHistory.js";
export * from "./GlobalsHelper.js";
export * from "./Node.js";
export * from "./OutputParser.js";
export * from "./Prompt.js";
export * from "./PromptHelper.js";
export * from "./QuestionGenerator.js";
export * from "./Response.js";
export * from "./Retriever.js";
export * from "./ServiceContext.js";
export * from "./TextSplitter.js";
export * from "./agent/index.js";
export * from "./callbacks/CallbackManager.js";
export * from "./cloud/index.js";
export * from "./constants.js";
export * from "./embeddings/index.js";
export * from "./engines/chat/index.js";
export * from "./engines/query/index.js";
export * from "./extractors/index.js";
export * from "./indices/index.js";
export * from "./ingestion/index.js";
export * from "./llm/index.js";
export * from "./nodeParsers/index.js";
export * from "./objects/index.js";
export * from "./postprocessors/index.js";
export * from "./prompts/index.js";
export * from "./readers/index.js";
export * from "./selectors/index.js";
export * from "./storage/index.js";
export * from "./synthesizers/index.js";
export * from "./tools/index.js";
+12 -109
View File
@@ -1,112 +1,15 @@
import { BaseNode, Document, jsonToNode } from "../Node";
import { BaseRetriever } from "../Retriever";
import { ServiceContext } from "../ServiceContext";
import { randomUUID } from "../env";
import { runTransformations } from "../ingestion";
import { StorageContext } from "../storage/StorageContext";
import { BaseDocumentStore } from "../storage/docStore/types";
import { BaseIndexStore } from "../storage/indexStore/types";
import { VectorStore } from "../storage/vectorStore/types";
import { BaseSynthesizer } from "../synthesizers";
import { BaseQueryEngine } from "../types";
/**
* The underlying structure of each index.
*/
export abstract class IndexStruct {
indexId: string;
summary?: string;
constructor(indexId = randomUUID(), summary = undefined) {
this.indexId = indexId;
this.summary = summary;
}
toJson(): Record<string, unknown> {
return {
indexId: this.indexId,
summary: this.summary,
};
}
getSummary(): string {
if (this.summary === undefined) {
throw new Error("summary field of the index dict is not set");
}
return this.summary;
}
}
export enum IndexStructType {
SIMPLE_DICT = "simple_dict",
LIST = "list",
KEYWORD_TABLE = "keyword_table",
}
export class IndexDict extends IndexStruct {
nodesDict: Record<string, BaseNode> = {};
type: IndexStructType = IndexStructType.SIMPLE_DICT;
getSummary(): string {
if (this.summary === undefined) {
throw new Error("summary field of the index dict is not set");
}
return this.summary;
}
addNode(node: BaseNode, textId?: string) {
const vectorId = textId ?? node.id_;
this.nodesDict[vectorId] = node;
}
toJson(): Record<string, unknown> {
return {
...super.toJson(),
nodesDict: this.nodesDict,
type: this.type,
};
}
delete(nodeId: string) {
delete this.nodesDict[nodeId];
}
}
export function jsonToIndexStruct(json: any): IndexStruct {
if (json.type === IndexStructType.LIST) {
const indexList = new IndexList(json.indexId, json.summary);
indexList.nodes = json.nodes;
return indexList;
} else if (json.type === IndexStructType.SIMPLE_DICT) {
const indexDict = new IndexDict(json.indexId, json.summary);
indexDict.nodesDict = Object.entries(json.nodesDict).reduce<
Record<string, BaseNode>
>((acc, [key, value]) => {
acc[key] = jsonToNode(value);
return acc;
}, {});
return indexDict;
} else {
throw new Error(`Unknown index struct type: ${json.type}`);
}
}
export class IndexList extends IndexStruct {
nodes: string[] = [];
type: IndexStructType = IndexStructType.LIST;
addNode(node: BaseNode) {
this.nodes.push(node.id_);
}
toJson(): Record<string, unknown> {
return {
...super.toJson(),
nodes: this.nodes,
type: this.type,
};
}
}
import { BaseNode, Document } from "../Node.js";
import { BaseRetriever } from "../Retriever.js";
import { ServiceContext } from "../ServiceContext.js";
import { runTransformations } from "../ingestion/IngestionPipeline.js";
import { StorageContext } from "../storage/StorageContext.js";
import { BaseDocumentStore } from "../storage/docStore/types.js";
import { BaseIndexStore } from "../storage/indexStore/types.js";
import { VectorStore } from "../storage/vectorStore/types.js";
import { BaseSynthesizer } from "../synthesizers/types.js";
import { BaseQueryEngine } from "../types.js";
import { IndexStruct } from "./IndexStruct.js";
import { IndexStructType } from "./json-to-index-struct.js";
// A table of keywords mapping keywords to text chunks.
export class KeywordTable extends IndexStruct {
+28
View File
@@ -0,0 +1,28 @@
import { randomUUID } from "@llamaindex/env";
/**
* The underlying structure of each index.
*/
export abstract class IndexStruct {
indexId: string;
summary?: string;
constructor(indexId = randomUUID(), summary = undefined) {
this.indexId = indexId;
this.summary = summary;
}
toJson(): Record<string, unknown> {
return {
indexId: this.indexId,
summary: this.summary,
};
}
getSummary(): string {
if (this.summary === undefined) {
throw new Error("summary field of the index dict is not set");
}
return this.summary;
}
}
+4 -4
View File
@@ -1,4 +1,4 @@
export * from "./BaseIndex";
export * from "./keyword";
export * from "./summary";
export * from "./vectorStore";
export * from "./BaseIndex.js";
export * from "./keyword/index.js";
export * from "./summary/index.js";
export * from "./vectorStore/index.js";
@@ -0,0 +1,71 @@
import { BaseNode, jsonToNode } from "../Node.js";
import { IndexStruct } from "./IndexStruct.js";
export enum IndexStructType {
SIMPLE_DICT = "simple_dict",
LIST = "list",
KEYWORD_TABLE = "keyword_table",
}
export class IndexDict extends IndexStruct {
nodesDict: Record<string, BaseNode> = {};
type: IndexStructType = IndexStructType.SIMPLE_DICT;
getSummary(): string {
if (this.summary === undefined) {
throw new Error("summary field of the index dict is not set");
}
return this.summary;
}
addNode(node: BaseNode, textId?: string) {
const vectorId = textId ?? node.id_;
this.nodesDict[vectorId] = node;
}
toJson(): Record<string, unknown> {
return {
...super.toJson(),
nodesDict: this.nodesDict,
type: this.type,
};
}
delete(nodeId: string) {
delete this.nodesDict[nodeId];
}
}
export function jsonToIndexStruct(json: any): IndexStruct {
if (json.type === IndexStructType.LIST) {
const indexList = new IndexList(json.indexId, json.summary);
indexList.nodes = json.nodes;
return indexList;
} else if (json.type === IndexStructType.SIMPLE_DICT) {
const indexDict = new IndexDict(json.indexId, json.summary);
indexDict.nodesDict = Object.entries(json.nodesDict).reduce<
Record<string, BaseNode>
>((acc, [key, value]) => {
acc[key] = jsonToNode(value);
return acc;
}, {});
return indexDict;
} else {
throw new Error(`Unknown index struct type: ${json.type}`);
}
}
export class IndexList extends IndexStruct {
nodes: string[] = [];
type: IndexStructType = IndexStructType.LIST;
addNode(node: BaseNode) {
this.nodes.push(node.id_);
}
toJson(): Record<string, unknown> {
return {
...super.toJson(),
nodes: this.nodes,
type: this.type,
};
}
}
@@ -1,278 +0,0 @@
import { BaseNode, Document, MetadataMode } from "../../Node";
import { defaultKeywordExtractPrompt } from "../../Prompt";
import { BaseRetriever } from "../../Retriever";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import { RetrieverQueryEngine } from "../../engines/query";
import { BaseNodePostprocessor } from "../../postprocessors";
import {
BaseDocumentStore,
StorageContext,
storageContextFromDefaults,
} from "../../storage";
import { BaseSynthesizer } from "../../synthesizers";
import { BaseQueryEngine } from "../../types";
import {
BaseIndex,
BaseIndexInit,
IndexStructType,
KeywordTable,
} from "../BaseIndex";
import {
KeywordTableLLMRetriever,
KeywordTableRAKERetriever,
KeywordTableSimpleRetriever,
} from "./KeywordTableIndexRetriever";
import { extractKeywordsGivenResponse } from "./utils";
export interface KeywordIndexOptions {
nodes?: BaseNode[];
indexStruct?: KeywordTable;
indexId?: string;
serviceContext?: ServiceContext;
storageContext?: StorageContext;
}
export enum KeywordTableRetrieverMode {
DEFAULT = "DEFAULT",
SIMPLE = "SIMPLE",
RAKE = "RAKE",
}
const KeywordTableRetrieverMap = {
[KeywordTableRetrieverMode.DEFAULT]: KeywordTableLLMRetriever,
[KeywordTableRetrieverMode.SIMPLE]: KeywordTableSimpleRetriever,
[KeywordTableRetrieverMode.RAKE]: KeywordTableRAKERetriever,
};
/**
* The KeywordTableIndex, an index that extracts keywords from each Node and builds a mapping from each keyword to the corresponding Nodes of that keyword.
*/
export class KeywordTableIndex extends BaseIndex<KeywordTable> {
constructor(init: BaseIndexInit<KeywordTable>) {
super(init);
}
static async init(options: KeywordIndexOptions): Promise<KeywordTableIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const { docStore, indexStore } = storageContext;
// Setup IndexStruct from storage
let indexStructs = (await indexStore.getIndexStructs()) as KeywordTable[];
let indexStruct: KeywordTable | null;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as KeywordTable;
} else {
indexStruct = null;
}
// check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.KEYWORD_TABLE) {
throw new Error(
"Attempting to initialize KeywordTableIndex with non-keyword table indexStruct",
);
}
if (indexStruct) {
if (options.nodes) {
throw new Error(
"Cannot initialize KeywordTableIndex with both nodes and indexStruct",
);
}
} else {
if (!options.nodes) {
throw new Error(
"Cannot initialize KeywordTableIndex without nodes or indexStruct",
);
}
indexStruct = await KeywordTableIndex.buildIndexFromNodes(
options.nodes,
storageContext.docStore,
serviceContext,
);
await indexStore.addIndexStruct(indexStruct);
}
return new KeywordTableIndex({
storageContext,
serviceContext,
docStore,
indexStore,
indexStruct,
});
}
asRetriever(options?: any): BaseRetriever {
const { mode = KeywordTableRetrieverMode.DEFAULT, ...otherOptions } =
options ?? {};
const KeywordTableRetriever =
KeywordTableRetrieverMap[mode as KeywordTableRetrieverMode];
if (KeywordTableRetriever) {
return new KeywordTableRetriever({ index: this, ...otherOptions });
}
throw new Error(`Unknown retriever mode: ${mode}`);
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: unknown;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine {
const { retriever, responseSynthesizer } = options ?? {};
return new RetrieverQueryEngine(
retriever ?? this.asRetriever(),
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
static async extractKeywords(
text: string,
serviceContext: ServiceContext,
): Promise<Set<string>> {
const response = await serviceContext.llm.complete({
prompt: defaultKeywordExtractPrompt({
context: text,
}),
});
return extractKeywordsGivenResponse(response.text, "KEYWORDS:");
}
/**
* High level API: split documents, get keywords, and build index.
* @param documents
* @param storageContext
* @param serviceContext
* @returns
*/
static async fromDocuments(
documents: Document[],
args: {
storageContext?: StorageContext;
serviceContext?: ServiceContext;
} = {},
): Promise<KeywordTableIndex> {
let { storageContext, serviceContext } = args;
storageContext = storageContext ?? (await storageContextFromDefaults({}));
serviceContext = serviceContext ?? serviceContextFromDefaults({});
const docStore = storageContext.docStore;
docStore.addDocuments(documents, true);
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
const index = await KeywordTableIndex.init({
nodes,
storageContext,
serviceContext,
});
return index;
}
/**
* Get keywords for nodes and place them into the index.
* @param nodes
* @param serviceContext
* @param vectorStore
* @returns
*/
static async buildIndexFromNodes(
nodes: BaseNode[],
docStore: BaseDocumentStore,
serviceContext: ServiceContext,
): Promise<KeywordTable> {
const indexStruct = new KeywordTable();
await docStore.addDocuments(nodes, true);
for (const node of nodes) {
const keywords = await KeywordTableIndex.extractKeywords(
node.getContent(MetadataMode.LLM),
serviceContext,
);
indexStruct.addNode([...keywords], node.id_);
}
return indexStruct;
}
async insertNodes(nodes: BaseNode[]) {
for (let node of nodes) {
const keywords = await KeywordTableIndex.extractKeywords(
node.getContent(MetadataMode.LLM),
this.serviceContext,
);
this.indexStruct.addNode([...keywords], node.id_);
}
}
deleteNode(nodeId: string): void {
const keywordsToDelete: Set<string> = new Set();
for (const [keyword, existingNodeIds] of Object.entries(
this.indexStruct.table,
)) {
const index = existingNodeIds.indexOf(nodeId);
if (index !== -1) {
existingNodeIds.splice(index, 1);
// Delete keywords that have zero nodes
if (existingNodeIds.length === 0) {
keywordsToDelete.add(keyword);
}
}
}
this.indexStruct.deleteNode([...keywordsToDelete], nodeId);
}
async deleteNodes(nodeIds: string[], deleteFromDocStore: boolean) {
nodeIds.forEach((nodeId) => {
this.deleteNode(nodeId);
});
if (deleteFromDocStore) {
for (const nodeId of nodeIds) {
await this.docStore.deleteDocument(nodeId, false);
}
}
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore?: boolean,
): Promise<void> {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (!refDocInfo) {
return;
}
await this.deleteNodes(refDocInfo.nodeIds, false);
if (deleteFromDocStore) {
await this.docStore.deleteRefDoc(refDocId, false);
}
return;
}
}
@@ -1,116 +0,0 @@
import { NodeWithScore } from "../../Node";
import {
defaultKeywordExtractPrompt,
defaultQueryKeywordExtractPrompt,
KeywordExtractPrompt,
QueryKeywordExtractPrompt,
} from "../../Prompt";
import { BaseRetriever } from "../../Retriever";
import { ServiceContext } from "../../ServiceContext";
import { BaseDocumentStore } from "../../storage/docStore/types";
import { KeywordTable } from "../BaseIndex";
import { KeywordTableIndex } from "./KeywordTableIndex";
import {
extractKeywordsGivenResponse,
rakeExtractKeywords,
simpleExtractKeywords,
} from "./utils";
// Base Keyword Table Retriever
abstract class BaseKeywordTableRetriever implements BaseRetriever {
protected index: KeywordTableIndex;
protected indexStruct: KeywordTable;
protected docstore: BaseDocumentStore;
protected serviceContext: ServiceContext;
protected maxKeywordsPerQuery: number; // Maximum number of keywords to extract from query.
protected numChunksPerQuery: number; // Maximum number of text chunks to query.
protected keywordExtractTemplate: KeywordExtractPrompt; // A Keyword Extraction Prompt
protected queryKeywordExtractTemplate: QueryKeywordExtractPrompt; // A Query Keyword Extraction Prompt
constructor({
index,
keywordExtractTemplate,
queryKeywordExtractTemplate,
maxKeywordsPerQuery = 10,
numChunksPerQuery = 10,
}: {
index: KeywordTableIndex;
keywordExtractTemplate?: KeywordExtractPrompt;
queryKeywordExtractTemplate?: QueryKeywordExtractPrompt;
maxKeywordsPerQuery: number;
numChunksPerQuery: number;
}) {
this.index = index;
this.indexStruct = index.indexStruct;
this.docstore = index.docStore;
this.serviceContext = index.serviceContext;
this.maxKeywordsPerQuery = maxKeywordsPerQuery;
this.numChunksPerQuery = numChunksPerQuery;
this.keywordExtractTemplate =
keywordExtractTemplate || defaultKeywordExtractPrompt;
this.queryKeywordExtractTemplate =
queryKeywordExtractTemplate || defaultQueryKeywordExtractPrompt;
}
abstract getKeywords(query: string): Promise<string[]>;
async retrieve(query: string): Promise<NodeWithScore[]> {
const keywords = await this.getKeywords(query);
const chunkIndicesCount: { [key: string]: number } = {};
const filteredKeywords = keywords.filter((keyword) =>
this.indexStruct.table.has(keyword),
);
for (let keyword of filteredKeywords) {
for (let nodeId of this.indexStruct.table.get(keyword) || []) {
chunkIndicesCount[nodeId] = (chunkIndicesCount[nodeId] ?? 0) + 1;
}
}
const sortedChunkIndices = Object.keys(chunkIndicesCount)
.sort((a, b) => chunkIndicesCount[b] - chunkIndicesCount[a])
.slice(0, this.numChunksPerQuery);
const sortedNodes = await this.docstore.getNodes(sortedChunkIndices);
return sortedNodes.map((node) => ({ node }));
}
getServiceContext(): ServiceContext {
return this.index.serviceContext;
}
}
// Extracts keywords using LLMs.
export class KeywordTableLLMRetriever extends BaseKeywordTableRetriever {
async getKeywords(query: string): Promise<string[]> {
const response = await this.serviceContext.llm.complete({
prompt: this.queryKeywordExtractTemplate({
question: query,
maxKeywords: this.maxKeywordsPerQuery,
}),
});
const keywords = extractKeywordsGivenResponse(response.text, "KEYWORDS:");
return [...keywords];
}
}
// Extracts keywords using simple regex-based keyword extractor.
export class KeywordTableSimpleRetriever extends BaseKeywordTableRetriever {
getKeywords(query: string): Promise<string[]> {
return Promise.resolve([
...simpleExtractKeywords(query, this.maxKeywordsPerQuery),
]);
}
}
// Extracts keywords using RAKE keyword extractor
export class KeywordTableRAKERetriever extends BaseKeywordTableRetriever {
getKeywords(query: string): Promise<string[]> {
return Promise.resolve([
...rakeExtractKeywords(query, this.maxKeywordsPerQuery),
]);
}
}
+377 -9
View File
@@ -1,9 +1,377 @@
export {
KeywordTableIndex,
KeywordTableRetrieverMode,
} from "./KeywordTableIndex";
export {
KeywordTableLLMRetriever,
KeywordTableRAKERetriever,
KeywordTableSimpleRetriever,
} from "./KeywordTableIndexRetriever";
import { BaseNode, Document, MetadataMode, NodeWithScore } from "../../Node.js";
import {
KeywordExtractPrompt,
QueryKeywordExtractPrompt,
defaultKeywordExtractPrompt,
defaultQueryKeywordExtractPrompt,
} from "../../Prompt.js";
import { BaseRetriever } from "../../Retriever.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext.js";
import { RetrieverQueryEngine } from "../../engines/query/index.js";
import { BaseNodePostprocessor } from "../../postprocessors/index.js";
import {
BaseDocumentStore,
StorageContext,
storageContextFromDefaults,
} from "../../storage/index.js";
import { BaseSynthesizer } from "../../synthesizers/index.js";
import { BaseQueryEngine } from "../../types.js";
import { BaseIndex, BaseIndexInit, KeywordTable } from "../BaseIndex.js";
import { IndexStructType } from "../json-to-index-struct.js";
import {
extractKeywordsGivenResponse,
rakeExtractKeywords,
simpleExtractKeywords,
} from "./utils.js";
export interface KeywordIndexOptions {
nodes?: BaseNode[];
indexStruct?: KeywordTable;
indexId?: string;
serviceContext?: ServiceContext;
storageContext?: StorageContext;
}
export enum KeywordTableRetrieverMode {
DEFAULT = "DEFAULT",
SIMPLE = "SIMPLE",
RAKE = "RAKE",
}
// Base Keyword Table Retriever
abstract class BaseKeywordTableRetriever implements BaseRetriever {
protected index: KeywordTableIndex;
protected indexStruct: KeywordTable;
protected docstore: BaseDocumentStore;
protected serviceContext: ServiceContext;
protected maxKeywordsPerQuery: number; // Maximum number of keywords to extract from query.
protected numChunksPerQuery: number; // Maximum number of text chunks to query.
protected keywordExtractTemplate: KeywordExtractPrompt; // A Keyword Extraction Prompt
protected queryKeywordExtractTemplate: QueryKeywordExtractPrompt; // A Query Keyword Extraction Prompt
constructor({
index,
keywordExtractTemplate,
queryKeywordExtractTemplate,
maxKeywordsPerQuery = 10,
numChunksPerQuery = 10,
}: {
index: KeywordTableIndex;
keywordExtractTemplate?: KeywordExtractPrompt;
queryKeywordExtractTemplate?: QueryKeywordExtractPrompt;
maxKeywordsPerQuery: number;
numChunksPerQuery: number;
}) {
this.index = index;
this.indexStruct = index.indexStruct;
this.docstore = index.docStore;
this.serviceContext = index.serviceContext;
this.maxKeywordsPerQuery = maxKeywordsPerQuery;
this.numChunksPerQuery = numChunksPerQuery;
this.keywordExtractTemplate =
keywordExtractTemplate || defaultKeywordExtractPrompt;
this.queryKeywordExtractTemplate =
queryKeywordExtractTemplate || defaultQueryKeywordExtractPrompt;
}
abstract getKeywords(query: string): Promise<string[]>;
async retrieve(query: string): Promise<NodeWithScore[]> {
const keywords = await this.getKeywords(query);
const chunkIndicesCount: { [key: string]: number } = {};
const filteredKeywords = keywords.filter((keyword) =>
this.indexStruct.table.has(keyword),
);
for (const keyword of filteredKeywords) {
for (const nodeId of this.indexStruct.table.get(keyword) || []) {
chunkIndicesCount[nodeId] = (chunkIndicesCount[nodeId] ?? 0) + 1;
}
}
const sortedChunkIndices = Object.keys(chunkIndicesCount)
.sort((a, b) => chunkIndicesCount[b] - chunkIndicesCount[a])
.slice(0, this.numChunksPerQuery);
const sortedNodes = await this.docstore.getNodes(sortedChunkIndices);
return sortedNodes.map((node) => ({ node }));
}
getServiceContext(): ServiceContext {
return this.index.serviceContext;
}
}
// Extracts keywords using LLMs.
export class KeywordTableLLMRetriever extends BaseKeywordTableRetriever {
async getKeywords(query: string): Promise<string[]> {
const response = await this.serviceContext.llm.complete({
prompt: this.queryKeywordExtractTemplate({
question: query,
maxKeywords: this.maxKeywordsPerQuery,
}),
});
const keywords = extractKeywordsGivenResponse(response.text, "KEYWORDS:");
return [...keywords];
}
}
// Extracts keywords using simple regex-based keyword extractor.
export class KeywordTableSimpleRetriever extends BaseKeywordTableRetriever {
getKeywords(query: string): Promise<string[]> {
return Promise.resolve([
...simpleExtractKeywords(query, this.maxKeywordsPerQuery),
]);
}
}
// Extracts keywords using RAKE keyword extractor
export class KeywordTableRAKERetriever extends BaseKeywordTableRetriever {
getKeywords(query: string): Promise<string[]> {
return Promise.resolve([
...rakeExtractKeywords(query, this.maxKeywordsPerQuery),
]);
}
}
const KeywordTableRetrieverMap = {
[KeywordTableRetrieverMode.DEFAULT]: KeywordTableLLMRetriever,
[KeywordTableRetrieverMode.SIMPLE]: KeywordTableSimpleRetriever,
[KeywordTableRetrieverMode.RAKE]: KeywordTableRAKERetriever,
};
/**
* The KeywordTableIndex, an index that extracts keywords from each Node and builds a mapping from each keyword to the corresponding Nodes of that keyword.
*/
export class KeywordTableIndex extends BaseIndex<KeywordTable> {
constructor(init: BaseIndexInit<KeywordTable>) {
super(init);
}
static async init(options: KeywordIndexOptions): Promise<KeywordTableIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const { docStore, indexStore } = storageContext;
// Setup IndexStruct from storage
const indexStructs = (await indexStore.getIndexStructs()) as KeywordTable[];
let indexStruct: KeywordTable | null;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as KeywordTable;
} else {
indexStruct = null;
}
// check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.KEYWORD_TABLE) {
throw new Error(
"Attempting to initialize KeywordTableIndex with non-keyword table indexStruct",
);
}
if (indexStruct) {
if (options.nodes) {
throw new Error(
"Cannot initialize KeywordTableIndex with both nodes and indexStruct",
);
}
} else {
if (!options.nodes) {
throw new Error(
"Cannot initialize KeywordTableIndex without nodes or indexStruct",
);
}
indexStruct = await KeywordTableIndex.buildIndexFromNodes(
options.nodes,
storageContext.docStore,
serviceContext,
);
await indexStore.addIndexStruct(indexStruct);
}
return new KeywordTableIndex({
storageContext,
serviceContext,
docStore,
indexStore,
indexStruct,
});
}
asRetriever(options?: any): BaseRetriever {
const { mode = KeywordTableRetrieverMode.DEFAULT, ...otherOptions } =
options ?? {};
const KeywordTableRetriever =
KeywordTableRetrieverMap[mode as KeywordTableRetrieverMode];
if (KeywordTableRetriever) {
return new KeywordTableRetriever({ index: this, ...otherOptions });
}
throw new Error(`Unknown retriever mode: ${mode}`);
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: unknown;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine {
const { retriever, responseSynthesizer } = options ?? {};
return new RetrieverQueryEngine(
retriever ?? this.asRetriever(),
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
static async extractKeywords(
text: string,
serviceContext: ServiceContext,
): Promise<Set<string>> {
const response = await serviceContext.llm.complete({
prompt: defaultKeywordExtractPrompt({
context: text,
}),
});
return extractKeywordsGivenResponse(response.text, "KEYWORDS:");
}
/**
* High level API: split documents, get keywords, and build index.
* @param documents
* @param storageContext
* @param serviceContext
* @returns
*/
static async fromDocuments(
documents: Document[],
args: {
storageContext?: StorageContext;
serviceContext?: ServiceContext;
} = {},
): Promise<KeywordTableIndex> {
let { storageContext, serviceContext } = args;
storageContext = storageContext ?? (await storageContextFromDefaults({}));
serviceContext = serviceContext ?? serviceContextFromDefaults({});
const docStore = storageContext.docStore;
docStore.addDocuments(documents, true);
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
const index = await KeywordTableIndex.init({
nodes,
storageContext,
serviceContext,
});
return index;
}
/**
* Get keywords for nodes and place them into the index.
* @param nodes
* @param serviceContext
* @param vectorStore
* @returns
*/
static async buildIndexFromNodes(
nodes: BaseNode[],
docStore: BaseDocumentStore,
serviceContext: ServiceContext,
): Promise<KeywordTable> {
const indexStruct = new KeywordTable();
await docStore.addDocuments(nodes, true);
for (const node of nodes) {
const keywords = await KeywordTableIndex.extractKeywords(
node.getContent(MetadataMode.LLM),
serviceContext,
);
indexStruct.addNode([...keywords], node.id_);
}
return indexStruct;
}
async insertNodes(nodes: BaseNode[]) {
for (const node of nodes) {
const keywords = await KeywordTableIndex.extractKeywords(
node.getContent(MetadataMode.LLM),
this.serviceContext,
);
this.indexStruct.addNode([...keywords], node.id_);
}
}
deleteNode(nodeId: string): void {
const keywordsToDelete: Set<string> = new Set();
for (const [keyword, existingNodeIds] of Object.entries(
this.indexStruct.table,
)) {
const index = existingNodeIds.indexOf(nodeId);
if (index !== -1) {
existingNodeIds.splice(index, 1);
// Delete keywords that have zero nodes
if (existingNodeIds.length === 0) {
keywordsToDelete.add(keyword);
}
}
}
this.indexStruct.deleteNode([...keywordsToDelete], nodeId);
}
async deleteNodes(nodeIds: string[], deleteFromDocStore: boolean) {
nodeIds.forEach((nodeId) => {
this.deleteNode(nodeId);
});
if (deleteFromDocStore) {
for (const nodeId of nodeIds) {
await this.docStore.deleteDocument(nodeId, false);
}
}
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore?: boolean,
): Promise<void> {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (!refDocInfo) {
return;
}
await this.deleteNodes(refDocInfo.nodeIds, false);
if (deleteFromDocStore) {
await this.docStore.deleteRefDoc(refDocId, false);
}
return;
}
}
+5 -5
View File
@@ -6,11 +6,11 @@ export function expandTokensWithSubtokens(tokens: Set<string>): Set<string> {
const results: Set<string> = new Set();
const regex: RegExp = /\w+/g;
for (let token of tokens) {
for (const token of tokens) {
results.add(token);
const subTokens: RegExpMatchArray | null = token.match(regex);
if (subTokens && subTokens.length > 1) {
for (let w of subTokens) {
for (const w of subTokens) {
results.add(w);
}
}
@@ -31,7 +31,7 @@ export function extractKeywordsGivenResponse(
}
const keywords: string[] = response.split(",");
for (let k of keywords) {
for (const k of keywords) {
let rk: string = k;
if (lowercase) {
rk = rk.toLowerCase();
@@ -47,13 +47,13 @@ export function simpleExtractKeywords(
maxKeywords?: number,
): Set<string> {
const regex: RegExp = /\w+/g;
let tokens: string[] = [...textChunk.matchAll(regex)].map((token) =>
const tokens: string[] = [...textChunk.matchAll(regex)].map((token) =>
token[0].toLowerCase().trim(),
);
// Creating a frequency map
const valueCounts: { [key: string]: number } = {};
for (let token of tokens) {
for (const token of tokens) {
valueCounts[token] = (valueCounts[token] || 0) + 1;
}
@@ -1,268 +0,0 @@
import _ from "lodash";
import { BaseNode, Document } from "../../Node";
import { BaseRetriever } from "../../Retriever";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import { RetrieverQueryEngine } from "../../engines/query";
import { BaseNodePostprocessor } from "../../postprocessors";
import {
BaseDocumentStore,
RefDocInfo,
StorageContext,
storageContextFromDefaults,
} from "../../storage";
import {
BaseSynthesizer,
CompactAndRefine,
ResponseSynthesizer,
} from "../../synthesizers";
import { BaseQueryEngine } from "../../types";
import {
BaseIndex,
BaseIndexInit,
IndexList,
IndexStructType,
} from "../BaseIndex";
import {
SummaryIndexLLMRetriever,
SummaryIndexRetriever,
} from "./SummaryIndexRetriever";
export enum SummaryRetrieverMode {
DEFAULT = "default",
// EMBEDDING = "embedding",
LLM = "llm",
}
export interface SummaryIndexOptions {
nodes?: BaseNode[];
indexStruct?: IndexList;
indexId?: string;
serviceContext?: ServiceContext;
storageContext?: StorageContext;
}
/**
* A SummaryIndex keeps nodes in a sequential order for use with summarization.
*/
export class SummaryIndex extends BaseIndex<IndexList> {
constructor(init: BaseIndexInit<IndexList>) {
super(init);
}
static async init(options: SummaryIndexOptions): Promise<SummaryIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const { docStore, indexStore } = storageContext;
// Setup IndexStruct from storage
let indexStructs = (await indexStore.getIndexStructs()) as IndexList[];
let indexStruct: IndexList | null;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as IndexList;
} else {
indexStruct = null;
}
// check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.LIST) {
throw new Error(
"Attempting to initialize SummaryIndex with non-list indexStruct",
);
}
if (indexStruct) {
if (options.nodes) {
throw new Error(
"Cannot initialize SummaryIndex with both nodes and indexStruct",
);
}
} else {
if (!options.nodes) {
throw new Error(
"Cannot initialize SummaryIndex without nodes or indexStruct",
);
}
indexStruct = await SummaryIndex.buildIndexFromNodes(
options.nodes,
storageContext.docStore,
);
await indexStore.addIndexStruct(indexStruct);
}
return new SummaryIndex({
storageContext,
serviceContext,
docStore,
indexStore,
indexStruct,
});
}
static async fromDocuments(
documents: Document[],
args: {
storageContext?: StorageContext;
serviceContext?: ServiceContext;
} = {},
): Promise<SummaryIndex> {
let { storageContext, serviceContext } = args;
storageContext = storageContext ?? (await storageContextFromDefaults({}));
serviceContext = serviceContext ?? serviceContextFromDefaults({});
const docStore = storageContext.docStore;
docStore.addDocuments(documents, true);
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
const index = await SummaryIndex.init({
nodes,
storageContext,
serviceContext,
});
return index;
}
asRetriever(options?: { mode: SummaryRetrieverMode }): BaseRetriever {
const { mode = SummaryRetrieverMode.DEFAULT } = options ?? {};
switch (mode) {
case SummaryRetrieverMode.DEFAULT:
return new SummaryIndexRetriever(this);
case SummaryRetrieverMode.LLM:
return new SummaryIndexLLMRetriever(this);
default:
throw new Error(`Unknown retriever mode: ${mode}`);
}
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: unknown;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine {
let { retriever, responseSynthesizer } = options ?? {};
if (!retriever) {
retriever = this.asRetriever();
}
if (!responseSynthesizer) {
let responseBuilder = new CompactAndRefine(this.serviceContext);
responseSynthesizer = new ResponseSynthesizer({
serviceContext: this.serviceContext,
responseBuilder,
});
}
return new RetrieverQueryEngine(
retriever,
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
static async buildIndexFromNodes(
nodes: BaseNode[],
docStore: BaseDocumentStore,
indexStruct?: IndexList,
): Promise<IndexList> {
indexStruct = indexStruct || new IndexList();
await docStore.addDocuments(nodes, true);
for (const node of nodes) {
indexStruct.addNode(node);
}
return indexStruct;
}
async insertNodes(nodes: BaseNode[]): Promise<void> {
for (const node of nodes) {
this.indexStruct.addNode(node);
}
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore?: boolean,
): Promise<void> {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (!refDocInfo) {
return;
}
await this.deleteNodes(refDocInfo.nodeIds, false);
if (deleteFromDocStore) {
await this.docStore.deleteRefDoc(refDocId, false);
}
return;
}
async deleteNodes(nodeIds: string[], deleteFromDocStore: boolean) {
this.indexStruct.nodes = this.indexStruct.nodes.filter(
(existingNodeId: string) => !nodeIds.includes(existingNodeId),
);
if (deleteFromDocStore) {
for (const nodeId of nodeIds) {
await this.docStore.deleteDocument(nodeId, false);
}
}
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
}
async getRefDocInfo(): Promise<Record<string, RefDocInfo>> {
const nodeDocIds = this.indexStruct.nodes;
const nodes = await this.docStore.getNodes(nodeDocIds);
const refDocInfoMap: Record<string, RefDocInfo> = {};
for (const node of nodes) {
const refNode = node.sourceNode;
if (_.isNil(refNode)) {
continue;
}
const refDocInfo = await this.docStore.getRefDocInfo(refNode.nodeId);
if (_.isNil(refDocInfo)) {
continue;
}
refDocInfoMap[refNode.nodeId] = refDocInfo;
}
return refDocInfoMap;
}
}
// Legacy
export type ListIndex = SummaryIndex;
export type ListRetrieverMode = SummaryRetrieverMode;
@@ -1,137 +0,0 @@
import _ from "lodash";
import { globalsHelper } from "../../GlobalsHelper";
import { NodeWithScore } from "../../Node";
import { ChoiceSelectPrompt, defaultChoiceSelectPrompt } from "../../Prompt";
import { BaseRetriever } from "../../Retriever";
import { ServiceContext } from "../../ServiceContext";
import { Event } from "../../callbacks/CallbackManager";
import { SummaryIndex } from "./SummaryIndex";
import {
ChoiceSelectParserFunction,
NodeFormatterFunction,
defaultFormatNodeBatchFn,
defaultParseChoiceSelectAnswerFn,
} from "./utils";
/**
* Simple retriever for SummaryIndex that returns all nodes
*/
export class SummaryIndexRetriever implements BaseRetriever {
index: SummaryIndex;
constructor(index: SummaryIndex) {
this.index = index;
}
async retrieve(query: string, parentEvent?: Event): Promise<NodeWithScore[]> {
const nodeIds = this.index.indexStruct.nodes;
const nodes = await this.index.docStore.getNodes(nodeIds);
const result = nodes.map((node) => ({
node: node,
score: 1,
}));
if (this.index.serviceContext.callbackManager.onRetrieve) {
this.index.serviceContext.callbackManager.onRetrieve({
query,
nodes: result,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
return result;
}
getServiceContext(): ServiceContext {
return this.index.serviceContext;
}
}
/**
* LLM retriever for SummaryIndex which lets you select the most relevant chunks.
*/
export class SummaryIndexLLMRetriever implements BaseRetriever {
index: SummaryIndex;
choiceSelectPrompt: ChoiceSelectPrompt;
choiceBatchSize: number;
formatNodeBatchFn: NodeFormatterFunction;
parseChoiceSelectAnswerFn: ChoiceSelectParserFunction;
serviceContext: ServiceContext;
// eslint-disable-next-line max-params
constructor(
index: SummaryIndex,
choiceSelectPrompt?: ChoiceSelectPrompt,
choiceBatchSize: number = 10,
formatNodeBatchFn?: NodeFormatterFunction,
parseChoiceSelectAnswerFn?: ChoiceSelectParserFunction,
serviceContext?: ServiceContext,
) {
this.index = index;
this.choiceSelectPrompt = choiceSelectPrompt || defaultChoiceSelectPrompt;
this.choiceBatchSize = choiceBatchSize;
this.formatNodeBatchFn = formatNodeBatchFn || defaultFormatNodeBatchFn;
this.parseChoiceSelectAnswerFn =
parseChoiceSelectAnswerFn || defaultParseChoiceSelectAnswerFn;
this.serviceContext = serviceContext || index.serviceContext;
}
async retrieve(query: string, parentEvent?: Event): Promise<NodeWithScore[]> {
const nodeIds = this.index.indexStruct.nodes;
const results: NodeWithScore[] = [];
for (let idx = 0; idx < nodeIds.length; idx += this.choiceBatchSize) {
const nodeIdsBatch = nodeIds.slice(idx, idx + this.choiceBatchSize);
const nodesBatch = await this.index.docStore.getNodes(nodeIdsBatch);
const fmtBatchStr = this.formatNodeBatchFn(nodesBatch);
const input = { context: fmtBatchStr, query: query };
const rawResponse = (
await this.serviceContext.llm.complete({
prompt: this.choiceSelectPrompt(input),
})
).text;
// parseResult is a map from doc number to relevance score
const parseResult = this.parseChoiceSelectAnswerFn(
rawResponse,
nodesBatch.length,
);
const choiceNodeIds = nodeIdsBatch.filter((nodeId, idx) => {
return `${idx}` in parseResult;
});
const choiceNodes = await this.index.docStore.getNodes(choiceNodeIds);
const nodeWithScores = choiceNodes.map((node, i) => ({
node: node,
score: _.get(parseResult, `${i + 1}`, 1),
}));
results.push(...nodeWithScores);
}
if (this.serviceContext.callbackManager.onRetrieve) {
this.serviceContext.callbackManager.onRetrieve({
query,
nodes: results,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
return results;
}
getServiceContext(): ServiceContext {
return this.serviceContext;
}
}
// Legacy
export type ListIndexRetriever = SummaryIndexRetriever;
export type ListIndexLLMRetriever = SummaryIndexLLMRetriever;
+392 -10
View File
@@ -1,10 +1,392 @@
export { SummaryIndex, SummaryRetrieverMode } from "./SummaryIndex";
export type { ListIndex, ListRetrieverMode } from "./SummaryIndex";
export {
SummaryIndexLLMRetriever,
SummaryIndexRetriever,
} from "./SummaryIndexRetriever";
export type {
ListIndexLLMRetriever,
ListIndexRetriever,
} from "./SummaryIndexRetriever";
import _ from "lodash";
import { globalsHelper } from "../../GlobalsHelper.js";
import { BaseNode, Document, NodeWithScore } from "../../Node.js";
import { ChoiceSelectPrompt, defaultChoiceSelectPrompt } from "../../Prompt.js";
import { BaseRetriever } from "../../Retriever.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { RetrieverQueryEngine } from "../../engines/query/index.js";
import { BaseNodePostprocessor } from "../../postprocessors/index.js";
import {
BaseDocumentStore,
RefDocInfo,
StorageContext,
storageContextFromDefaults,
} from "../../storage/index.js";
import {
BaseSynthesizer,
CompactAndRefine,
ResponseSynthesizer,
} from "../../synthesizers/index.js";
import { BaseQueryEngine } from "../../types.js";
import { BaseIndex, BaseIndexInit } from "../BaseIndex.js";
import { IndexList, IndexStructType } from "../json-to-index-struct.js";
import {
ChoiceSelectParserFunction,
NodeFormatterFunction,
defaultFormatNodeBatchFn,
defaultParseChoiceSelectAnswerFn,
} from "./utils.js";
export enum SummaryRetrieverMode {
DEFAULT = "default",
// EMBEDDING = "embedding",
LLM = "llm",
}
export interface SummaryIndexOptions {
nodes?: BaseNode[];
indexStruct?: IndexList;
indexId?: string;
serviceContext?: ServiceContext;
storageContext?: StorageContext;
}
/**
* A SummaryIndex keeps nodes in a sequential order for use with summarization.
*/
export class SummaryIndex extends BaseIndex<IndexList> {
constructor(init: BaseIndexInit<IndexList>) {
super(init);
}
static async init(options: SummaryIndexOptions): Promise<SummaryIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const { docStore, indexStore } = storageContext;
// Setup IndexStruct from storage
const indexStructs = (await indexStore.getIndexStructs()) as IndexList[];
let indexStruct: IndexList | null;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as IndexList;
} else {
indexStruct = null;
}
// check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.LIST) {
throw new Error(
"Attempting to initialize SummaryIndex with non-list indexStruct",
);
}
if (indexStruct) {
if (options.nodes) {
throw new Error(
"Cannot initialize SummaryIndex with both nodes and indexStruct",
);
}
} else {
if (!options.nodes) {
throw new Error(
"Cannot initialize SummaryIndex without nodes or indexStruct",
);
}
indexStruct = await SummaryIndex.buildIndexFromNodes(
options.nodes,
storageContext.docStore,
);
await indexStore.addIndexStruct(indexStruct);
}
return new SummaryIndex({
storageContext,
serviceContext,
docStore,
indexStore,
indexStruct,
});
}
static async fromDocuments(
documents: Document[],
args: {
storageContext?: StorageContext;
serviceContext?: ServiceContext;
} = {},
): Promise<SummaryIndex> {
let { storageContext, serviceContext } = args;
storageContext = storageContext ?? (await storageContextFromDefaults({}));
serviceContext = serviceContext ?? serviceContextFromDefaults({});
const docStore = storageContext.docStore;
docStore.addDocuments(documents, true);
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
const nodes = serviceContext.nodeParser.getNodesFromDocuments(documents);
const index = await SummaryIndex.init({
nodes,
storageContext,
serviceContext,
});
return index;
}
asRetriever(options?: { mode: SummaryRetrieverMode }): BaseRetriever {
const { mode = SummaryRetrieverMode.DEFAULT } = options ?? {};
switch (mode) {
case SummaryRetrieverMode.DEFAULT:
return new SummaryIndexRetriever(this);
case SummaryRetrieverMode.LLM:
return new SummaryIndexLLMRetriever(this);
default:
throw new Error(`Unknown retriever mode: ${mode}`);
}
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: unknown;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine {
let { retriever, responseSynthesizer } = options ?? {};
if (!retriever) {
retriever = this.asRetriever();
}
if (!responseSynthesizer) {
const responseBuilder = new CompactAndRefine(this.serviceContext);
responseSynthesizer = new ResponseSynthesizer({
serviceContext: this.serviceContext,
responseBuilder,
});
}
return new RetrieverQueryEngine(
retriever,
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
static async buildIndexFromNodes(
nodes: BaseNode[],
docStore: BaseDocumentStore,
indexStruct?: IndexList,
): Promise<IndexList> {
indexStruct = indexStruct || new IndexList();
await docStore.addDocuments(nodes, true);
for (const node of nodes) {
indexStruct.addNode(node);
}
return indexStruct;
}
async insertNodes(nodes: BaseNode[]): Promise<void> {
for (const node of nodes) {
this.indexStruct.addNode(node);
}
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore?: boolean,
): Promise<void> {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (!refDocInfo) {
return;
}
await this.deleteNodes(refDocInfo.nodeIds, false);
if (deleteFromDocStore) {
await this.docStore.deleteRefDoc(refDocId, false);
}
return;
}
async deleteNodes(nodeIds: string[], deleteFromDocStore: boolean) {
this.indexStruct.nodes = this.indexStruct.nodes.filter(
(existingNodeId: string) => !nodeIds.includes(existingNodeId),
);
if (deleteFromDocStore) {
for (const nodeId of nodeIds) {
await this.docStore.deleteDocument(nodeId, false);
}
}
await this.storageContext.indexStore.addIndexStruct(this.indexStruct);
}
async getRefDocInfo(): Promise<Record<string, RefDocInfo>> {
const nodeDocIds = this.indexStruct.nodes;
const nodes = await this.docStore.getNodes(nodeDocIds);
const refDocInfoMap: Record<string, RefDocInfo> = {};
for (const node of nodes) {
const refNode = node.sourceNode;
if (_.isNil(refNode)) {
continue;
}
const refDocInfo = await this.docStore.getRefDocInfo(refNode.nodeId);
if (_.isNil(refDocInfo)) {
continue;
}
refDocInfoMap[refNode.nodeId] = refDocInfo;
}
return refDocInfoMap;
}
}
// Legacy
export type ListIndex = SummaryIndex;
export type ListRetrieverMode = SummaryRetrieverMode;
/**
* Simple retriever for SummaryIndex that returns all nodes
*/
export class SummaryIndexRetriever implements BaseRetriever {
index: SummaryIndex;
constructor(index: SummaryIndex) {
this.index = index;
}
async retrieve(query: string, parentEvent?: Event): Promise<NodeWithScore[]> {
const nodeIds = this.index.indexStruct.nodes;
const nodes = await this.index.docStore.getNodes(nodeIds);
const result = nodes.map((node) => ({
node: node,
score: 1,
}));
if (this.index.serviceContext.callbackManager.onRetrieve) {
this.index.serviceContext.callbackManager.onRetrieve({
query,
nodes: result,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
return result;
}
getServiceContext(): ServiceContext {
return this.index.serviceContext;
}
}
/**
* LLM retriever for SummaryIndex which lets you select the most relevant chunks.
*/
export class SummaryIndexLLMRetriever implements BaseRetriever {
index: SummaryIndex;
choiceSelectPrompt: ChoiceSelectPrompt;
choiceBatchSize: number;
formatNodeBatchFn: NodeFormatterFunction;
parseChoiceSelectAnswerFn: ChoiceSelectParserFunction;
serviceContext: ServiceContext;
// eslint-disable-next-line max-params
constructor(
index: SummaryIndex,
choiceSelectPrompt?: ChoiceSelectPrompt,
choiceBatchSize: number = 10,
formatNodeBatchFn?: NodeFormatterFunction,
parseChoiceSelectAnswerFn?: ChoiceSelectParserFunction,
serviceContext?: ServiceContext,
) {
this.index = index;
this.choiceSelectPrompt = choiceSelectPrompt || defaultChoiceSelectPrompt;
this.choiceBatchSize = choiceBatchSize;
this.formatNodeBatchFn = formatNodeBatchFn || defaultFormatNodeBatchFn;
this.parseChoiceSelectAnswerFn =
parseChoiceSelectAnswerFn || defaultParseChoiceSelectAnswerFn;
this.serviceContext = serviceContext || index.serviceContext;
}
async retrieve(query: string, parentEvent?: Event): Promise<NodeWithScore[]> {
const nodeIds = this.index.indexStruct.nodes;
const results: NodeWithScore[] = [];
for (let idx = 0; idx < nodeIds.length; idx += this.choiceBatchSize) {
const nodeIdsBatch = nodeIds.slice(idx, idx + this.choiceBatchSize);
const nodesBatch = await this.index.docStore.getNodes(nodeIdsBatch);
const fmtBatchStr = this.formatNodeBatchFn(nodesBatch);
const input = { context: fmtBatchStr, query: query };
const rawResponse = (
await this.serviceContext.llm.complete({
prompt: this.choiceSelectPrompt(input),
})
).text;
// parseResult is a map from doc number to relevance score
const parseResult = this.parseChoiceSelectAnswerFn(
rawResponse,
nodesBatch.length,
);
const choiceNodeIds = nodeIdsBatch.filter((nodeId, idx) => {
return `${idx}` in parseResult;
});
const choiceNodes = await this.index.docStore.getNodes(choiceNodeIds);
const nodeWithScores = choiceNodes.map((node, i) => ({
node: node,
score: _.get(parseResult, `${i + 1}`, 1),
}));
results.push(...nodeWithScores);
}
if (this.serviceContext.callbackManager.onRetrieve) {
this.serviceContext.callbackManager.onRetrieve({
query,
nodes: results,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
return results;
}
getServiceContext(): ServiceContext {
return this.serviceContext;
}
}
// Legacy
export type ListIndexRetriever = SummaryIndexRetriever;
export type ListIndexLLMRetriever = SummaryIndexLLMRetriever;
+4 -4
View File
@@ -1,5 +1,5 @@
import _ from "lodash";
import { BaseNode, MetadataMode } from "../../Node";
import { BaseNode, MetadataMode } from "../../Node.js";
export type NodeFormatterFunction = (summaryNodes: BaseNode[]) => string;
export const defaultFormatNodeBatchFn: NodeFormatterFunction = (
@@ -32,7 +32,7 @@ export const defaultParseChoiceSelectAnswerFn: ChoiceSelectParserFunction = (
const lineTokens: string[][] = answer
.split("\n")
.map((line: string) => {
let lineTokens = line.split(",");
const lineTokens = line.split(",");
if (lineTokens.length !== 2) {
if (raiseErr) {
throw new Error(
@@ -50,8 +50,8 @@ export const defaultParseChoiceSelectAnswerFn: ChoiceSelectParserFunction = (
return lineTokens.reduce(
(parseResult: ChoiceSelectParseResult, lineToken: string[]) => {
try {
let docNum = parseInt(lineToken[0].split(":")[1].trim());
let answerRelevance = parseFloat(lineToken[1].split(":")[1].trim());
const docNum = parseInt(lineToken[0].split(":")[1].trim());
const answerRelevance = parseFloat(lineToken[1].split(":")[1].trim());
if (docNum < 1 || docNum > numChoices) {
if (raiseErr) {
throw new Error(
@@ -1,149 +0,0 @@
import { globalsHelper } from "../../GlobalsHelper";
import { ImageNode, Metadata, NodeWithScore } from "../../Node";
import { BaseRetriever } from "../../Retriever";
import { ServiceContext } from "../../ServiceContext";
import { Event } from "../../callbacks/CallbackManager";
import { DEFAULT_SIMILARITY_TOP_K } from "../../constants";
import { BaseEmbedding } from "../../embeddings";
import {
MetadataFilters,
VectorStoreQuery,
VectorStoreQueryMode,
VectorStoreQueryResult,
} from "../../storage/vectorStore/types";
import { VectorStoreIndex } from "./VectorStoreIndex";
/**
* VectorIndexRetriever retrieves nodes from a VectorIndex.
*/
export type VectorIndexRetrieverOptions = {
index: VectorStoreIndex;
similarityTopK?: number;
imageSimilarityTopK?: number;
};
export class VectorIndexRetriever implements BaseRetriever {
index: VectorStoreIndex;
similarityTopK: number;
imageSimilarityTopK: number;
private serviceContext: ServiceContext;
constructor({
index,
similarityTopK,
imageSimilarityTopK,
}: VectorIndexRetrieverOptions) {
this.index = index;
this.serviceContext = this.index.serviceContext;
this.similarityTopK = similarityTopK ?? DEFAULT_SIMILARITY_TOP_K;
this.imageSimilarityTopK = imageSimilarityTopK ?? DEFAULT_SIMILARITY_TOP_K;
}
async retrieve(
query: string,
parentEvent?: Event,
preFilters?: MetadataFilters,
): Promise<NodeWithScore[]> {
let nodesWithScores = await this.textRetrieve(query, preFilters);
nodesWithScores = nodesWithScores.concat(
await this.textToImageRetrieve(query, preFilters),
);
this.sendEvent(query, nodesWithScores, parentEvent);
return nodesWithScores;
}
protected async textRetrieve(
query: string,
preFilters?: MetadataFilters,
): Promise<NodeWithScore[]> {
const options = {};
const q = await this.buildVectorStoreQuery(
this.index.embedModel,
query,
this.similarityTopK,
preFilters,
);
const result = await this.index.vectorStore.query(q, options);
return this.buildNodeListFromQueryResult(result);
}
private async textToImageRetrieve(
query: string,
preFilters?: MetadataFilters,
) {
if (!this.index.imageEmbedModel || !this.index.imageVectorStore) {
// no-op if image embedding and vector store are not set
return [];
}
const q = await this.buildVectorStoreQuery(
this.index.imageEmbedModel,
query,
this.imageSimilarityTopK,
preFilters,
);
const result = await this.index.imageVectorStore.query(q, preFilters);
return this.buildNodeListFromQueryResult(result);
}
protected sendEvent(
query: string,
nodesWithScores: NodeWithScore<Metadata>[],
parentEvent: Event | undefined,
) {
if (this.serviceContext.callbackManager.onRetrieve) {
this.serviceContext.callbackManager.onRetrieve({
query,
nodes: nodesWithScores,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
}
protected async buildVectorStoreQuery(
embedModel: BaseEmbedding,
query: string,
similarityTopK: number,
preFilters?: MetadataFilters,
): Promise<VectorStoreQuery> {
const queryEmbedding = await embedModel.getQueryEmbedding(query);
return {
queryEmbedding: queryEmbedding,
mode: VectorStoreQueryMode.DEFAULT,
similarityTopK: similarityTopK,
filters: preFilters ?? undefined,
};
}
protected buildNodeListFromQueryResult(result: VectorStoreQueryResult) {
let nodesWithScores: NodeWithScore[] = [];
for (let i = 0; i < result.ids.length; i++) {
const nodeFromResult = result.nodes?.[i];
if (!this.index.indexStruct.nodesDict[result.ids[i]] && nodeFromResult) {
this.index.indexStruct.nodesDict[result.ids[i]] = nodeFromResult;
}
const node = this.index.indexStruct.nodesDict[result.ids[i]];
// XXX: Hack, if it's an image node, we reconstruct the image from the URL
// Alternative: Store image in doc store and retrieve it here
if (node instanceof ImageNode) {
node.image = node.getUrl();
}
nodesWithScores.push({
node: node,
score: result.similarities[i],
});
}
return nodesWithScores;
}
getServiceContext(): ServiceContext {
return this.serviceContext;
}
}
@@ -1,398 +0,0 @@
import {
BaseNode,
Document,
ImageNode,
MetadataMode,
ObjectType,
splitNodesByType,
} from "../../Node";
import { BaseRetriever } from "../../Retriever";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext";
import {
BaseEmbedding,
ClipEmbedding,
MultiModalEmbedding,
} from "../../embeddings";
import { RetrieverQueryEngine } from "../../engines/query";
import { runTransformations } from "../../ingestion";
import { BaseNodePostprocessor } from "../../postprocessors";
import {
BaseIndexStore,
MetadataFilters,
StorageContext,
VectorStore,
storageContextFromDefaults,
} from "../../storage";
import { BaseSynthesizer } from "../../synthesizers";
import { BaseQueryEngine } from "../../types";
import {
BaseIndex,
BaseIndexInit,
IndexDict,
IndexStructType,
} from "../BaseIndex";
import {
VectorIndexRetriever,
VectorIndexRetrieverOptions,
} from "./VectorIndexRetriever";
interface IndexStructOptions {
indexStruct?: IndexDict;
indexId?: string;
}
export interface VectorIndexOptions extends IndexStructOptions {
nodes?: BaseNode[];
serviceContext?: ServiceContext;
storageContext?: StorageContext;
imageVectorStore?: VectorStore;
vectorStore?: VectorStore;
logProgress?: boolean;
}
export interface VectorIndexConstructorProps extends BaseIndexInit<IndexDict> {
indexStore: BaseIndexStore;
imageVectorStore?: VectorStore;
}
/**
* The VectorStoreIndex, an index that stores the nodes only according to their vector embedings.
*/
export class VectorStoreIndex extends BaseIndex<IndexDict> {
vectorStore: VectorStore;
indexStore: BaseIndexStore;
embedModel: BaseEmbedding;
imageVectorStore?: VectorStore;
imageEmbedModel?: MultiModalEmbedding;
private constructor(init: VectorIndexConstructorProps) {
super(init);
this.indexStore = init.indexStore;
this.vectorStore = init.vectorStore ?? init.storageContext.vectorStore;
this.embedModel = init.serviceContext.embedModel;
this.imageVectorStore =
init.imageVectorStore ?? init.storageContext.imageVectorStore;
if (this.imageVectorStore) {
this.imageEmbedModel = new ClipEmbedding();
}
}
/**
* The async init function creates a new VectorStoreIndex.
* @param options
* @returns
*/
public static async init(
options: VectorIndexOptions,
): Promise<VectorStoreIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const indexStore = storageContext.indexStore;
const docStore = storageContext.docStore;
let indexStruct = await VectorStoreIndex.setupIndexStructFromStorage(
indexStore,
options,
);
if (!options.nodes && !indexStruct) {
throw new Error(
"Cannot initialize VectorStoreIndex without nodes or indexStruct",
);
}
indexStruct = indexStruct ?? new IndexDict();
const index = new this({
storageContext,
serviceContext,
docStore,
indexStruct,
indexStore,
vectorStore: options.vectorStore,
imageVectorStore: options.imageVectorStore,
});
if (options.nodes) {
// If nodes are passed in, then we need to update the index
await index.buildIndexFromNodes(options.nodes, {
logProgress: options.logProgress,
});
}
return index;
}
private static async setupIndexStructFromStorage(
indexStore: BaseIndexStore,
options: IndexStructOptions,
) {
let indexStructs = (await indexStore.getIndexStructs()) as IndexDict[];
let indexStruct: IndexDict | undefined;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as IndexDict;
}
// Check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.SIMPLE_DICT) {
throw new Error(
"Attempting to initialize VectorStoreIndex with non-vector indexStruct",
);
}
return indexStruct;
}
/**
* Calculates the embeddings for the given nodes.
*
* @param nodes - An array of BaseNode objects representing the nodes for which embeddings are to be calculated.
* @param {Object} [options] - An optional object containing additional parameters.
* @param {boolean} [options.logProgress] - A boolean indicating whether to log progress to the console (useful for debugging).
*/
async getNodeEmbeddingResults(
nodes: BaseNode[],
options?: { logProgress?: boolean },
): Promise<BaseNode[]> {
const texts = nodes.map((node) => node.getContent(MetadataMode.EMBED));
const embeddings = await this.embedModel.getTextEmbeddingsBatch(texts, {
logProgress: options?.logProgress,
});
return nodes.map((node, i) => {
node.embedding = embeddings[i];
return node;
});
}
/**
* Get embeddings for nodes and place them into the index.
* @param nodes
* @returns
*/
async buildIndexFromNodes(
nodes: BaseNode[],
options?: { logProgress?: boolean },
) {
// Check if the index already has nodes with the same hash
const newNodes = nodes.filter((node) =>
Object.entries(this.indexStruct!.nodesDict).reduce(
(acc, [key, value]) => {
if (value.hash === node.hash) {
acc = false;
}
return acc;
},
true,
),
);
await this.insertNodes(newNodes, options);
}
/**
* High level API: split documents, get embeddings, and build index.
* @param documents
* @param args
* @returns
*/
static async fromDocuments(
documents: Document[],
args: VectorIndexOptions = {},
): Promise<VectorStoreIndex> {
args.storageContext =
args.storageContext ?? (await storageContextFromDefaults({}));
args.serviceContext = args.serviceContext ?? serviceContextFromDefaults({});
const docStore = args.storageContext.docStore;
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
if (args.logProgress) {
console.log("Using node parser on documents...");
}
args.nodes = await runTransformations(documents, [
args.serviceContext.nodeParser,
]);
if (args.logProgress) {
console.log("Finished parsing documents.");
}
return await this.init(args);
}
static async fromVectorStore(
vectorStore: VectorStore,
serviceContext: ServiceContext,
imageVectorStore?: VectorStore,
) {
if (!vectorStore.storesText) {
throw new Error(
"Cannot initialize from a vector store that does not store text",
);
}
const storageContext = await storageContextFromDefaults({
vectorStore,
imageVectorStore,
});
const index = await this.init({
nodes: [],
storageContext,
serviceContext,
});
return index;
}
asRetriever(
options?: Omit<VectorIndexRetrieverOptions, "index">,
): VectorIndexRetriever {
return new VectorIndexRetriever({ index: this, ...options });
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: MetadataFilters;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine & RetrieverQueryEngine {
const { retriever, responseSynthesizer } = options ?? {};
return new RetrieverQueryEngine(
retriever ?? this.asRetriever(),
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
protected async insertNodesToStore(
vectorStore: VectorStore,
nodes: BaseNode[],
): Promise<void> {
const newIds = await vectorStore.add(nodes);
// NOTE: if the vector store doesn't store text,
// we need to add the nodes to the index struct and document store
// NOTE: if the vector store keeps text,
// we only need to add image and index nodes
for (let i = 0; i < nodes.length; ++i) {
const type = nodes[i].getType();
if (
!vectorStore.storesText ||
type === ObjectType.INDEX ||
type === ObjectType.IMAGE
) {
const nodeWithoutEmbedding = nodes[i].clone();
nodeWithoutEmbedding.embedding = undefined;
this.indexStruct.addNode(nodeWithoutEmbedding, newIds[i]);
await this.docStore.addDocuments([nodeWithoutEmbedding], true);
}
}
}
async insertNodes(
nodes: BaseNode[],
options?: { logProgress?: boolean },
): Promise<void> {
if (!nodes || nodes.length === 0) {
return;
}
const { imageNodes, textNodes } = splitNodesByType(nodes);
if (imageNodes.length > 0) {
if (!this.imageVectorStore) {
throw new Error("Cannot insert image nodes without image vector store");
}
const imageNodesWithEmbedding = await this.getImageNodeEmbeddingResults(
imageNodes,
options,
);
await this.insertNodesToStore(
this.imageVectorStore,
imageNodesWithEmbedding,
);
}
const embeddingResults = await this.getNodeEmbeddingResults(
textNodes,
options,
);
await this.insertNodesToStore(this.vectorStore, embeddingResults);
await this.indexStore.addIndexStruct(this.indexStruct);
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore: boolean = true,
): Promise<void> {
await this.deleteRefDocFromStore(this.vectorStore, refDocId);
if (this.imageVectorStore) {
await this.deleteRefDocFromStore(this.imageVectorStore, refDocId);
}
if (deleteFromDocStore) {
await this.docStore.deleteDocument(refDocId, false);
}
}
protected async deleteRefDocFromStore(
vectorStore: VectorStore,
refDocId: string,
): Promise<void> {
vectorStore.delete(refDocId);
if (!vectorStore.storesText) {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (refDocInfo) {
for (const nodeId of refDocInfo.nodeIds) {
this.indexStruct.delete(nodeId);
vectorStore.delete(nodeId);
}
}
await this.indexStore.addIndexStruct(this.indexStruct);
}
}
/**
* Calculates the embeddings for the given image nodes.
*
* @param nodes - An array of ImageNode objects representing the nodes for which embeddings are to be calculated.
* @param {Object} [options] - An optional object containing additional parameters.
* @param {boolean} [options.logProgress] - A boolean indicating whether to log progress to the console (useful for debugging).
*/
async getImageNodeEmbeddingResults(
nodes: ImageNode[],
options?: { logProgress?: boolean },
): Promise<ImageNode[]> {
if (!this.imageEmbedModel) {
return [];
}
const nodesWithEmbeddings: ImageNode[] = [];
for (let i = 0; i < nodes.length; ++i) {
const node = nodes[i];
if (options?.logProgress) {
console.log(`Getting embedding for node ${i + 1}/${nodes.length}`);
}
node.embedding = await this.imageEmbedModel.getImageEmbedding(node.image);
nodesWithEmbeddings.push(node);
}
return nodesWithEmbeddings;
}
}
+533 -2
View File
@@ -1,2 +1,533 @@
export { VectorIndexRetriever } from "./VectorIndexRetriever";
export { VectorStoreIndex } from "./VectorStoreIndex";
import { globalsHelper } from "../../GlobalsHelper.js";
import {
BaseNode,
Document,
ImageNode,
Metadata,
MetadataMode,
NodeWithScore,
ObjectType,
splitNodesByType,
} from "../../Node.js";
import { BaseRetriever } from "../../Retriever.js";
import {
ServiceContext,
serviceContextFromDefaults,
} from "../../ServiceContext.js";
import { Event } from "../../callbacks/CallbackManager.js";
import { DEFAULT_SIMILARITY_TOP_K } from "../../constants.js";
import {
BaseEmbedding,
ClipEmbedding,
MultiModalEmbedding,
} from "../../embeddings/index.js";
import { RetrieverQueryEngine } from "../../engines/query/RetrieverQueryEngine.js";
import { runTransformations } from "../../ingestion/index.js";
import { BaseNodePostprocessor } from "../../postprocessors/types.js";
import {
BaseIndexStore,
MetadataFilters,
StorageContext,
VectorStore,
VectorStoreQuery,
VectorStoreQueryMode,
VectorStoreQueryResult,
storageContextFromDefaults,
} from "../../storage/index.js";
import { BaseSynthesizer } from "../../synthesizers/types.js";
import { BaseQueryEngine } from "../../types.js";
import { BaseIndex, BaseIndexInit } from "../BaseIndex.js";
import { IndexDict, IndexStructType } from "../json-to-index-struct.js";
interface IndexStructOptions {
indexStruct?: IndexDict;
indexId?: string;
}
export interface VectorIndexOptions extends IndexStructOptions {
nodes?: BaseNode[];
serviceContext?: ServiceContext;
storageContext?: StorageContext;
imageVectorStore?: VectorStore;
vectorStore?: VectorStore;
logProgress?: boolean;
}
export interface VectorIndexConstructorProps extends BaseIndexInit<IndexDict> {
indexStore: BaseIndexStore;
imageVectorStore?: VectorStore;
}
/**
* The VectorStoreIndex, an index that stores the nodes only according to their vector embedings.
*/
export class VectorStoreIndex extends BaseIndex<IndexDict> {
vectorStore: VectorStore;
indexStore: BaseIndexStore;
embedModel: BaseEmbedding;
imageVectorStore?: VectorStore;
imageEmbedModel?: MultiModalEmbedding;
private constructor(init: VectorIndexConstructorProps) {
super(init);
this.indexStore = init.indexStore;
this.vectorStore = init.vectorStore ?? init.storageContext.vectorStore;
this.embedModel = init.serviceContext.embedModel;
this.imageVectorStore =
init.imageVectorStore ?? init.storageContext.imageVectorStore;
if (this.imageVectorStore) {
this.imageEmbedModel = new ClipEmbedding();
}
}
/**
* The async init function creates a new VectorStoreIndex.
* @param options
* @returns
*/
public static async init(
options: VectorIndexOptions,
): Promise<VectorStoreIndex> {
const storageContext =
options.storageContext ?? (await storageContextFromDefaults({}));
const serviceContext =
options.serviceContext ?? serviceContextFromDefaults({});
const indexStore = storageContext.indexStore;
const docStore = storageContext.docStore;
let indexStruct = await VectorStoreIndex.setupIndexStructFromStorage(
indexStore,
options,
);
if (!options.nodes && !indexStruct) {
throw new Error(
"Cannot initialize VectorStoreIndex without nodes or indexStruct",
);
}
indexStruct = indexStruct ?? new IndexDict();
const index = new this({
storageContext,
serviceContext,
docStore,
indexStruct,
indexStore,
vectorStore: options.vectorStore,
imageVectorStore: options.imageVectorStore,
});
if (options.nodes) {
// If nodes are passed in, then we need to update the index
await index.buildIndexFromNodes(options.nodes, {
logProgress: options.logProgress,
});
}
return index;
}
private static async setupIndexStructFromStorage(
indexStore: BaseIndexStore,
options: IndexStructOptions,
) {
const indexStructs = (await indexStore.getIndexStructs()) as IndexDict[];
let indexStruct: IndexDict | undefined;
if (options.indexStruct && indexStructs.length > 0) {
throw new Error(
"Cannot initialize index with both indexStruct and indexStore",
);
}
if (options.indexStruct) {
indexStruct = options.indexStruct;
} else if (indexStructs.length == 1) {
indexStruct = indexStructs[0];
} else if (indexStructs.length > 1 && options.indexId) {
indexStruct = (await indexStore.getIndexStruct(
options.indexId,
)) as IndexDict;
}
// Check indexStruct type
if (indexStruct && indexStruct.type !== IndexStructType.SIMPLE_DICT) {
throw new Error(
"Attempting to initialize VectorStoreIndex with non-vector indexStruct",
);
}
return indexStruct;
}
/**
* Calculates the embeddings for the given nodes.
*
* @param nodes - An array of BaseNode objects representing the nodes for which embeddings are to be calculated.
* @param {Object} [options] - An optional object containing additional parameters.
* @param {boolean} [options.logProgress] - A boolean indicating whether to log progress to the console (useful for debugging).
*/
async getNodeEmbeddingResults(
nodes: BaseNode[],
options?: { logProgress?: boolean },
): Promise<BaseNode[]> {
const texts = nodes.map((node) => node.getContent(MetadataMode.EMBED));
const embeddings = await this.embedModel.getTextEmbeddingsBatch(texts, {
logProgress: options?.logProgress,
});
return nodes.map((node, i) => {
node.embedding = embeddings[i];
return node;
});
}
/**
* Get embeddings for nodes and place them into the index.
* @param nodes
* @returns
*/
async buildIndexFromNodes(
nodes: BaseNode[],
options?: { logProgress?: boolean },
) {
// Check if the index already has nodes with the same hash
const newNodes = nodes.filter((node) =>
Object.entries(this.indexStruct!.nodesDict).reduce(
(acc, [key, value]) => {
if (value.hash === node.hash) {
acc = false;
}
return acc;
},
true,
),
);
await this.insertNodes(newNodes, options);
}
/**
* High level API: split documents, get embeddings, and build index.
* @param documents
* @param args
* @returns
*/
static async fromDocuments(
documents: Document[],
args: VectorIndexOptions = {},
): Promise<VectorStoreIndex> {
args.storageContext =
args.storageContext ?? (await storageContextFromDefaults({}));
args.serviceContext = args.serviceContext ?? serviceContextFromDefaults({});
const docStore = args.storageContext.docStore;
for (const doc of documents) {
docStore.setDocumentHash(doc.id_, doc.hash);
}
if (args.logProgress) {
console.log("Using node parser on documents...");
}
args.nodes = await runTransformations(documents, [
args.serviceContext.nodeParser,
]);
if (args.logProgress) {
console.log("Finished parsing documents.");
}
return await this.init(args);
}
static async fromVectorStore(
vectorStore: VectorStore,
serviceContext: ServiceContext,
imageVectorStore?: VectorStore,
) {
if (!vectorStore.storesText) {
throw new Error(
"Cannot initialize from a vector store that does not store text",
);
}
const storageContext = await storageContextFromDefaults({
vectorStore,
imageVectorStore,
});
const index = await this.init({
nodes: [],
storageContext,
serviceContext,
});
return index;
}
asRetriever(
options?: Omit<VectorIndexRetrieverOptions, "index">,
): VectorIndexRetriever {
return new VectorIndexRetriever({ index: this, ...options });
}
asQueryEngine(options?: {
retriever?: BaseRetriever;
responseSynthesizer?: BaseSynthesizer;
preFilters?: MetadataFilters;
nodePostprocessors?: BaseNodePostprocessor[];
}): BaseQueryEngine & RetrieverQueryEngine {
const { retriever, responseSynthesizer } = options ?? {};
return new RetrieverQueryEngine(
retriever ?? this.asRetriever(),
responseSynthesizer,
options?.preFilters,
options?.nodePostprocessors,
);
}
protected async insertNodesToStore(
vectorStore: VectorStore,
nodes: BaseNode[],
): Promise<void> {
const newIds = await vectorStore.add(nodes);
// NOTE: if the vector store doesn't store text,
// we need to add the nodes to the index struct and document store
// NOTE: if the vector store keeps text,
// we only need to add image and index nodes
for (let i = 0; i < nodes.length; ++i) {
const type = nodes[i].getType();
if (
!vectorStore.storesText ||
type === ObjectType.INDEX ||
type === ObjectType.IMAGE
) {
const nodeWithoutEmbedding = nodes[i].clone();
nodeWithoutEmbedding.embedding = undefined;
this.indexStruct.addNode(nodeWithoutEmbedding, newIds[i]);
await this.docStore.addDocuments([nodeWithoutEmbedding], true);
}
}
}
async insertNodes(
nodes: BaseNode[],
options?: { logProgress?: boolean },
): Promise<void> {
if (!nodes || nodes.length === 0) {
return;
}
const { imageNodes, textNodes } = splitNodesByType(nodes);
if (imageNodes.length > 0) {
if (!this.imageVectorStore) {
throw new Error("Cannot insert image nodes without image vector store");
}
const imageNodesWithEmbedding = await this.getImageNodeEmbeddingResults(
imageNodes,
options,
);
await this.insertNodesToStore(
this.imageVectorStore,
imageNodesWithEmbedding,
);
}
const embeddingResults = await this.getNodeEmbeddingResults(
textNodes,
options,
);
await this.insertNodesToStore(this.vectorStore, embeddingResults);
await this.indexStore.addIndexStruct(this.indexStruct);
}
async deleteRefDoc(
refDocId: string,
deleteFromDocStore: boolean = true,
): Promise<void> {
await this.deleteRefDocFromStore(this.vectorStore, refDocId);
if (this.imageVectorStore) {
await this.deleteRefDocFromStore(this.imageVectorStore, refDocId);
}
if (deleteFromDocStore) {
await this.docStore.deleteDocument(refDocId, false);
}
}
protected async deleteRefDocFromStore(
vectorStore: VectorStore,
refDocId: string,
): Promise<void> {
vectorStore.delete(refDocId);
if (!vectorStore.storesText) {
const refDocInfo = await this.docStore.getRefDocInfo(refDocId);
if (refDocInfo) {
for (const nodeId of refDocInfo.nodeIds) {
this.indexStruct.delete(nodeId);
vectorStore.delete(nodeId);
}
}
await this.indexStore.addIndexStruct(this.indexStruct);
}
}
/**
* Calculates the embeddings for the given image nodes.
*
* @param nodes - An array of ImageNode objects representing the nodes for which embeddings are to be calculated.
* @param {Object} [options] - An optional object containing additional parameters.
* @param {boolean} [options.logProgress] - A boolean indicating whether to log progress to the console (useful for debugging).
*/
async getImageNodeEmbeddingResults(
nodes: ImageNode[],
options?: { logProgress?: boolean },
): Promise<ImageNode[]> {
if (!this.imageEmbedModel) {
return [];
}
const nodesWithEmbeddings: ImageNode[] = [];
for (let i = 0; i < nodes.length; ++i) {
const node = nodes[i];
if (options?.logProgress) {
console.log(`Getting embedding for node ${i + 1}/${nodes.length}`);
}
node.embedding = await this.imageEmbedModel.getImageEmbedding(node.image);
nodesWithEmbeddings.push(node);
}
return nodesWithEmbeddings;
}
}
/**
* VectorIndexRetriever retrieves nodes from a VectorIndex.
*/
export type VectorIndexRetrieverOptions = {
index: VectorStoreIndex;
similarityTopK?: number;
imageSimilarityTopK?: number;
};
export class VectorIndexRetriever implements BaseRetriever {
index: VectorStoreIndex;
similarityTopK: number;
imageSimilarityTopK: number;
private serviceContext: ServiceContext;
constructor({
index,
similarityTopK,
imageSimilarityTopK,
}: VectorIndexRetrieverOptions) {
this.index = index;
this.serviceContext = this.index.serviceContext;
this.similarityTopK = similarityTopK ?? DEFAULT_SIMILARITY_TOP_K;
this.imageSimilarityTopK = imageSimilarityTopK ?? DEFAULT_SIMILARITY_TOP_K;
}
async retrieve(
query: string,
parentEvent?: Event,
preFilters?: MetadataFilters,
): Promise<NodeWithScore[]> {
let nodesWithScores = await this.textRetrieve(query, preFilters);
nodesWithScores = nodesWithScores.concat(
await this.textToImageRetrieve(query, preFilters),
);
this.sendEvent(query, nodesWithScores, parentEvent);
return nodesWithScores;
}
protected async textRetrieve(
query: string,
preFilters?: MetadataFilters,
): Promise<NodeWithScore[]> {
const options = {};
const q = await this.buildVectorStoreQuery(
this.index.embedModel,
query,
this.similarityTopK,
preFilters,
);
const result = await this.index.vectorStore.query(q, options);
return this.buildNodeListFromQueryResult(result);
}
private async textToImageRetrieve(
query: string,
preFilters?: MetadataFilters,
) {
if (!this.index.imageEmbedModel || !this.index.imageVectorStore) {
// no-op if image embedding and vector store are not set
return [];
}
const q = await this.buildVectorStoreQuery(
this.index.imageEmbedModel,
query,
this.imageSimilarityTopK,
preFilters,
);
const result = await this.index.imageVectorStore.query(q, preFilters);
return this.buildNodeListFromQueryResult(result);
}
protected sendEvent(
query: string,
nodesWithScores: NodeWithScore<Metadata>[],
parentEvent: Event | undefined,
) {
if (this.serviceContext.callbackManager.onRetrieve) {
this.serviceContext.callbackManager.onRetrieve({
query,
nodes: nodesWithScores,
event: globalsHelper.createEvent({
parentEvent,
type: "retrieve",
}),
});
}
}
protected async buildVectorStoreQuery(
embedModel: BaseEmbedding,
query: string,
similarityTopK: number,
preFilters?: MetadataFilters,
): Promise<VectorStoreQuery> {
const queryEmbedding = await embedModel.getQueryEmbedding(query);
return {
queryEmbedding: queryEmbedding,
mode: VectorStoreQueryMode.DEFAULT,
similarityTopK: similarityTopK,
filters: preFilters ?? undefined,
};
}
protected buildNodeListFromQueryResult(result: VectorStoreQueryResult) {
const nodesWithScores: NodeWithScore[] = [];
for (let i = 0; i < result.ids.length; i++) {
const nodeFromResult = result.nodes?.[i];
if (!this.index.indexStruct.nodesDict[result.ids[i]] && nodeFromResult) {
this.index.indexStruct.nodesDict[result.ids[i]] = nodeFromResult;
}
const node = this.index.indexStruct.nodesDict[result.ids[i]];
// XXX: Hack, if it's an image node, we reconstruct the image from the URL
// Alternative: Store image in doc store and retrieve it here
if (node instanceof ImageNode) {
node.image = node.getUrl();
}
nodesWithScores.push({
node: node,
score: result.similarities[i],
});
}
return nodesWithScores;
}
getServiceContext(): ServiceContext {
return this.serviceContext;
}
}
@@ -1,12 +1,12 @@
import { BaseNode, MetadataMode } from "../Node";
import { createSHA256 } from "../env";
import { docToJson, jsonToDoc } from "../storage/docStore/utils";
import { SimpleKVStore } from "../storage/kvStore/SimpleKVStore";
import { BaseKVStore } from "../storage/kvStore/types";
import { TransformComponent } from "./types";
import { createSHA256 } from "@llamaindex/env";
import { BaseNode, MetadataMode } from "../Node.js";
import { docToJson, jsonToDoc } from "../storage/docStore/utils.js";
import { SimpleKVStore } from "../storage/kvStore/SimpleKVStore.js";
import { BaseKVStore } from "../storage/kvStore/types.js";
import { TransformComponent } from "./types.js";
const transformToJSON = (obj: TransformComponent) => {
let seen: any[] = [];
const seen: any[] = [];
const replacer = (key: string, value: any) => {
if (value != null && typeof value == "object") {
@@ -1,9 +1,13 @@
import { BaseNode, Document } from "../Node";
import { BaseReader } from "../readers/type";
import { BaseDocumentStore, VectorStore } from "../storage";
import { IngestionCache, getTransformationHash } from "./IngestionCache";
import { DocStoreStrategy, createDocStoreStrategy } from "./strategies";
import { TransformComponent } from "./types";
import { BaseNode, Document } from "../Node.js";
import { BaseReader } from "../readers/type.js";
import { BaseDocumentStore } from "../storage/docStore/types.js";
import { VectorStore } from "../storage/vectorStore/types.js";
import { IngestionCache, getTransformationHash } from "./IngestionCache.js";
import {
DocStoreStrategy,
createDocStoreStrategy,
} from "./strategies/index.js";
import { TransformComponent } from "./types.js";
type IngestionRunArgs = {
documents?: Document[];
+2 -2
View File
@@ -1,2 +1,2 @@
export * from "./IngestionPipeline";
export * from "./types";
export * from "./IngestionPipeline.js";
export * from "./types.js";
@@ -1,6 +1,6 @@
import { BaseNode } from "../../Node";
import { BaseDocumentStore } from "../../storage";
import { TransformComponent } from "../types";
import { BaseNode } from "../../Node.js";
import { BaseDocumentStore } from "../../storage/docStore/types.js";
import { TransformComponent } from "../types.js";
/**
* Handle doc store duplicates by checking all hashes.
@@ -1,6 +1,6 @@
import { BaseNode } from "../../Node";
import { BaseDocumentStore, VectorStore } from "../../storage";
import { classify } from "./classify";
import { BaseNode } from "../../Node.js";
import { BaseDocumentStore, VectorStore } from "../../storage/index.js";
import { classify } from "./classify.js";
/**
* Handle docstore upserts by checking hashes and ids.
@@ -1,7 +1,8 @@
import { BaseNode } from "../../Node";
import { BaseDocumentStore, VectorStore } from "../../storage";
import { TransformComponent } from "../types";
import { classify } from "./classify";
import { BaseNode } from "../../Node.js";
import { BaseDocumentStore } from "../../storage/docStore/types.js";
import { VectorStore } from "../../storage/vectorStore/types.js";
import { TransformComponent } from "../types.js";
import { classify } from "./classify.js";
/**
* Handles doc store upserts by checking hashes and ids.
@@ -1,5 +1,5 @@
import { BaseNode } from "../../Node";
import { BaseDocumentStore } from "../../storage";
import { BaseNode } from "../../Node.js";
import { BaseDocumentStore } from "../../storage/docStore/types.js";
export async function classify(docStore: BaseDocumentStore, nodes: BaseNode[]) {
const existingDocIds = Object.values(await docStore.getAllDocumentHashes());
@@ -1,7 +1,8 @@
import { BaseDocumentStore, VectorStore } from "../../storage";
import { TransformComponent } from "../types";
import { DuplicatesStrategy } from "./DuplicatesStrategy";
import { UpsertsStrategy } from "./UpsertsStrategy";
import { BaseDocumentStore } from "../../storage/docStore/types.js";
import { VectorStore } from "../../storage/vectorStore/types.js";
import { TransformComponent } from "../types.js";
import { DuplicatesStrategy } from "./DuplicatesStrategy.js";
import { UpsertsStrategy } from "./UpsertsStrategy.js";
export enum DocStoreStrategy {
UPSERTS = "upserts",
+1 -1
View File
@@ -1,4 +1,4 @@
import { BaseNode } from "../Node";
import { BaseNode } from "../Node.js";
export interface TransformComponent {
transform(nodes: BaseNode[], options?: any): Promise<BaseNode[]>;
+11 -11
View File
@@ -6,28 +6,28 @@ import {
EventType,
OpenAIStreamToken,
StreamCallbackResponse,
} from "../callbacks/CallbackManager";
} from "../callbacks/CallbackManager.js";
import { ChatCompletionMessageParam } from "openai/resources";
import { ChatCompletionMessageParam } from "openai/resources/index.js";
import { LLMOptions } from "portkey-ai";
import { Tokenizers, globalsHelper } from "../GlobalsHelper";
import { Tokenizers, globalsHelper } from "../GlobalsHelper.js";
import {
ANTHROPIC_AI_PROMPT,
ANTHROPIC_HUMAN_PROMPT,
AnthropicSession,
getAnthropicSession,
} from "./anthropic";
} from "./anthropic.js";
import {
AzureOpenAIConfig,
getAzureBaseUrl,
getAzureConfigFromEnv,
getAzureModel,
shouldUseAzure,
} from "./azure";
import { BaseLLM } from "./base";
import { OpenAISession, getOpenAISession } from "./open_ai";
import { PortkeySession, getPortkeySession } from "./portkey";
import { ReplicateSession } from "./replicate_ai";
} from "./azure.js";
import { BaseLLM } from "./base.js";
import { OpenAISession, getOpenAISession } from "./open_ai.js";
import { PortkeySession, getPortkeySession } from "./portkey.js";
import { ReplicateSession } from "./replicate_ai.js";
import {
ChatMessage,
ChatResponse,
@@ -36,7 +36,7 @@ import {
LLMChatParamsStreaming,
LLMMetadata,
MessageType,
} from "./types";
} from "./types.js";
export const GPT4_MODELS = {
"gpt-4": { contextWindow: 8192 },
@@ -235,7 +235,7 @@ export class OpenAI extends BaseLLM {
params: LLMChatParamsNonStreaming | LLMChatParamsStreaming,
): Promise<ChatResponse | AsyncIterable<ChatResponseChunk>> {
const { messages, parentEvent, stream, tools, toolChoice } = params;
let baseRequestParams: OpenAILLM.Chat.ChatCompletionCreateParams = {
const baseRequestParams: OpenAILLM.Chat.ChatCompletionCreateParams = {
model: this.model,
temperature: this.temperature,
max_tokens: this.maxTokens,
+1 -1
View File
@@ -26,7 +26,7 @@ export class AnthropicSession {
// I'm not 100% sure this is necessary vs. just starting a new session
// every time we make a call. They say they try to reuse connections
// so in theory this is more efficient, but we should test it in the future.
let defaultAnthropicSession: {
const defaultAnthropicSession: {
session: AnthropicSession;
options: ClientOptions;
}[] = [];
+2 -2
View File
@@ -9,8 +9,8 @@ import {
LLMCompletionParamsNonStreaming,
LLMCompletionParamsStreaming,
LLMMetadata,
} from "./types";
import { streamConverter } from "./utils";
} from "./types.js";
import { streamConverter } from "./utils.js";
export abstract class BaseLLM implements LLM {
abstract metadata: LLMMetadata;
+1 -1
View File
@@ -1,4 +1,4 @@
import { OpenAI } from "./LLM";
import { OpenAI } from "./LLM.js";
export class FireworksLLM extends OpenAI {
constructor(init?: Partial<OpenAI>) {
+7 -7
View File
@@ -1,11 +1,11 @@
export * from "./LLM";
export { FireworksLLM } from "./fireworks";
export * from "./LLM.js";
export { FireworksLLM } from "./fireworks.js";
export {
ALL_AVAILABLE_MISTRAL_MODELS,
MistralAI,
MistralAISession,
} from "./mistral";
export { Ollama } from "./ollama";
export * from "./open_ai";
export { TogetherLLM } from "./together";
export * from "./types";
} from "./mistral.js";
export { Ollama } from "./ollama.js";
export * from "./open_ai.js";
export { TogetherLLM } from "./together.js";
export * from "./types.js";
+3 -3
View File
@@ -3,15 +3,15 @@ import {
Event,
EventType,
StreamCallbackResponse,
} from "../callbacks/CallbackManager";
import { BaseLLM } from "./base";
} from "../callbacks/CallbackManager.js";
import { BaseLLM } from "./base.js";
import {
ChatMessage,
ChatResponse,
ChatResponseChunk,
LLMChatParamsNonStreaming,
LLMChatParamsStreaming,
} from "./types";
} from "./types.js";
export const ALL_AVAILABLE_MISTRAL_MODELS = {
"mistral-tiny": { contextWindow: 32000 },
+4 -4
View File
@@ -1,6 +1,6 @@
import { CallbackManager, Event } from "../callbacks/CallbackManager";
import { BaseEmbedding } from "../embeddings/types";
import { ok } from "../env";
import { ok } from "@llamaindex/env";
import { CallbackManager, Event } from "../callbacks/CallbackManager.js";
import { BaseEmbedding } from "../embeddings/types.js";
import {
ChatMessage,
ChatResponse,
@@ -12,7 +12,7 @@ import {
LLMCompletionParamsNonStreaming,
LLMCompletionParamsStreaming,
LLMMetadata,
} from "./types";
} from "./types.js";
const messageAccessor = (data: any): ChatResponseChunk => {
return {
+4 -2
View File
@@ -35,8 +35,10 @@ export class OpenAISession {
// I'm not 100% sure this is necessary vs. just starting a new session
// every time we make a call. They say they try to reuse connections
// so in theory this is more efficient, but we should test it in the future.
let defaultOpenAISession: { session: OpenAISession; options: ClientOptions }[] =
[];
const defaultOpenAISession: {
session: OpenAISession;
options: ClientOptions;
}[] = [];
/**
* Get a session for the OpenAI API. If one already exists with the same options,

Some files were not shown because too many files have changed in this diff Show More