Compare commits

..

25 Commits

Author SHA1 Message Date
Emanuel Ferreira 0b2d43b532 chore: remove console.log 2024-03-04 08:13:16 -03:00
Emanuel Ferreira 02feb54070 chore: string response example 2024-03-04 08:12:57 -03:00
Emanuel Ferreira 9bf778eb36 chore: remove files 2024-03-04 08:10:56 -03:00
Emanuel Ferreira 746408b992 chore: remove build files 2024-03-04 08:07:10 -03:00
Emanuel Ferreira ea64162b89 merge 2024-03-03 12:28:32 -03:00
Emanuel Ferreira 0094a2e420 wip 2024-03-03 12:27:30 -03:00
Alex Yang d13143e322 RELEASING: Releasing 3 package(s)
Releases:
  llamaindex@0.1.20
  @llamaindex/env@0.0.5
  docs@0.0.4

[skip ci]
2024-03-02 18:42:24 -06:00
Alex Yang 5116ad8d08 fix: compatibility issue with Deno (#598) 2024-03-02 18:40:01 -06:00
Emanuel Ferreira 64683a55f3 fix: prefix messages always true (#596) 2024-03-01 21:45:02 -03:00
Emanuel Ferreira 698cd9c631 fix: step wise agent + examples (#594) 2024-03-01 21:28:02 -03:00
Alex Yang c744a99102 chore: bump @llamaindex/cloud (#595) 2024-03-01 17:22:50 -06:00
Emanuel Ferreira ef1e8b4121 fix: reinstancing query bundle 2024-03-01 07:56:38 -03:00
Huu Le (Lee) 2d2935085e feat: Add use LlamaParse option to create-llama (#591) 2024-03-01 16:54:06 +07:00
Marcus Schiesser 1b31e2c8cd chore: update @llamaindex/cloud to 0.0.2 2024-03-01 15:59:10 +07:00
Thuc Pham 7257751993 fix: empty store bugs (#592)
Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
2024-03-01 15:04:10 +07:00
Emanuel Ferreira a20704bbf8 wip 2024-02-29 11:27:11 -03:00
Marcus Schiesser de6bfdb1b1 RELEASING: Releasing 1 package(s)
Releases:
  llamaindex@0.1.19

[skip ci]
2024-02-29 15:35:13 +07:00
Marcus Schiesser 9e49f4411b fix: copy README and license 2024-02-29 15:34:27 +07:00
Thuc Pham 026d068ddf feat: enhance pinecone usage (#586) 2024-02-29 15:34:08 +07:00
Marcus Schiesser 7055d6fc3c docs: add OpenAIEmbedding to examples 2024-02-29 11:11:43 +07:00
Alex Yang e9c2366bf1 fix: allow passing model metadata (#588) 2024-02-29 10:41:06 +07:00
Emanuel Ferreira 247a3d0b5f wip 2024-02-28 08:38:14 -03:00
Alex Yang 6278152e49 fix: lazy import pg (#584) 2024-02-27 19:16:54 -06:00
Emanuel Ferreira 76010c0cea chore: remove duplicated example and minor example update (#582) 2024-02-27 09:02:37 -03:00
Emanuel Ferreira 889b84cfb9 docs: remove query engine from correctness evaluator (#581) 2024-02-27 08:15:41 -03:00
77 changed files with 1995 additions and 139 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"create-llama": patch
---
Add LlamaParse option when selecting a pdf file or a folder
+1
View File
@@ -44,6 +44,7 @@ test-results/
playwright-report/
blob-report/
playwright/.cache/
.tsbuildinfo
# intellij
**/.idea
+7
View File
@@ -1,5 +1,12 @@
# docs
## 0.0.4
### Patch Changes
- Updated dependencies [5116ad8]
- @llamaindex/env@0.0.5
## 0.0.3
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "docs",
"version": "0.0.3",
"version": "0.0.4",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
+1 -1
View File
@@ -8,7 +8,7 @@ import {
async function main() {
// Load the documents
const documents = await new SimpleDirectoryReader().loadData({
directoryPath: "node_modules/llamaindex/examples/",
directoryPath: "node_modules/llamaindex/examples",
});
// Create a vector index from the documents
+95
View File
@@ -0,0 +1,95 @@
import { FunctionTool, OpenAIAgent } from "llamaindex";
// Define a function to sum two numbers
function sumNumbers({ a, b }: { a: number; b: number }): number {
return a + b;
}
// Define a function to divide two numbers
function divideNumbers({ a, b }: { a: number; b: number }): number {
return a / b;
}
// Define the parameters of the sum function as a JSON schema
const sumJSON = {
type: "object",
properties: {
a: {
type: "number",
description: "The first number",
},
b: {
type: "number",
description: "The second number",
},
},
required: ["a", "b"],
};
const divideJSON = {
type: "object",
properties: {
a: {
type: "number",
description: "The dividend a to divide",
},
b: {
type: "number",
description: "The divisor b to divide by",
},
},
required: ["a", "b"],
};
async function main() {
// Create a function tool from the sum function
const functionTool = new FunctionTool(sumNumbers, {
name: "sumNumbers",
description: "Use this function to sum two numbers",
parameters: sumJSON,
});
// Create a function tool from the divide function
const functionTool2 = new FunctionTool(divideNumbers, {
name: "divideNumbers",
description: "Use this function to divide two numbers",
parameters: divideJSON,
});
// Create an OpenAIAgent with the function tools
const agent = new OpenAIAgent({
tools: [functionTool, functionTool2],
verbose: true,
});
// Create a task to sum and divide numbers
const task = agent.createTask("How much is 5 + 5? then divide by 2");
let count = 0;
while (true) {
const stepOutput = await agent.runStep(task.taskId);
console.log(`Runnning step ${count++}`);
console.log(`======== OUTPUT ==========`);
if (stepOutput.output.response) {
console.log(stepOutput.output.response);
} else {
console.log(stepOutput.output.sources);
}
console.log(`==========================`);
if (stepOutput.isLast) {
const finalResponse = await agent.finalizeResponse(
task.taskId,
stepOutput,
);
console.log({ finalResponse });
break;
}
}
}
main().then(() => {
console.log("Done");
});
@@ -8,7 +8,7 @@ import {
async function main() {
// Load the documents
const documents = await new SimpleDirectoryReader().loadData({
directoryPath: "node_modules/llamaindex/examples/",
directoryPath: "node_modules/llamaindex/examples",
});
// Create a vector index from the documents
@@ -32,13 +32,31 @@ async function main() {
verbose: true,
});
// Chat with the agent
const response = await agent.chat({
message: "What was his salary?",
});
const task = agent.createTask("What was his salary?");
// Print the response
console.log(String(response));
let count = 0;
while (true) {
const stepOutput = await agent.runStep(task.taskId);
console.log(`Runnning step ${count++}`);
console.log(`======== OUTPUT ==========`);
if (stepOutput.output.response) {
console.log(stepOutput.output.response);
} else {
console.log(stepOutput.output.sources);
}
console.log(`==========================`);
if (stepOutput.isLast) {
const finalResponse = await agent.finalizeResponse(
task.taskId,
stepOutput,
);
console.log({ finalResponse });
break;
}
}
}
main().then(() => {
+90
View File
@@ -0,0 +1,90 @@
import { FunctionTool, ReActAgent } from "llamaindex";
// Define a function to sum two numbers
function sumNumbers({ a, b }: { a: number; b: number }): number {
return a + b;
}
// Define a function to divide two numbers
function divideNumbers({ a, b }: { a: number; b: number }): number {
return a / b;
}
// Define the parameters of the sum function as a JSON schema
const sumJSON = {
type: "object",
properties: {
a: {
type: "number",
description: "The first number",
},
b: {
type: "number",
description: "The second number",
},
},
required: ["a", "b"],
};
const divideJSON = {
type: "object",
properties: {
a: {
type: "number",
description: "The dividend",
},
b: {
type: "number",
description: "The divisor",
},
},
required: ["a", "b"],
};
async function main() {
// Create a function tool from the sum function
const functionTool = new FunctionTool(sumNumbers, {
name: "sumNumbers",
description: "Use this function to sum two numbers",
parameters: sumJSON,
});
// Create a function tool from the divide function
const functionTool2 = new FunctionTool(divideNumbers, {
name: "divideNumbers",
description: "Use this function to divide two numbers",
parameters: divideJSON,
});
// Create an OpenAIAgent with the function tools
const agent = new ReActAgent({
tools: [functionTool, functionTool2],
verbose: true,
});
const task = agent.createTask("Divide 16 by 2 then add 20");
let count = 0;
while (true) {
const stepOutput = await agent.runStep(task.taskId);
console.log(`Runnning step ${count++}`);
console.log(`======== OUTPUT ==========`);
console.log(stepOutput.output);
console.log(`==========================`);
if (stepOutput.isLast) {
const finalResponse = await agent.finalizeResponse(
task.taskId,
stepOutput,
);
console.log({ finalResponse });
break;
}
}
}
main().then(() => {
console.log("Done");
});
+81
View File
@@ -0,0 +1,81 @@
import knex from "knex";
import {
NLSQLQueryEngine,
OpenAI,
SQLDatabase,
serviceContextFromDefaults,
} from "llamaindex";
async function main() {
const llm = new OpenAI({
model: "gpt-4",
});
const engine = knex({
client: "sqlite3", // or 'better-sqlite3'
connection: {
filename: ":memory:",
},
});
const db = new SQLDatabase({
engine,
schema: undefined,
metadata: {},
ignoreTables: undefined,
includeTables: ["test_table_1"],
sampleRowsInTableInfo: 3,
indexesInTableInfo: true,
customTableInfo: undefined,
maxStringLength: 100,
});
const tableName = "test_table_1";
await engine.schema.createTable(tableName, async (table) => {
table.increments("id");
table.string("comment");
table.string("author");
await db.insertIntoTable(tableName, {
comment: "this is a test1",
author: "emanuel",
});
await db.insertIntoTable(tableName, {
comment: "this is a test2",
author: "alex",
});
await db.insertIntoTable(tableName, {
comment: "this is a test3",
author: "yi",
});
await db.insertIntoTable(tableName, {
comment: "this is a test4",
author: "alex",
});
const ctx = serviceContextFromDefaults({
llm,
});
const engine = new NLSQLQueryEngine({
sqlDatabase: db,
tables: ["test_table_1"],
verbose: true,
serviceContext: ctx,
synthesizeResponse: true,
});
const response = await engine.query({
query: "What's the comment from author yi and emanuel?",
});
console.log({ response });
process.exit(0);
});
}
main().then(() => [
// process.exit(0)
]);
+7 -1
View File
@@ -1,4 +1,4 @@
import { OpenAI } from "llamaindex";
import { OpenAI, OpenAIEmbedding } from "llamaindex";
(async () => {
const llm = new OpenAI({ model: "gpt-4-1106-preview", temperature: 0.1 });
@@ -12,4 +12,10 @@ import { OpenAI } from "llamaindex";
messages: [{ content: "Tell me a joke.", role: "user" }],
});
console.log(response2.message.content);
// embeddings
const embedModel = new OpenAIEmbedding();
const texts = ["hello", "world"];
const embeddings = await embedModel.getTextEmbeddingsBatch(texts);
console.log(`\nWe have ${embeddings.length} embeddings`);
})();
+3 -1
View File
@@ -9,8 +9,10 @@
"chromadb": "^1.8.1",
"commander": "^11.1.0",
"dotenv": "^16.4.1",
"knex": "^3.1.0",
"llamaindex": "latest",
"mongodb": "^6.2.0"
"mongodb": "^6.2.0",
"sqlite3": "^5.1.7"
},
"devDependencies": {
"@types/node": "^18.19.10",
+3 -2
View File
@@ -7,8 +7,9 @@ There are two scripts available here: load-docs.ts and query.ts
You'll need a Pinecone account, project, and index. Pinecone does not allow automatic creation of indexes on the free plan,
so this vector store does not check and create the index (unlike, e.g., the PGVectorStore)
Set the **PINECONE_API_KEY** and **PINECONE_ENVIRONMENT** environment variables to match your specific values. You will likely also need to set **PINECONE_INDEX_NAME**, unless your
index is the default value "llama".
Set the **PINECONE_API_KEY** and **PINECONE_ENVIRONMENT** environment variables to match your specific values.
You will likely also need to set **PINECONE_INDEX_NAME**, unless your index is the default value "llama".
By default, all operations take place inside the default namespace '', but you can set **PINECONE_NAMESPACE** to a different value if you need to.
You'll also need a value for OPENAI_API_KEY in your environment.
+46
View File
@@ -0,0 +1,46 @@
import knex from "knex";
import { SQLDatabase } from "llamaindex";
async function main() {
const engine = knex({
client: "sqlite3", // or 'better-sqlite3'
connection: {
filename: ":memory:",
},
});
const db = new SQLDatabase({
engine,
schema: undefined,
metadata: {},
ignoreTables: undefined,
includeTables: ["test_table"],
sampleRowsInTableInfo: 3,
indexesInTableInfo: true,
customTableInfo: undefined,
maxStringLength: 100,
});
const tableName = "test_table";
await engine.schema.createTable(tableName, () => {});
await db.insertIntoTable(tableName, {
name: "test1",
comment: "this is a test1",
});
await db.insertIntoTable(tableName, {
name: "test2",
comment: "this is a test2",
});
await db.insertIntoTable(tableName, {
name: "test3",
comment: "this is a test3",
});
await db.insertIntoTable(tableName, {
name: "test4",
comment: "this is a test4",
});
}
main();
+2
View File
@@ -1 +1,3 @@
.turbo
README.md
LICENSE
+17
View File
@@ -1,5 +1,22 @@
# llamaindex
## 0.1.20
### Patch Changes
- 64683a5: fix: prefix messages always true
- 698cd9c: fix: step wise agent + examples
- 7257751: fixed removeRefDocNode and persist store on delete
- 5116ad8: fix: compatibility issue with Deno
- Updated dependencies [5116ad8]
- @llamaindex/env@0.0.5
## 0.1.19
### Patch Changes
- 026d068: feat: enhance pinecone usage
## 0.1.18
### Patch Changes
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@llamaindex/core",
"version": "0.1.20",
"exports": "./src/index.ts",
"imports": {
"@llamaindex/env": "jsr:@llamaindex/env@0.0.5"
}
}
+10 -8
View File
@@ -1,28 +1,29 @@
{
"name": "llamaindex",
"version": "0.1.18",
"version": "0.1.20",
"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",
"@types/lodash": "^4.14.202",
"@types/node": "^18.19.14",
"@types/papaparse": "^5.3.14",
"@types/pg": "^8.11.0",
"@llamaindex/cloud": "^0.0.1",
"@llamaindex/cloud": "0.0.4",
"@llamaindex/env": "workspace:*",
"@mistralai/mistralai": "^0.0.10",
"@notionhq/client": "^2.2.14",
"@pinecone-database/pinecone": "^2.0.1",
"@qdrant/js-client-rest": "^1.7.0",
"@types/lodash": "^4.14.202",
"@types/node": "^18.19.14",
"@types/papaparse": "^5.3.14",
"@types/pg": "^8.11.0",
"@xenova/transformers": "^2.15.0",
"assemblyai": "^4.2.2",
"chromadb": "~1.7.3",
"cohere-ai": "^7.7.5",
"file-type": "^18.7.0",
"js-tiktoken": "^1.0.10",
"knex": "^3.1.0",
"lodash": "^4.17.21",
"mammoth": "^1.6.0",
"md-utils-ts": "^2.0.0",
@@ -94,8 +95,9 @@
"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",
"build:type": "pnpm run -w type-check",
"postbuild": "node -e \"require('fs').writeFileSync('./dist/cjs/package.json', JSON.stringify({ type: 'commonjs' }))\"",
"build:type": "rm -f .tsbuildinfo && tsc -b --diagnostics",
"copy": "cp -r ../../README.md ../../LICENSE .",
"postbuild": "pnpm run copy && node -e \"require('fs').writeFileSync('./dist/cjs/package.json', JSON.stringify({ type: 'commonjs' }))\"",
"circular-check": "madge -c ./src/index.ts",
"dev": "concurrently \"pnpm run build:esm --watch\" \"pnpm run build:cjs --watch\" \"pnpm run build:type --watch\""
}
-2
View File
@@ -37,8 +37,6 @@ export class OpenAIAgent extends AgentRunner {
toolRetriever,
systemPrompt,
}: OpenAIAgentParams) {
prefixMessages = prefixMessages || [];
llm = llm ?? new OpenAI({ model: "gpt-3.5-turbo-0613" });
if (systemPrompt) {
+3 -2
View File
@@ -14,7 +14,7 @@ import { AgentState, BaseAgentRunner, TaskState } from "./types.js";
const validateStepFromArgs = (
taskId: string,
input: string,
input?: string | null,
step?: any,
kwargs?: any,
): TaskStep | undefined => {
@@ -24,6 +24,7 @@ const validateStepFromArgs = (
}
return step;
} else {
if (!input) return;
return new TaskStep(taskId, step, input, kwargs);
}
};
@@ -194,7 +195,7 @@ export class AgentRunner extends BaseAgentRunner {
*/
async runStep(
taskId: string,
input: string,
input?: string | null,
step?: TaskStep,
kwargs: any = {},
): Promise<TaskStepOutput> {
+2 -2
View File
@@ -161,13 +161,13 @@ export class TaskStep implements ITaskStep {
* @param isLast: isLast
*/
export class TaskStepOutput {
output: unknown;
output: any;
taskStep: TaskStep;
nextSteps: TaskStep[];
isLast: boolean;
constructor(
output: unknown,
output: any,
taskStep: TaskStep,
nextSteps: TaskStep[],
isLast: boolean = false,
+3 -2
View File
@@ -1,4 +1,5 @@
import type { PlatformApiClient } from "@llamaindex/cloud";
import { getEnv } from "@llamaindex/env";
import type { ClientParams } from "./types.js";
import { DEFAULT_BASE_URL } from "./types.js";
@@ -7,8 +8,8 @@ export async function getClient({
baseUrl,
}: ClientParams = {}): Promise<PlatformApiClient> {
// Get the environment variables or use defaults
baseUrl = baseUrl ?? process.env.LLAMA_CLOUD_BASE_URL ?? DEFAULT_BASE_URL;
apiKey = apiKey ?? process.env.LLAMA_CLOUD_API_KEY;
baseUrl = baseUrl ?? getEnv("LLAMA_CLOUD_BASE_URL") ?? DEFAULT_BASE_URL;
apiKey = apiKey ?? getEnv("LLAMA_CLOUD_API_KEY");
const { PlatformApiClient } = await import("@llamaindex/cloud");
+2 -1
View File
@@ -1,9 +1,10 @@
import { getEnv } from "@llamaindex/env";
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
export class FireworksEmbedding extends OpenAIEmbedding {
constructor(init?: Partial<OpenAIEmbedding>) {
const {
apiKey = process.env.FIREWORKS_API_KEY,
apiKey = getEnv("FIREWORKS_API_KEY"),
additionalSessionOptions = {},
model = "nomic-ai/nomic-embed-text-v1.5",
...rest
+2 -1
View File
@@ -1,9 +1,10 @@
import { getEnv } from "@llamaindex/env";
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
export class TogetherEmbedding extends OpenAIEmbedding {
constructor(init?: Partial<OpenAIEmbedding>) {
const {
apiKey = process.env.TOGETHER_API_KEY,
apiKey = getEnv("TOGETHER_API_KEY"),
additionalSessionOptions = {},
model = "togethercomputer/m2-bert-80M-32k-retrieval",
...rest
+1
View File
@@ -1,3 +1,4 @@
export * from "./RetrieverQueryEngine.js";
export * from "./RouterQueryEngine.js";
export * from "./SubQuestionQueryEngine.js";
export * from "./sql/index.js";
@@ -0,0 +1,59 @@
import {
NLSQLRetriever,
type SQLDatabase,
type ServiceContext,
} from "../../../index.js";
import type { TextToSQLPrompt } from "../../../retriever/sql/prompts.js";
import { BaseSQLTableQueryEngine } from "./types.js";
type NLSQLQueryEngineParams = {
sqlDatabase: SQLDatabase;
textToSQLPrompt?: TextToSQLPrompt;
contextQueryKwargs?: any | null;
synthesizeResponse?: boolean;
responseSynthesisPrompt?: any | null;
tables?: any[] | string[] | undefined;
serviceContext?: ServiceContext | undefined;
contextStrPrefix?: string | undefined;
sqlOnly?: boolean;
verbose?: boolean;
};
export class NLSQLQueryEngine extends BaseSQLTableQueryEngine {
_sqlRetriever: NLSQLRetriever;
constructor({
sqlDatabase,
textToSQLPrompt,
contextQueryKwargs = null,
synthesizeResponse = true,
responseSynthesisPrompt = null,
tables,
serviceContext,
contextStrPrefix,
sqlOnly = false,
verbose = false,
}: NLSQLQueryEngineParams) {
super({
synthesizeResponse,
responseSynthesisPrompt,
serviceContext,
verbose,
});
this._sqlRetriever = new NLSQLRetriever({
sqlDatabase,
textToSQLPrompt,
contextQueryKwargs,
tables,
contextStrPrefix,
serviceContext,
sqlOnly,
verbose,
});
}
get sqlRetriever(): NLSQLRetriever {
return this._sqlRetriever;
}
}
@@ -0,0 +1 @@
export * from "./NLSQLQueryEngine.js";
@@ -0,0 +1,17 @@
export const defaultResponseSynthesisPrompt = ({
query,
context,
sqlQuery,
}: {
query?: string;
context?: string;
sqlQuery: string;
}) => `
Given an input question, synthesize a response from the query results.
Query: ${query}
SQL: ${sqlQuery}
SQL Response: ${context}
Response:
`;
export type ResponseSynthesisPrompt = typeof defaultResponseSynthesisPrompt;
@@ -0,0 +1,117 @@
import { Response } from "../../../Response.js";
import {
serviceContextFromDefaults,
type ServiceContext,
} from "../../../ServiceContext.js";
import {
CompactAndRefine,
MetadataMode,
ResponseSynthesizer,
} from "../../../index.js";
import type { SQLRetriever } from "../../../retriever/sql/types.js";
import type {
BaseQueryEngine,
QueryEngineParamsNonStreaming,
QueryEngineParamsStreaming,
} from "../../../types.js";
import {
defaultResponseSynthesisPrompt,
type ResponseSynthesisPrompt,
} from "./prompts.js";
export abstract class BaseSQLTableQueryEngine implements BaseQueryEngine {
synthesizeResponse: boolean;
responseSynthesisPrompt: ResponseSynthesisPrompt;
serviceContext: ServiceContext;
verbose: boolean;
constructor(init: {
synthesizeResponse?: boolean;
responseSynthesisPrompt?: ResponseSynthesisPrompt;
serviceContext?: ServiceContext;
verbose?: boolean;
}) {
this.synthesizeResponse = init.synthesizeResponse ?? true;
this.responseSynthesisPrompt =
init.responseSynthesisPrompt || defaultResponseSynthesisPrompt;
this.serviceContext = init.serviceContext || serviceContextFromDefaults({});
this.verbose = init.verbose || false;
}
getPrompts(): {
responseSynthesisPrompt: ResponseSynthesisPrompt;
} {
return { responseSynthesisPrompt: this.responseSynthesisPrompt };
}
updatePrompts(prompts: {
responseSynthesisPrompt: ResponseSynthesisPrompt;
}): void {
if ("responseSynthesisPrompt" in prompts) {
this.responseSynthesisPrompt = prompts.responseSynthesisPrompt;
}
}
getPromptModules(): {
sqlRetriever: SQLRetriever;
} {
return { sqlRetriever: this.sqlRetriever };
}
abstract get sqlRetriever(): SQLRetriever;
query(params: QueryEngineParamsStreaming): Promise<AsyncIterable<Response>>;
query(params: QueryEngineParamsNonStreaming): Promise<Response>;
async query(
params: QueryEngineParamsStreaming | QueryEngineParamsNonStreaming,
): Promise<Response | AsyncIterable<Response>> {
const { query, stream } = params;
if (stream) {
throw new Error("Streaming is not supported");
}
const [retrievedNodes, metadata] =
await this.sqlRetriever.retrieveWithMetadata({
queryStr: query,
});
const sqlQueryStr = metadata.sqlQuery;
console.log(`> SQL query: ${sqlQueryStr}`); // TODO: Remove
console.log(`> Sythesize Response ${this.synthesizeResponse}`);
if (this.synthesizeResponse) {
const responseBuilder = new CompactAndRefine(
this.serviceContext,
({ query, context }) =>
this.responseSynthesisPrompt({
query,
context,
sqlQuery: sqlQueryStr,
}),
);
const responseSynthesizer = new ResponseSynthesizer({
serviceContext: this.serviceContext,
responseBuilder,
});
const response = await responseSynthesizer.synthesize({
query,
nodesWithScore: retrievedNodes,
});
response.metadata.sqlQuery = sqlQueryStr;
return response;
}
const responseStr = retrievedNodes
.map((node) => node.node.getContent(MetadataMode.ALL))
.join("\n");
return new Response(responseStr, []);
}
}
+2
View File
@@ -26,7 +26,9 @@ export * from "./objects/index.js";
export * from "./postprocessors/index.js";
export * from "./prompts/index.js";
export * from "./readers/index.js";
export * from "./retriever/index.js";
export * from "./selectors/index.js";
export * from "./storage/index.js";
export * from "./synthesizers/index.js";
export * from "./tools/index.js";
export * from "./utilities/index.js";
+1 -1
View File
@@ -260,7 +260,7 @@ export class OpenAI extends BaseLLM {
stream: false,
});
const content = response.choices[0].message?.content ?? "";
const content = response.choices[0].message?.content ?? null;
const kwargsOutput: Record<string, any> = {};
+2 -3
View File
@@ -1,5 +1,6 @@
import type { ClientOptions } from "@anthropic-ai/sdk";
import Anthropic, { AI_PROMPT, HUMAN_PROMPT } from "@anthropic-ai/sdk";
import { getEnv } from "@llamaindex/env";
import _ from "lodash";
export class AnthropicSession {
@@ -7,9 +8,7 @@ export class AnthropicSession {
constructor(options: ClientOptions = {}) {
if (!options.apiKey) {
if (typeof process !== undefined) {
options.apiKey = process.env.ANTHROPIC_API_KEY;
}
options.apiKey = getEnv("ANTHROPIC_API_KEY");
}
if (!options.apiKey) {
+16 -14
View File
@@ -1,3 +1,5 @@
import { getEnv } from "@llamaindex/env";
export interface AzureOpenAIConfig {
apiKey?: string;
endpoint?: string;
@@ -67,24 +69,24 @@ export function getAzureConfigFromEnv(
return {
apiKey:
init?.apiKey ??
process.env.AZURE_OPENAI_KEY ?? // From Azure docs
process.env.OPENAI_API_KEY ?? // Python compatible
process.env.AZURE_OPENAI_API_KEY, // LCJS compatible
getEnv("AZURE_OPENAI_KEY") ?? // From Azure docs
getEnv("OPENAI_API_KEY") ?? // Python compatible
getEnv("AZURE_OPENAI_API_KEY"), // LCJS compatible
endpoint:
init?.endpoint ??
process.env.AZURE_OPENAI_ENDPOINT ?? // From Azure docs
process.env.OPENAI_API_BASE ?? // Python compatible
process.env.AZURE_OPENAI_API_INSTANCE_NAME, // LCJS compatible
getEnv("AZURE_OPENAI_ENDPOINT") ?? // From Azure docs
getEnv("OPENAI_API_BASE") ?? // Python compatible
getEnv("AZURE_OPENAI_API_INSTANCE_NAME"), // LCJS compatible
apiVersion:
init?.apiVersion ??
process.env.AZURE_OPENAI_API_VERSION ?? // From Azure docs
process.env.OPENAI_API_VERSION ?? // Python compatible
process.env.AZURE_OPENAI_API_VERSION ?? // LCJS compatible
getEnv("AZURE_OPENAI_API_VERSION") ?? // From Azure docs
getEnv("OPENAI_API_VERSION") ?? // Python compatible
getEnv("AZURE_OPENAI_API_VERSION") ?? // LCJS compatible
DEFAULT_API_VERSION,
deploymentName:
init?.deploymentName ??
process.env.AZURE_OPENAI_DEPLOYMENT ?? // From Azure docs
process.env.AZURE_OPENAI_API_DEPLOYMENT_NAME ?? // LCJS compatible
getEnv("AZURE_OPENAI_DEPLOYMENT") ?? // From Azure docs
getEnv("AZURE_OPENAI_API_DEPLOYMENT_NAME") ?? // LCJS compatible
init?.model, // Fall back to model name, Python compatible
};
}
@@ -113,8 +115,8 @@ export function getAzureModel(openAIModel: string) {
export function shouldUseAzure() {
return (
process.env.AZURE_OPENAI_ENDPOINT ||
process.env.AZURE_OPENAI_API_INSTANCE_NAME ||
process.env.OPENAI_API_TYPE === "azure"
getEnv("AZURE_OPENAI_ENDPOINT") ||
getEnv("AZURE_OPENAI_API_INSTANCE_NAME") ||
getEnv("OPENAI_API_TYPE") === "azure"
);
}
+2 -1
View File
@@ -1,9 +1,10 @@
import { getEnv } from "@llamaindex/env";
import { OpenAI } from "./LLM.js";
export class FireworksLLM extends OpenAI {
constructor(init?: Partial<OpenAI>) {
const {
apiKey = process.env.FIREWORKS_API_KEY,
apiKey = getEnv("FIREWORKS_API_KEY"),
additionalSessionOptions = {},
model = "accounts/fireworks/models/mixtral-8x7b-instruct",
...rest
+2 -1
View File
@@ -1,9 +1,10 @@
import { getEnv } from "@llamaindex/env";
import { OpenAI } from "./LLM.js";
export class Groq extends OpenAI {
constructor(init?: Partial<OpenAI>) {
const {
apiKey = process.env.GROQ_API_KEY,
apiKey = getEnv("GROQ_API_KEY"),
additionalSessionOptions = {},
model = "mixtral-8x7b-32768",
...rest
+2 -3
View File
@@ -1,3 +1,4 @@
import { getEnv } from "@llamaindex/env";
import type {
CallbackManager,
Event,
@@ -27,9 +28,7 @@ export class MistralAISession {
if (init?.apiKey) {
this.apiKey = init?.apiKey;
} else {
if (typeof process !== undefined) {
this.apiKey = process.env.MISTRAL_API_KEY;
}
this.apiKey = getEnv("MISTRAL_API_KEY");
}
if (!this.apiKey) {
throw new Error("Set Mistral API key in MISTRAL_API_KEY env variable"); // Overriding MistralAI package's error message
+5
View File
@@ -37,14 +37,18 @@ export class Ollama extends BaseEmbedding implements LLM {
additionalChatOptions?: Record<string, unknown>;
callbackManager?: CallbackManager;
protected modelMetadata: Partial<LLMMetadata>;
constructor(
init: Partial<Ollama> & {
// model is required
model: string;
modelMetadata?: Partial<LLMMetadata>;
},
) {
super();
this.model = init.model;
this.modelMetadata = init.modelMetadata ?? {};
Object.assign(this, init);
}
@@ -56,6 +60,7 @@ export class Ollama extends BaseEmbedding implements LLM {
maxTokens: undefined,
contextWindow: this.contextWindow,
tokenizer: undefined,
...this.modelMetadata,
};
}
+2 -3
View File
@@ -1,3 +1,4 @@
import { getEnv } from "@llamaindex/env";
import _ from "lodash";
import type { ClientOptions } from "openai";
import OpenAI from "openai";
@@ -13,9 +14,7 @@ export class OpenAISession {
constructor(options: ClientOptions & { azure?: boolean } = {}) {
if (!options.apiKey) {
if (typeof process !== undefined) {
options.apiKey = process.env.OPENAI_API_KEY;
}
options.apiKey = getEnv("OPENAI_API_KEY");
}
if (!options.apiKey) {
+3 -12
View File
@@ -1,17 +1,8 @@
import { getEnv } from "@llamaindex/env";
import _ from "lodash";
import type { LLMOptions } from "portkey-ai";
import { Portkey } from "portkey-ai";
export const readEnv = (
env: string,
default_val?: string,
): string | undefined => {
if (typeof process !== "undefined") {
return process.env?.[env] ?? default_val;
}
return default_val;
};
interface PortkeyOptions {
apiKey?: string;
baseURL?: string;
@@ -24,11 +15,11 @@ export class PortkeySession {
constructor(options: PortkeyOptions = {}) {
if (!options.apiKey) {
options.apiKey = readEnv("PORTKEY_API_KEY");
options.apiKey = getEnv("PORTKEY_API_KEY");
}
if (!options.baseURL) {
options.baseURL = readEnv("PORTKEY_BASE_URL", "https://api.portkey.ai");
options.baseURL = getEnv("PORTKEY_BASE_URL") ?? "https://api.portkey.ai";
}
this.portkey = new Portkey({});
+3 -2
View File
@@ -1,3 +1,4 @@
import { getEnv } from "@llamaindex/env";
import Replicate from "replicate";
export class ReplicateSession {
@@ -7,8 +8,8 @@ export class ReplicateSession {
constructor(replicateKey: string | null = null) {
if (replicateKey) {
this.replicateKey = replicateKey;
} else if (process.env.REPLICATE_API_TOKEN) {
this.replicateKey = process.env.REPLICATE_API_TOKEN;
} else if (getEnv("REPLICATE_API_TOKEN")) {
this.replicateKey = getEnv("REPLICATE_API_TOKEN") as string;
} else {
throw new Error(
"Set Replicate token in REPLICATE_API_TOKEN env variable",
+2 -1
View File
@@ -1,9 +1,10 @@
import { getEnv } from "@llamaindex/env";
import { OpenAI } from "./LLM.js";
export class TogetherLLM extends OpenAI {
constructor(init?: Partial<OpenAI>) {
const {
apiKey = process.env.TOGETHER_API_KEY,
apiKey = getEnv("TOGETHER_API_KEY"),
additionalSessionOptions = {},
model = "togethercomputer/llama-2-7b-chat",
...rest
@@ -1,3 +1,4 @@
import { getEnv } from "@llamaindex/env";
import type {
BaseServiceParams,
SubtitleFormat,
@@ -28,7 +29,7 @@ abstract class AssemblyAIReader implements BaseReader {
options = {};
}
if (!options.apiKey) {
options.apiKey = process.env.ASSEMBLYAI_API_KEY;
options.apiKey = getEnv("ASSEMBLYAI_API_KEY");
}
if (!options.apiKey) {
throw new Error(
@@ -1,5 +1,4 @@
import type { GenericFileSystem } from "@llamaindex/env";
import { defaultFS } from "@llamaindex/env";
import { defaultFS, getEnv, type GenericFileSystem } from "@llamaindex/env";
import { Document } from "../Node.js";
import type { FileReader } from "./type.js";
@@ -24,7 +23,7 @@ export class LlamaParseReader implements FileReader {
constructor(params: Partial<LlamaParseReader> = {}) {
Object.assign(this, params);
params.apiKey = params.apiKey ?? process.env.LLAMA_CLOUD_API_KEY;
params.apiKey = params.apiKey ?? getEnv("LLAMA_CLOUD_API_KEY");
if (!params.apiKey) {
throw new Error(
"API Key is required for LlamaParseReader. Please pass the apiKey parameter or set the LLAMA_CLOUD_API_KEY environment variable.",
+1
View File
@@ -0,0 +1 @@
export * from "./sql/index.js";
@@ -0,0 +1,259 @@
import { serviceContextFromDefaults } from "../../ServiceContext.js";
import {
TextNode,
type BaseRetriever,
type CallbackManager,
type LLM,
type NodeWithScore,
type ObjectRetriever,
type SQLDatabase,
type ServiceContext,
} from "../../index.js";
import { QueryBundle } from "../../types.js";
import { defaultTextToSQLPrompt, type TextToSQLPrompt } from "./prompts.js";
import {
DefaultSQLParser,
SQLParserMode,
SQLRetriever,
type SQLTableSchema,
} from "./types.js";
export class NLSQLRetriever extends SQLRetriever implements BaseRetriever {
sqlDatabase: SQLDatabase;
sqlRetriever: SQLRetriever;
sqlParser: DefaultSQLParser;
textToSQLPrompt: TextToSQLPrompt;
contextQueryKwargs: Record<string, any> | undefined;
tables: any[] | string[] | undefined;
tableRetriever: ObjectRetriever | undefined;
contextStrPrefix: string | undefined;
sqlParserMode: SQLParserMode;
llm: LLM;
serviceContext: ServiceContext;
returnRaw: boolean;
handleSQLErrors: boolean;
sqlOnly: boolean;
callbackManager: CallbackManager | undefined;
verbose: boolean;
getTables: any;
constructor({
sqlDatabase,
textToSQLPrompt,
contextQueryKwargs,
tables,
tableRetriever,
contextStrPrefix,
sqlParserMode,
llm,
serviceContext,
returnRaw,
handleSQLErrors,
sqlOnly,
callbackManager,
verbose,
}: {
sqlDatabase: SQLDatabase;
textToSQLPrompt?: TextToSQLPrompt;
contextQueryKwargs?: Record<string, any>;
tables?: any[] | string[];
tableRetriever?: ObjectRetriever;
contextStrPrefix?: string;
sqlParserMode?: SQLParserMode;
llm?: LLM;
serviceContext?: ServiceContext;
returnRaw?: boolean;
handleSQLErrors?: boolean;
sqlOnly?: boolean;
callbackManager?: CallbackManager;
verbose?: boolean;
}) {
super(sqlDatabase, returnRaw, callbackManager);
this.sqlRetriever = new SQLRetriever(sqlDatabase, returnRaw);
this.sqlDatabase = sqlDatabase;
this.getTables = this.loadGetTablesFn(
sqlDatabase,
tables,
contextQueryKwargs,
tableRetriever,
);
this.contextStrPrefix = contextStrPrefix;
this.serviceContext = serviceContext ?? serviceContextFromDefaults();
this.textToSQLPrompt = textToSQLPrompt ?? defaultTextToSQLPrompt;
this.sqlParserMode = sqlParserMode ?? SQLParserMode.DEFAULT;
this.sqlParser = this.loadSQLParser(
this.sqlParserMode,
this.serviceContext,
);
this.handleSQLErrors = handleSQLErrors ?? true;
this.sqlOnly = sqlOnly ?? false;
this.verbose = verbose ?? false;
this.returnRaw = returnRaw ?? false;
this.llm = llm ?? this.serviceContext.llm;
}
_getPrompts() {
return {
textToSQLPrompt: this.textToSQLPrompt,
};
}
_updatePrompts(prompts: Record<string, any>) {
if ("textToSQLPrompt" in prompts) {
this.textToSQLPrompt = prompts.textToSQLPrompt;
}
}
_getPromptModules() {
return {};
}
getServiceContext(): ServiceContext {
return this.serviceContext;
}
loadSQLParser(sqlParserMode: SQLParserMode, serviceContext: ServiceContext) {
if (sqlParserMode === SQLParserMode.DEFAULT) {
return new DefaultSQLParser();
} else {
throw new Error(`Unknown SQL parser mode: ${sqlParserMode}`);
}
}
loadGetTablesFn(
sqlDatabase: SQLDatabase,
tables: any[] | string[] | undefined,
contextQueryKwargs: Record<string, any> | undefined,
tableRetriever: ObjectRetriever | undefined,
) {
contextQueryKwargs = contextQueryKwargs || {};
if (tableRetriever) {
return async (queryStr: string) =>
await tableRetriever.retrieve(queryStr);
} else {
let tableNames: SQLTableSchema[] | string[];
if (tables) {
tableNames = tables.map((t) => t);
} else {
tableNames = Array.from(sqlDatabase.usableTableNames);
}
const contextStrs: string[] = [];
const tableSchemas = tableNames.map((t, i) => {
if (typeof t === "string") {
return {
tableName: t,
...(contextQueryKwargs
? { contextStr: contextQueryKwargs[t] }
: {}),
};
}
return {
tableName: t.tableName,
...(contextQueryKwargs
? { contextStr: contextQueryKwargs[t.tableName] }
: {}),
};
});
return () => tableSchemas;
}
}
async retrieveWithMetadata(strOrQueryBundle: string | QueryBundle): Promise<
[
NodeWithScore[],
{
sqlQuery: string;
},
]
> {
const queryBundle =
typeof strOrQueryBundle === "string"
? { queryStr: strOrQueryBundle }
: strOrQueryBundle;
const tableDescStr = await this.getTableContext(queryBundle);
if (this.verbose) {
console.log(`> Table desc str: ${tableDescStr}`);
}
const response = await this.serviceContext?.llm?.complete({
prompt: this.textToSQLPrompt({
dialect: "sql",
schema: tableDescStr,
queryStr: queryBundle.queryStr,
}),
});
if (!response) {
throw new Error("No response from LLM");
}
const sqlQueryStr = this.sqlParser.parseResponseToSQL(
response?.text,
queryBundle,
);
if (this.verbose) {
console.log(`> Predicted SQL query: ${sqlQueryStr}`);
}
let retrievedNodes: NodeWithScore[];
let metadata: Record<string, unknown> = {};
if (this.sqlOnly) {
const sqlOnlyNode = new TextNode({ text: sqlQueryStr });
retrievedNodes = [{ node: sqlOnlyNode }];
metadata = {};
} else {
try {
const retrieverResponse = await this.sqlRetriever.retrieveWithMetadata({
queryStr: sqlQueryStr,
});
retrievedNodes = retrieverResponse[0];
metadata = retrieverResponse[1];
} catch (e) {
if (this.handleSQLErrors) {
const errNode = new TextNode({ text: `Error: ${e}` });
retrievedNodes = [{ node: errNode }];
metadata = {};
} else {
throw e;
}
}
}
return [retrievedNodes, { sqlQuery: sqlQueryStr, ...metadata }];
}
async retrieve(query: string): Promise<NodeWithScore[]> {
const [retrievedNodes] = await this.retrieveWithMetadata(query);
return retrievedNodes;
}
async getTableContext(queryBundle: QueryBundle) {
const tableSchemaObjs = this.getTables(queryBundle.queryStr);
const contextStrs = [];
if (this.contextStrPrefix) {
contextStrs.push(this.contextStrPrefix);
}
for (const tableSchemaObj of tableSchemaObjs) {
let tableInfo = await this.sqlDatabase.getSingleTableInfo(
tableSchemaObj.tableName,
);
if (tableSchemaObj.contextStr) {
const tableOptContext = `The table description is: ${tableSchemaObj.contextStr}`;
tableInfo += tableOptContext;
}
contextStrs.push(tableInfo);
}
return contextStrs.join("\n\n");
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./NLSQLRetriever.js";
@@ -0,0 +1,31 @@
export const defaultTextToSQLPrompt = ({
dialect,
schema,
queryStr,
}: {
dialect: string;
schema: string;
queryStr: string;
}) => `Given an input question, first create a syntactically correct ${dialect}
query to run, then look at the results of the query and return the answer.
You can order the results by a relevant column to return the most
interesting examples in the database.
Never query for all the columns from a specific table, only ask for a
few relevant columns given the question.
Pay attention to use only the column names that you can see in the schema
description.
Be careful to not query for columns that do not exist.
Pay attention to which column is in which table.
Also, qualify column names with the table name when needed.
You are required to use the following format, each taking one line:
Question: Question here
SQLQuery: SQL Query to run
SQLResult: Result of the SQLQuery
Answer: Final answer here
Only use tables listed below.
${schema}
Question: ${queryStr}
SQLQuery:
`;
export type TextToSQLPrompt = typeof defaultTextToSQLPrompt;
+105
View File
@@ -0,0 +1,105 @@
import type { BaseRetriever } from "../../Retriever.js";
import {
TextNode,
type CallbackManager,
type Event,
type NodeWithScore,
type SQLDatabase,
type ServiceContext,
} from "../../index.js";
import type { QueryBundle } from "../../types.js";
export interface SQLTableSchema {
tableName: string;
contextStr: string;
}
export enum SQLParserMode {
DEFAULT = "default",
PGVECTOR = "pgvector",
}
// export type SQLParserMode = "default" | "pgvector";
export interface BaseSQLParser {
parseResponseToSQL(response: string, queryBundle: QueryBundle): string;
}
export class DefaultSQLParser implements BaseSQLParser {
parseResponseToSQL(response: string, queryBundle: QueryBundle): string {
const sqlQueryStart = response.indexOf("SQLQuery:");
if (sqlQueryStart !== -1) {
response = response.slice(sqlQueryStart);
if (response.startsWith("SQLQuery:")) {
response = response.slice("SQLQuery:".length);
}
}
const sqlResultStart = response.indexOf("SQLResult:");
if (sqlResultStart !== -1) {
response = response.slice(0, sqlResultStart);
}
return response.trim().replace("```", "").trim();
}
}
export class SQLRetriever implements BaseRetriever {
sqlDatabase: SQLDatabase;
returnRaw: boolean;
constructor(
sqlDatabase: SQLDatabase,
returnRaw: boolean = true,
callbackManager: CallbackManager | null = null,
kwargs: any = {},
) {
this.sqlDatabase = sqlDatabase;
this.returnRaw = returnRaw;
}
getServiceContext(): ServiceContext {
throw new Error("Method not implemented.");
}
_formatNodeResults(results: any[][], colKeys: string[]): NodeWithScore[] {
const nodes: NodeWithScore[] = [];
for (const result of results) {
const metadata = Object.fromEntries(
colKeys.map((key, i) => [key, result[i]]),
);
const textNode = new TextNode({
text: "",
metadata,
});
nodes.push({ node: textNode });
}
return nodes;
}
async retrieveWithMetadata(
strOrQueryBundle: QueryBundle,
): Promise<[NodeWithScore[], any]> {
const [rawResponseStr, metadata] = await this.sqlDatabase.runSQL(
strOrQueryBundle.queryStr,
);
if (this.returnRaw) {
return [[{ node: new TextNode({ text: rawResponseStr }) }], metadata];
} else {
const results = metadata.result;
const colKeys = metadata.colKeys;
return [this._formatNodeResults(results, colKeys), metadata];
}
}
async retrieve(
query: string,
parentEvent: Event | undefined,
preFilters: unknown,
): Promise<NodeWithScore[]> {
const retrievedNodes = await this.retrieveWithMetadata({
queryStr: query,
});
return retrievedNodes;
}
}
@@ -1,4 +1,4 @@
import _, * as lodash from "lodash";
import _ from "lodash";
import type { BaseNode } from "../../Node.js";
import { ObjectType } from "../../Node.js";
import { DEFAULT_NAMESPACE } from "../constants.js";
@@ -123,10 +123,10 @@ export class KVDocumentStore extends BaseDocumentStore {
const refDocInfo = await this.kvstore.get(refDocId, this.refDocCollection);
if (!_.isNil(refDocInfo)) {
lodash.pull(refDocInfo.docIds, docId);
!_.pull(refDocInfo.nodeIds, docId);
if (refDocInfo.docIds.length > 0) {
this.kvstore.put(refDocId, refDocInfo.toDict(), this.refDocCollection);
if (refDocInfo.nodeIds.length > 0) {
this.kvstore.put(refDocId, refDocInfo, this.refDocCollection);
}
this.kvstore.delete(refDocId, this.metadataCollection);
}
@@ -54,6 +54,9 @@ export class SimpleKVStore extends BaseKVStore {
): Promise<boolean> {
if (key in this.data[collection]) {
delete this.data[collection][key];
if (this.persistPath) {
await this.persist(this.persistPath, this.fs);
}
return true;
}
return false;
@@ -1,5 +1,6 @@
import { AstraDB } from "@datastax/astra-db-ts";
import type { Collection } from "@datastax/astra-db-ts/dist/collections";
import { getEnv } from "@llamaindex/env";
import type { BaseNode } from "../../Node.js";
import { MetadataMode } from "../../Node.js";
import type {
@@ -34,9 +35,8 @@ export class AstraDBVectorStore implements VectorStore {
if (init?.astraDBClient) {
this.astraDBClient = init.astraDBClient;
} else {
const token =
init?.params?.token ?? process.env.ASTRA_DB_APPLICATION_TOKEN;
const endpoint = init?.params?.endpoint ?? process.env.ASTRA_DB_ENDPOINT;
const token = init?.params?.token ?? getEnv("ASTRA_DB_APPLICATION_TOKEN");
const endpoint = init?.params?.endpoint ?? getEnv("ASTRA_DB_ENDPOINT");
if (!token) {
throw new Error(
@@ -48,7 +48,7 @@ export class AstraDBVectorStore implements VectorStore {
}
const namespace =
init?.params?.namespace ??
process.env.ASTRA_DB_NAMESPACE ??
getEnv("ASTRA_DB_NAMESPACE") ??
"default_keyspace";
this.astraDBClient = new AstraDB(token, endpoint, namespace);
}
@@ -1,3 +1,4 @@
import { getEnv } from "@llamaindex/env";
import type { BulkWriteOptions, Collection } from "mongodb";
import { MongoClient } from "mongodb";
import type { BaseNode } from "../../Node.js";
@@ -44,7 +45,7 @@ export class MongoDBAtlasVectorSearch implements VectorStore {
if (init.mongodbClient) {
this.mongodbClient = init.mongodbClient;
} else {
const mongoUri = process.env.MONGODB_URI;
const mongoUri = getEnv("MONGODB_URI");
if (!mongoUri) {
throw new Error(
"Must specify MONGODB_URI via env variable if not directly passing in client.",
@@ -1,5 +1,4 @@
import pg from "pg";
import pgvector from "pgvector/pg";
import type pg from "pg";
import type {
VectorStore,
@@ -83,16 +82,18 @@ export class PGVectorStore implements VectorStore {
private async getDb(): Promise<pg.Client> {
if (!this.db) {
try {
const { Client } = await import("pg");
const { registerType } = await import("pgvector/pg");
// Create DB connection
// Read connection params from env - see comment block above
const db = new pg.Client({
const db = new Client({
connectionString: this.connectionString,
});
await db.connect();
// Check vector extension
db.query("CREATE EXTENSION IF NOT EXISTS vector");
await pgvector.registerType(db);
await registerType(db);
// Check schema, table(s), index(es)
await this.checkSchema(db);
@@ -6,19 +6,21 @@ import type {
VectorStoreQueryResult,
} from "./types.js";
import type { GenericFileSystem } from "@llamaindex/env";
import { getEnv, type GenericFileSystem } from "@llamaindex/env";
import type {
FetchResponse,
Index,
ScoredPineconeRecord,
} from "@pinecone-database/pinecone";
import { Pinecone } from "@pinecone-database/pinecone";
import { type Pinecone } from "@pinecone-database/pinecone";
import type { BaseNode, Metadata } from "../../Node.js";
import { metadataDictToNode, nodeToMetadata } from "./utils.js";
type PineconeParams = {
indexName?: string;
chunkSize?: number;
namespace?: string;
textKey?: string;
};
/**
@@ -37,18 +39,23 @@ export class PineconeVectorStore implements VectorStore {
*/
db?: Pinecone;
indexName: string;
namespace: string;
chunkSize: number;
textKey: string;
constructor(params?: PineconeParams) {
this.indexName =
params?.indexName ?? process.env.PINECONE_INDEX_NAME ?? "llama";
params?.indexName ?? getEnv("PINECONE_INDEX_NAME") ?? "llama";
this.namespace = params?.namespace ?? getEnv("PINECONE_NAMESPACE") ?? "";
this.chunkSize =
params?.chunkSize ??
Number.parseInt(process.env.PINECONE_CHUNK_SIZE ?? "100");
Number.parseInt(getEnv("PINECONE_CHUNK_SIZE") ?? "100");
this.textKey = params?.textKey ?? "text";
}
private async getDb(): Promise<Pinecone> {
if (!this.db) {
const { Pinecone } = await import("@pinecone-database/pinecone");
this.db = await new Pinecone();
}
@@ -148,24 +155,23 @@ export class PineconeVectorStore implements VectorStore {
};
const idx = await this.index();
const results = await idx.query(options);
const results = await idx.namespace(this.namespace).query(options);
const idList = results.matches.map((row) => row.id);
const records: FetchResponse<any> = await idx.fetch(idList);
const records: FetchResponse<any> = await idx
.namespace(this.namespace)
.fetch(idList);
const rows = Object.values(records.records);
const nodes = rows.map((row) => {
const metadata = this.metaWithoutText(row.metadata);
const text = this.textFromResultRow(row);
const node = metadataDictToNode(metadata, {
const node = metadataDictToNode(row.metadata, {
fallback: {
id: row.id,
text,
metadata,
text: this.textFromResultRow(row),
metadata: this.metaWithoutText(row.metadata),
embedding: row.values,
},
});
node.setContent(text);
return node;
});
@@ -199,12 +205,12 @@ export class PineconeVectorStore implements VectorStore {
}
textFromResultRow(row: ScoredPineconeRecord<Metadata>): string {
return row.metadata?.text ?? "";
return row.metadata?.[this.textKey] ?? "";
}
metaWithoutText(meta: Metadata): any {
return Object.keys(meta)
.filter((key) => key != "text")
.filter((key) => key != this.textKey)
.reduce((acc: any, key: string) => {
acc[key] = meta[key];
return acc;
@@ -82,6 +82,9 @@ export class SimpleVectorStore implements VectorStore {
delete this.data.embeddingDict[textId];
delete this.data.textIdToRefDocId[textId];
}
if (this.persistPath) {
await this.persist(this.persistPath, this.fs);
}
return Promise.resolve();
}
+126
View File
@@ -0,0 +1,126 @@
import knex from "knex";
type SQLDatabaseParams = {
engine: knex.Knex;
schema: string | undefined;
metadata: any;
ignoreTables: string[] | undefined;
includeTables: string[] | undefined;
sampleRowsInTableInfo: number;
indexesInTableInfo: boolean;
customTableInfo: Record<string, any> | undefined;
maxStringLength: number;
};
export class SQLDatabase {
engine: knex.Knex;
schema: string | undefined;
metadata: any;
inspector: knex.Knex;
allTables: Set<string>;
includeTables: Set<string>;
ignoreTables: Set<string>;
usableTables: Set<string>;
sampleRowsInTableInfo: number;
indexesInTableInfo: boolean;
customTableInfo: Record<string, any> | undefined;
maxStringLength: number;
constructor({
engine,
schema,
metadata,
ignoreTables,
includeTables,
sampleRowsInTableInfo,
indexesInTableInfo,
customTableInfo,
maxStringLength,
}: SQLDatabaseParams) {
this.engine = engine;
this.schema = schema;
this.metadata = metadata;
this.inspector = engine;
this.allTables = new Set(["test_table_1"]);
this.includeTables = new Set(includeTables || []);
this.ignoreTables = new Set(ignoreTables || []);
this.usableTables = new Set();
this.sampleRowsInTableInfo = sampleRowsInTableInfo;
this.indexesInTableInfo = indexesInTableInfo;
this.customTableInfo = customTableInfo;
this.maxStringLength = maxStringLength;
}
get usableTableNames(): string[] {
if (this.includeTables.size > 0) {
return Array.from(this.includeTables);
}
return Array.from(this.allTables);
}
async getTableColumns(tableName: string) {
return await this.inspector(tableName).columnInfo();
}
async getSingleTableInfo(tableName: string) {
const columns = await this.getTableColumns(tableName);
const columnStr = Object.keys(columns)
.map((column) => {
return `${column} (${columns[column].type})`;
})
.join(", ");
return `Table '${tableName}' has columns: ${columnStr}.`;
}
insertIntoTable(tableName: string, data: Record<string, any>): Promise<void> {
return this.engine(tableName).insert(data);
}
truncateWord(content: any, length: number, suffix = "..."): string {
if (typeof content !== "string" || length <= 0) {
return content;
}
if (content.length <= length) {
return content;
}
return (
content
.slice(0, length - suffix.length - 1)
.split(" ")
.slice(0, -1)
.join(" ") + suffix
);
}
async runSQL(
command: string,
): Promise<[string, { result: any[]; colKeys: string[] }]> {
return this.engine.raw(command).then((result: any) => {
if (result.length > 0) {
const truncatedResults = result.map((row: any) =>
this.truncateWord(row, this.maxStringLength),
);
return [
JSON.stringify(truncatedResults),
{ result: truncatedResults, colKeys: Object.keys(result[0]) },
];
}
return ["", { result: [], colKeys: [] }];
});
}
async getTableInfo(tableName: string): Promise<string> {
const columns = await this.getTableColumns(tableName);
const columnStr = Object.keys(columns)
.map((column: any) => {
const comment = column.COMMENT ? `'${column.COMMENT}'` : "";
return `${column.COLUMN_NAME} (${column.DATA_TYPE}): ${comment}`;
})
.join(", ");
return `Table '${tableName}' has columns: ${columnStr}.`;
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./SQLWrapper.js";
+9 -1
View File
@@ -6,5 +6,13 @@
"moduleResolution": "node16",
"target": "ESNext"
},
"include": ["./**/*.ts"]
"include": ["./**/*.ts"],
"references": [
{
"path": "../../core/tsconfig.json"
},
{
"path": "../../env/tsconfig.json"
}
]
}
+7 -1
View File
@@ -3,6 +3,7 @@
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist/type",
"tsBuildInfoFile": ".tsbuildinfo",
"emitDeclarationOnly": true,
"module": "node16",
"moduleResolution": "node16",
@@ -10,5 +11,10 @@
"strict": true
},
"include": ["./src"],
"exclude": ["node_modules"]
"exclude": ["node_modules"],
"references": [
{
"path": "../env/tsconfig.json"
}
]
}
+2
View File
@@ -32,6 +32,7 @@ export async function createApp({
eslint,
frontend,
openAiKey,
llamaCloudKey,
model,
communityProjectPath,
llamapack,
@@ -77,6 +78,7 @@ export async function createApp({
isOnline,
eslint,
openAiKey,
llamaCloudKey,
model,
communityProjectPath,
llamapack,
+6
View File
@@ -26,6 +26,7 @@ const createEnvLocalFile = async (
root: string,
opts?: {
openAiKey?: string;
llamaCloudKey?: string;
vectorDb?: TemplateVectorDB;
model?: string;
framework?: TemplateFramework;
@@ -46,6 +47,10 @@ const createEnvLocalFile = async (
content += `OPENAI_API_KEY=${opts?.openAiKey}\n`;
}
if (opts?.llamaCloudKey) {
content += `LLAMA_CLOUD_API_KEY=${opts?.llamaCloudKey}\n`;
}
switch (opts?.vectorDb) {
case "mongo": {
content += `# For generating a connection URI, see https://www.mongodb.com/docs/guides/atlas/connection-string\n`;
@@ -205,6 +210,7 @@ export const installTemplate = async (
// Copy the environment file to the target directory.
await createEnvLocalFile(props.root, {
openAiKey: props.openAiKey,
llamaCloudKey: props.llamaCloudKey,
vectorDb: props.vectorDb,
model: props.model,
framework: props.framework,
+9 -5
View File
@@ -8,6 +8,7 @@ import { templatesDir } from "./dir";
import { isPoetryAvailable, tryPoetryInstall } from "./poetry";
import { Tool } from "./tools";
import {
FileSourceConfig,
InstallTemplateArgs,
TemplateDataSource,
TemplateVectorDB,
@@ -244,13 +245,16 @@ export const installPythonTemplate = async ({
const dataSourceType = dataSource?.type;
if (dataSourceType !== undefined && dataSourceType !== "none") {
const loaderPath =
dataSourceType === "folder"
? path.join(compPath, "loaders", "python", "file")
: path.join(compPath, "loaders", "python", dataSourceType);
let loaderFolder: string;
if (dataSourceType === "file" || dataSourceType === "folder") {
const dataSourceConfig = dataSource?.config as FileSourceConfig;
loaderFolder = dataSourceConfig.useLlamaParse ? "llama_parse" : "file";
} else {
loaderFolder = dataSourceType;
}
await copy("**", enginePath, {
parents: true,
cwd: loaderPath,
cwd: path.join(compPath, "loaders", "python", loaderFolder),
});
}
}
+2
View File
@@ -15,6 +15,7 @@ export type TemplateDataSourceType = "none" | "file" | "folder" | "web";
// Config for both file and folder
export type FileSourceConfig = {
path?: string;
useLlamaParse?: boolean;
};
export type WebSourceConfig = {
baseUrl?: string;
@@ -35,6 +36,7 @@ export interface InstallTemplateArgs {
eslint: boolean;
customApiPath?: string;
openAiKey?: string;
llamaCloudKey?: string;
forBackend?: string;
model: string;
communityProjectPath?: string;
+16
View File
@@ -154,6 +154,18 @@ const program = new Commander.Command(packageJson.name)
`
Specify the tools you want to use by providing a comma-separated list. For example, 'wikipedia.WikipediaToolSpec,google.GoogleSearchToolSpec'. Use 'none' to not using any tools.
`,
)
.option(
"--llama-parse",
`
Enable LlamaParse.
`,
)
.option(
"--llama-cloud-key <key>",
`
Provide a LlamaCloud API key.
`,
)
.allowUnknownOption()
@@ -171,6 +183,9 @@ if (process.argv.includes("--tools")) {
program.tools = getTools(program.tools.split(","));
}
}
if (process.argv.includes("--no-llama-parse")) {
program.llamaParse = false;
}
const packageManager = !!program.useNpm
? "npm"
@@ -264,6 +279,7 @@ async function run(): Promise<void> {
eslint: program.eslint,
frontend: program.frontend,
openAiKey: program.openAiKey,
llamaCloudKey: program.llamaCloudKey,
model: program.model,
communityProjectPath: program.communityProjectPath,
llamapack: program.llamapack,
+65 -2
View File
@@ -5,7 +5,11 @@ import path from "path";
import { blue, green, red } from "picocolors";
import prompts from "prompts";
import { InstallAppArgs } from "./create-app";
import { TemplateDataSourceType, TemplateFramework } from "./helpers";
import {
FileSourceConfig,
TemplateDataSourceType,
TemplateFramework,
} from "./helpers";
import { COMMUNITY_OWNER, COMMUNITY_REPO } from "./helpers/constant";
import { templatesDir } from "./helpers/dir";
import { getAvailableLlamapackOptions } from "./helpers/llama-pack";
@@ -15,7 +19,7 @@ import { supportedTools, toolsRequireConfig } from "./helpers/tools";
export type QuestionArgs = Omit<
InstallAppArgs,
"appPath" | "packageManager"
> & { files?: string };
> & { files?: string; llamaParse?: boolean };
const supportedContextFileTypes = [
".pdf",
".doc",
@@ -63,6 +67,7 @@ const defaults: QuestionArgs = {
eslint: true,
frontend: false,
openAiKey: "",
llamaCloudKey: "",
model: "gpt-3.5-turbo",
communityProjectPath: "",
llamapack: "",
@@ -521,6 +526,64 @@ export const askQuestions = async (
}
}
if (
program.dataSource?.type === "file" ||
(program.dataSource?.type === "folder" && program.framework === "fastapi")
) {
if (ciInfo.isCI) {
program.llamaCloudKey = getPrefOrDefault("llamaCloudKey");
} else {
const dataSourceConfig = program.dataSource.config as FileSourceConfig;
dataSourceConfig.useLlamaParse = program.llamaParse;
// Is pdf file selected as data source or is it a folder data source
const askingLlamaParse =
dataSourceConfig.useLlamaParse === undefined &&
(program.dataSource.type === "folder"
? true
: dataSourceConfig.path &&
path.extname(dataSourceConfig.path) === ".pdf");
// Ask if user wants to use LlamaParse
if (askingLlamaParse) {
const { useLlamaParse } = await prompts(
{
type: "toggle",
name: "useLlamaParse",
message:
"Would you like to use LlamaParse (improved parser for RAG - requires API key)?",
initial: true,
active: "yes",
inactive: "no",
},
handlers,
);
dataSourceConfig.useLlamaParse = useLlamaParse;
program.dataSource.config = dataSourceConfig;
}
// Ask for LlamaCloud API key
if (
dataSourceConfig.useLlamaParse &&
program.llamaCloudKey === undefined
) {
const { llamaCloudKey } = await prompts(
{
type: "text",
name: "llamaCloudKey",
message: "Please provide your LlamaIndex Cloud API key:",
validate: (value) =>
value
? true
: "LlamaIndex Cloud API key is required. You can get it from: https://cloud.llamaindex.ai/api-key",
},
handlers,
);
program.llamaCloudKey = llamaCloudKey;
}
}
}
if (program.dataSource?.type === "web" && program.framework === "fastapi") {
let { baseUrl } = await prompts(
{
@@ -1,6 +1,6 @@
from llama_index.core.readers import SimpleDirectoryReader
DATA_DIR = "data" # directory to cache the generated index
DATA_DIR = "data" # directory containing the documents
def get_documents():
@@ -0,0 +1,14 @@
from llama_parse import LlamaParse
from llama_index.core import SimpleDirectoryReader
DATA_DIR = "data" # directory containing the documents
def get_documents():
parser = LlamaParse(
result_type="markdown",
verbose=True,
)
reader = SimpleDirectoryReader(DATA_DIR, file_extractor={".pdf": parser})
return reader.load_data()
+6
View File
@@ -1,5 +1,11 @@
# @llamaindex/env
## 0.0.5
### Patch Changes
- 5116ad8: fix: compatibility issue with Deno
## 0.0.4
### Patch Changes
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@llamaindex/env",
"version": "0.0.5",
"exports": {
".": "./src/index.ts",
"./type": "./src/type.ts"
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/env",
"description": "environment wrapper",
"version": "0.0.4",
"version": "0.0.5",
"type": "module",
"types": "dist/type/index.d.ts",
"main": "dist/cjs/index.js",
+1
View File
@@ -39,3 +39,4 @@ export function randomUUID(): string {
return crypto.randomUUID();
}
export * from "./type.js";
export { getEnv } from "./utils.js";
+2 -1
View File
@@ -34,5 +34,6 @@ export const defaultFS: CompleteFileSystem = {
stat: fs.stat,
};
export * from "./type.js";
export type * from "./type.js";
export { getEnv } from "./utils.js";
export { EOL, ok, path, randomUUID };
+1 -2
View File
@@ -58,9 +58,8 @@ export class InMemoryFileSystem implements CompleteFileSystem {
}
}
async mkdir(path: string) {
async mkdir(path: string): Promise<undefined> {
this.files[path] = _.get(this.files, path, null);
return undefined;
}
async readdir(path: string): Promise<string[]> {
+12
View File
@@ -0,0 +1,12 @@
export function getEnv(name: string): string | undefined {
if (typeof process === "undefined" || typeof process.env === "undefined") {
// @ts-expect-error
if (typeof Deno === "undefined") {
throw new Error("Current environment is not supported");
} else {
// @ts-expect-error
return Deno.env.get(name);
}
}
return process.env[name];
}
+1
View File
@@ -3,6 +3,7 @@
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist/type",
"tsBuildInfoFile": ".tsbuildinfo",
"emitDeclarationOnly": true,
"module": "node16",
"moduleResolution": "node16",
+1
View File
@@ -36,6 +36,7 @@ module.exports = {
"PINECONE_INDEX_NAME",
"PINECONE_CHUNK_SIZE",
"PINECONE_INDEX_NAME",
"PINECONE_NAMESPACE",
"AZURE_OPENAI_API_KEY",
"AZURE_OPENAI_API_INSTANCE_NAME",
+604 -21
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -11,7 +11,13 @@
"outDir": "./lib",
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"incremental": true,
"composite": true
"composite": true,
"paths": {
"llamaindex": ["./packages/core/src/index.ts"],
"llamaindex/*": ["./packages/core/src/*.ts"],
"@llamaindex/env": ["./packages/env/src/index.ts"],
"@llamaindex/env/*": ["./packages/env/src/*.ts"]
}
},
"files": [],
"references": [