mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-09 03:23:09 -04:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d9421d6a3 | |||
| caf7e91779 | |||
| 034639153b | |||
| 1914b52708 | |||
| cb021e7196 | |||
| c2aa836b35 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@llamaindex/community": patch
|
||||
---
|
||||
|
||||
Added Claude 3.7 Sonnet support
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@llamaindex/core": patch
|
||||
"llamaindex": patch
|
||||
"@llamaindex/core-tests": patch
|
||||
---
|
||||
|
||||
feat(node-parser): support async function
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@llamaindex/voyage-ai": major
|
||||
---
|
||||
|
||||
Adding VoyageAI embedding package
|
||||
@@ -41,8 +41,15 @@ pnpm install
|
||||
|
||||
### Build the packages
|
||||
|
||||
You'll need Turbo to build the packages. If you don't have it, you can run it with `pnpx`.
|
||||
|
||||
To build all packages, run:
|
||||
|
||||
```shell
|
||||
# Build all packages
|
||||
pnpx turbo build --filter "./packages/*"
|
||||
|
||||
# Or if you have turbo installed, you can run:
|
||||
turbo build --filter "./packages/*"
|
||||
```
|
||||
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: VoyageAI
|
||||
---
|
||||
|
||||
To use VoyageAI embeddings, you need to import `VoyageAIEmbedding` from `@llamaindex/voyage-ai`.
|
||||
|
||||
## Installation
|
||||
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
|
||||
<Tabs groupId="install" items={["npm", "yarn", "pnpm"]} persist>
|
||||
```shell tab="npm"
|
||||
npm install llamaindex @llamaindex/voyage-ai
|
||||
```
|
||||
|
||||
```shell tab="yarn"
|
||||
yarn add llamaindex @llamaindex/voyage-ai
|
||||
```
|
||||
|
||||
```shell tab="pnpm"
|
||||
pnpm add llamaindex @llamaindex/voyage-ai
|
||||
```
|
||||
</Tabs>
|
||||
|
||||
```ts
|
||||
import { VoyageAIEmbedding } from "@llamaindex/voyage-ai";
|
||||
import { Document, Settings, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
Settings.embedModel = new VoyageAIEmbedding();
|
||||
|
||||
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,
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- [VoyageAIEmbedding](/docs/api/classes/VoyageAIEmbedding)
|
||||
@@ -37,6 +37,31 @@ Settings.embedModel = new OpenAIEmbedding({
|
||||
|
||||
For local embeddings, you can use the [HuggingFace](/docs/llamaindex/modules/embeddings/available_embeddings/huggingface) embedding model.
|
||||
|
||||
## Local Ollama Embeddings With Remote Host
|
||||
|
||||
Ollama provides a way to run embedding models locally or connect to a remote Ollama instance. This is particularly useful when you need to:
|
||||
- Run embeddings without relying on external API services
|
||||
- Use custom embedding models
|
||||
- Connect to a shared Ollama instance in your network
|
||||
|
||||
The ENV variable method you will find elsewhere sometimes may not work with the OllamaEmbedding class. Also note, you'll need to change the host
|
||||
in the Ollama server to `0.0.0.0` to allow connections from other machines.
|
||||
|
||||
To use Ollama embeddings with a remote host, you need to specify the host URL in the configuration like this:
|
||||
|
||||
```typescript
|
||||
import { OllamaEmbedding } from "@llamaindex/ollama";
|
||||
import { Settings } from "llamaindex";
|
||||
|
||||
// Configure Ollama with a remote host
|
||||
Settings.embedModel = new OllamaEmbedding({
|
||||
model: "nomic-embed-text",
|
||||
config: {
|
||||
host: "http://your-ollama-host:11434"
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Available Embeddings
|
||||
|
||||
Most available embeddings are listed in the sidebar on the left.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "workspace:*",
|
||||
"llamaindex": "0.9.3",
|
||||
"next": "15.1.7",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
"@llamaindex/upstash": "^0.0.7",
|
||||
"@llamaindex/vercel": "^0.0.13",
|
||||
"@llamaindex/vllm": "^0.0.24",
|
||||
"@llamaindex/voyage-ai": "^0.0.1",
|
||||
"@llamaindex/weaviate": "^0.0.7",
|
||||
"@llamaindex/workflow": "^0.0.11",
|
||||
"@notionhq/client": "^2.2.15",
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { VoyageAIEmbedding } from "@llamaindex/voyage-ai";
|
||||
|
||||
async function main() {
|
||||
// API token can be provided as an environment variable too
|
||||
// using VOYAGE_API_TOKEN variable
|
||||
const apiKey = process.env.VOYAGE_API_TOKEN ?? "YOUR_API_TOKEN";
|
||||
const model = "voyage-3-lite";
|
||||
const embedModel = new VoyageAIEmbedding({
|
||||
model,
|
||||
apiKey,
|
||||
});
|
||||
const texts = ["hello", "world"];
|
||||
const embeddings = await embedModel.getTextEmbeddingsBatch(texts);
|
||||
console.log(`\nWe have ${embeddings.length} embeddings`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -6,7 +6,19 @@ export type ToolChoice =
|
||||
| { type: "auto" }
|
||||
| { type: "tool"; name: string };
|
||||
|
||||
export type AnthropicAdditionalChatOptions = { toolChoice: ToolChoice };
|
||||
export interface ThinkingConfigDisabled {
|
||||
type: "disabled";
|
||||
}
|
||||
|
||||
export interface ThinkingConfigEnabled {
|
||||
budget_tokens: number;
|
||||
type: "enabled";
|
||||
}
|
||||
|
||||
export type AnthropicAdditionalChatOptions = {
|
||||
toolChoice: ToolChoice;
|
||||
thinking?: ThinkingConfigDisabled | ThinkingConfigEnabled;
|
||||
};
|
||||
|
||||
type Usage = {
|
||||
input_tokens: number;
|
||||
|
||||
@@ -69,6 +69,7 @@ export const BEDROCK_MODELS = {
|
||||
ANTHROPIC_CLAUDE_3_5_SONNET: "anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
ANTHROPIC_CLAUDE_3_5_SONNET_V2: "anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
ANTHROPIC_CLAUDE_3_5_HAIKU: "anthropic.claude-3-5-haiku-20241022-v1:0",
|
||||
ANTHROPIC_CLAUDE_3_7_SONNET: "anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
META_LLAMA2_13B_CHAT: "meta.llama2-13b-chat-v1",
|
||||
META_LLAMA2_70B_CHAT: "meta.llama2-70b-chat-v1",
|
||||
META_LLAMA3_8B_INSTRUCT: "meta.llama3-8b-instruct-v1:0",
|
||||
@@ -100,6 +101,8 @@ export const INFERENCE_BEDROCK_MODELS = {
|
||||
"us.anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
US_ANTHROPIC_CLAUDE_3_5_SONNET_V2:
|
||||
"us.anthropic.claude-3-5-sonnet-20241022-v2:0",
|
||||
US_ANTHROPIC_CLAUDE_3_7_SONNET:
|
||||
"us.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
US_META_LLAMA_3_2_1B_INSTRUCT: "us.meta.llama3-2-1b-instruct-v1:0",
|
||||
US_META_LLAMA_3_2_3B_INSTRUCT: "us.meta.llama3-2-3b-instruct-v1:0",
|
||||
US_META_LLAMA_3_2_11B_INSTRUCT: "us.meta.llama3-2-11b-instruct-v1:0",
|
||||
@@ -113,6 +116,8 @@ export const INFERENCE_BEDROCK_MODELS = {
|
||||
EU_ANTHROPIC_CLAUDE_3_SONNET: "eu.anthropic.claude-3-sonnet-20240229-v1:0",
|
||||
EU_ANTHROPIC_CLAUDE_3_5_SONNET:
|
||||
"eu.anthropic.claude-3-5-sonnet-20240620-v1:0",
|
||||
EU_ANTHROPIC_CLAUDE_3_7_SONNET:
|
||||
"eu.anthropic.claude-3-7-sonnet-20250219-v1:0",
|
||||
EU_META_LLAMA_3_2_1B_INSTRUCT: "eu.meta.llama3-2-1b-instruct-v1:0",
|
||||
EU_META_LLAMA_3_2_3B_INSTRUCT: "eu.meta.llama3-2-3b-instruct-v1:0",
|
||||
};
|
||||
@@ -132,6 +137,8 @@ export const INFERENCE_TO_BEDROCK_MAP: Record<
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.US_ANTHROPIC_CLAUDE_3_5_SONNET]:
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.US_ANTHROPIC_CLAUDE_3_7_SONNET]:
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.US_ANTHROPIC_CLAUDE_3_5_SONNET_V2]:
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET_V2,
|
||||
[INFERENCE_BEDROCK_MODELS.US_ANTHROPIC_CLAUDE_3_5_HAIKU]:
|
||||
@@ -158,6 +165,8 @@ export const INFERENCE_TO_BEDROCK_MAP: Record<
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.EU_ANTHROPIC_CLAUDE_3_5_SONNET]:
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.EU_ANTHROPIC_CLAUDE_3_7_SONNET]:
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET,
|
||||
[INFERENCE_BEDROCK_MODELS.EU_META_LLAMA_3_2_1B_INSTRUCT]:
|
||||
BEDROCK_MODELS.META_LLAMA3_2_1B_INSTRUCT,
|
||||
[INFERENCE_BEDROCK_MODELS.EU_META_LLAMA_3_2_3B_INSTRUCT]:
|
||||
@@ -191,6 +200,7 @@ const CHAT_ONLY_MODELS = {
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET]: 200000,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET_V2]: 200000,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_HAIKU]: 200000,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET]: 200000,
|
||||
[BEDROCK_MODELS.META_LLAMA2_13B_CHAT]: 2048,
|
||||
[BEDROCK_MODELS.META_LLAMA2_70B_CHAT]: 4096,
|
||||
[BEDROCK_MODELS.META_LLAMA3_8B_INSTRUCT]: 8192,
|
||||
@@ -230,6 +240,7 @@ export const STREAMING_MODELS = new Set([
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET_V2,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_HAIKU,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET,
|
||||
BEDROCK_MODELS.META_LLAMA2_13B_CHAT,
|
||||
BEDROCK_MODELS.META_LLAMA2_70B_CHAT,
|
||||
BEDROCK_MODELS.META_LLAMA3_8B_INSTRUCT,
|
||||
@@ -256,6 +267,7 @@ export const TOOL_CALL_MODELS: BEDROCK_MODELS[] = [
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET_V2,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_HAIKU,
|
||||
BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET,
|
||||
BEDROCK_MODELS.META_LLAMA3_1_405B_INSTRUCT,
|
||||
BEDROCK_MODELS.META_LLAMA3_2_1B_INSTRUCT,
|
||||
BEDROCK_MODELS.META_LLAMA3_2_3B_INSTRUCT,
|
||||
@@ -294,6 +306,7 @@ export const BEDROCK_MODEL_MAX_TOKENS: Partial<Record<BEDROCK_MODELS, number>> =
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET]: 4096,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_SONNET_V2]: 8192,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_5_HAIKU]: 8192,
|
||||
[BEDROCK_MODELS.ANTHROPIC_CLAUDE_3_7_SONNET]: 8192,
|
||||
[BEDROCK_MODELS.META_LLAMA2_13B_CHAT]: 2048,
|
||||
[BEDROCK_MODELS.META_LLAMA2_70B_CHAT]: 2048,
|
||||
[BEDROCK_MODELS.META_LLAMA3_8B_INSTRUCT]: 2048,
|
||||
|
||||
@@ -7,21 +7,27 @@ import {
|
||||
TextNode,
|
||||
TransformComponent,
|
||||
} from "../schema";
|
||||
import { isPromise } from "../utils";
|
||||
|
||||
export abstract class NodeParser extends TransformComponent<BaseNode[]> {
|
||||
export abstract class NodeParser<
|
||||
Result extends TextNode[] | Promise<TextNode[]> =
|
||||
| TextNode[]
|
||||
| Promise<TextNode[]>,
|
||||
> extends TransformComponent<Result> {
|
||||
includeMetadata: boolean = true;
|
||||
includePrevNextRel: boolean = true;
|
||||
|
||||
constructor() {
|
||||
super((nodes: BaseNode[]): BaseNode[] => {
|
||||
super((nodes: BaseNode[]): Result => {
|
||||
// alex: should we fix `as` type?
|
||||
return this.getNodesFromDocuments(nodes as TextNode[]);
|
||||
});
|
||||
}
|
||||
|
||||
protected postProcessParsedNodes(
|
||||
nodes: TextNode[],
|
||||
nodes: Awaited<Result>,
|
||||
parentDocMap: Map<string, TextNode>,
|
||||
): TextNode[] {
|
||||
): Awaited<Result> {
|
||||
nodes.forEach((node, i) => {
|
||||
const parentDoc = parentDocMap.get(node.sourceNode?.nodeId || "");
|
||||
|
||||
@@ -73,9 +79,9 @@ export abstract class NodeParser extends TransformComponent<BaseNode[]> {
|
||||
protected abstract parseNodes(
|
||||
documents: TextNode[],
|
||||
showProgress?: boolean,
|
||||
): TextNode[];
|
||||
): Result;
|
||||
|
||||
public getNodesFromDocuments(documents: TextNode[]): TextNode[] {
|
||||
public getNodesFromDocuments(documents: TextNode[]): Result {
|
||||
const docsId: Map<string, TextNode> = new Map(
|
||||
documents.map((doc) => [doc.id_, doc]),
|
||||
);
|
||||
@@ -85,20 +91,36 @@ export abstract class NodeParser extends TransformComponent<BaseNode[]> {
|
||||
documents,
|
||||
});
|
||||
|
||||
const nodes = this.postProcessParsedNodes(
|
||||
this.parseNodes(documents),
|
||||
docsId,
|
||||
);
|
||||
const parsedNodes = this.parseNodes(documents);
|
||||
if (isPromise(parsedNodes)) {
|
||||
return parsedNodes.then((parsedNodes) => {
|
||||
const nodes = this.postProcessParsedNodes(
|
||||
parsedNodes as Awaited<Result>,
|
||||
docsId,
|
||||
);
|
||||
|
||||
callbackManager.dispatchEvent("node-parsing-end", {
|
||||
nodes,
|
||||
});
|
||||
callbackManager.dispatchEvent("node-parsing-end", {
|
||||
nodes,
|
||||
});
|
||||
|
||||
return nodes;
|
||||
return nodes;
|
||||
}) as Result;
|
||||
} else {
|
||||
const nodes = this.postProcessParsedNodes(
|
||||
parsedNodes as Awaited<Result>,
|
||||
docsId,
|
||||
);
|
||||
|
||||
callbackManager.dispatchEvent("node-parsing-end", {
|
||||
nodes,
|
||||
});
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class TextSplitter extends NodeParser {
|
||||
export abstract class TextSplitter extends NodeParser<TextNode[]> {
|
||||
abstract splitText(text: string): string[];
|
||||
|
||||
public splitTexts(texts: string[]): string[] {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from "../schema";
|
||||
import { NodeParser } from "./base";
|
||||
|
||||
export class MarkdownNodeParser extends NodeParser {
|
||||
export class MarkdownNodeParser extends NodeParser<TextNode[]> {
|
||||
override parseNodes(nodes: TextNode[], showProgress?: boolean): TextNode[] {
|
||||
return nodes.reduce<TextNode[]>((allNodes, node) => {
|
||||
const markdownNodes = this.getNodesFromNode(node);
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import { NodeParser } from "./base";
|
||||
import { splitBySentenceTokenizer, type TextSplitterFn } from "./utils";
|
||||
|
||||
export class SentenceWindowNodeParser extends NodeParser {
|
||||
export class SentenceWindowNodeParser extends NodeParser<TextNode[]> {
|
||||
static DEFAULT_WINDOW_SIZE = 3;
|
||||
static DEFAULT_WINDOW_METADATA_KEY = "window";
|
||||
static DEFAULT_ORIGINAL_TEXT_METADATA_KEY = "originalText";
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import type { JSONValue } from "../global";
|
||||
|
||||
export const isPromise = <T>(obj: unknown): obj is Promise<T> => {
|
||||
return obj != null && typeof obj === "object" && "then" in obj;
|
||||
};
|
||||
|
||||
export const isAsyncIterable = (
|
||||
obj: unknown,
|
||||
): obj is AsyncIterable<unknown> => {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { NodeParser } from "@llamaindex/core/node-parser";
|
||||
import { TextNode } from "@llamaindex/core/schema";
|
||||
import { describe, expect, test } from "vitest";
|
||||
|
||||
describe("NodeParser", () => {
|
||||
test("node parser should allow async parse function", async () => {
|
||||
class MyNodeParser extends NodeParser<Promise<TextNode[]>> {
|
||||
protected async parseNodes(documents: TextNode[]): Promise<TextNode[]> {
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
return documents;
|
||||
}
|
||||
}
|
||||
|
||||
const nodeParser = new MyNodeParser();
|
||||
const nodes = [
|
||||
new TextNode({
|
||||
text: "Hello, world!",
|
||||
}),
|
||||
];
|
||||
const result = nodeParser(nodes);
|
||||
expect(result).toBeInstanceOf(Promise);
|
||||
await expect(result).resolves.toEqual(nodes);
|
||||
});
|
||||
});
|
||||
@@ -296,7 +296,7 @@ export class KeywordTableIndex extends BaseIndex<KeywordTable> {
|
||||
await docStore.setDocumentHash(doc.id_, doc.hash);
|
||||
}
|
||||
|
||||
const nodes = Settings.nodeParser.getNodesFromDocuments(documents);
|
||||
const nodes = await Settings.nodeParser.getNodesFromDocuments(documents);
|
||||
const index = await KeywordTableIndex.init({
|
||||
nodes,
|
||||
storageContext,
|
||||
|
||||
@@ -145,7 +145,7 @@ export class SummaryIndex extends BaseIndex<IndexList> {
|
||||
await docStore.setDocumentHash(doc.id_, doc.hash);
|
||||
}
|
||||
|
||||
const nodes = Settings.nodeParser.getNodesFromDocuments(documents);
|
||||
const nodes = await Settings.nodeParser.getNodesFromDocuments(documents);
|
||||
|
||||
const index = await SummaryIndex.init({
|
||||
nodes,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "@llamaindex/voyage-ai",
|
||||
"description": "VoyageAI Adapter for LlamaIndex",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"main": "./dist/index.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": {
|
||||
"types": "./dist/index.d.cts",
|
||||
"default": "./dist/index.cjs"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"default": "./dist/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/run-llama/LlamaIndexTS.git",
|
||||
"directory": "packages/providers/voyage-ai"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bunchee",
|
||||
"dev": "bunchee --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"bunchee": "6.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/core": "workspace:*",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"voyageai": "0.0.3-1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import { BaseEmbedding } from "@llamaindex/core/embeddings";
|
||||
import type { MessageContentDetail } from "@llamaindex/core/llms";
|
||||
import { extractSingleText } from "@llamaindex/core/utils";
|
||||
import { getEnv } from "@llamaindex/env";
|
||||
import { VoyageAI, VoyageAIClient } from "voyageai";
|
||||
|
||||
const DEFAULT_MODEL = "voyage-3";
|
||||
const API_TOKEN_ENV_VARIABLE_NAME = "VOYAGE_API_TOKEN";
|
||||
// const API_ROOT = "https://api.voyageai.com/v1/embeddings";
|
||||
const DEFAULT_TIMEOUT = 60 * 1000;
|
||||
const DEFAULT_MAX_RETRIES = 5;
|
||||
|
||||
/**
|
||||
* VoyageAIEmbedding is an alias for VoyageAI that implements the BaseEmbedding interface.
|
||||
*/
|
||||
export class VoyageAIEmbedding extends BaseEmbedding {
|
||||
/**
|
||||
* VoyageAI model to use
|
||||
* @default "voyage-3"
|
||||
* @see https://docs.voyageai.com/docs/embeddings
|
||||
*/
|
||||
model: string;
|
||||
|
||||
/**
|
||||
* VoyageAI API token
|
||||
* @see https://docs.voyageai.com/docs/api-key-and-installation
|
||||
* If not provided, it will try to get the token from the environment variable `VOYAGE_API_KEY`
|
||||
*
|
||||
*/
|
||||
apiKey: string;
|
||||
|
||||
/**
|
||||
* Maximum number of retries
|
||||
* @default 5
|
||||
*/
|
||||
maxRetries: number;
|
||||
|
||||
/**
|
||||
* Timeout in seconds
|
||||
* @default 60
|
||||
*/
|
||||
timeout: number;
|
||||
/**
|
||||
* Whether to truncate the input texts to fit within the context length. Defaults to `true`.
|
||||
* If `true`, over-length input texts will be truncated to fit within the context length, before vectorized by the embedding model.
|
||||
* If `false`, an error will be raised if any given text exceeds the context length.
|
||||
*/
|
||||
truncation: boolean;
|
||||
|
||||
/**
|
||||
* VoyageAI supports `document` and `query` as input types, or it can be left undefined. Using an input type prepends the input with a prompt before embedding.
|
||||
* Example from their docs: using "query" adds "Represent the query for retrieving supporting documents:"
|
||||
* VoyageAI says these types improve performance, but it will add to token usage. Embeddings with input types are compatible with those that don't use them.
|
||||
* Setting this to `query` will use the `query` input type for getQueryEmbedding(s).
|
||||
* Setting this to `document` will use the `document` input type for getTextEmbedding(s).
|
||||
* Setting this to `both` will do both of the above.
|
||||
* By default, this is undefined, which means no input types are used.
|
||||
* @see https://docs.voyageai.com/docs/embeddings
|
||||
* @default undefined
|
||||
*/
|
||||
useInputTypes: "query" | "document" | "both" | undefined;
|
||||
|
||||
/**
|
||||
* VoyageAI client
|
||||
*/
|
||||
client: VoyageAIClient;
|
||||
|
||||
constructor(init?: Partial<VoyageAIEmbedding>) {
|
||||
super();
|
||||
|
||||
this.model = init?.model ?? DEFAULT_MODEL;
|
||||
this.apiKey = init?.apiKey ?? getEnv(API_TOKEN_ENV_VARIABLE_NAME) ?? "";
|
||||
this.maxRetries = init?.maxRetries ?? DEFAULT_MAX_RETRIES;
|
||||
this.timeout = init?.timeout ?? DEFAULT_TIMEOUT;
|
||||
this.truncation = init?.truncation ?? true;
|
||||
this.useInputTypes = init?.useInputTypes;
|
||||
this.client = new VoyageAIClient({
|
||||
apiKey: this.apiKey,
|
||||
});
|
||||
}
|
||||
|
||||
async getTextEmbedding(text: string): Promise<number[]> {
|
||||
const embeddings = await this.getVoyageAIEmbedding([text], "document");
|
||||
return embeddings[0]!;
|
||||
}
|
||||
|
||||
async getQueryEmbedding(
|
||||
query: MessageContentDetail,
|
||||
): Promise<number[] | null> {
|
||||
const text = extractSingleText(query);
|
||||
if (text) {
|
||||
const embeddings = await this.getVoyageAIEmbedding([text], "query");
|
||||
return embeddings[0]!;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getTextEmbeddings = async (texts: string[]): Promise<number[][]> => {
|
||||
return this.getVoyageAIEmbedding(texts, "document");
|
||||
};
|
||||
|
||||
async getQueryEmbeddings(queries: string[]): Promise<number[][]> {
|
||||
return this.getVoyageAIEmbedding(queries, "query");
|
||||
}
|
||||
|
||||
private getInputType(requestType: "query" | "document") {
|
||||
if (this.useInputTypes === "both") {
|
||||
return requestType;
|
||||
} else if (this.useInputTypes === requestType) {
|
||||
return requestType;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private async getVoyageAIEmbedding(
|
||||
inputs: VoyageAI.EmbedRequestInput,
|
||||
inputType: VoyageAI.EmbedRequestInputType,
|
||||
): Promise<number[][]> {
|
||||
const request: VoyageAI.EmbedRequest = {
|
||||
model: this.model,
|
||||
input: inputs,
|
||||
truncation: this.truncation,
|
||||
};
|
||||
const preferredInputType = this.getInputType(inputType);
|
||||
if (preferredInputType) {
|
||||
request.inputType = preferredInputType;
|
||||
}
|
||||
const response = await this.client.embed(request);
|
||||
if (response.data) {
|
||||
return response.data.map((item) => item.embedding ?? []);
|
||||
} else {
|
||||
throw new Error("Failed to get embeddings from VoyageAI");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { VoyageAIEmbedding } from "./embedding";
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"outDir": "./lib",
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo"
|
||||
},
|
||||
"include": ["./src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../openai/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../../env/tsconfig.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
+101
-3
@@ -454,7 +454,7 @@ importers:
|
||||
e2e/examples/nextjs-edge-runtime:
|
||||
dependencies:
|
||||
llamaindex:
|
||||
specifier: workspace:*
|
||||
specifier: 0.9.3
|
||||
version: link:../../../packages/llamaindex
|
||||
next:
|
||||
specifier: 15.1.7
|
||||
@@ -685,6 +685,9 @@ importers:
|
||||
'@llamaindex/vllm':
|
||||
specifier: ^0.0.24
|
||||
version: link:../packages/providers/vllm
|
||||
'@llamaindex/voyage-ai':
|
||||
specifier: ^0.0.1
|
||||
version: link:../packages/providers/voyage-ai
|
||||
'@llamaindex/weaviate':
|
||||
specifier: ^0.0.7
|
||||
version: link:../packages/providers/storage/weaviate
|
||||
@@ -1443,7 +1446,7 @@ importers:
|
||||
version: link:../../../env
|
||||
chromadb:
|
||||
specifier: 1.10.3
|
||||
version: 1.10.3(cohere-ai@7.14.0)(openai@4.83.0(ws@8.18.0(bufferutil@4.0.9))(zod@3.24.2))
|
||||
version: 1.10.3(cohere-ai@7.14.0)(openai@4.83.0(ws@8.18.0(bufferutil@4.0.9))(zod@3.24.2))(voyageai@0.0.3-1)
|
||||
chromadb-default-embed:
|
||||
specifier: ^2.13.2
|
||||
version: 2.13.2
|
||||
@@ -1636,6 +1639,22 @@ importers:
|
||||
specifier: 6.3.4
|
||||
version: 6.3.4(patch_hash=pavboztthlgni7m5gzw7643oru)(typescript@5.7.3)
|
||||
|
||||
packages/providers/voyage-ai:
|
||||
dependencies:
|
||||
'@llamaindex/core':
|
||||
specifier: workspace:*
|
||||
version: link:../../core
|
||||
'@llamaindex/env':
|
||||
specifier: workspace:*
|
||||
version: link:../../env
|
||||
voyageai:
|
||||
specifier: 0.0.3-1
|
||||
version: 0.0.3-1
|
||||
devDependencies:
|
||||
bunchee:
|
||||
specifier: 6.0.3
|
||||
version: 6.0.3(typescript@5.7.3)
|
||||
|
||||
packages/readers:
|
||||
dependencies:
|
||||
'@azure/cosmos':
|
||||
@@ -4263,6 +4282,15 @@ packages:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/plugin-node-resolve@15.3.1':
|
||||
resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
peerDependencies:
|
||||
rollup: ^2.78.0||^3.0.0||^4.0.0
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
|
||||
'@rollup/plugin-node-resolve@16.0.0':
|
||||
resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@@ -5926,6 +5954,16 @@ packages:
|
||||
resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==}
|
||||
engines: {node: '>=6.14.2'}
|
||||
|
||||
bunchee@6.0.3:
|
||||
resolution: {integrity: sha512-Yq/srd3ocXPAHv0KEdJvhFMNUOOVVqy0kNzaGVCirk/+MfnLdvZO5uf5BHugIHe/qSvWUQTJZ3SAfB/VABONeQ==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
typescript: ^4.1 || ^5.0
|
||||
peerDependenciesMeta:
|
||||
typescript:
|
||||
optional: true
|
||||
|
||||
bunchee@6.3.4:
|
||||
resolution: {integrity: sha512-bMy2/+tdMPXOqBAX+9BI0HTNjOXOZ2TXjgFpp5Prt0ztP15xQQUcsECnU7wuBPpLH+4id3rXakH9icdbBRZHZQ==}
|
||||
engines: {node: '>= 18.0.0'}
|
||||
@@ -11534,6 +11572,9 @@ packages:
|
||||
jsdom:
|
||||
optional: true
|
||||
|
||||
voyageai@0.0.3-1:
|
||||
resolution: {integrity: sha512-R3jN/xnILWoMBL3jPY61Ydm1JbpK3J+VmXBoHvlNg1Xz8h0xdX7sEffXeSu+sAEKQaPyWXVQDmM/jpBhPXw58g==}
|
||||
|
||||
vue-demi@0.14.10:
|
||||
resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -14803,6 +14844,16 @@ snapshots:
|
||||
optionalDependencies:
|
||||
rollup: 4.34.6
|
||||
|
||||
'@rollup/plugin-node-resolve@15.3.1(rollup@4.34.6)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.6)
|
||||
'@types/resolve': 1.20.2
|
||||
deepmerge: 4.3.1
|
||||
is-module: 1.0.0
|
||||
resolve: 1.22.10
|
||||
optionalDependencies:
|
||||
rollup: 4.34.6
|
||||
|
||||
'@rollup/plugin-node-resolve@16.0.0(rollup@4.34.6)':
|
||||
dependencies:
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.6)
|
||||
@@ -16932,6 +16983,31 @@ snapshots:
|
||||
dependencies:
|
||||
node-gyp-build: 4.8.4
|
||||
|
||||
bunchee@6.0.3(typescript@5.7.3):
|
||||
dependencies:
|
||||
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.6)
|
||||
'@rollup/plugin-json': 6.1.0(rollup@4.34.6)
|
||||
'@rollup/plugin-node-resolve': 15.3.1(rollup@4.34.6)
|
||||
'@rollup/plugin-replace': 6.0.2(rollup@4.34.6)
|
||||
'@rollup/plugin-wasm': 6.2.2(rollup@4.34.6)
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.6)
|
||||
'@swc/core': 1.10.16(@swc/helpers@0.5.15)
|
||||
'@swc/helpers': 0.5.15
|
||||
clean-css: 5.3.3
|
||||
glob: 11.0.1
|
||||
magic-string: 0.30.17
|
||||
ora: 8.2.0
|
||||
picomatch: 4.0.2
|
||||
pretty-bytes: 5.6.0
|
||||
rollup: 4.34.6
|
||||
rollup-plugin-dts: 6.1.1(rollup@4.34.6)(typescript@5.7.3)
|
||||
rollup-plugin-swc3: 0.11.2(@swc/core@1.10.16(@swc/helpers@0.5.15))(rollup@4.34.6)
|
||||
rollup-preserve-directives: 1.1.3(rollup@4.34.6)
|
||||
tslib: 2.8.1
|
||||
yargs: 17.7.2
|
||||
optionalDependencies:
|
||||
typescript: 5.7.3
|
||||
|
||||
bunchee@6.3.4(patch_hash=pavboztthlgni7m5gzw7643oru)(typescript@5.7.2):
|
||||
dependencies:
|
||||
'@rollup/plugin-commonjs': 28.0.2(rollup@4.34.6)
|
||||
@@ -17134,13 +17210,14 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- bare-buffer
|
||||
|
||||
chromadb@1.10.3(cohere-ai@7.14.0)(openai@4.83.0(ws@8.18.0(bufferutil@4.0.9))(zod@3.24.2)):
|
||||
chromadb@1.10.3(cohere-ai@7.14.0)(openai@4.83.0(ws@8.18.0(bufferutil@4.0.9))(zod@3.24.2))(voyageai@0.0.3-1):
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
isomorphic-fetch: 3.0.0
|
||||
optionalDependencies:
|
||||
cohere-ai: 7.14.0
|
||||
openai: 4.83.0(ws@8.18.0(bufferutil@4.0.9))(zod@3.24.2)
|
||||
voyageai: 0.0.3-1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
@@ -22738,6 +22815,15 @@ snapshots:
|
||||
rollup: 4.34.6
|
||||
rollup-preserve-directives: 1.1.3(rollup@4.34.6)
|
||||
|
||||
rollup-plugin-swc3@0.11.2(@swc/core@1.10.16(@swc/helpers@0.5.15))(rollup@4.34.6):
|
||||
dependencies:
|
||||
'@fastify/deepmerge': 1.3.0
|
||||
'@rollup/pluginutils': 5.1.4(rollup@4.34.6)
|
||||
'@swc/core': 1.10.16(@swc/helpers@0.5.15)
|
||||
get-tsconfig: 4.10.0
|
||||
rollup: 4.34.6
|
||||
rollup-preserve-directives: 1.1.3(rollup@4.34.6)
|
||||
|
||||
rollup-pluginutils@2.8.2:
|
||||
dependencies:
|
||||
estree-walker: 0.6.1
|
||||
@@ -24326,6 +24412,18 @@ snapshots:
|
||||
- supports-color
|
||||
- terser
|
||||
|
||||
voyageai@0.0.3-1:
|
||||
dependencies:
|
||||
form-data: 4.0.0
|
||||
formdata-node: 6.0.3
|
||||
js-base64: 3.7.2
|
||||
node-fetch: 2.7.0
|
||||
qs: 6.11.2
|
||||
readable-stream: 4.7.0
|
||||
url-join: 4.0.1
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
|
||||
vue-demi@0.14.10(vue@3.5.13(typescript@5.7.2)):
|
||||
dependencies:
|
||||
vue: 3.5.13(typescript@5.7.2)
|
||||
|
||||
Reference in New Issue
Block a user