mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-16 07:14:29 -04:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b2d43b532 | |||
| 02feb54070 | |||
| 9bf778eb36 | |||
| 746408b992 | |||
| ea64162b89 | |||
| 0094a2e420 | |||
| d13143e322 | |||
| 5116ad8d08 | |||
| 64683a55f3 | |||
| 698cd9c631 | |||
| c744a99102 | |||
| ef1e8b4121 | |||
| 2d2935085e | |||
| 1b31e2c8cd | |||
| 7257751993 | |||
| a20704bbf8 | |||
| de6bfdb1b1 | |||
| 9e49f4411b | |||
| 026d068ddf | |||
| 7055d6fc3c | |||
| e9c2366bf1 | |||
| 247a3d0b5f | |||
| 6278152e49 | |||
| 76010c0cea | |||
| 889b84cfb9 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"create-llama": patch
|
||||
---
|
||||
|
||||
Add LlamaParse option when selecting a pdf file or a folder
|
||||
@@ -44,6 +44,7 @@ test-results/
|
||||
playwright-report/
|
||||
blob-report/
|
||||
playwright/.cache/
|
||||
.tsbuildinfo
|
||||
|
||||
# intellij
|
||||
**/.idea
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# docs
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5116ad8]
|
||||
- @llamaindex/env@0.0.5
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.3",
|
||||
"version": "0.0.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(() => {
|
||||
@@ -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");
|
||||
});
|
||||
@@ -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
@@ -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`);
|
||||
})();
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -1 +1,3 @@
|
||||
.turbo
|
||||
README.md
|
||||
LICENSE
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "@llamaindex/core",
|
||||
"version": "0.1.20",
|
||||
"exports": "./src/index.ts",
|
||||
"imports": {
|
||||
"@llamaindex/env": "jsr:@llamaindex/env@0.0.5"
|
||||
}
|
||||
}
|
||||
@@ -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\""
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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, []);
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
@@ -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> = {};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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({});
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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.",
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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}.`;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./SQLWrapper.js";
|
||||
@@ -6,5 +6,13 @@
|
||||
"moduleResolution": "node16",
|
||||
"target": "ESNext"
|
||||
},
|
||||
"include": ["./**/*.ts"]
|
||||
"include": ["./**/*.ts"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../../env/tsconfig.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
Vendored
+6
@@ -1,5 +1,11 @@
|
||||
# @llamaindex/env
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 5116ad8: fix: compatibility issue with Deno
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "@llamaindex/env",
|
||||
"version": "0.0.5",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./type": "./src/type.ts"
|
||||
}
|
||||
}
|
||||
Vendored
+1
-1
@@ -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",
|
||||
|
||||
Vendored
+1
@@ -39,3 +39,4 @@ export function randomUUID(): string {
|
||||
return crypto.randomUUID();
|
||||
}
|
||||
export * from "./type.js";
|
||||
export { getEnv } from "./utils.js";
|
||||
|
||||
Vendored
+2
-1
@@ -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 };
|
||||
|
||||
Vendored
+1
-2
@@ -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[]> {
|
||||
|
||||
Vendored
+12
@@ -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];
|
||||
}
|
||||
Vendored
+1
@@ -3,6 +3,7 @@
|
||||
"compilerOptions": {
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist/type",
|
||||
"tsBuildInfoFile": ".tsbuildinfo",
|
||||
"emitDeclarationOnly": true,
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
|
||||
@@ -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",
|
||||
|
||||
Generated
+604
-21
File diff suppressed because it is too large
Load Diff
+7
-1
@@ -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": [
|
||||
|
||||
Reference in New Issue
Block a user