mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-11 00:04:07 -04:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5cb270d07f | |||
| 62771058aa | |||
| ca348a6570 | |||
| 44a7fd72e8 | |||
| d8d952d937 | |||
| 216ba1f22b | |||
| 74686f5776 | |||
| 1ebf9e67a4 | |||
| aeefc77da0 | |||
| 13d8d7cbbe | |||
| 9c34e44b85 | |||
| cb2dc802d9 | |||
| 5a6cc0e32e | |||
| a63256eb84 | |||
| 0a160b97a0 | |||
| 95602c7959 | |||
| 20bc466ca1 | |||
| efb1c56ba5 | |||
| 286499388d |
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
"@llamaindex/edge": patch
|
||||
---
|
||||
|
||||
refactor: use ollama official sdk
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
"llamaindex": patch
|
||||
"@llamaindex/edge": patch
|
||||
---
|
||||
|
||||
feat: support output to json format
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -14,7 +14,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Publish to GitHub Releases
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "llamaindex@*"
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build tarball
|
||||
run: |
|
||||
pnpm pack
|
||||
working-directory: packages/core
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "packages/core/llamaindex-*.tgz"
|
||||
name: Release ${{ github.ref }}
|
||||
bodyFile: "packages/core/CHANGELOG.md"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,57 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Add auth token to .npmrc file
|
||||
run: |
|
||||
cat << EOF >> ".npmrc"
|
||||
//registry.npmjs.org/:_authToken=$NPM_TOKEN
|
||||
EOF
|
||||
env:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Get changeset status
|
||||
id: get-changeset-status
|
||||
run: |
|
||||
pnpm changeset status --output .changeset/status.json
|
||||
new_version=$(jq -r '.releases[] | select(.name == "llamaindex") | .newVersion' < .changeset/status.json)
|
||||
rm -v .changeset/status.json
|
||||
echo "new-version=${new_version}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Create Release Pull Request or Publish to npm
|
||||
id: changesets
|
||||
uses: changesets/action@v1
|
||||
with:
|
||||
commit: Release ${{ steps.get-changeset-status.outputs.new-version }}
|
||||
title: Release ${{ steps.get-changeset-status.outputs.new-version }}
|
||||
# update version PR with the latest changesets
|
||||
version: pnpm new-version
|
||||
# build package and call changeset publish
|
||||
publish: pnpm release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
@@ -17,16 +17,18 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 21.x]
|
||||
node-version: [18.x, 20.x, 22.x]
|
||||
name: E2E on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
@@ -37,13 +39,13 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 21.x]
|
||||
node-version: [18.x, 20.x, 22.x]
|
||||
name: Test on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -58,7 +60,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -87,7 +89,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -105,7 +107,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: pnpm/action-setup@v3
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
|
||||
+5
-11
@@ -91,16 +91,10 @@ Please send a descriptive changeset for each PR.
|
||||
|
||||
## Publishing (maintainers only)
|
||||
|
||||
To publish a new version of the library, first create a new version:
|
||||
The [Release Github Action](.github/workflows/release.yml) is automatically generating and updating a
|
||||
PR called "Release {version}".
|
||||
|
||||
```shell
|
||||
pnpm new-version
|
||||
```
|
||||
This PR will update the `package.json` and `CHANGELOG.md` files of each package according to
|
||||
the current changesets in the [.changeset](.changeset/) folder.
|
||||
|
||||
If everything looks good, commit the generated files and release the new version:
|
||||
|
||||
```shell
|
||||
pnpm release
|
||||
git push # push to the main branch
|
||||
git push --tags
|
||||
```
|
||||
If this PR is merged it will automatically add version tags to the repository and publish the updated packages to NPM.
|
||||
|
||||
@@ -114,14 +114,21 @@ Add the following config to your `next.config.js` to ignore specific packages in
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
serverComponentsExternalPackages: ["pdf2json", "@zilliz/milvus2-sdk-node"],
|
||||
serverComponentsExternalPackages: [
|
||||
"pdf2json",
|
||||
"@zilliz/milvus2-sdk-node",
|
||||
"sharp",
|
||||
"onnxruntime-node",
|
||||
],
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
sharp$: false,
|
||||
"onnxruntime-node$": false,
|
||||
};
|
||||
config.externals.push({
|
||||
pdf2json: "commonjs pdf2json",
|
||||
"@zilliz/milvus2-sdk-node": "commonjs @zilliz/milvus2-sdk-node",
|
||||
sharp: "commonjs sharp",
|
||||
"onnxruntime-node": "commonjs onnxruntime-node",
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# docs
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6277105]
|
||||
- llamaindex@0.2.13
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d8d952d]
|
||||
- llamaindex@0.2.12
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [87142b2]
|
||||
- Updated dependencies [5a6cc0e]
|
||||
- Updated dependencies [87142b2]
|
||||
- llamaindex@0.2.11
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Gemini
|
||||
|
||||
To use Gemini embeddings, you need to import `GeminiEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { GeminiEmbedding, Settings } from "llamaindex";
|
||||
|
||||
// Update Embed Model
|
||||
Settings.embedModel = new GeminiEmbedding();
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
|
||||
Per default, `GeminiEmbedding` is using the `gemini-pro` model. You can change the model by passing the `model` parameter to the constructor.
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import { GEMINI_MODEL, GeminiEmbedding } from "llamaindex";
|
||||
|
||||
Settings.embedModel = new GeminiEmbedding({
|
||||
model: GEMINI_MODEL.GEMINI_PRO_LATEST,
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,21 @@
|
||||
# Jina AI
|
||||
|
||||
To use Jina AI embeddings, you need to import `JinaAIEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { JinaAIEmbedding, Settings } from "llamaindex";
|
||||
|
||||
Settings.embedModel = new JinaAIEmbedding();
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# Gemini
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Gemini, Settings, GEMINI_MODEL } from "llamaindex";
|
||||
|
||||
Settings.llm = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
```
|
||||
|
||||
## Load and index documents
|
||||
|
||||
For this example, we will use a single document. In a real-world scenario, you would have multiple documents to index.
|
||||
|
||||
```ts
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
```
|
||||
|
||||
## Query
|
||||
|
||||
```ts
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
Gemini,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
Settings,
|
||||
GEMINI_MODEL,
|
||||
} from "llamaindex";
|
||||
|
||||
Settings.llm = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
// Load and index documents
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
});
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
// Query
|
||||
const response = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
|
||||
// Log the response
|
||||
console.log(response.response);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# Jina AI Reranker
|
||||
|
||||
The Jina AI Reranker is a postprocessor that uses the Jina AI Reranker API to rerank the results of a search query.
|
||||
|
||||
## Setup
|
||||
|
||||
Firstly, you will need to install the `llamaindex` package.
|
||||
|
||||
```bash
|
||||
pnpm install llamaindex
|
||||
```
|
||||
|
||||
Now, you will need to sign up for an API key at [Jina AI](https://jina.ai/reranker). Once you have your API key you can import the necessary modules and create a new instance of the `JinaAIReranker` class.
|
||||
|
||||
```ts
|
||||
import {
|
||||
JinaAIReranker,
|
||||
Document,
|
||||
OpenAI,
|
||||
VectorStoreIndex,
|
||||
Settings,
|
||||
} from "llamaindex";
|
||||
```
|
||||
|
||||
## Load and index documents
|
||||
|
||||
For this example, we will use a single document. In a real-world scenario, you would have multiple documents to index.
|
||||
|
||||
```ts
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
Settings.llm = new OpenAI({ model: "gpt-3.5-turbo", temperature: 0.1 });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
```
|
||||
|
||||
## Increase similarity topK to retrieve more results
|
||||
|
||||
The default value for `similarityTopK` is 2. This means that only the most similar document will be returned. To retrieve more results, you can increase the value of `similarityTopK`.
|
||||
|
||||
```ts
|
||||
const retriever = index.asRetriever();
|
||||
retriever.similarityTopK = 5;
|
||||
```
|
||||
|
||||
## Create a new instance of the JinaAIReranker class
|
||||
|
||||
Then you can create a new instance of the `JinaAIReranker` class and pass in the number of results you want to return.
|
||||
The Jina AI Reranker API key is set in the `JINAAI_API_KEY` environment variable.
|
||||
|
||||
```bash
|
||||
export JINAAI_API_KEY=<YOUR API KEY>
|
||||
```
|
||||
|
||||
```ts
|
||||
const nodePostprocessor = new JinaAIReranker({
|
||||
topN: 5,
|
||||
});
|
||||
```
|
||||
|
||||
## Create a query engine with the retriever and node postprocessor
|
||||
|
||||
```ts
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
nodePostprocessors: [nodePostprocessor],
|
||||
});
|
||||
|
||||
// log the response
|
||||
const response = await queryEngine.query("Where did the author grown up?");
|
||||
```
|
||||
@@ -163,7 +163,7 @@ const config = {
|
||||
"docusaurus-plugin-typedoc",
|
||||
{
|
||||
entryPoints: ["../../packages/core/src/index.ts"],
|
||||
tsconfig: "../../packages/core/tsconfig.json",
|
||||
tsconfig: "../../tsconfig.json",
|
||||
readme: "none",
|
||||
sourceLinkTemplate:
|
||||
"https://github.com/run-llama/LlamaIndexTS/blob/{gitRevision}/{path}#L{line}",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
@@ -20,6 +20,7 @@
|
||||
"@llamaindex/examples": "workspace:*",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"clsx": "^2.1.0",
|
||||
"llamaindex": "workspace:*",
|
||||
"postcss": "^8.4.38",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { GEMINI_MODEL, GeminiEmbedding } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
if (!process.env.GOOGLE_API_KEY) {
|
||||
throw new Error("Please set the GOOGLE_API_KEY environment variable.");
|
||||
}
|
||||
const embedModel = new GeminiEmbedding({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
const texts = ["hello", "world"];
|
||||
const embeddings = await embedModel.getTextEmbeddingsBatch(texts);
|
||||
console.log(`\nWe have ${embeddings.length} embeddings`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Gemini, GEMINI_MODEL } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
if (!process.env.GOOGLE_API_KEY) {
|
||||
throw new Error("Please set the GOOGLE_API_KEY environment variable.");
|
||||
}
|
||||
const gemini = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
const result = await gemini.chat({
|
||||
messages: [
|
||||
{ content: "You want to talk in rhymes.", role: "system" },
|
||||
{
|
||||
content:
|
||||
"How much wood would a woodchuck chuck if a woodchuck could chuck wood?",
|
||||
role: "user",
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log(result);
|
||||
})();
|
||||
@@ -1,16 +1,5 @@
|
||||
import * as fs from "fs";
|
||||
import { ClipEmbedding, similarity, SimilarityType } from "llamaindex";
|
||||
|
||||
async function loadImageFromDisk(path: string) {
|
||||
try {
|
||||
const file = fs.readFileSync(path);
|
||||
return new Blob([file]);
|
||||
} catch (error) {
|
||||
console.error(`Error loading image from disk: ${error}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const clip = new ClipEmbedding();
|
||||
|
||||
@@ -23,8 +12,7 @@ async function main() {
|
||||
// Get image embedding
|
||||
const image =
|
||||
"https://huggingface.co/datasets/Xenova/transformers.js-docs/resolve/main/football-match.jpg";
|
||||
const blobImage = await loadImageFromDisk("./data/football-match.jpg");
|
||||
const imageEmbedding = await clip.getImageEmbedding(blobImage || image);
|
||||
const imageEmbedding = await clip.getImageEmbedding(image);
|
||||
|
||||
// Calc similarity
|
||||
const sim1 = similarity(
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB |
@@ -4,7 +4,6 @@ import {
|
||||
VectorStoreIndex,
|
||||
storageContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
import { DocStoreStrategy } from "llamaindex/ingestion/strategies/index";
|
||||
|
||||
import * as path from "path";
|
||||
|
||||
@@ -32,7 +31,6 @@ async function generateDatasource() {
|
||||
});
|
||||
await VectorStoreIndex.fromDocuments(documents, {
|
||||
storageContext,
|
||||
docStoreStrategy: DocStoreStrategy.NONE,
|
||||
});
|
||||
});
|
||||
console.log(`Storage successfully generated in ${ms / 1000}s.`);
|
||||
|
||||
@@ -3,20 +3,21 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node --loader ts-node/esm ./src/simple-directory-reader.ts",
|
||||
"start:csv": "node --loader ts-node/esm ./src/csv.ts",
|
||||
"start:docx": "node --loader ts-node/esm ./src/docx.ts",
|
||||
"start:html": "node --loader ts-node/esm ./src/html.ts",
|
||||
"start:markdown": "node --loader ts-node/esm ./src/markdown.ts",
|
||||
"start:pdf": "node --loader ts-node/esm ./src/pdf.ts",
|
||||
"start:llamaparse": "node --loader ts-node/esm ./src/llamaparse.ts"
|
||||
"start": "node --import tsx ./src/simple-directory-reader.ts",
|
||||
"start:csv": "node --import tsx ./src/csv.ts",
|
||||
"start:docx": "node --import tsx ./src/docx.ts",
|
||||
"start:html": "node --import tsx ./src/html.ts",
|
||||
"start:markdown": "node --import tsx ./src/markdown.ts",
|
||||
"start:pdf": "node --import tsx ./src/pdf.ts",
|
||||
"start:llamaparse": "node --import tsx ./src/llamaparse.ts",
|
||||
"start:notion": "node --import tsx ./src/notion.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.7",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.3"
|
||||
"tsx": "^4.7.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { createInterface } from "node:readline/promises";
|
||||
|
||||
program
|
||||
.argument("[page]", "Notion page id (must be provided)")
|
||||
.action(async (page, _options, command) => {
|
||||
.action(async (page, _options) => {
|
||||
// Initializing a client
|
||||
|
||||
if (!process.env.NOTION_TOKEN) {
|
||||
@@ -55,7 +55,7 @@ program
|
||||
.filter((page) => page !== null);
|
||||
console.log("Found pages:");
|
||||
console.table(pages);
|
||||
console.log(`To run, run ts-node ${command.name()} [page id]`);
|
||||
console.log(`To run, run with [page id]`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
.turbo
|
||||
/README.md
|
||||
LICENSE
|
||||
LICENSE
|
||||
*.tgz
|
||||
@@ -1,5 +1,25 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6277105: fix: allow passing empty tools to llms
|
||||
|
||||
## 0.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d8d952d: feat: add gemini llm and embedding
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 87142b2: refactor: use ollama official sdk
|
||||
- 5a6cc0e: feat: support jina ai embedding and reranker
|
||||
- 87142b2: feat: support output to json format
|
||||
|
||||
## 0.2.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -2,7 +2,7 @@ import { consola } from "consola";
|
||||
import { Anthropic, FunctionTool, Settings, type LLM } from "llamaindex";
|
||||
import { AnthropicAgent } from "llamaindex/agent/anthropic";
|
||||
import { extractText } from "llamaindex/llm/utils";
|
||||
import { ok } from "node:assert";
|
||||
import { ok, strictEqual } from "node:assert";
|
||||
import { beforeEach, test } from "node:test";
|
||||
import { sumNumbersTool } from "./fixtures/tools.js";
|
||||
import { mockLLMEvent } from "./utils.js";
|
||||
@@ -71,10 +71,12 @@ await test("anthropic agent", async (t) => {
|
||||
},
|
||||
],
|
||||
});
|
||||
const { response } = await agent.chat({
|
||||
const { response, sources } = await agent.chat({
|
||||
message: "What is the weather in San Francisco?",
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
|
||||
strictEqual(sources.length, 1);
|
||||
ok(extractText(response.message.content).includes("35"));
|
||||
});
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
SummaryIndex,
|
||||
VectorStoreIndex,
|
||||
type LLM,
|
||||
type ToolOutput,
|
||||
} from "llamaindex";
|
||||
import { extractText } from "llamaindex/llm/utils";
|
||||
import { ok, strictEqual } from "node:assert";
|
||||
@@ -222,10 +223,12 @@ await test("agent with object function call", async (t) => {
|
||||
),
|
||||
],
|
||||
});
|
||||
const { response } = await agent.chat({
|
||||
const { response, sources } = await agent.chat({
|
||||
message: "What is the weather in San Francisco?",
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
|
||||
strictEqual(sources.length, 1);
|
||||
ok(extractText(response.message.content).includes("72"));
|
||||
});
|
||||
});
|
||||
@@ -253,10 +256,12 @@ await test("agent", async (t) => {
|
||||
},
|
||||
],
|
||||
});
|
||||
const { response } = await agent.chat({
|
||||
const { response, sources } = await agent.chat({
|
||||
message: "What is the weather in San Francisco?",
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
|
||||
strictEqual(sources.length, 1);
|
||||
ok(extractText(response.message.content).includes("35"));
|
||||
});
|
||||
|
||||
@@ -290,9 +295,10 @@ await test("agent", async (t) => {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [showUniqueId],
|
||||
});
|
||||
const { response } = await agent.chat({
|
||||
const { response, sources } = await agent.chat({
|
||||
message: "My name is Alex Yang. What is my unique id?",
|
||||
});
|
||||
strictEqual(sources.length, 1);
|
||||
ok(extractText(response.message.content).includes(uniqueId));
|
||||
});
|
||||
|
||||
@@ -301,10 +307,11 @@ await test("agent", async (t) => {
|
||||
tools: [sumNumbersTool],
|
||||
});
|
||||
|
||||
const { response } = await openaiAgent.chat({
|
||||
const { response, sources } = await openaiAgent.chat({
|
||||
message: "how much is 1 + 1?",
|
||||
});
|
||||
|
||||
strictEqual(sources.length, 1);
|
||||
ok(extractText(response.message.content).includes("2"));
|
||||
});
|
||||
});
|
||||
@@ -319,18 +326,21 @@ await test("agent stream", async (t) => {
|
||||
tools: [sumNumbersTool, divideNumbersTool],
|
||||
});
|
||||
|
||||
const { response } = await agent.chat({
|
||||
const stream = await agent.chat({
|
||||
message: "Divide 16 by 2 then add 20",
|
||||
stream: true,
|
||||
});
|
||||
|
||||
let message = "";
|
||||
let soruces: ToolOutput[] = [];
|
||||
|
||||
for await (const chunk of response) {
|
||||
message += chunk.delta;
|
||||
for await (const { response, sources: _sources } of stream) {
|
||||
message += response.delta;
|
||||
soruces = _sources;
|
||||
}
|
||||
|
||||
strictEqual(fn.mock.callCount(), 2);
|
||||
strictEqual(soruces.length, 2);
|
||||
ok(message.includes("28"));
|
||||
Settings.callbackManager.off("llm-tool-call", fn);
|
||||
});
|
||||
|
||||
@@ -4,14 +4,11 @@
|
||||
"outDir": "./lib",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"target": "ESNext"
|
||||
"target": "ESNext",
|
||||
"lib": ["ES2022"],
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": [
|
||||
"./**/*.ts",
|
||||
"./mock-module.js",
|
||||
"./mock-register.js",
|
||||
"./fixtures"
|
||||
],
|
||||
"include": ["./node", "./mock-module.js", "./mock-register.js", "./fixtures"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../core/tsconfig.json"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.2.10",
|
||||
"version": "0.2.13",
|
||||
"expectedMinorVersion": "2",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@@ -8,11 +8,11 @@
|
||||
"@anthropic-ai/sdk": "^0.20.6",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@datastax/astra-db-ts": "^1.0.1",
|
||||
"@google/generative-ai": "^0.8.0",
|
||||
"@grpc/grpc-js": "^1.10.6",
|
||||
"@llamaindex/cloud": "0.0.5",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@mistralai/mistralai": "^0.1.3",
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@pinecone-database/pinecone": "^2.2.0",
|
||||
"@qdrant/js-client-rest": "^1.8.2",
|
||||
"@types/lodash": "^4.17.0",
|
||||
@@ -31,7 +31,7 @@
|
||||
"mammoth": "^1.7.1",
|
||||
"md-utils-ts": "^2.0.0",
|
||||
"mongodb": "^6.5.0",
|
||||
"notion-md-crawler": "^0.0.2",
|
||||
"notion-md-crawler": "^1.0.0",
|
||||
"ollama": "^0.5.0",
|
||||
"openai": "^4.38.0",
|
||||
"papaparse": "^5.4.1",
|
||||
@@ -45,7 +45,11 @@
|
||||
"wikipedia": "^2.1.2",
|
||||
"wink-nlp": "^1.14.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@notionhq/client": "^2.2.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@swc/cli": "^0.3.12",
|
||||
"@swc/core": "^1.4.16",
|
||||
"concurrently": "^8.2.2",
|
||||
|
||||
@@ -326,6 +326,37 @@ export class ImageNode<T extends Metadata = Metadata> extends TextNode<T> {
|
||||
const absPath = path.resolve(this.id_);
|
||||
return new URL(`file://${absPath}`);
|
||||
}
|
||||
|
||||
// Calculates the image part of the hash
|
||||
private generateImageHash() {
|
||||
const hashFunction = createSHA256();
|
||||
|
||||
if (this.image instanceof Blob) {
|
||||
// TODO: ideally we should use the blob's content to calculate the hash:
|
||||
// hashFunction.update(new Uint8Array(await this.image.arrayBuffer()));
|
||||
// as this is async, we're using the node's ID for the time being
|
||||
hashFunction.update(this.id_);
|
||||
} else if (this.image instanceof URL) {
|
||||
hashFunction.update(this.image.toString());
|
||||
} else if (typeof this.image === "string") {
|
||||
hashFunction.update(this.image);
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unknown image type: ${typeof this.image}. Can't calculate hash`,
|
||||
);
|
||||
}
|
||||
|
||||
return hashFunction.digest();
|
||||
}
|
||||
|
||||
generateHash() {
|
||||
const hashFunction = createSHA256();
|
||||
// calculates hash based on hash of both components (image and text)
|
||||
hashFunction.update(super.generateHash());
|
||||
hashFunction.update(this.generateImageHash());
|
||||
|
||||
return hashFunction.digest();
|
||||
}
|
||||
}
|
||||
|
||||
export class ImageDocument<T extends Metadata = Metadata> extends ImageNode<T> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { pipeline, randomUUID } from "@llamaindex/env";
|
||||
import {
|
||||
type ChatEngine,
|
||||
type ChatEngineParamsNonStreaming,
|
||||
type ChatEngineParamsStreaming,
|
||||
} from "../engines/chat/index.js";
|
||||
@@ -171,8 +172,9 @@ export async function* createTaskImpl<
|
||||
}
|
||||
|
||||
export type AgentStreamChatResponse<Options extends object> = {
|
||||
response: ReadableStream<ChatResponseChunk<Options>>;
|
||||
sources: ToolOutput[];
|
||||
response: ChatResponseChunk<Options>;
|
||||
// sources of the response, will emit when new tool outputs are available
|
||||
sources?: ToolOutput[];
|
||||
};
|
||||
|
||||
export type AgentChatResponse<Options extends object> = {
|
||||
@@ -276,7 +278,12 @@ export abstract class AgentRunner<
|
||||
>
|
||||
? AdditionalMessageOptions
|
||||
: never,
|
||||
> {
|
||||
> implements
|
||||
ChatEngine<
|
||||
AgentChatResponse<AdditionalMessageOptions>,
|
||||
ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
|
||||
>
|
||||
{
|
||||
readonly #llm: AI;
|
||||
readonly #tools:
|
||||
| BaseToolWithCall[]
|
||||
@@ -370,13 +377,13 @@ export abstract class AgentRunner<
|
||||
): Promise<AgentChatResponse<AdditionalMessageOptions>>;
|
||||
async chat(
|
||||
params: ChatEngineParamsStreaming,
|
||||
): Promise<AgentStreamChatResponse<AdditionalMessageOptions>>;
|
||||
): Promise<ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>>;
|
||||
@wrapEventCaller
|
||||
async chat(
|
||||
params: ChatEngineParamsNonStreaming | ChatEngineParamsStreaming,
|
||||
): Promise<
|
||||
| AgentChatResponse<AdditionalMessageOptions>
|
||||
| AgentStreamChatResponse<AdditionalMessageOptions>
|
||||
| ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
|
||||
> {
|
||||
const task = await this.createTask(params.message, !!params.stream);
|
||||
const stepOutput = await pipeline(
|
||||
@@ -397,14 +404,26 @@ export abstract class AgentRunner<
|
||||
const { output, taskStep } = stepOutput;
|
||||
this.#chatHistory = [...taskStep.context.store.messages];
|
||||
if (isAsyncIterable(output)) {
|
||||
return {
|
||||
response: output,
|
||||
sources: [...taskStep.context.store.toolOutputs],
|
||||
} satisfies AgentStreamChatResponse<AdditionalMessageOptions>;
|
||||
return output.pipeThrough<
|
||||
AgentStreamChatResponse<AdditionalMessageOptions>
|
||||
>(
|
||||
new TransformStream({
|
||||
transform(chunk, controller) {
|
||||
controller.enqueue({
|
||||
response: chunk,
|
||||
get sources() {
|
||||
return [...taskStep.context.store.toolOutputs];
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
return {
|
||||
response: output,
|
||||
sources: [...taskStep.context.store.toolOutputs],
|
||||
get sources() {
|
||||
return [...taskStep.context.store.toolOutputs];
|
||||
},
|
||||
} satisfies AgentChatResponse<AdditionalMessageOptions>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine.js";
|
||||
import type { TransformComponent } from "../ingestion/types.js";
|
||||
import type { BaseNodePostprocessor } from "../postprocessors/types.js";
|
||||
import type { BaseSynthesizer } from "../synthesizers/types.js";
|
||||
import type { BaseQueryEngine } from "../types.js";
|
||||
import type { QueryEngine } from "../types.js";
|
||||
import type { CloudRetrieveParams } from "./LlamaCloudRetriever.js";
|
||||
import { LlamaCloudRetriever } from "./LlamaCloudRetriever.js";
|
||||
import { getPipelineCreate } from "./config.js";
|
||||
@@ -178,7 +178,7 @@ export class LlamaCloudIndex {
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
} & CloudRetrieveParams,
|
||||
): BaseQueryEngine {
|
||||
): QueryEngine {
|
||||
const retriever = new LlamaCloudRetriever({
|
||||
...this.params,
|
||||
...params,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
GEMINI_MODEL,
|
||||
GeminiSessionStore,
|
||||
type GeminiConfig,
|
||||
type GeminiSession,
|
||||
} from "../llm/gemini.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
|
||||
/**
|
||||
* GeminiEmbedding is an alias for Gemini that implements the BaseEmbedding interface.
|
||||
*/
|
||||
export class GeminiEmbedding extends BaseEmbedding {
|
||||
model: GEMINI_MODEL;
|
||||
temperature: number;
|
||||
topP: number;
|
||||
maxTokens?: number;
|
||||
session: GeminiSession;
|
||||
|
||||
constructor(init?: GeminiConfig) {
|
||||
super();
|
||||
this.model = init?.model ?? GEMINI_MODEL.GEMINI_PRO;
|
||||
this.temperature = init?.temperature ?? 0.1;
|
||||
this.topP = init?.topP ?? 1;
|
||||
this.maxTokens = init?.maxTokens ?? undefined;
|
||||
this.session = init?.session ?? GeminiSessionStore.get();
|
||||
}
|
||||
|
||||
private async getEmbedding(prompt: string): Promise<number[]> {
|
||||
const client = this.session.gemini.getGenerativeModel({
|
||||
model: this.model,
|
||||
});
|
||||
const result = await client.embedContent(prompt);
|
||||
return result.embedding.values;
|
||||
}
|
||||
|
||||
getTextEmbedding(text: string): Promise<number[]> {
|
||||
return this.getEmbedding(text);
|
||||
}
|
||||
|
||||
getQueryEmbedding(query: string): Promise<number[]> {
|
||||
return this.getTextEmbedding(query);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { getEnv } from "@llamaindex/env";
|
||||
import { OpenAIEmbedding } from "./OpenAIEmbedding.js";
|
||||
|
||||
export class JinaAIEmbedding extends OpenAIEmbedding {
|
||||
constructor(init?: Partial<OpenAIEmbedding>) {
|
||||
const {
|
||||
apiKey = getEnv("JINAAI_API_KEY"),
|
||||
additionalSessionOptions = {},
|
||||
model = "jina-embeddings-v2-base-en",
|
||||
...rest
|
||||
} = init ?? {};
|
||||
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
"Set Jina AI API Key in JINAAI_API_KEY env variable. Get one for free or top up your key at https://jina.ai/embeddings",
|
||||
);
|
||||
}
|
||||
|
||||
additionalSessionOptions.baseURL =
|
||||
additionalSessionOptions.baseURL ?? "https://api.jina.ai/v1";
|
||||
|
||||
super({
|
||||
apiKey,
|
||||
additionalSessionOptions,
|
||||
model,
|
||||
...rest,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
export * from "./ClipEmbedding.js";
|
||||
export * from "./GeminiEmbedding.js";
|
||||
export * from "./HuggingFaceEmbedding.js";
|
||||
export * from "./JinaAIEmbedding.js";
|
||||
export * from "./MistralAIEmbedding.js";
|
||||
export * from "./MultiModalEmbedding.js";
|
||||
export { OllamaEmbedding } from "./OllamaEmbedding.js";
|
||||
|
||||
@@ -12,7 +12,7 @@ import { wrapEventCaller } from "../../internal/context/EventCaller.js";
|
||||
import type { ChatMessage, LLM } from "../../llm/index.js";
|
||||
import { extractText, streamReducer } from "../../llm/utils.js";
|
||||
import { PromptMixin } from "../../prompts/index.js";
|
||||
import type { BaseQueryEngine } from "../../types.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type {
|
||||
ChatEngine,
|
||||
ChatEngineParamsNonStreaming,
|
||||
@@ -33,13 +33,13 @@ export class CondenseQuestionChatEngine
|
||||
extends PromptMixin
|
||||
implements ChatEngine
|
||||
{
|
||||
queryEngine: BaseQueryEngine;
|
||||
queryEngine: QueryEngine;
|
||||
chatHistory: ChatHistory;
|
||||
llm: LLM;
|
||||
condenseMessagePrompt: CondenseQuestionPrompt;
|
||||
|
||||
constructor(init: {
|
||||
queryEngine: BaseQueryEngine;
|
||||
queryEngine: QueryEngine;
|
||||
chatHistory: ChatMessage[];
|
||||
serviceContext?: ServiceContext;
|
||||
condenseMessagePrompt?: CondenseQuestionPrompt;
|
||||
|
||||
@@ -23,21 +23,21 @@ export interface ChatEngineParamsNonStreaming extends ChatEngineParamsBase {
|
||||
stream?: false | null;
|
||||
}
|
||||
|
||||
export interface ChatEngineAgentParams extends ChatEngineParamsBase {
|
||||
toolChoice?: string | Record<string, any>;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ChatEngine is used to handle back and forth chats between the application and the LLM.
|
||||
*/
|
||||
export interface ChatEngine {
|
||||
export interface ChatEngine<
|
||||
// synchronous response
|
||||
R = Response,
|
||||
// asynchronous response
|
||||
AR extends AsyncIterable<unknown> = AsyncIterable<R>,
|
||||
> {
|
||||
/**
|
||||
* Send message along with the class's current chat history to the LLM.
|
||||
* @param params
|
||||
*/
|
||||
chat(params: ChatEngineParamsStreaming): Promise<AsyncIterable<Response>>;
|
||||
chat(params: ChatEngineParamsNonStreaming): Promise<Response>;
|
||||
chat(params: ChatEngineParamsStreaming): Promise<AR>;
|
||||
chat(params: ChatEngineParamsNonStreaming): Promise<R>;
|
||||
|
||||
/**
|
||||
* Resets the chat history so that it's empty.
|
||||
|
||||
@@ -7,7 +7,7 @@ import { PromptMixin } from "../../prompts/Mixin.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/index.js";
|
||||
import { ResponseSynthesizer } from "../../synthesizers/index.js";
|
||||
import type {
|
||||
BaseQueryEngine,
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "../../types.js";
|
||||
@@ -15,10 +15,7 @@ import type {
|
||||
/**
|
||||
* A query engine that uses a retriever to query an index and then synthesizes the response.
|
||||
*/
|
||||
export class RetrieverQueryEngine
|
||||
extends PromptMixin
|
||||
implements BaseQueryEngine
|
||||
{
|
||||
export class RetrieverQueryEngine extends PromptMixin implements QueryEngine {
|
||||
retriever: BaseRetriever;
|
||||
responseSynthesizer: BaseSynthesizer;
|
||||
nodePostprocessors: BaseNodePostprocessor[];
|
||||
|
||||
@@ -7,14 +7,14 @@ import type { BaseSelector } from "../../selectors/index.js";
|
||||
import { LLMSingleSelector } from "../../selectors/index.js";
|
||||
import { TreeSummarize } from "../../synthesizers/index.js";
|
||||
import type {
|
||||
BaseQueryEngine,
|
||||
QueryBundle,
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "../../types.js";
|
||||
|
||||
type RouterQueryEngineTool = {
|
||||
queryEngine: BaseQueryEngine;
|
||||
queryEngine: QueryEngine;
|
||||
description: string;
|
||||
};
|
||||
|
||||
@@ -54,9 +54,9 @@ async function combineResponses(
|
||||
/**
|
||||
* A query engine that uses multiple query engines and selects the best one.
|
||||
*/
|
||||
export class RouterQueryEngine extends PromptMixin implements BaseQueryEngine {
|
||||
export class RouterQueryEngine extends PromptMixin implements QueryEngine {
|
||||
private selector: BaseSelector;
|
||||
private queryEngines: BaseQueryEngine[];
|
||||
private queryEngines: QueryEngine[];
|
||||
private metadatas: RouterQueryEngineMetadata[];
|
||||
private summarizer: TreeSummarize;
|
||||
private verbose: boolean;
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
} from "../../synthesizers/index.js";
|
||||
|
||||
import type {
|
||||
BaseQueryEngine,
|
||||
BaseTool,
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
ToolMetadata,
|
||||
@@ -24,10 +24,7 @@ import type { BaseQuestionGenerator, SubQuestion } from "./types.js";
|
||||
/**
|
||||
* SubQuestionQueryEngine decomposes a question into subquestions and then
|
||||
*/
|
||||
export class SubQuestionQueryEngine
|
||||
extends PromptMixin
|
||||
implements BaseQueryEngine
|
||||
{
|
||||
export class SubQuestionQueryEngine extends PromptMixin implements QueryEngine {
|
||||
responseSynthesizer: BaseSynthesizer;
|
||||
questionGen: BaseQuestionGenerator;
|
||||
queryEngines: BaseTool[];
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { BaseDocumentStore } from "../storage/docStore/types.js";
|
||||
import type { BaseIndexStore } from "../storage/indexStore/types.js";
|
||||
import type { VectorStore } from "../storage/vectorStore/types.js";
|
||||
import type { BaseSynthesizer } from "../synthesizers/types.js";
|
||||
import type { BaseQueryEngine } from "../types.js";
|
||||
import type { QueryEngine } from "../types.js";
|
||||
import { IndexStruct } from "./IndexStruct.js";
|
||||
import { IndexStructType } from "./json-to-index-struct.js";
|
||||
|
||||
@@ -87,7 +87,7 @@ export abstract class BaseIndex<T> {
|
||||
abstract asQueryEngine(options?: {
|
||||
retriever?: BaseRetriever;
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
}): BaseQueryEngine;
|
||||
}): QueryEngine;
|
||||
|
||||
/**
|
||||
* Insert a document into the index.
|
||||
|
||||
@@ -17,7 +17,7 @@ import type { StorageContext } from "../../storage/StorageContext.js";
|
||||
import { storageContextFromDefaults } from "../../storage/StorageContext.js";
|
||||
import type { BaseDocumentStore } from "../../storage/docStore/types.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/index.js";
|
||||
import type { BaseQueryEngine } from "../../types.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type { BaseIndexInit } from "../BaseIndex.js";
|
||||
import { BaseIndex, KeywordTable } from "../BaseIndex.js";
|
||||
import { IndexStructType } from "../json-to-index-struct.js";
|
||||
@@ -234,7 +234,7 @@ export class KeywordTableIndex extends BaseIndex<KeywordTable> {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
}): BaseQueryEngine {
|
||||
}): QueryEngine {
|
||||
const { retriever, responseSynthesizer } = options ?? {};
|
||||
return new RetrieverQueryEngine(
|
||||
retriever ?? this.asRetriever(),
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
CompactAndRefine,
|
||||
ResponseSynthesizer,
|
||||
} from "../../synthesizers/index.js";
|
||||
import type { BaseQueryEngine } from "../../types.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type { BaseIndexInit } from "../BaseIndex.js";
|
||||
import { BaseIndex } from "../BaseIndex.js";
|
||||
import { IndexList, IndexStructType } from "../json-to-index-struct.js";
|
||||
@@ -171,7 +171,7 @@ export class SummaryIndex extends BaseIndex<IndexList> {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
}): BaseQueryEngine & RetrieverQueryEngine {
|
||||
}): QueryEngine & RetrieverQueryEngine {
|
||||
let { retriever, responseSynthesizer } = options ?? {};
|
||||
|
||||
if (!retriever) {
|
||||
|
||||
@@ -37,7 +37,7 @@ import type {
|
||||
import type { BaseIndexStore } from "../../storage/indexStore/types.js";
|
||||
import { VectorStoreQueryMode } from "../../storage/vectorStore/types.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/types.js";
|
||||
import type { BaseQueryEngine } from "../../types.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type { BaseIndexInit } from "../BaseIndex.js";
|
||||
import { BaseIndex } from "../BaseIndex.js";
|
||||
import { IndexDict, IndexStructType } from "../json-to-index-struct.js";
|
||||
@@ -284,7 +284,7 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: MetadataFilters;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
}): BaseQueryEngine & RetrieverQueryEngine {
|
||||
}): QueryEngine & RetrieverQueryEngine {
|
||||
const { retriever, responseSynthesizer } = options ?? {};
|
||||
return new RetrieverQueryEngine(
|
||||
retriever ?? this.asRetriever(),
|
||||
|
||||
@@ -94,20 +94,20 @@ export class IngestionPipeline {
|
||||
documents?: Document[],
|
||||
nodes?: BaseNode[],
|
||||
): Promise<BaseNode[]> {
|
||||
const inputNodes: BaseNode[] = [];
|
||||
const inputNodes: BaseNode[][] = [];
|
||||
if (documents) {
|
||||
inputNodes.push(...documents);
|
||||
inputNodes.push(documents);
|
||||
}
|
||||
if (nodes) {
|
||||
inputNodes.push(...nodes);
|
||||
inputNodes.push(nodes);
|
||||
}
|
||||
if (this.documents) {
|
||||
inputNodes.push(...this.documents);
|
||||
inputNodes.push(this.documents);
|
||||
}
|
||||
if (this.reader) {
|
||||
inputNodes.push(...(await this.reader.loadData()));
|
||||
inputNodes.push(await this.reader.loadData());
|
||||
}
|
||||
return inputNodes;
|
||||
return inputNodes.flat();
|
||||
}
|
||||
|
||||
async run(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ClientOptions } from "@anthropic-ai/sdk";
|
||||
import { Anthropic as SDKAnthropic } from "@anthropic-ai/sdk";
|
||||
import type {
|
||||
MessageCreateParamsNonStreaming,
|
||||
Tool,
|
||||
ToolResultBlockParam,
|
||||
ToolUseBlock,
|
||||
@@ -264,7 +265,7 @@ export class Anthropic extends ToolCallLLM<AnthropicAdditionalChatOptions> {
|
||||
const anthropic = this.session.anthropic;
|
||||
|
||||
if (tools) {
|
||||
const response = await anthropic.beta.tools.messages.create({
|
||||
const params: MessageCreateParamsNonStreaming = {
|
||||
messages: this.formatMessages<true>(messages),
|
||||
tools: tools.map(Anthropic.toTool),
|
||||
model: this.getModelName(this.model),
|
||||
@@ -272,7 +273,12 @@ export class Anthropic extends ToolCallLLM<AnthropicAdditionalChatOptions> {
|
||||
max_tokens: this.maxTokens ?? 4096,
|
||||
top_p: this.topP,
|
||||
...(systemPrompt && { system: systemPrompt }),
|
||||
});
|
||||
};
|
||||
// Remove tools if there are none, as it will cause an error
|
||||
if (tools.length === 0) {
|
||||
delete params.tools;
|
||||
}
|
||||
const response = await anthropic.beta.tools.messages.create(params);
|
||||
|
||||
const toolUseBlock = response.content.find(
|
||||
(content): content is ToolUseBlock => content.type === "tool_use",
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
import {
|
||||
ChatSession,
|
||||
GoogleGenerativeAI,
|
||||
type Content as GeminiMessageContent,
|
||||
type Part,
|
||||
} from "@google/generative-ai";
|
||||
import { getEnv } from "@llamaindex/env";
|
||||
import { ToolCallLLM } from "./base.js";
|
||||
import type {
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
ChatResponseChunk,
|
||||
CompletionResponse,
|
||||
LLMChatParamsNonStreaming,
|
||||
LLMChatParamsStreaming,
|
||||
LLMCompletionParamsNonStreaming,
|
||||
LLMCompletionParamsStreaming,
|
||||
LLMMetadata,
|
||||
MessageContent,
|
||||
MessageContentImageDetail,
|
||||
MessageContentTextDetail,
|
||||
MessageType,
|
||||
ToolCallLLMMessageOptions,
|
||||
} from "./types.js";
|
||||
import { streamConverter, wrapLLMEvent } from "./utils.js";
|
||||
|
||||
// Session and Model Type Definitions
|
||||
type GeminiSessionOptions = {
|
||||
apiKey?: string;
|
||||
};
|
||||
|
||||
export enum GEMINI_MODEL {
|
||||
GEMINI_PRO = "gemini-pro",
|
||||
GEMINI_PRO_VISION = "gemini-pro-vision",
|
||||
EMBEDDING_001 = "embedding-001",
|
||||
AQA = "aqa",
|
||||
GEMINI_PRO_LATEST = "gemini-1.5-pro-latest",
|
||||
}
|
||||
|
||||
export interface GeminiModelInfo {
|
||||
contextWindow: number;
|
||||
}
|
||||
|
||||
export const GEMINI_MODEL_INFO_MAP: Record<GEMINI_MODEL, GeminiModelInfo> = {
|
||||
[GEMINI_MODEL.GEMINI_PRO]: { contextWindow: 30720 },
|
||||
[GEMINI_MODEL.GEMINI_PRO_VISION]: { contextWindow: 12288 },
|
||||
[GEMINI_MODEL.EMBEDDING_001]: { contextWindow: 2048 },
|
||||
[GEMINI_MODEL.AQA]: { contextWindow: 7168 },
|
||||
[GEMINI_MODEL.GEMINI_PRO_LATEST]: { contextWindow: 10 ** 6 },
|
||||
};
|
||||
|
||||
const SUPPORT_TOOL_CALL_MODELS: GEMINI_MODEL[] = [
|
||||
GEMINI_MODEL.GEMINI_PRO,
|
||||
GEMINI_MODEL.GEMINI_PRO_VISION,
|
||||
GEMINI_MODEL.EMBEDDING_001,
|
||||
GEMINI_MODEL.AQA,
|
||||
];
|
||||
|
||||
const DEFAULT_GEMINI_PARAMS = {
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
temperature: 0.1,
|
||||
topP: 1,
|
||||
maxTokens: undefined,
|
||||
};
|
||||
|
||||
export type GeminiConfig = Partial<typeof DEFAULT_GEMINI_PARAMS> & {
|
||||
session?: GeminiSession;
|
||||
};
|
||||
|
||||
/// Chat Type Definitions
|
||||
type GeminiMessageRole = "user" | "model";
|
||||
|
||||
export type GeminiAdditionalChatOptions = {};
|
||||
|
||||
export type GeminiChatParamsStreaming = LLMChatParamsStreaming<
|
||||
GeminiAdditionalChatOptions,
|
||||
ToolCallLLMMessageOptions
|
||||
>;
|
||||
|
||||
export type GeminiChatStreamResponse = AsyncIterable<
|
||||
ChatResponseChunk<ToolCallLLMMessageOptions>
|
||||
>;
|
||||
|
||||
export type GeminiChatParamsNonStreaming = LLMChatParamsNonStreaming<
|
||||
GeminiAdditionalChatOptions,
|
||||
ToolCallLLMMessageOptions
|
||||
>;
|
||||
|
||||
export type GeminiChatNonStreamResponse =
|
||||
ChatResponse<ToolCallLLMMessageOptions>;
|
||||
|
||||
/**
|
||||
* Gemini Session to manage the connection to the Gemini API
|
||||
*/
|
||||
export class GeminiSession {
|
||||
gemini: GoogleGenerativeAI;
|
||||
|
||||
constructor(options: GeminiSessionOptions) {
|
||||
if (!options.apiKey) {
|
||||
options.apiKey = getEnv("GOOGLE_API_KEY");
|
||||
}
|
||||
if (!options.apiKey) {
|
||||
throw new Error("Set Google API Key in GOOGLE_API_KEY env variable");
|
||||
}
|
||||
this.gemini = new GoogleGenerativeAI(options.apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gemini Session Store to manage the current Gemini sessions
|
||||
*/
|
||||
export class GeminiSessionStore {
|
||||
static sessions: Array<{
|
||||
session: GeminiSession;
|
||||
options: GeminiSessionOptions;
|
||||
}> = [];
|
||||
|
||||
private static sessionMatched(
|
||||
o1: GeminiSessionOptions,
|
||||
o2: GeminiSessionOptions,
|
||||
): boolean {
|
||||
return o1.apiKey === o2.apiKey;
|
||||
}
|
||||
|
||||
static get(options: GeminiSessionOptions = {}): GeminiSession {
|
||||
let session = this.sessions.find((session) =>
|
||||
this.sessionMatched(session.options, options),
|
||||
)?.session;
|
||||
if (!session) {
|
||||
session = new GeminiSession(options);
|
||||
this.sessions.push({ session, options });
|
||||
}
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class providing utility functions for Gemini
|
||||
*/
|
||||
class GeminiHelper {
|
||||
// Gemini only has user and model roles. Put the rest in user role.
|
||||
public static readonly ROLES_TO_GEMINI: Record<
|
||||
MessageType,
|
||||
GeminiMessageRole
|
||||
> = {
|
||||
user: "user",
|
||||
system: "user",
|
||||
assistant: "user",
|
||||
memory: "user",
|
||||
};
|
||||
|
||||
public static readonly ROLES_FROM_GEMINI: Record<
|
||||
GeminiMessageRole,
|
||||
MessageType
|
||||
> = {
|
||||
user: "user",
|
||||
model: "assistant",
|
||||
};
|
||||
|
||||
public static mergeNeighboringSameRoleMessages(
|
||||
messages: ChatMessage[],
|
||||
): ChatMessage[] {
|
||||
// Gemini does not support multiple messages of the same role in a row, so we merge them
|
||||
const mergedMessages: ChatMessage[] = [];
|
||||
let i: number = 0;
|
||||
|
||||
while (i < messages.length) {
|
||||
const currentMessage: ChatMessage = messages[i];
|
||||
// Initialize merged content with current message content
|
||||
const mergedContent: MessageContent[] = [currentMessage.content];
|
||||
|
||||
// Check if the next message exists and has the same role
|
||||
while (
|
||||
i + 1 < messages.length &&
|
||||
this.ROLES_TO_GEMINI[messages[i + 1].role] ===
|
||||
this.ROLES_TO_GEMINI[currentMessage.role]
|
||||
) {
|
||||
i++;
|
||||
const nextMessage: ChatMessage = messages[i];
|
||||
mergedContent.push(nextMessage.content);
|
||||
}
|
||||
|
||||
// Create a new ChatMessage object with merged content
|
||||
const mergedMessage: ChatMessage = {
|
||||
role: currentMessage.role,
|
||||
content: mergedContent.join("\n"),
|
||||
};
|
||||
mergedMessages.push(mergedMessage);
|
||||
i++;
|
||||
}
|
||||
|
||||
return mergedMessages;
|
||||
}
|
||||
|
||||
public static messageContentToGeminiParts(content: MessageContent): Part[] {
|
||||
if (typeof content === "string") {
|
||||
return [{ text: content }];
|
||||
}
|
||||
|
||||
const parts: Part[] = [];
|
||||
const imageContents = content.filter(
|
||||
(i) => i.type === "image_url",
|
||||
) as MessageContentImageDetail[];
|
||||
parts.push(
|
||||
...imageContents.map((i) => ({
|
||||
fileData: {
|
||||
mimeType: i.type,
|
||||
fileUri: i.image_url.url,
|
||||
},
|
||||
})),
|
||||
);
|
||||
const textContents = content.filter(
|
||||
(i) => i.type === "text",
|
||||
) as MessageContentTextDetail[];
|
||||
parts.push(...textContents.map((t) => ({ text: t.text })));
|
||||
return parts;
|
||||
}
|
||||
|
||||
public static chatMessageToGemini(
|
||||
message: ChatMessage,
|
||||
): GeminiMessageContent {
|
||||
return {
|
||||
role: this.ROLES_TO_GEMINI[message.role],
|
||||
parts: this.messageContentToGeminiParts(message.content),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ToolCallLLM for Gemini
|
||||
*/
|
||||
export class Gemini extends ToolCallLLM<GeminiAdditionalChatOptions> {
|
||||
model: GEMINI_MODEL;
|
||||
temperature: number;
|
||||
topP: number;
|
||||
maxTokens?: number;
|
||||
session: GeminiSession;
|
||||
|
||||
constructor(init?: GeminiConfig) {
|
||||
super();
|
||||
this.model = init?.model ?? GEMINI_MODEL.GEMINI_PRO;
|
||||
this.temperature = init?.temperature ?? 0.1;
|
||||
this.topP = init?.topP ?? 1;
|
||||
this.maxTokens = init?.maxTokens ?? undefined;
|
||||
this.session = init?.session ?? GeminiSessionStore.get();
|
||||
}
|
||||
|
||||
get supportToolCall(): boolean {
|
||||
return SUPPORT_TOOL_CALL_MODELS.includes(this.model);
|
||||
}
|
||||
|
||||
get metadata(): LLMMetadata {
|
||||
return {
|
||||
model: this.model,
|
||||
temperature: this.temperature,
|
||||
topP: this.topP,
|
||||
maxTokens: this.maxTokens,
|
||||
contextWindow: GEMINI_MODEL_INFO_MAP[this.model].contextWindow,
|
||||
tokenizer: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
private prepareChat(
|
||||
params: GeminiChatParamsStreaming | GeminiChatParamsNonStreaming,
|
||||
): {
|
||||
chat: ChatSession;
|
||||
messageContent: Part[];
|
||||
} {
|
||||
const { messages } = params;
|
||||
const mergedMessages =
|
||||
GeminiHelper.mergeNeighboringSameRoleMessages(messages);
|
||||
const history = mergedMessages.slice(0, -1);
|
||||
const nextMessage = mergedMessages[mergedMessages.length - 1];
|
||||
const messageContent = GeminiHelper.chatMessageToGemini(nextMessage).parts;
|
||||
|
||||
const client = this.session.gemini.getGenerativeModel(this.metadata);
|
||||
|
||||
const chat = client.startChat({
|
||||
history: history.map(GeminiHelper.chatMessageToGemini),
|
||||
});
|
||||
|
||||
return {
|
||||
chat,
|
||||
messageContent,
|
||||
};
|
||||
}
|
||||
|
||||
protected async nonStreamChat(
|
||||
params: GeminiChatParamsNonStreaming,
|
||||
): Promise<GeminiChatNonStreamResponse> {
|
||||
const { chat, messageContent } = this.prepareChat(params);
|
||||
const result = await chat.sendMessage(messageContent);
|
||||
const { response } = result;
|
||||
const topCandidate = response.candidates![0];
|
||||
return {
|
||||
raw: response,
|
||||
message: {
|
||||
content: response.text(),
|
||||
role: GeminiHelper.ROLES_FROM_GEMINI[
|
||||
topCandidate.content.role as GeminiMessageRole
|
||||
],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected async *streamChat(
|
||||
params: GeminiChatParamsStreaming,
|
||||
): GeminiChatStreamResponse {
|
||||
const { chat, messageContent } = this.prepareChat(params);
|
||||
const result = await chat.sendMessageStream(messageContent);
|
||||
return streamConverter(result.stream, (response) => {
|
||||
return {
|
||||
text: response.text(),
|
||||
raw: response,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
chat(params: GeminiChatParamsStreaming): Promise<GeminiChatStreamResponse>;
|
||||
chat(
|
||||
params: GeminiChatParamsNonStreaming,
|
||||
): Promise<GeminiChatNonStreamResponse>;
|
||||
@wrapLLMEvent
|
||||
async chat(
|
||||
params: GeminiChatParamsStreaming | GeminiChatParamsNonStreaming,
|
||||
): Promise<GeminiChatStreamResponse | GeminiChatNonStreamResponse> {
|
||||
if (params.stream) return this.streamChat(params);
|
||||
return this.nonStreamChat(params);
|
||||
}
|
||||
|
||||
complete(
|
||||
params: LLMCompletionParamsStreaming,
|
||||
): Promise<AsyncIterable<CompletionResponse>>;
|
||||
complete(
|
||||
params: LLMCompletionParamsNonStreaming,
|
||||
): Promise<CompletionResponse>;
|
||||
async complete(
|
||||
params: LLMCompletionParamsStreaming | LLMCompletionParamsNonStreaming,
|
||||
): Promise<CompletionResponse | AsyncIterable<CompletionResponse>> {
|
||||
const { prompt, stream } = params;
|
||||
const client = this.session.gemini.getGenerativeModel(this.metadata);
|
||||
|
||||
if (stream) {
|
||||
const result = await client.generateContentStream(
|
||||
GeminiHelper.messageContentToGeminiParts(prompt),
|
||||
);
|
||||
return streamConverter(result.stream, (response) => {
|
||||
return {
|
||||
text: response.text(),
|
||||
raw: response,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
const result = await client.generateContent(
|
||||
GeminiHelper.messageContentToGeminiParts(prompt),
|
||||
);
|
||||
return {
|
||||
text: result.response.text(),
|
||||
raw: result.response,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ export * from "./openai.js";
|
||||
export { Portkey } from "./portkey.js";
|
||||
export * from "./replicate_ai.js";
|
||||
// Note: The type aliases for replicate are to simplify usage for Llama 2 (we're using replicate for Llama 2 support)
|
||||
export { GEMINI_MODEL, Gemini } from "./gemini.js";
|
||||
export {
|
||||
DeuceChatStrategy,
|
||||
LlamaDeuce,
|
||||
|
||||
@@ -349,6 +349,14 @@ export class OpenAI extends ToolCallLLM<OpenAIAdditionalChatOptions> {
|
||||
...Object.assign({}, this.additionalChatOptions, additionalChatOptions),
|
||||
};
|
||||
|
||||
if (
|
||||
Array.isArray(baseRequestParams.tools) &&
|
||||
baseRequestParams.tools.length === 0
|
||||
) {
|
||||
// remove empty tools array to avoid OpenAI error
|
||||
delete baseRequestParams.tools;
|
||||
}
|
||||
|
||||
// Streaming
|
||||
if (stream) {
|
||||
return this.streamChat(baseRequestParams);
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import { getEnv } from "@llamaindex/env";
|
||||
import type { NodeWithScore } from "../../Node.js";
|
||||
import { MetadataMode } from "../../Node.js";
|
||||
import type { BaseNodePostprocessor } from "../types.js";
|
||||
|
||||
interface JinaAIRerankerResult {
|
||||
index: number;
|
||||
document?: {
|
||||
text?: string;
|
||||
};
|
||||
relevance_score: number;
|
||||
}
|
||||
|
||||
export class JinaAIReranker implements BaseNodePostprocessor {
|
||||
model: string = "jina-reranker-v1-base-en";
|
||||
topN?: number;
|
||||
apiKey?: string = undefined;
|
||||
|
||||
constructor(init?: Partial<JinaAIReranker>) {
|
||||
this.topN = init?.topN ?? 2;
|
||||
this.model = init?.model ?? "jina-reranker-v1-base-en";
|
||||
this.apiKey = getEnv("JINAAI_API_KEY");
|
||||
|
||||
if (!this.apiKey) {
|
||||
throw new Error(
|
||||
"Set Jina AI API Key in JINAAI_API_KEY env variable. Get one for free or top up your key at https://jina.ai/reranker",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async rerank(
|
||||
query: string,
|
||||
documents: string[],
|
||||
topN: number | undefined = this.topN,
|
||||
): Promise<JinaAIRerankerResult[]> {
|
||||
const url = "https://api.jina.ai/v1/rerank";
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${this.apiKey}`,
|
||||
};
|
||||
const data = {
|
||||
model: this.model,
|
||||
query: query,
|
||||
documents: documents,
|
||||
top_n: topN,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: headers,
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
const jsonData = await response.json();
|
||||
|
||||
return jsonData.results;
|
||||
} catch (error) {
|
||||
console.error("Error while reranking:", error);
|
||||
throw new Error("Failed to rerank documents due to an API error");
|
||||
}
|
||||
}
|
||||
|
||||
async postprocessNodes(
|
||||
nodes: NodeWithScore[],
|
||||
query?: string,
|
||||
): Promise<NodeWithScore[]> {
|
||||
if (nodes.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (query === undefined) {
|
||||
throw new Error("JinaAIReranker requires a query");
|
||||
}
|
||||
|
||||
const documents = nodes.map((n) => n.node.getContent(MetadataMode.ALL));
|
||||
const results = await this.rerank(query, documents, this.topN);
|
||||
const newNodes: NodeWithScore[] = [];
|
||||
|
||||
for (const result of results) {
|
||||
const node = nodes[result.index];
|
||||
newNodes.push({
|
||||
node: node.node,
|
||||
score: result.relevance_score,
|
||||
});
|
||||
}
|
||||
|
||||
return newNodes;
|
||||
}
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./CohereRerank.js";
|
||||
export * from "./JinaAIReranker.js";
|
||||
|
||||
@@ -19,7 +19,7 @@ export class ImageReader implements FileReader {
|
||||
file: string,
|
||||
fs: GenericFileSystem = defaultFS,
|
||||
): Promise<Document[]> {
|
||||
const dataBuffer = await fs.readFile(file);
|
||||
const dataBuffer = await fs.readRawFile(file);
|
||||
const blob = new Blob([dataBuffer]);
|
||||
return [new ImageDocument({ image: blob, id_: file })];
|
||||
}
|
||||
|
||||
@@ -1,21 +1,9 @@
|
||||
import type { Client } from "@notionhq/client";
|
||||
import type { Crawler, Pages } from "notion-md-crawler";
|
||||
import type { Crawler, CrawlerOptions, Page } from "notion-md-crawler";
|
||||
import { crawler, pageToString } from "notion-md-crawler";
|
||||
import { Document } from "../Node.js";
|
||||
import type { BaseReader } from "./type.js";
|
||||
|
||||
type OptionalSerializers = Parameters<Crawler>[number]["serializers"];
|
||||
|
||||
/**
|
||||
* Options for initializing the NotionReader class
|
||||
* @typedef {Object} NotionReaderOptions
|
||||
* @property {Client} client - The Notion Client object for API interactions
|
||||
* @property {OptionalSerializers} [serializers] - Option to customize serialization. See [the url](https://github.com/TomPenguin/notion-md-crawler/tree/main) for details.
|
||||
*/
|
||||
type NotionReaderOptions = {
|
||||
client: Client;
|
||||
serializers?: OptionalSerializers;
|
||||
};
|
||||
type NotionReaderOptions = Pick<CrawlerOptions, "client" | "serializers">;
|
||||
|
||||
/**
|
||||
* Notion pages are retrieved recursively and converted to Document objects.
|
||||
@@ -25,7 +13,7 @@ type NotionReaderOptions = {
|
||||
* Please refer to [this document](https://www.notion.so/help/create-integrations-with-the-notion-api) for details.
|
||||
*/
|
||||
export class NotionReader implements BaseReader {
|
||||
private crawl: ReturnType<Crawler>;
|
||||
private readonly crawl: ReturnType<Crawler>;
|
||||
|
||||
/**
|
||||
* Constructor for the NotionReader class
|
||||
@@ -37,10 +25,10 @@ export class NotionReader implements BaseReader {
|
||||
|
||||
/**
|
||||
* Converts Pages to an array of Document objects
|
||||
* @param {Pages} pages - The Notion pages to convert (Return value of `loadPages`)
|
||||
* @param {Page} pages - The Notion pages to convert (Return value of `loadPages`)
|
||||
* @returns {Document[]} An array of Document objects
|
||||
*/
|
||||
toDocuments(pages: Pages): Document[] {
|
||||
toDocuments(pages: Page[]): Document[] {
|
||||
return Object.values(pages).map((page) => {
|
||||
const text = pageToString(page);
|
||||
return new Document({
|
||||
@@ -54,10 +42,21 @@ export class NotionReader implements BaseReader {
|
||||
/**
|
||||
* Loads recursively the Notion page with the specified root page ID.
|
||||
* @param {string} rootPageId - The root Notion page ID
|
||||
* @returns {Promise<Pages>} A Promise that resolves to a Pages object(Convertible with the `toDocuments` method)
|
||||
* @returns {Promise<Page[]>} A Promise that resolves to a Pages object(Convertible with the `toDocuments` method)
|
||||
*/
|
||||
async loadPages(rootPageId: string): Promise<Pages> {
|
||||
return this.crawl(rootPageId);
|
||||
async loadPages(rootPageId: string): Promise<Page[]> {
|
||||
const iter = this.crawl(rootPageId);
|
||||
const pages: Page[] = [];
|
||||
for await (const result of iter) {
|
||||
if (result.success) {
|
||||
pages.push(result.page);
|
||||
} else {
|
||||
console.error(
|
||||
`Failed to load page (${result.failure.parentId}): ${result.failure.reason}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { CompleteFileSystem } from "@llamaindex/env";
|
||||
import { defaultFS, path } from "@llamaindex/env";
|
||||
import { Document } from "../Node.js";
|
||||
import { Document, type Metadata } from "../Node.js";
|
||||
import { walk } from "../storage/FileSystem.js";
|
||||
import { TextFileReader } from "./TextFileReader.js";
|
||||
import type { BaseReader } from "./type.js";
|
||||
@@ -89,6 +89,7 @@ export class SimpleDirectoryReader implements BaseReader {
|
||||
}
|
||||
|
||||
const fileDocs = await reader.loadData(filePath, fs);
|
||||
fileDocs.forEach(addMetaData(filePath));
|
||||
|
||||
// Observer can still cancel addition of the resulting docs from this file
|
||||
if (this.doObserverCheck("file", filePath, ReaderStatus.COMPLETE)) {
|
||||
@@ -124,3 +125,10 @@ export class SimpleDirectoryReader implements BaseReader {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function addMetaData(filePath: string): (doc: Document<Metadata>) => void {
|
||||
return (doc: Document<Metadata>) => {
|
||||
doc.metadata["file_path"] = path.resolve(filePath);
|
||||
doc.metadata["file_name"] = path.basename(filePath);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { JSONSchemaType } from "ajv";
|
||||
import type { BaseQueryEngine, BaseTool, ToolMetadata } from "../types.js";
|
||||
import type { BaseTool, QueryEngine, ToolMetadata } from "../types.js";
|
||||
|
||||
const DEFAULT_NAME = "query_engine_tool";
|
||||
const DEFAULT_DESCRIPTION =
|
||||
@@ -17,7 +17,7 @@ const DEFAULT_PARAMETERS: JSONSchemaType<QueryEngineParam> = {
|
||||
};
|
||||
|
||||
export type QueryEngineToolParams = {
|
||||
queryEngine: BaseQueryEngine;
|
||||
queryEngine: QueryEngine;
|
||||
metadata: ToolMetadata<JSONSchemaType<QueryEngineParam>>;
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ export type QueryEngineParam = {
|
||||
};
|
||||
|
||||
export class QueryEngineTool implements BaseTool<QueryEngineParam> {
|
||||
private queryEngine: BaseQueryEngine;
|
||||
private queryEngine: QueryEngine;
|
||||
metadata: ToolMetadata<JSONSchemaType<QueryEngineParam>>;
|
||||
|
||||
constructor({ queryEngine, metadata }: QueryEngineToolParams) {
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface QueryEngineParamsNonStreaming extends QueryEngineParamsBase {
|
||||
/**
|
||||
* A query engine is a question answerer that can use one or more steps.
|
||||
*/
|
||||
export interface BaseQueryEngine {
|
||||
export interface QueryEngine {
|
||||
/**
|
||||
* Query the query engine and get a response.
|
||||
* @param params
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Document } from "llamaindex/Node";
|
||||
import { Document, ImageDocument } from "llamaindex/Node";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
describe("Document", () => {
|
||||
@@ -6,4 +6,16 @@ describe("Document", () => {
|
||||
const doc = new Document({ text: "text", id_: "docId" });
|
||||
expect(doc).toBeDefined();
|
||||
});
|
||||
|
||||
test("should generate different hash for different image contents", () => {
|
||||
const imageNode1 = new ImageDocument({
|
||||
id_: "image",
|
||||
image: "data:image/png;base64,sample_image_content1",
|
||||
});
|
||||
const imageNode2 = new ImageDocument({
|
||||
id_: "image",
|
||||
image: "data:image/png;base64,sample_image_content2",
|
||||
});
|
||||
expect(imageNode1.hash).not.toBe(imageNode2.hash);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Document } from "llamaindex/Node";
|
||||
import { IngestionPipeline } from "llamaindex/ingestion/IngestionPipeline";
|
||||
import { test } from "vitest";
|
||||
|
||||
// Refs: https://github.com/run-llama/LlamaIndexTS/pull/760
|
||||
test("load large data should not cause RangeError #760", async () => {
|
||||
const pipeline = new IngestionPipeline({
|
||||
reader: {
|
||||
loadData: async () => {
|
||||
return Array.from(
|
||||
{ length: 1e6 },
|
||||
(_, i) =>
|
||||
new Document({
|
||||
id_: `${i}`,
|
||||
text: "some text",
|
||||
}),
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
await pipeline.prepareInput();
|
||||
});
|
||||
@@ -1,5 +1,20 @@
|
||||
# test-edge-runtime
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6277105]
|
||||
- @llamaindex/edge@0.2.13
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [87142b2]
|
||||
- Updated dependencies [87142b2]
|
||||
- @llamaindex/edge@0.2.11
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "test-edge-runtime",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -14,7 +14,7 @@
|
||||
"react-dom": "^18"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/node": "^20.12.7",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"typescript": "^5"
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@llamaindex/edge",
|
||||
"version": "0.2.10",
|
||||
"version": "0.2.13",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.20.6",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@datastax/astra-db-ts": "^1.0.1",
|
||||
"@google/generative-ai": "^0.8.0",
|
||||
"@grpc/grpc-js": "^1.10.6",
|
||||
"@llamaindex/cloud": "0.0.5",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@mistralai/mistralai": "^0.1.3",
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@pinecone-database/pinecone": "^2.2.0",
|
||||
"@qdrant/js-client-rest": "^1.8.2",
|
||||
"@types/lodash": "^4.17.0",
|
||||
@@ -30,7 +30,7 @@
|
||||
"mammoth": "^1.7.1",
|
||||
"md-utils-ts": "^2.0.0",
|
||||
"mongodb": "^6.5.0",
|
||||
"notion-md-crawler": "^0.0.2",
|
||||
"notion-md-crawler": "^1.0.0",
|
||||
"ollama": "^0.5.0",
|
||||
"openai": "^4.38.0",
|
||||
"papaparse": "^5.4.1",
|
||||
@@ -82,5 +82,17 @@
|
||||
"update:deps": "node scripts/update-deps.js",
|
||||
"build:core": "pnpm --filter llamaindex build && cp -r ../core/dist . && rm -rf dist/cjs",
|
||||
"build": "pnpm run update:deps && pnpm run build:core && pnpm copy"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@swc/cli": "^0.3.12",
|
||||
"@swc/core": "^1.4.16",
|
||||
"concurrently": "^8.2.2",
|
||||
"glob": "^10.3.12",
|
||||
"madge": "^7.0.0",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@notionhq/client": "^2.2.15"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ const edgePackagePath = path.join(process.cwd(), "package.json");
|
||||
const edgePackage = readJson(edgePackagePath);
|
||||
const corePackage = readJson(corePackagePath);
|
||||
edgePackage.dependencies = corePackage.dependencies;
|
||||
edgePackage.devDependencies = corePackage.devDependencies;
|
||||
edgePackage.peerDependencies = corePackage.peerDependencies;
|
||||
edgePackage.version = corePackage.version;
|
||||
writeJson(edgePackagePath, edgePackage);
|
||||
execSync("pnpm install --lockfile-only", { stdio: "inherit" });
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @llamaindex/experimental
|
||||
|
||||
## 0.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6277105]
|
||||
- llamaindex@0.2.13
|
||||
|
||||
## 0.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d8d952d]
|
||||
- llamaindex@0.2.12
|
||||
|
||||
## 0.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [87142b2]
|
||||
- Updated dependencies [5a6cc0e]
|
||||
- Updated dependencies [87142b2]
|
||||
- llamaindex@0.2.11
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/experimental",
|
||||
"description": "Experimental package for LlamaIndexTS",
|
||||
"version": "0.0.13",
|
||||
"version": "0.0.16",
|
||||
"type": "module",
|
||||
"types": "dist/type/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Response } from "llamaindex";
|
||||
import { serviceContextFromDefaults, type ServiceContext } from "llamaindex";
|
||||
|
||||
import type {
|
||||
BaseQueryEngine,
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "llamaindex";
|
||||
@@ -89,7 +89,7 @@ type OutputProcessor = typeof defaultOutputProcessor;
|
||||
/**
|
||||
* A JSON query engine that uses JSONPath to query a JSON object.
|
||||
*/
|
||||
export class JSONQueryEngine implements BaseQueryEngine {
|
||||
export class JSONQueryEngine implements QueryEngine {
|
||||
jsonValue: JSONSchemaType;
|
||||
jsonSchema: JSONSchemaType;
|
||||
serviceContext: ServiceContext;
|
||||
|
||||
Generated
+1030
-1110
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user