mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-01 22:14:03 -04:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24eabe7f35 | |||
| ecfa939ea6 | |||
| b48bcc3add | |||
| fa01fa2051 | |||
| fb36eff5e1 | |||
| d24d3d1e8c | |||
| 5c4badbcca | |||
| 2cd1383dc8 |
@@ -13,8 +13,10 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
POSTGRES_USER: runneradmin
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
TURBO_REMOTE_ONLY: true
|
||||
|
||||
jobs:
|
||||
e2e:
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# docs
|
||||
|
||||
## 0.0.73
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.0.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.71",
|
||||
"version": "0.0.73",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
|
||||
@@ -27,10 +27,12 @@ async function main() {
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const stream = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
stream: true,
|
||||
});
|
||||
const stream = await queryEngine.query(
|
||||
{
|
||||
query: "What did the author do in college?",
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
// Output response
|
||||
for await (const chunk of stream) {
|
||||
|
||||
@@ -37,10 +37,12 @@ async function main() {
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const stream = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
stream: true,
|
||||
});
|
||||
const stream = await queryEngine.query(
|
||||
{
|
||||
query: "What did the author do in college?",
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
// Output response
|
||||
for await (const chunk of stream) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
Document,
|
||||
getResponseSynthesizer,
|
||||
NodeWithScore,
|
||||
ResponseSynthesizer,
|
||||
SentenceSplitter,
|
||||
TextNode,
|
||||
} from "llamaindex";
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
|
||||
console.log(nodes);
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer();
|
||||
const responseSynthesizer = getResponseSynthesizer("compact");
|
||||
|
||||
const nodesWithScore: NodeWithScore[] = [
|
||||
{
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
const stream = await responseSynthesizer.synthesize(
|
||||
{
|
||||
query: "What age am I?",
|
||||
nodesWithScore,
|
||||
nodes: nodesWithScore,
|
||||
},
|
||||
true,
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
MultiModalResponseSynthesizer,
|
||||
getResponseSynthesizer,
|
||||
OpenAI,
|
||||
Settings,
|
||||
VectorStoreIndex,
|
||||
@@ -27,13 +27,15 @@ async function main() {
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine({
|
||||
responseSynthesizer: new MultiModalResponseSynthesizer(),
|
||||
responseSynthesizer: getResponseSynthesizer("multi_modal"),
|
||||
retriever: index.asRetriever({ topK: { TEXT: 3, IMAGE: 1 } }),
|
||||
});
|
||||
const stream = await queryEngine.query({
|
||||
query: "Tell me more about Vincent van Gogh's famous paintings",
|
||||
stream: true,
|
||||
});
|
||||
const stream = await queryEngine.query(
|
||||
{
|
||||
query: "Tell me more about Vincent van Gogh's famous paintings",
|
||||
},
|
||||
true,
|
||||
);
|
||||
for await (const chunk of stream) {
|
||||
process.stdout.write(chunk.response);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {
|
||||
Document,
|
||||
getResponseSynthesizer,
|
||||
PromptTemplate,
|
||||
ResponseSynthesizer,
|
||||
TreeSummarize,
|
||||
TreeSummarizePrompt,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
@@ -27,9 +26,7 @@ async function main() {
|
||||
|
||||
const query = "The quick brown fox jumps over the lazy dog";
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new TreeSummarize(),
|
||||
});
|
||||
const responseSynthesizer = getResponseSynthesizer("tree_summarize");
|
||||
|
||||
const queryEngine = index.asQueryEngine({
|
||||
responseSynthesizer,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import {
|
||||
CompactAndRefine,
|
||||
getResponseSynthesizer,
|
||||
OpenAI,
|
||||
PromptTemplate,
|
||||
ResponseSynthesizer,
|
||||
Settings,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
@@ -29,8 +28,8 @@ Given the CSV file, generate me Typescript code to answer the question: {query}.
|
||||
`,
|
||||
});
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(undefined, csvPrompt),
|
||||
const responseSynthesizer = getResponseSynthesizer("compact", {
|
||||
textQATemplate: csvPrompt,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine({ responseSynthesizer });
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createMessageContent } from "@llamaindex/core/utils";
|
||||
import {
|
||||
Document,
|
||||
ImageNode,
|
||||
@@ -6,7 +7,6 @@ import {
|
||||
PromptTemplate,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
import { createMessageContent } from "llamaindex/synthesizers/utils";
|
||||
|
||||
const reader = new LlamaParseReader();
|
||||
async function main() {
|
||||
|
||||
@@ -2,12 +2,10 @@ import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Anthropic,
|
||||
CompactAndRefine,
|
||||
Document,
|
||||
ResponseSynthesizer,
|
||||
Settings,
|
||||
VectorStoreIndex,
|
||||
anthropicTextQaPrompt,
|
||||
getResponseSynthesizer,
|
||||
} from "llamaindex";
|
||||
|
||||
// Update llm to use Anthropic
|
||||
@@ -23,9 +21,7 @@ async function main() {
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(undefined, anthropicTextQaPrompt),
|
||||
});
|
||||
const responseSynthesizer = getResponseSynthesizer("compact");
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import {
|
||||
getResponseSynthesizer,
|
||||
OpenAI,
|
||||
OpenAIEmbedding,
|
||||
ResponseSynthesizer,
|
||||
RetrieverQueryEngine,
|
||||
Settings,
|
||||
TextNode,
|
||||
TreeSummarize,
|
||||
VectorIndexRetriever,
|
||||
VectorStore,
|
||||
VectorStoreIndex,
|
||||
@@ -165,10 +164,7 @@ async function main() {
|
||||
similarityTopK: 500,
|
||||
});
|
||||
|
||||
const responseSynthesizer = new ResponseSynthesizer({
|
||||
responseBuilder: new TreeSummarize(),
|
||||
});
|
||||
|
||||
const responseSynthesizer = getResponseSynthesizer("tree_summarize");
|
||||
return new RetrieverQueryEngine(retriever, responseSynthesizer, {
|
||||
filter,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/autotool
|
||||
|
||||
## 3.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 3.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 3.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @llamaindex/autotool-01-node-example
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
- @llamaindex/autotool@3.0.4
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
- @llamaindex/autotool@3.0.3
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"scripts": {
|
||||
"start": "node --import tsx --import @llamaindex/autotool/node ./src/index.ts"
|
||||
},
|
||||
"version": "0.0.11"
|
||||
"version": "0.0.13"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
# @llamaindex/autotool-02-next-example
|
||||
|
||||
## 0.1.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
- @llamaindex/autotool@3.0.4
|
||||
|
||||
## 0.1.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
- @llamaindex/autotool@3.0.3
|
||||
|
||||
## 0.1.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool-02-next-example",
|
||||
"private": true,
|
||||
"version": "0.1.55",
|
||||
"version": "0.1.57",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool",
|
||||
"type": "module",
|
||||
"version": "3.0.2",
|
||||
"version": "3.0.4",
|
||||
"description": "auto transpile your JS function to LLM Agent compatible",
|
||||
"files": [
|
||||
"dist",
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# @llamaindex/cloud
|
||||
|
||||
## 0.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fb36eff: fix: backport for node.js 18
|
||||
|
||||
There could have one missing API in the node.js 18, so we need to backport it to make it work.
|
||||
|
||||
- d24d3d1: fix: print warning when llama parse reader has error
|
||||
- Updated dependencies [2cd1383]
|
||||
- @llamaindex/core@0.2.3
|
||||
|
||||
## 0.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/cloud",
|
||||
"version": "0.2.6",
|
||||
"version": "0.2.7",
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
@@ -50,12 +50,12 @@
|
||||
"devDependencies": {
|
||||
"@hey-api/client-fetch": "^0.2.4",
|
||||
"@hey-api/openapi-ts": "^0.53.0",
|
||||
"@llamaindex/core": "workspace:^0.2.2",
|
||||
"@llamaindex/core": "workspace:^0.2.3",
|
||||
"@llamaindex/env": "workspace:^0.1.11",
|
||||
"bunchee": "5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@llamaindex/core": "workspace:^0.2.2",
|
||||
"@llamaindex/core": "workspace:^0.2.3",
|
||||
"@llamaindex/env": "workspace:^0.1.11"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -229,20 +229,18 @@ export class LlamaParseReader extends FileReader {
|
||||
}
|
||||
|
||||
// Create a job for the LlamaParse API
|
||||
private async createJob(
|
||||
data: Uint8Array,
|
||||
fileName: string = "unknown",
|
||||
): Promise<string> {
|
||||
private async createJob(data: Uint8Array): Promise<string> {
|
||||
// Load data, set the mime type
|
||||
const { mime, extension } = await LlamaParseReader.getMimeType(data);
|
||||
const { mime } = await LlamaParseReader.getMimeType(data);
|
||||
|
||||
if (this.verbose) {
|
||||
const name = fileName ? fileName : extension;
|
||||
console.log(`Starting load for ${name} file`);
|
||||
console.log("Started uploading the file");
|
||||
}
|
||||
|
||||
const body = {
|
||||
file: new File([data], fileName, { type: mime }),
|
||||
file: new Blob([data], {
|
||||
type: mime,
|
||||
}),
|
||||
language: this.language,
|
||||
parsing_instruction: this.parsingInstruction,
|
||||
skip_diagonal_text: this.skipDiagonalText,
|
||||
@@ -373,14 +371,10 @@ export class LlamaParseReader extends FileReader {
|
||||
* To be used with resultType = "text" and "markdown"
|
||||
*
|
||||
* @param {Uint8Array} fileContent - The content of the file to be loaded.
|
||||
* @param {string} [fileName] - The optional name of the file to be loaded.
|
||||
* @return {Promise<Document[]>} A Promise object that resolves to an array of Document objects.
|
||||
*/
|
||||
async loadDataAsContent(
|
||||
fileContent: Uint8Array,
|
||||
fileName?: string,
|
||||
): Promise<Document[]> {
|
||||
return this.createJob(fileContent, fileName)
|
||||
async loadDataAsContent(fileContent: Uint8Array): Promise<Document[]> {
|
||||
return this.createJob(fileContent)
|
||||
.then(async (jobId) => {
|
||||
if (this.verbose) {
|
||||
console.log(`Started parsing the file under job id ${jobId}`);
|
||||
@@ -403,6 +397,7 @@ export class LlamaParseReader extends FileReader {
|
||||
})
|
||||
.catch((error) => {
|
||||
if (this.ignoreErrors) {
|
||||
console.warn(`Error while parsing the file: ${error.message}`);
|
||||
return [];
|
||||
} else {
|
||||
throw error;
|
||||
@@ -437,8 +432,8 @@ export class LlamaParseReader extends FileReader {
|
||||
resultJson.file_path = isFilePath ? filePathOrContent : undefined;
|
||||
return [resultJson];
|
||||
} catch (e) {
|
||||
console.error(`Error while parsing the file under job id ${jobId}`, e);
|
||||
if (this.ignoreErrors) {
|
||||
console.error(`Error while parsing the file under job id ${jobId}`, e);
|
||||
return [];
|
||||
} else {
|
||||
throw e;
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/community
|
||||
|
||||
## 0.0.38
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- @llamaindex/core@0.2.4
|
||||
- @llamaindex/env@0.1.12
|
||||
|
||||
## 0.0.37
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- @llamaindex/core@0.2.3
|
||||
|
||||
## 0.0.36
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/community",
|
||||
"description": "Community package for LlamaIndexTS",
|
||||
"version": "0.0.36",
|
||||
"version": "0.0.38",
|
||||
"type": "module",
|
||||
"types": "dist/type/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# @llamaindex/core
|
||||
|
||||
## 0.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b48bcc3: feat: add `load-transformers` event type when loading `@xenova/transformers` module
|
||||
|
||||
This would benefit user who want to customize the transformer env.
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- @llamaindex/env@0.1.12
|
||||
|
||||
## 0.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2cd1383: refactor: align `response-synthesizers` & `chat-engine` module
|
||||
|
||||
- builtin event system
|
||||
- correct class extends
|
||||
- aligin APIs, naming with llama-index python
|
||||
- move stream out of first parameter to second parameter for the better tyep checking
|
||||
- remove JSONQueryEngine in `@llamaindex/experimental`, as the code quality is not satisify and we will bring it back later
|
||||
|
||||
## 0.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/core",
|
||||
"type": "module",
|
||||
"version": "0.2.2",
|
||||
"version": "0.2.4",
|
||||
"description": "LlamaIndex Core Module",
|
||||
"exports": {
|
||||
"./node-parser": {
|
||||
@@ -185,6 +185,20 @@
|
||||
"types": "./dist/storage/chat-store/index.d.ts",
|
||||
"default": "./dist/storage/chat-store/index.js"
|
||||
}
|
||||
},
|
||||
"./response-synthesizers": {
|
||||
"require": {
|
||||
"types": "./dist/response-synthesizers/index.d.cts",
|
||||
"default": "./dist/response-synthesizers/index.cjs"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/response-synthesizers/index.d.ts",
|
||||
"default": "./dist/response-synthesizers/index.js"
|
||||
},
|
||||
"default": {
|
||||
"types": "./dist/response-synthesizers/index.d.ts",
|
||||
"default": "./dist/response-synthesizers/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
@@ -210,6 +224,7 @@
|
||||
"dependencies": {
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@types/node": "^22.5.1",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,13 @@ import type {
|
||||
ToolCall,
|
||||
ToolOutput,
|
||||
} from "../../llms";
|
||||
import type { QueryEndEvent, QueryStartEvent } from "../../query-engine";
|
||||
import type {
|
||||
SynthesizeEndEvent,
|
||||
SynthesizeStartEvent,
|
||||
} from "../../response-synthesizers";
|
||||
import { TextNode } from "../../schema";
|
||||
import { EventCaller, getEventCaller } from "../../utils/event-caller";
|
||||
import { EventCaller, getEventCaller } from "../../utils";
|
||||
import type { UUID } from "../type";
|
||||
|
||||
export type LLMStartEvent = {
|
||||
@@ -60,6 +65,10 @@ export interface LlamaIndexEventMaps {
|
||||
"chunking-end": ChunkingEndEvent;
|
||||
"node-parsing-start": NodeParsingStartEvent;
|
||||
"node-parsing-end": NodeParsingEndEvent;
|
||||
"query-start": QueryStartEvent;
|
||||
"query-end": QueryEndEvent;
|
||||
"synthesize-start": SynthesizeStartEvent;
|
||||
"synthesize-end": SynthesizeEndEvent;
|
||||
}
|
||||
|
||||
export class LlamaIndexCustomEvent<T = any> extends CustomEvent<T> {
|
||||
@@ -119,16 +128,29 @@ export class CallbackManager {
|
||||
dispatchEvent<K extends keyof LlamaIndexEventMaps>(
|
||||
event: K,
|
||||
detail: LlamaIndexEventMaps[K],
|
||||
sync = false,
|
||||
) {
|
||||
const cbs = this.#handlers.get(event);
|
||||
if (!cbs) {
|
||||
return;
|
||||
}
|
||||
queueMicrotask(() => {
|
||||
if (typeof queueMicrotask === "undefined") {
|
||||
console.warn(
|
||||
"queueMicrotask is not available, dispatching synchronously",
|
||||
);
|
||||
sync = true;
|
||||
}
|
||||
if (sync) {
|
||||
cbs.forEach((handler) =>
|
||||
handler(LlamaIndexCustomEvent.fromEvent(event, { ...detail })),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
queueMicrotask(() => {
|
||||
cbs.forEach((handler) =>
|
||||
handler(LlamaIndexCustomEvent.fromEvent(event, { ...detail })),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { type Tokenizer, tokenizers } from "@llamaindex/env";
|
||||
import {
|
||||
DEFAULT_CHUNK_OVERLAP_RATIO,
|
||||
DEFAULT_CHUNK_SIZE,
|
||||
DEFAULT_CONTEXT_WINDOW,
|
||||
DEFAULT_NUM_OUTPUTS,
|
||||
DEFAULT_PADDING,
|
||||
Settings,
|
||||
} from "../global";
|
||||
import type { LLMMetadata } from "../llms";
|
||||
import { SentenceSplitter } from "../node-parser";
|
||||
import type { PromptTemplate } from "../prompts";
|
||||
|
||||
@@ -133,4 +136,29 @@ export class PromptHelper {
|
||||
const combinedStr = textChunks.join("\n\n");
|
||||
return textSplitter.splitText(combinedStr);
|
||||
}
|
||||
|
||||
static fromLLMMetadata(
|
||||
metadata: LLMMetadata,
|
||||
options?: {
|
||||
chunkOverlapRatio?: number;
|
||||
chunkSizeLimit?: number;
|
||||
tokenizer?: Tokenizer;
|
||||
separator?: string;
|
||||
},
|
||||
) {
|
||||
const {
|
||||
chunkOverlapRatio = DEFAULT_CHUNK_OVERLAP_RATIO,
|
||||
chunkSizeLimit = DEFAULT_CHUNK_SIZE,
|
||||
tokenizer = Settings.tokenizer,
|
||||
separator = " ",
|
||||
} = options ?? {};
|
||||
return new PromptHelper({
|
||||
contextWindow: metadata.contextWindow,
|
||||
numOutput: metadata.maxTokens ?? DEFAULT_NUM_OUTPUTS,
|
||||
chunkOverlapRatio,
|
||||
chunkSizeLimit,
|
||||
tokenizer,
|
||||
separator,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { randomUUID } from "@llamaindex/env";
|
||||
import { Settings } from "../global";
|
||||
import type { MessageContent } from "../llms";
|
||||
import { EngineResponse, type NodeWithScore } from "../schema";
|
||||
import { PromptMixin } from "../prompts";
|
||||
import { EngineResponse } from "../schema";
|
||||
import { wrapEventCaller } from "../utils";
|
||||
|
||||
/**
|
||||
* @link https://docs.llamaindex.ai/en/stable/api_reference/schema/?h=querybundle#llama_index.core.schema.QueryBundle
|
||||
@@ -14,16 +18,37 @@ export type QueryBundle = {
|
||||
|
||||
export type QueryType = string | QueryBundle;
|
||||
|
||||
export interface BaseQueryEngine {
|
||||
export type QueryFn = (
|
||||
strOrQueryBundle: QueryType,
|
||||
stream?: boolean,
|
||||
) => Promise<AsyncIterable<EngineResponse> | EngineResponse>;
|
||||
|
||||
export abstract class BaseQueryEngine extends PromptMixin {
|
||||
protected constructor(protected readonly _query: QueryFn) {
|
||||
super();
|
||||
}
|
||||
|
||||
query(
|
||||
strOrQueryBundle: QueryType,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(strOrQueryBundle: QueryType, stream?: false): Promise<EngineResponse>;
|
||||
|
||||
synthesize?(
|
||||
@wrapEventCaller
|
||||
async query(
|
||||
strOrQueryBundle: QueryType,
|
||||
nodes: NodeWithScore[],
|
||||
additionalSources?: Iterator<NodeWithScore>,
|
||||
): Promise<EngineResponse>;
|
||||
stream = false,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const id = randomUUID();
|
||||
const callbackManager = Settings.callbackManager;
|
||||
callbackManager.dispatchEvent("query-start", {
|
||||
id,
|
||||
query: strOrQueryBundle,
|
||||
});
|
||||
const response = await this._query(strOrQueryBundle, stream);
|
||||
callbackManager.dispatchEvent("query-end", {
|
||||
id,
|
||||
response,
|
||||
});
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
export type { BaseQueryEngine, QueryBundle, QueryType } from "./base";
|
||||
export { BaseQueryEngine, type QueryBundle, type QueryType } from "./base";
|
||||
export type { QueryEndEvent, QueryStartEvent } from "./type";
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { EngineResponse } from "../schema";
|
||||
import type { QueryType } from "./base";
|
||||
|
||||
export type QueryStartEvent = {
|
||||
id: string;
|
||||
query: QueryType;
|
||||
};
|
||||
|
||||
export type QueryEndEvent = {
|
||||
id: string;
|
||||
response: EngineResponse | AsyncIterable<EngineResponse>;
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
import { randomUUID } from "@llamaindex/env";
|
||||
import { Settings } from "../global";
|
||||
import { PromptHelper } from "../indices";
|
||||
import type { LLM, MessageContent } from "../llms";
|
||||
import { PromptMixin } from "../prompts";
|
||||
import { EngineResponse, type NodeWithScore } from "../schema";
|
||||
import type { SynthesizeQuery } from "./type";
|
||||
|
||||
export type BaseSynthesizerOptions = {
|
||||
llm?: LLM;
|
||||
promptHelper?: PromptHelper;
|
||||
};
|
||||
|
||||
export abstract class BaseSynthesizer extends PromptMixin {
|
||||
llm: LLM;
|
||||
promptHelper: PromptHelper;
|
||||
|
||||
protected constructor(options: Partial<BaseSynthesizerOptions>) {
|
||||
super();
|
||||
this.llm = options.llm ?? Settings.llm;
|
||||
this.promptHelper =
|
||||
options.promptHelper ?? PromptHelper.fromLLMMetadata(this.llm.metadata);
|
||||
}
|
||||
|
||||
protected abstract getResponse(
|
||||
query: MessageContent,
|
||||
textChunks: NodeWithScore[],
|
||||
stream: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>>;
|
||||
|
||||
synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
synthesize(query: SynthesizeQuery, stream?: false): Promise<EngineResponse>;
|
||||
async synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream = false,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const callbackManager = Settings.callbackManager;
|
||||
const id = randomUUID();
|
||||
callbackManager.dispatchEvent("synthesize-start", { id, query });
|
||||
let response: EngineResponse | AsyncIterable<EngineResponse>;
|
||||
if (query.nodes.length === 0) {
|
||||
if (stream) {
|
||||
response = EngineResponse.fromResponse("Empty Response", true);
|
||||
} else {
|
||||
response = EngineResponse.fromResponse("Empty Response", false);
|
||||
}
|
||||
} else {
|
||||
const queryMessage: MessageContent =
|
||||
typeof query.query === "string" ? query.query : query.query.query;
|
||||
response = await this.getResponse(queryMessage, query.nodes, stream);
|
||||
}
|
||||
callbackManager.dispatchEvent("synthesize-end", { id, query, response });
|
||||
return response;
|
||||
}
|
||||
}
|
||||
+191
-164
@@ -1,108 +1,52 @@
|
||||
import { getBiggestPrompt, type PromptHelper } from "@llamaindex/core/indices";
|
||||
import type { LLM } from "@llamaindex/core/llms";
|
||||
import { z } from "zod";
|
||||
import { getBiggestPrompt } from "../indices";
|
||||
import type { MessageContent } from "../llms";
|
||||
import {
|
||||
PromptMixin,
|
||||
defaultRefinePrompt,
|
||||
defaultTextQAPrompt,
|
||||
defaultTreeSummarizePrompt,
|
||||
type ModuleRecord,
|
||||
type PromptsRecord,
|
||||
type RefinePrompt,
|
||||
type TextQAPrompt,
|
||||
type TreeSummarizePrompt,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import type { QueryType } from "@llamaindex/core/query-engine";
|
||||
import { extractText, streamConverter } from "@llamaindex/core/utils";
|
||||
import type { ServiceContext } from "../ServiceContext.js";
|
||||
} from "../prompts";
|
||||
import {
|
||||
llmFromSettingsOrContext,
|
||||
promptHelperFromSettingsOrContext,
|
||||
} from "../Settings.js";
|
||||
import type { ResponseBuilder, ResponseBuilderQuery } from "./types.js";
|
||||
EngineResponse,
|
||||
MetadataMode,
|
||||
type NodeWithScore,
|
||||
TextNode,
|
||||
} from "../schema";
|
||||
import { createMessageContent, extractText, streamConverter } from "../utils";
|
||||
import {
|
||||
BaseSynthesizer,
|
||||
type BaseSynthesizerOptions,
|
||||
} from "./base-synthesizer";
|
||||
|
||||
/**
|
||||
* Response modes of the response synthesizer
|
||||
*/
|
||||
enum ResponseMode {
|
||||
REFINE = "refine",
|
||||
COMPACT = "compact",
|
||||
TREE_SUMMARIZE = "tree_summarize",
|
||||
SIMPLE = "simple",
|
||||
}
|
||||
const responseModeSchema = z.enum([
|
||||
"refine",
|
||||
"compact",
|
||||
"tree_summarize",
|
||||
"multi_modal",
|
||||
]);
|
||||
|
||||
/**
|
||||
* A response builder that just concatenates responses.
|
||||
*/
|
||||
export class SimpleResponseBuilder
|
||||
extends PromptMixin
|
||||
implements ResponseBuilder
|
||||
{
|
||||
llm: LLM;
|
||||
textQATemplate: TextQAPrompt;
|
||||
|
||||
constructor(serviceContext?: ServiceContext, textQATemplate?: TextQAPrompt) {
|
||||
super();
|
||||
this.llm = llmFromSettingsOrContext(serviceContext);
|
||||
this.textQATemplate = textQATemplate ?? defaultTextQAPrompt;
|
||||
}
|
||||
|
||||
protected _getPrompts(): PromptsRecord {
|
||||
return {
|
||||
textQATemplate: this.textQATemplate,
|
||||
};
|
||||
}
|
||||
protected _updatePrompts(prompts: { textQATemplate: TextQAPrompt }): void {
|
||||
if (prompts.textQATemplate) {
|
||||
this.textQATemplate = prompts.textQATemplate;
|
||||
}
|
||||
}
|
||||
protected _getPromptModules(): ModuleRecord {
|
||||
return {};
|
||||
}
|
||||
|
||||
getResponse(
|
||||
query: ResponseBuilderQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<string>>;
|
||||
getResponse(query: ResponseBuilderQuery, stream?: false): Promise<string>;
|
||||
async getResponse(
|
||||
{ query, textChunks }: ResponseBuilderQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
const prompt = this.textQATemplate.format({
|
||||
query: extractText(query),
|
||||
context: textChunks.join("\n\n"),
|
||||
});
|
||||
if (stream) {
|
||||
const response = await this.llm.complete({ prompt, stream: true });
|
||||
return streamConverter(response, (chunk) => chunk.text);
|
||||
} else {
|
||||
const response = await this.llm.complete({ prompt, stream: false });
|
||||
return response.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
export type ResponseMode = z.infer<typeof responseModeSchema>;
|
||||
|
||||
/**
|
||||
* A response builder that uses the query to ask the LLM generate a better response using multiple text chunks.
|
||||
*/
|
||||
export class Refine extends PromptMixin implements ResponseBuilder {
|
||||
llm: LLM;
|
||||
promptHelper: PromptHelper;
|
||||
class Refine extends BaseSynthesizer {
|
||||
textQATemplate: TextQAPrompt;
|
||||
refineTemplate: RefinePrompt;
|
||||
|
||||
constructor(
|
||||
serviceContext?: ServiceContext,
|
||||
textQATemplate?: TextQAPrompt,
|
||||
refineTemplate?: RefinePrompt,
|
||||
options: BaseSynthesizerOptions & {
|
||||
textQATemplate?: TextQAPrompt | undefined;
|
||||
refineTemplate?: RefinePrompt | undefined;
|
||||
},
|
||||
) {
|
||||
super();
|
||||
|
||||
this.llm = llmFromSettingsOrContext(serviceContext);
|
||||
this.promptHelper = promptHelperFromSettingsOrContext(serviceContext);
|
||||
this.textQATemplate = textQATemplate ?? defaultTextQAPrompt;
|
||||
this.refineTemplate = refineTemplate ?? defaultRefinePrompt;
|
||||
super(options);
|
||||
this.textQATemplate = options.textQATemplate ?? defaultTextQAPrompt;
|
||||
this.refineTemplate = options.refineTemplate ?? defaultRefinePrompt;
|
||||
}
|
||||
|
||||
protected _getPromptModules(): ModuleRecord {
|
||||
@@ -132,41 +76,47 @@ export class Refine extends PromptMixin implements ResponseBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
getResponse(
|
||||
query: ResponseBuilderQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<string>>;
|
||||
getResponse(query: ResponseBuilderQuery, stream?: false): Promise<string>;
|
||||
async getResponse(
|
||||
{ query, textChunks, prevResponse }: ResponseBuilderQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
let response: AsyncIterable<string> | string | undefined = prevResponse;
|
||||
query: MessageContent,
|
||||
nodes: NodeWithScore[],
|
||||
stream: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
let response: AsyncIterable<string> | string | undefined = undefined;
|
||||
const textChunks = nodes.map(({ node }) =>
|
||||
node.getContent(MetadataMode.LLM),
|
||||
);
|
||||
|
||||
for (let i = 0; i < textChunks.length; i++) {
|
||||
const chunk = textChunks[i]!;
|
||||
const text = textChunks[i]!;
|
||||
const lastChunk = i === textChunks.length - 1;
|
||||
if (!response) {
|
||||
response = await this.giveResponseSingle(
|
||||
query,
|
||||
chunk,
|
||||
text,
|
||||
!!stream && lastChunk,
|
||||
);
|
||||
} else {
|
||||
response = await this.refineResponseSingle(
|
||||
response as string,
|
||||
query,
|
||||
chunk,
|
||||
text,
|
||||
!!stream && lastChunk,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return response ?? "Empty Response";
|
||||
// fixme: no source nodes provided, cannot fix right now due to lack of context
|
||||
if (typeof response === "string") {
|
||||
return EngineResponse.fromResponse(response, false);
|
||||
} else {
|
||||
return streamConverter(response!, (text) =>
|
||||
EngineResponse.fromResponse(text, true),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async giveResponseSingle(
|
||||
query: QueryType,
|
||||
query: MessageContent,
|
||||
textChunk: string,
|
||||
stream: boolean,
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
@@ -203,10 +153,10 @@ export class Refine extends PromptMixin implements ResponseBuilder {
|
||||
// eslint-disable-next-line max-params
|
||||
private async refineResponseSingle(
|
||||
initialReponse: string,
|
||||
query: QueryType,
|
||||
query: MessageContent,
|
||||
textChunk: string,
|
||||
stream: boolean,
|
||||
) {
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
const refineTemplate: RefinePrompt = this.refineTemplate.partialFormat({
|
||||
query: extractText(query),
|
||||
});
|
||||
@@ -246,59 +196,54 @@ export class Refine extends PromptMixin implements ResponseBuilder {
|
||||
/**
|
||||
* CompactAndRefine is a slight variation of Refine that first compacts the text chunks into the smallest possible number of chunks.
|
||||
*/
|
||||
export class CompactAndRefine extends Refine {
|
||||
getResponse(
|
||||
query: ResponseBuilderQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<string>>;
|
||||
getResponse(query: ResponseBuilderQuery, stream?: false): Promise<string>;
|
||||
class CompactAndRefine extends Refine {
|
||||
async getResponse(
|
||||
{ query, textChunks, prevResponse }: ResponseBuilderQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
query: MessageContent,
|
||||
nodes: NodeWithScore[],
|
||||
stream: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const textQATemplate: TextQAPrompt = this.textQATemplate.partialFormat({
|
||||
query: extractText(query),
|
||||
});
|
||||
const refineTemplate: RefinePrompt = this.refineTemplate.partialFormat({
|
||||
query: extractText(query),
|
||||
});
|
||||
const textChunks = nodes.map(({ node }) =>
|
||||
node.getContent(MetadataMode.LLM),
|
||||
);
|
||||
|
||||
const maxPrompt = getBiggestPrompt([textQATemplate, refineTemplate]);
|
||||
const newTexts = this.promptHelper.repack(maxPrompt, textChunks);
|
||||
const params = {
|
||||
query,
|
||||
textChunks: newTexts,
|
||||
prevResponse,
|
||||
};
|
||||
const newNodes = newTexts.map((text) => new TextNode({ text }));
|
||||
if (stream) {
|
||||
return super.getResponse(
|
||||
{
|
||||
...params,
|
||||
},
|
||||
query,
|
||||
newNodes.map((node) => ({ node })),
|
||||
true,
|
||||
);
|
||||
}
|
||||
return super.getResponse(params);
|
||||
return super.getResponse(
|
||||
query,
|
||||
newNodes.map((node) => ({ node })),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TreeSummarize repacks the text chunks into the smallest possible number of chunks and then summarizes them, then recursively does so until there's one chunk left.
|
||||
*/
|
||||
export class TreeSummarize extends PromptMixin implements ResponseBuilder {
|
||||
llm: LLM;
|
||||
promptHelper: PromptHelper;
|
||||
class TreeSummarize extends BaseSynthesizer {
|
||||
summaryTemplate: TreeSummarizePrompt;
|
||||
|
||||
constructor(
|
||||
serviceContext?: ServiceContext,
|
||||
summaryTemplate?: TreeSummarizePrompt,
|
||||
options: BaseSynthesizerOptions & {
|
||||
summaryTemplate?: TreeSummarizePrompt;
|
||||
},
|
||||
) {
|
||||
super();
|
||||
|
||||
this.llm = llmFromSettingsOrContext(serviceContext);
|
||||
this.promptHelper = promptHelperFromSettingsOrContext(serviceContext);
|
||||
this.summaryTemplate = summaryTemplate ?? defaultTreeSummarizePrompt;
|
||||
super(options);
|
||||
this.summaryTemplate =
|
||||
options.summaryTemplate ?? defaultTreeSummarizePrompt;
|
||||
}
|
||||
|
||||
protected _getPromptModules(): ModuleRecord {
|
||||
@@ -319,15 +264,14 @@ export class TreeSummarize extends PromptMixin implements ResponseBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
getResponse(
|
||||
query: ResponseBuilderQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<string>>;
|
||||
getResponse(query: ResponseBuilderQuery, stream?: false): Promise<string>;
|
||||
async getResponse(
|
||||
{ query, textChunks }: ResponseBuilderQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<string> | string> {
|
||||
query: MessageContent,
|
||||
nodes: NodeWithScore[],
|
||||
stream: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const textChunks = nodes.map(({ node }) =>
|
||||
node.getContent(MetadataMode.LLM),
|
||||
);
|
||||
if (!textChunks || textChunks.length === 0) {
|
||||
throw new Error("Must have at least one text chunk");
|
||||
}
|
||||
@@ -347,9 +291,14 @@ export class TreeSummarize extends PromptMixin implements ResponseBuilder {
|
||||
};
|
||||
if (stream) {
|
||||
const response = await this.llm.complete({ ...params, stream });
|
||||
return streamConverter(response, (chunk) => chunk.text);
|
||||
return streamConverter(response, (chunk) =>
|
||||
EngineResponse.fromResponse(chunk.text, true),
|
||||
);
|
||||
}
|
||||
return (await this.llm.complete(params)).text;
|
||||
return EngineResponse.fromResponse(
|
||||
(await this.llm.complete(params)).text,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
const summaries = await Promise.all(
|
||||
packedTextChunks.map((chunk) =>
|
||||
@@ -362,40 +311,118 @@ export class TreeSummarize extends PromptMixin implements ResponseBuilder {
|
||||
),
|
||||
);
|
||||
|
||||
const params = {
|
||||
query,
|
||||
textChunks: summaries.map((s) => s.text),
|
||||
};
|
||||
if (stream) {
|
||||
return this.getResponse(
|
||||
{
|
||||
...params,
|
||||
},
|
||||
query,
|
||||
summaries.map((s) => ({
|
||||
node: new TextNode({
|
||||
text: s.text,
|
||||
}),
|
||||
})),
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.getResponse(params);
|
||||
return this.getResponse(
|
||||
query,
|
||||
summaries.map((s) => ({
|
||||
node: new TextNode({
|
||||
text: s.text,
|
||||
}),
|
||||
})),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getResponseBuilder(
|
||||
serviceContext?: ServiceContext,
|
||||
responseMode?: ResponseMode,
|
||||
): ResponseBuilder {
|
||||
switch (responseMode) {
|
||||
case ResponseMode.SIMPLE:
|
||||
return new SimpleResponseBuilder(serviceContext);
|
||||
case ResponseMode.REFINE:
|
||||
return new Refine(serviceContext);
|
||||
case ResponseMode.TREE_SUMMARIZE:
|
||||
return new TreeSummarize(serviceContext);
|
||||
default:
|
||||
return new CompactAndRefine(serviceContext);
|
||||
class MultiModal extends BaseSynthesizer {
|
||||
metadataMode: MetadataMode;
|
||||
textQATemplate: TextQAPrompt;
|
||||
|
||||
constructor({
|
||||
textQATemplate,
|
||||
metadataMode,
|
||||
...options
|
||||
}: BaseSynthesizerOptions & {
|
||||
textQATemplate?: TextQAPrompt;
|
||||
metadataMode?: MetadataMode;
|
||||
} = {}) {
|
||||
super(options);
|
||||
|
||||
this.metadataMode = metadataMode ?? MetadataMode.NONE;
|
||||
this.textQATemplate = textQATemplate ?? defaultTextQAPrompt;
|
||||
}
|
||||
|
||||
protected _getPromptModules(): ModuleRecord {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected _getPrompts(): { textQATemplate: TextQAPrompt } {
|
||||
return {
|
||||
textQATemplate: this.textQATemplate,
|
||||
};
|
||||
}
|
||||
|
||||
protected _updatePrompts(promptsDict: {
|
||||
textQATemplate: TextQAPrompt;
|
||||
}): void {
|
||||
if (promptsDict.textQATemplate) {
|
||||
this.textQATemplate = promptsDict.textQATemplate;
|
||||
}
|
||||
}
|
||||
|
||||
protected async getResponse(
|
||||
query: MessageContent,
|
||||
nodes: NodeWithScore[],
|
||||
stream: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const prompt = await createMessageContent(
|
||||
this.textQATemplate,
|
||||
nodes.map(({ node }) => node),
|
||||
// this might not be good as this remove the image information
|
||||
{ query: extractText(query) },
|
||||
this.metadataMode,
|
||||
);
|
||||
|
||||
const llm = this.llm;
|
||||
|
||||
if (stream) {
|
||||
const response = await llm.complete({
|
||||
prompt,
|
||||
stream,
|
||||
});
|
||||
return streamConverter(response, ({ text }) =>
|
||||
EngineResponse.fromResponse(text, true),
|
||||
);
|
||||
}
|
||||
const response = await llm.complete({
|
||||
prompt,
|
||||
});
|
||||
return EngineResponse.fromResponse(response.text, false);
|
||||
}
|
||||
}
|
||||
|
||||
export type ResponseBuilderPrompts =
|
||||
| TextQAPrompt
|
||||
| TreeSummarizePrompt
|
||||
| RefinePrompt;
|
||||
export function getResponseSynthesizer(
|
||||
mode: ResponseMode,
|
||||
options: BaseSynthesizerOptions & {
|
||||
textQATemplate?: TextQAPrompt;
|
||||
refineTemplate?: RefinePrompt;
|
||||
summaryTemplate?: TreeSummarizePrompt;
|
||||
metadataMode?: MetadataMode;
|
||||
} = {},
|
||||
) {
|
||||
switch (mode) {
|
||||
case "compact": {
|
||||
return new CompactAndRefine(options);
|
||||
}
|
||||
case "refine": {
|
||||
return new Refine(options);
|
||||
}
|
||||
case "tree_summarize": {
|
||||
return new TreeSummarize(options);
|
||||
}
|
||||
case "multi_modal": {
|
||||
return new MultiModal(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
export {
|
||||
BaseSynthesizer,
|
||||
type BaseSynthesizerOptions,
|
||||
} from "./base-synthesizer";
|
||||
export { getResponseSynthesizer, type ResponseMode } from "./factory";
|
||||
export type {
|
||||
SynthesizeEndEvent,
|
||||
SynthesizeQuery,
|
||||
SynthesizeStartEvent,
|
||||
} from "./type";
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { QueryType } from "../query-engine";
|
||||
import { EngineResponse, type NodeWithScore } from "../schema";
|
||||
|
||||
export type SynthesizeQuery = {
|
||||
query: QueryType;
|
||||
nodes: NodeWithScore[];
|
||||
additionalSourceNodes?: NodeWithScore[];
|
||||
};
|
||||
|
||||
export type SynthesizeStartEvent = {
|
||||
id: string;
|
||||
query: SynthesizeQuery;
|
||||
};
|
||||
|
||||
export type SynthesizeEndEvent = {
|
||||
id: string;
|
||||
query: SynthesizeQuery;
|
||||
response: EngineResponse | AsyncIterable<EngineResponse>;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
export { wrapEventCaller } from "./event-caller";
|
||||
export { EventCaller, getEventCaller, wrapEventCaller } from "./event-caller";
|
||||
|
||||
export async function* streamConverter<S, D>(
|
||||
stream: AsyncIterable<S>,
|
||||
@@ -47,10 +47,12 @@ export async function* streamReducer<S, D>(params: {
|
||||
export { wrapLLMEvent } from "./wrap-llm-event";
|
||||
|
||||
export {
|
||||
createMessageContent,
|
||||
extractDataUrlComponents,
|
||||
extractImage,
|
||||
extractSingleText,
|
||||
extractText,
|
||||
imageToDataUrl,
|
||||
messagesToHistory,
|
||||
toToolDescriptions,
|
||||
} from "./llms";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { fs } from "@llamaindex/env";
|
||||
import { filetypemime } from "magic-bytes.js";
|
||||
import type {
|
||||
ChatMessage,
|
||||
MessageContent,
|
||||
@@ -5,8 +7,16 @@ import type {
|
||||
MessageContentTextDetail,
|
||||
ToolMetadata,
|
||||
} from "../llms";
|
||||
import type { BasePromptTemplate } from "../prompts";
|
||||
import type { QueryType } from "../query-engine";
|
||||
import type { ImageType } from "../schema";
|
||||
import {
|
||||
type BaseNode,
|
||||
ImageNode,
|
||||
MetadataMode,
|
||||
ModalityType,
|
||||
splitNodesByType,
|
||||
} from "../schema";
|
||||
|
||||
/**
|
||||
* Extracts just the text whether from
|
||||
@@ -107,3 +117,99 @@ export function toToolDescriptions(tools: ToolMetadata[]): string {
|
||||
|
||||
return JSON.stringify(toolsObj, null, 4);
|
||||
}
|
||||
|
||||
async function blobToDataUrl(input: Blob) {
|
||||
const buffer = Buffer.from(await input.arrayBuffer());
|
||||
const mimes = filetypemime(buffer);
|
||||
if (mimes.length < 1) {
|
||||
throw new Error("Unsupported image type");
|
||||
}
|
||||
return "data:" + mimes[0] + ";base64," + buffer.toString("base64");
|
||||
}
|
||||
|
||||
export async function imageToDataUrl(
|
||||
input: ImageType | Uint8Array,
|
||||
): Promise<string> {
|
||||
// first ensure, that the input is a Blob
|
||||
if (
|
||||
(input instanceof URL && input.protocol === "file:") ||
|
||||
typeof input === "string"
|
||||
) {
|
||||
// string or file URL
|
||||
const dataBuffer = await fs.readFile(
|
||||
input instanceof URL ? input.pathname : input,
|
||||
);
|
||||
input = new Blob([dataBuffer]);
|
||||
} else if (!(input instanceof Blob)) {
|
||||
if (input instanceof URL) {
|
||||
throw new Error(`Unsupported URL with protocol: ${input.protocol}`);
|
||||
} else if (input instanceof Uint8Array) {
|
||||
input = new Blob([input]); // convert Uint8Array to Blob
|
||||
} else {
|
||||
throw new Error(`Unsupported input type: ${typeof input}`);
|
||||
}
|
||||
}
|
||||
return await blobToDataUrl(input);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
async function createContentPerModality(
|
||||
prompt: BasePromptTemplate,
|
||||
type: ModalityType,
|
||||
nodes: BaseNode[],
|
||||
extraParams: Record<string, string>,
|
||||
metadataMode: MetadataMode,
|
||||
): Promise<MessageContentDetail[]> {
|
||||
switch (type) {
|
||||
case ModalityType.TEXT:
|
||||
return [
|
||||
{
|
||||
type: "text",
|
||||
text: prompt.format({
|
||||
...extraParams,
|
||||
context: nodes.map((r) => r.getContent(metadataMode)).join("\n\n"),
|
||||
}),
|
||||
},
|
||||
];
|
||||
case ModalityType.IMAGE:
|
||||
const images: MessageContentDetail[] = await Promise.all(
|
||||
(nodes as ImageNode[]).map(async (node) => {
|
||||
return {
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: await imageToDataUrl(node.image),
|
||||
},
|
||||
} satisfies MessageContentDetail;
|
||||
}),
|
||||
);
|
||||
return images;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function createMessageContent(
|
||||
prompt: BasePromptTemplate,
|
||||
nodes: BaseNode[],
|
||||
extraParams: Record<string, string> = {},
|
||||
metadataMode: MetadataMode = MetadataMode.NONE,
|
||||
): Promise<MessageContentDetail[]> {
|
||||
const content: MessageContentDetail[] = [];
|
||||
const nodeMap = splitNodesByType(nodes);
|
||||
for (const type in nodeMap) {
|
||||
// for each retrieved modality type, create message content
|
||||
const nodes = nodeMap[type as ModalityType];
|
||||
if (nodes) {
|
||||
content.push(
|
||||
...(await createContentPerModality(
|
||||
prompt,
|
||||
type as ModalityType,
|
||||
nodes,
|
||||
extraParams,
|
||||
metadataMode,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
Vendored
+8
@@ -1,5 +1,13 @@
|
||||
# @llamaindex/env
|
||||
|
||||
## 0.1.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b48bcc3: feat: add `load-transformers` event type when loading `@xenova/transformers` module
|
||||
|
||||
This would benefit user who want to customize the transformer env.
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
Vendored
+13
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/env",
|
||||
"description": "environment wrapper, supports all JS environment including node, deno, bun, edge runtime, and cloudflare worker",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.12",
|
||||
"type": "module",
|
||||
"types": "dist/type/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
@@ -74,16 +74,18 @@
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@swc/cli": "^0.4.0",
|
||||
"@swc/core": "^1.7.22",
|
||||
"@xenova/transformers": "^2.17.2",
|
||||
"concurrently": "^8.2.2",
|
||||
"pathe": "^1.1.2",
|
||||
"tiktoken": "^1.0.16",
|
||||
"vitest": "^2.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/lodash": "^4.17.7",
|
||||
"@types/node": "^22.5.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@xenova/transformers": "^2.17.2",
|
||||
"js-tiktoken": "^1.0.12",
|
||||
"pathe": "^1.1.2",
|
||||
"tiktoken": "^1.0.15"
|
||||
@@ -92,8 +94,17 @@
|
||||
"@aws-crypto/sha256-js": {
|
||||
"optional": true
|
||||
},
|
||||
"@xenova/transformers": {
|
||||
"optional": true
|
||||
},
|
||||
"pathe": {
|
||||
"optional": true
|
||||
},
|
||||
"tiktoken": {
|
||||
"optional": true
|
||||
},
|
||||
"js-tiktoken": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+6
@@ -6,6 +6,12 @@
|
||||
import "./global-check.js";
|
||||
export * from "./web-polyfill.js";
|
||||
|
||||
export {
|
||||
loadTransformers,
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./multi-model/index.browser.js";
|
||||
export { Tokenizers, tokenizers, type Tokenizer } from "./tokenizers/js.js";
|
||||
|
||||
// @ts-expect-error
|
||||
|
||||
Vendored
+6
@@ -6,4 +6,10 @@
|
||||
import "./global-check.js";
|
||||
export * from "./node-polyfill.js";
|
||||
|
||||
export {
|
||||
loadTransformers,
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./multi-model/index.non-nodejs.js";
|
||||
export { Tokenizers, tokenizers, type Tokenizer } from "./tokenizers/js.js";
|
||||
|
||||
Vendored
+6
@@ -33,6 +33,12 @@ export function createSHA256(): SHA256 {
|
||||
};
|
||||
}
|
||||
|
||||
export {
|
||||
loadTransformers,
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./multi-model/index.js";
|
||||
export { Tokenizers, tokenizers, type Tokenizer } from "./tokenizers/node.js";
|
||||
export {
|
||||
AsyncLocalStorage,
|
||||
|
||||
Vendored
+6
@@ -13,4 +13,10 @@ export function getEnv(name: string): string | undefined {
|
||||
return INTERNAL_ENV[name];
|
||||
}
|
||||
|
||||
export {
|
||||
loadTransformers,
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./multi-model/index.non-nodejs.js";
|
||||
export { Tokenizers, tokenizers, type Tokenizer } from "./tokenizers/js.js";
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { getTransformers, setTransformers, type OnLoad } from "./shared.js";
|
||||
|
||||
export {
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./shared.js";
|
||||
export async function loadTransformers(onLoad: OnLoad) {
|
||||
if (getTransformers() === null) {
|
||||
setTransformers(
|
||||
// @ts-expect-error
|
||||
await import("https://cdn.jsdelivr.net/npm/@xenova/transformers@2.17.2"),
|
||||
);
|
||||
} else {
|
||||
return getTransformers()!;
|
||||
}
|
||||
const transformer = getTransformers()!;
|
||||
onLoad(transformer);
|
||||
return transformer;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { getTransformers, setTransformers, type OnLoad } from "./shared.js";
|
||||
export {
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./shared.js";
|
||||
|
||||
export async function loadTransformers(onLoad: OnLoad) {
|
||||
if (getTransformers() === null) {
|
||||
/**
|
||||
* If you see this warning, it means that the current environment does not support the transformer.
|
||||
* because "@xeonva/transformers" highly depends on Node.js APIs.
|
||||
*
|
||||
* One possible solution is to fix their implementation to make it work in the non-Node.js environment,
|
||||
* but it's not worth the effort because Edge Runtime and Cloudflare Workers are not the for heavy Machine Learning task.
|
||||
*
|
||||
* Or you can provide an RPC server that runs the transformer in a Node.js environment.
|
||||
* Or you just run the code in a Node.js environment.
|
||||
*
|
||||
* Refs: https://github.com/xenova/transformers.js/issues/309
|
||||
*/
|
||||
console.warn(
|
||||
'"@xenova/transformers" is not officially supported in this environment, some features may not work as expected.',
|
||||
);
|
||||
setTransformers(
|
||||
// @ts-expect-error
|
||||
await import("@xenova/transformers/dist/transformers"),
|
||||
);
|
||||
} else {
|
||||
return getTransformers()!;
|
||||
}
|
||||
const transformer = getTransformers()!;
|
||||
onLoad(transformer);
|
||||
return transformer;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { getTransformers, setTransformers, type OnLoad } from "./shared.js";
|
||||
|
||||
export {
|
||||
setTransformers,
|
||||
type LoadTransformerEvent,
|
||||
type OnLoad,
|
||||
} from "./shared.js";
|
||||
|
||||
export async function loadTransformers(onLoad: OnLoad) {
|
||||
if (getTransformers() === null) {
|
||||
setTransformers(await import("@xenova/transformers"));
|
||||
} else {
|
||||
return getTransformers()!;
|
||||
}
|
||||
const transformer = getTransformers()!;
|
||||
|
||||
onLoad(transformer);
|
||||
|
||||
return transformer;
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
let transformer: typeof import("@xenova/transformers") | null = null;
|
||||
|
||||
export function getTransformers() {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
export function setTransformers(t: typeof import("@xenova/transformers")) {
|
||||
transformer = t;
|
||||
}
|
||||
|
||||
export type OnLoad = (
|
||||
transformer: typeof import("@xenova/transformers"),
|
||||
) => void;
|
||||
|
||||
export type LoadTransformerEvent = {
|
||||
transformer: typeof import("@xenova/transformers");
|
||||
};
|
||||
@@ -1,5 +1,28 @@
|
||||
# @llamaindex/experimental
|
||||
|
||||
## 0.0.82
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.0.81
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2cd1383: refactor: align `response-synthesizers` & `chat-engine` module
|
||||
|
||||
- builtin event system
|
||||
- correct class extends
|
||||
- aligin APIs, naming with llama-index python
|
||||
- move stream out of first parameter to second parameter for the better tyep checking
|
||||
- remove JSONQueryEngine in `@llamaindex/experimental`, as the code quality is not satisify and we will bring it back later
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.0.80
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/experimental",
|
||||
"description": "Experimental package for LlamaIndexTS",
|
||||
"version": "0.0.80",
|
||||
"version": "0.0.82",
|
||||
"type": "module",
|
||||
"types": "dist/type/index.d.ts",
|
||||
"main": "dist/cjs/index.js",
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
import jsonpath from "jsonpath";
|
||||
|
||||
import { EngineResponse } from "llamaindex";
|
||||
|
||||
import { serviceContextFromDefaults, type ServiceContext } from "llamaindex";
|
||||
|
||||
import type {
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "llamaindex";
|
||||
|
||||
import {
|
||||
defaultJsonPathPrompt,
|
||||
defaultResponseSynthesizePrompt,
|
||||
type JSONPathPrompt,
|
||||
type ResponseSynthesisPrompt,
|
||||
} from "./prompt.js";
|
||||
|
||||
export type JSONSchemaType = Record<string, unknown>;
|
||||
|
||||
function removeExtraQuotes(expr: string) {
|
||||
let startIndex = 0;
|
||||
let endIndex = expr.length;
|
||||
|
||||
// Trim the leading backticks and single quotes
|
||||
while (
|
||||
startIndex < endIndex &&
|
||||
(expr[startIndex] === "`" || expr[startIndex] === "'")
|
||||
) {
|
||||
startIndex++;
|
||||
}
|
||||
|
||||
// Trim the trailing backticks and single quotes
|
||||
while (
|
||||
endIndex > startIndex &&
|
||||
(expr[endIndex - 1] === "`" || expr[endIndex - 1] === "'")
|
||||
) {
|
||||
endIndex--;
|
||||
}
|
||||
|
||||
// Return the trimmed substring
|
||||
return expr.substring(startIndex, endIndex);
|
||||
}
|
||||
|
||||
export const defaultOutputProcessor = async ({
|
||||
llmOutput,
|
||||
jsonValue,
|
||||
}: {
|
||||
llmOutput: string;
|
||||
jsonValue: JSONSchemaType;
|
||||
}): Promise<Record<string, unknown>[]> => {
|
||||
const expressions = llmOutput
|
||||
.split(",")
|
||||
.map((expr) => removeExtraQuotes(expr.trim()));
|
||||
|
||||
const results: Record<string, unknown>[] = [];
|
||||
|
||||
for (const expression of expressions) {
|
||||
// get the key for example content from $.content
|
||||
const key = expression.split(".").pop();
|
||||
|
||||
try {
|
||||
const datums = jsonpath.query(jsonValue, expression);
|
||||
|
||||
if (!key) throw new Error(`Invalid JSON Path: ${expression}`);
|
||||
|
||||
for (const datum of datums) {
|
||||
// in case there is a filter like [?(@.username=='simon')] without a key ie: $..comments[?(@.username=='simon').content]
|
||||
if (key.includes("==")) {
|
||||
results.push(datum);
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push({
|
||||
[key]: datum,
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error(`Invalid JSON Path: ${expression}`);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
type OutputProcessor = typeof defaultOutputProcessor;
|
||||
|
||||
/**
|
||||
* A JSON query engine that uses JSONPath to query a JSON object.
|
||||
*/
|
||||
export class JSONQueryEngine implements QueryEngine {
|
||||
jsonValue: JSONSchemaType;
|
||||
jsonSchema: JSONSchemaType;
|
||||
serviceContext: ServiceContext;
|
||||
outputProcessor: OutputProcessor;
|
||||
verbose: boolean;
|
||||
jsonPathPrompt: JSONPathPrompt;
|
||||
synthesizeResponse: boolean;
|
||||
responseSynthesisPrompt: ResponseSynthesisPrompt;
|
||||
|
||||
constructor(init: {
|
||||
jsonValue: JSONSchemaType;
|
||||
jsonSchema: JSONSchemaType;
|
||||
serviceContext?: ServiceContext;
|
||||
jsonPathPrompt?: JSONPathPrompt;
|
||||
outputProcessor?: OutputProcessor;
|
||||
synthesizeResponse?: boolean;
|
||||
responseSynthesisPrompt?: ResponseSynthesisPrompt;
|
||||
verbose?: boolean;
|
||||
}) {
|
||||
this.jsonValue = init.jsonValue;
|
||||
this.jsonSchema = init.jsonSchema;
|
||||
this.serviceContext = init.serviceContext ?? serviceContextFromDefaults({});
|
||||
this.jsonPathPrompt = init.jsonPathPrompt ?? defaultJsonPathPrompt;
|
||||
this.outputProcessor = init.outputProcessor ?? defaultOutputProcessor;
|
||||
this.verbose = init.verbose ?? false;
|
||||
this.synthesizeResponse = init.synthesizeResponse ?? true;
|
||||
this.responseSynthesisPrompt =
|
||||
init.responseSynthesisPrompt ?? defaultResponseSynthesizePrompt;
|
||||
}
|
||||
|
||||
getPrompts(): Record<string, unknown> {
|
||||
return {
|
||||
jsonPathPrompt: this.jsonPathPrompt,
|
||||
responseSynthesisPrompt: this.responseSynthesisPrompt,
|
||||
};
|
||||
}
|
||||
|
||||
updatePrompts(prompts: {
|
||||
jsonPathPrompt?: JSONPathPrompt;
|
||||
responseSynthesisPrompt?: ResponseSynthesisPrompt;
|
||||
}): void {
|
||||
if (prompts.jsonPathPrompt) {
|
||||
this.jsonPathPrompt = prompts.jsonPathPrompt;
|
||||
}
|
||||
if (prompts.responseSynthesisPrompt) {
|
||||
this.responseSynthesisPrompt = prompts.responseSynthesisPrompt;
|
||||
}
|
||||
}
|
||||
|
||||
getPromptModules(): Record<string, unknown> {
|
||||
return {};
|
||||
}
|
||||
|
||||
getSchemaContext(): string {
|
||||
return JSON.stringify(this.jsonSchema);
|
||||
}
|
||||
|
||||
query(
|
||||
params: QueryEngineParamsStreaming,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<EngineResponse>;
|
||||
async query(
|
||||
params: QueryEngineParamsStreaming | QueryEngineParamsNonStreaming,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const { query, stream } = params;
|
||||
|
||||
if (stream) {
|
||||
throw new Error("Streaming is not supported");
|
||||
}
|
||||
|
||||
const schema = this.getSchemaContext();
|
||||
|
||||
const { text: jsonPathResponse } = await this.serviceContext.llm.complete({
|
||||
prompt: this.jsonPathPrompt({ query, schema }),
|
||||
});
|
||||
|
||||
if (this.verbose) {
|
||||
console.log(
|
||||
`> JSONPath Instructions:\n\`\`\`\n${jsonPathResponse}\n\`\`\`\n`,
|
||||
);
|
||||
}
|
||||
|
||||
const jsonPathOutput = await this.outputProcessor({
|
||||
llmOutput: jsonPathResponse,
|
||||
jsonValue: this.jsonValue,
|
||||
});
|
||||
|
||||
if (this.verbose) {
|
||||
console.log(`> JSONPath Output: ${jsonPathOutput}\n`);
|
||||
}
|
||||
|
||||
let responseStr;
|
||||
|
||||
if (this.synthesizeResponse) {
|
||||
responseStr = await this.serviceContext.llm.complete({
|
||||
prompt: this.responseSynthesisPrompt({
|
||||
query,
|
||||
jsonSchema: schema,
|
||||
jsonPath: jsonPathResponse,
|
||||
jsonPathValue: JSON.stringify(jsonPathOutput),
|
||||
}),
|
||||
});
|
||||
|
||||
responseStr = responseStr.text;
|
||||
} else {
|
||||
responseStr = JSON.stringify(jsonPathOutput);
|
||||
}
|
||||
|
||||
const responseMetadata = {
|
||||
jsonPathResponse,
|
||||
};
|
||||
|
||||
const response = EngineResponse.fromResponse(responseStr, false);
|
||||
|
||||
response.metadata = responseMetadata;
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./JSONQueryEngine.js";
|
||||
@@ -1,36 +0,0 @@
|
||||
export const defaultJsonPathPrompt = ({
|
||||
query,
|
||||
schema,
|
||||
}: {
|
||||
query: string;
|
||||
schema: string;
|
||||
}) => `
|
||||
We have provided a JSON schema below:
|
||||
${schema}
|
||||
Given a task, respond with a JSON Path query that can retrieve data from a JSON value that matches the schema.
|
||||
Task: ${query}
|
||||
JSONPath:
|
||||
`;
|
||||
|
||||
export type JSONPathPrompt = typeof defaultJsonPathPrompt;
|
||||
|
||||
export const defaultResponseSynthesizePrompt = ({
|
||||
query,
|
||||
jsonSchema,
|
||||
jsonPath,
|
||||
jsonPathValue,
|
||||
}: {
|
||||
query: string;
|
||||
jsonSchema: string;
|
||||
jsonPath: string;
|
||||
jsonPathValue: string;
|
||||
}) => `
|
||||
Given a query, synthesize a response to satisfy the query using the JSON results. Only include details that are relevant to the query. If you don't know the answer, then say that.
|
||||
JSON Schema: ${jsonSchema}
|
||||
JSON Path: ${jsonPath}
|
||||
Value at path: ${jsonPathValue}
|
||||
Query: ${query}
|
||||
Response:
|
||||
`;
|
||||
|
||||
export type ResponseSynthesisPrompt = typeof defaultResponseSynthesizePrompt;
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./engines/query/index.js";
|
||||
|
||||
@@ -1,5 +1,40 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.6.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b48bcc3: feat: add `load-transformers` event type when loading `@xenova/transformers` module
|
||||
|
||||
This would benefit user who want to customize the transformer env.
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- @llamaindex/core@0.2.4
|
||||
- @llamaindex/env@0.1.12
|
||||
- @llamaindex/openai@0.1.6
|
||||
- @llamaindex/groq@0.0.5
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2cd1383: refactor: align `response-synthesizers` & `chat-engine` module
|
||||
|
||||
- builtin event system
|
||||
- correct class extends
|
||||
- aligin APIs, naming with llama-index python
|
||||
- move stream out of first parameter to second parameter for the better tyep checking
|
||||
- remove JSONQueryEngine in `@llamaindex/experimental`, as the code quality is not satisify and we will bring it back later
|
||||
|
||||
- 5c4badb: Extend JinaAPIEmbedding parameters
|
||||
- Updated dependencies [fb36eff]
|
||||
- Updated dependencies [d24d3d1]
|
||||
- Updated dependencies [2cd1383]
|
||||
- @llamaindex/cloud@0.2.7
|
||||
- @llamaindex/core@0.2.3
|
||||
- @llamaindex/openai@0.1.5
|
||||
- @llamaindex/groq@0.0.4
|
||||
|
||||
## 0.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
POSTGRES_USER=runner
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/cloudflare-worker-agent-test
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/cloudflare-worker-agent-test",
|
||||
"version": "0.0.64",
|
||||
"version": "0.0.66",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -100,7 +100,8 @@
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
|
||||
"tsBuildInfoFile": "./dist/.tsbuildinfo"
|
||||
},
|
||||
"exclude": ["test"]
|
||||
}
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @llamaindex/llama-parse-browser-test
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [fb36eff]
|
||||
- Updated dependencies [d24d3d1]
|
||||
- @llamaindex/cloud@0.2.7
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/llama-parse-browser-test",
|
||||
"private": true,
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/next-agent-test
|
||||
|
||||
## 0.1.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.1.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.1.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/next-agent-test",
|
||||
"version": "0.1.64",
|
||||
"version": "0.1.66",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# test-edge-runtime
|
||||
|
||||
## 0.1.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.1.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.1.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/nextjs-edge-runtime-test",
|
||||
"version": "0.1.63",
|
||||
"version": "0.1.65",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
:root {
|
||||
--max-width: 1100px;
|
||||
--border-radius: 12px;
|
||||
--font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono",
|
||||
"Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro",
|
||||
"Fira Mono", "Droid Sans Mono", "Courier New", monospace;
|
||||
|
||||
--foreground-rgb: 0, 0, 0;
|
||||
--background-start-rgb: 214, 219, 220;
|
||||
--background-end-rgb: 255, 255, 255;
|
||||
|
||||
--primary-glow: conic-gradient(
|
||||
from 180deg at 50% 50%,
|
||||
#16abff33 0deg,
|
||||
#0885ff33 55deg,
|
||||
#54d6ff33 120deg,
|
||||
#0071ff33 160deg,
|
||||
transparent 360deg
|
||||
);
|
||||
--secondary-glow: radial-gradient(
|
||||
rgba(255, 255, 255, 1),
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 239, 245, 249;
|
||||
--tile-end-rgb: 228, 232, 233;
|
||||
--tile-border: conic-gradient(
|
||||
#00000080,
|
||||
#00000040,
|
||||
#00000030,
|
||||
#00000020,
|
||||
#00000010,
|
||||
#00000010,
|
||||
#00000080
|
||||
);
|
||||
|
||||
--callout-rgb: 238, 240, 241;
|
||||
--callout-border-rgb: 172, 175, 176;
|
||||
--card-rgb: 180, 185, 188;
|
||||
--card-border-rgb: 131, 134, 135;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--foreground-rgb: 255, 255, 255;
|
||||
--background-start-rgb: 0, 0, 0;
|
||||
--background-end-rgb: 0, 0, 0;
|
||||
|
||||
--primary-glow: radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));
|
||||
--secondary-glow: linear-gradient(
|
||||
to bottom right,
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0),
|
||||
rgba(1, 65, 255, 0.3)
|
||||
);
|
||||
|
||||
--tile-start-rgb: 2, 13, 46;
|
||||
--tile-end-rgb: 2, 5, 19;
|
||||
--tile-border: conic-gradient(
|
||||
#ffffff80,
|
||||
#ffffff40,
|
||||
#ffffff30,
|
||||
#ffffff20,
|
||||
#ffffff10,
|
||||
#ffffff10,
|
||||
#ffffff80
|
||||
);
|
||||
|
||||
--callout-rgb: 20, 20, 20;
|
||||
--callout-border-rgb: 108, 108, 108;
|
||||
--card-rgb: 100, 100, 100;
|
||||
--card-border-rgb: 200, 200, 200;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
color: rgb(var(--foreground-rgb));
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent,
|
||||
rgb(var(--background-end-rgb))
|
||||
)
|
||||
rgb(var(--background-start-rgb));
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// test runtime
|
||||
import "llamaindex";
|
||||
import { ClipEmbedding } from "llamaindex/embeddings/ClipEmbedding";
|
||||
import { ClipEmbedding } from "llamaindex";
|
||||
import "llamaindex/readers/SimpleDirectoryReader";
|
||||
|
||||
// @ts-expect-error
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/next-node-runtime
|
||||
|
||||
## 0.0.47
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.0.46
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.0.45
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/next-node-runtime-test",
|
||||
"version": "0.0.45",
|
||||
"version": "0.0.47",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# @llamaindex/waku-query-engine-test
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b48bcc3]
|
||||
- llamaindex@0.6.4
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2cd1383]
|
||||
- Updated dependencies [5c4badb]
|
||||
- llamaindex@0.6.3
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/waku-query-engine-test",
|
||||
"version": "0.0.64",
|
||||
"version": "0.0.66",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
import { Document, VectorStoreIndex, type QueryEngine } from "llamaindex";
|
||||
import { BaseQueryEngine, Document, VectorStoreIndex } from "llamaindex";
|
||||
import { readFile } from "node:fs/promises";
|
||||
let _queryEngine: QueryEngine;
|
||||
let _queryEngine: BaseQueryEngine;
|
||||
|
||||
async function lazyLoadQueryEngine() {
|
||||
if (!_queryEngine) {
|
||||
|
||||
@@ -1,8 +1,41 @@
|
||||
import { ClipEmbedding, ImageNode } from "llamaindex";
|
||||
import type { LoadTransformerEvent } from "@llamaindex/env";
|
||||
import { setTransformers } from "@llamaindex/env";
|
||||
import { ClipEmbedding, ImageNode, Settings } from "llamaindex";
|
||||
import assert from "node:assert";
|
||||
import { test } from "node:test";
|
||||
import { type Mock, test } from "node:test";
|
||||
|
||||
let callback: Mock<(event: any) => void>;
|
||||
test.before(() => {
|
||||
callback = test.mock.fn((event: any) => {
|
||||
const { transformer } = event.detail as LoadTransformerEvent;
|
||||
assert.ok(transformer);
|
||||
assert.ok(transformer.env);
|
||||
});
|
||||
Settings.callbackManager.on("load-transformers", callback);
|
||||
});
|
||||
|
||||
test.beforeEach(() => {
|
||||
callback.mock.resetCalls();
|
||||
});
|
||||
|
||||
await test("clip embedding", async (t) => {
|
||||
await t.test("should trigger load transformer event", async () => {
|
||||
const nodes = [
|
||||
new ImageNode({
|
||||
image: new URL(
|
||||
"../../fixtures/img/llamaindex-white.png",
|
||||
import.meta.url,
|
||||
),
|
||||
}),
|
||||
];
|
||||
assert.equal(callback.mock.callCount(), 0);
|
||||
const clipEmbedding = new ClipEmbedding();
|
||||
assert.equal(callback.mock.callCount(), 0);
|
||||
const result = await clipEmbedding(nodes);
|
||||
assert.strictEqual(result.length, 1);
|
||||
assert.equal(callback.mock.callCount(), 1);
|
||||
});
|
||||
|
||||
await t.test("init & get image embedding", async () => {
|
||||
const clipEmbedding = new ClipEmbedding();
|
||||
const imgUrl = new URL(
|
||||
@@ -27,4 +60,25 @@ await test("clip embedding", async (t) => {
|
||||
assert.strictEqual(result.length, 1);
|
||||
assert.ok(result[0]!.embedding);
|
||||
});
|
||||
|
||||
await t.test("custom transformer", async () => {
|
||||
const transformers = await import("@xenova/transformers");
|
||||
const getter = test.mock.fn((t, k, r) => {
|
||||
return Reflect.get(t, k, r);
|
||||
});
|
||||
setTransformers(
|
||||
new Proxy(transformers, {
|
||||
get: getter,
|
||||
}),
|
||||
);
|
||||
const clipEmbedding = new ClipEmbedding();
|
||||
const imgUrl = new URL(
|
||||
"../../fixtures/img/llamaindex-white.png",
|
||||
import.meta.url,
|
||||
);
|
||||
assert.equal(getter.mock.callCount(), 0);
|
||||
const vec = await clipEmbedding.getImageEmbedding(imgUrl);
|
||||
assert.ok(vec);
|
||||
assert.ok(getter.mock.callCount() > 0);
|
||||
});
|
||||
});
|
||||
|
||||
+14
-10
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable turbo/no-undeclared-env-vars */
|
||||
import { config } from "dotenv";
|
||||
import { Document, VectorStoreQueryMode } from "llamaindex";
|
||||
import { PGVectorStore } from "llamaindex/vector-store/PGVectorStore";
|
||||
import assert from "node:assert";
|
||||
@@ -5,15 +7,21 @@ import { test } from "node:test";
|
||||
import pg from "pg";
|
||||
import { registerTypes } from "pgvector/pg";
|
||||
|
||||
config({ path: [".env.local", ".env", ".env.ci"] });
|
||||
|
||||
let pgClient: pg.Client | pg.Pool;
|
||||
test.afterEach(async () => {
|
||||
await pgClient.end();
|
||||
});
|
||||
|
||||
const pgConfig = {
|
||||
user: process.env.POSTGRES_USER ?? "user",
|
||||
password: process.env.POSTGRES_PASSWORD ?? "password",
|
||||
database: "llamaindex_node_test",
|
||||
};
|
||||
|
||||
await test("init with client", async () => {
|
||||
pgClient = new pg.Client({
|
||||
database: "llamaindex_node_test",
|
||||
});
|
||||
pgClient = new pg.Client(pgConfig);
|
||||
await pgClient.connect();
|
||||
await pgClient.query("CREATE EXTENSION IF NOT EXISTS vector");
|
||||
await registerTypes(pgClient);
|
||||
@@ -22,9 +30,7 @@ await test("init with client", async () => {
|
||||
});
|
||||
|
||||
await test("init with pool", async () => {
|
||||
pgClient = new pg.Pool({
|
||||
database: "llamaindex_node_test",
|
||||
});
|
||||
pgClient = new pg.Pool(pgConfig);
|
||||
await pgClient.query("CREATE EXTENSION IF NOT EXISTS vector");
|
||||
const client = await pgClient.connect();
|
||||
await registerTypes(client);
|
||||
@@ -34,9 +40,7 @@ await test("init with pool", async () => {
|
||||
});
|
||||
|
||||
await test("init without client", async () => {
|
||||
const vectorStore = new PGVectorStore({
|
||||
database: "llamaindex_node_test",
|
||||
});
|
||||
const vectorStore = new PGVectorStore(pgConfig);
|
||||
pgClient = (await vectorStore.client()) as pg.Client;
|
||||
assert.notDeepStrictEqual(pgClient, undefined);
|
||||
});
|
||||
@@ -52,7 +56,7 @@ await test("simple node", async () => {
|
||||
embedding: [0.1, 0.2, 0.3],
|
||||
});
|
||||
const vectorStore = new PGVectorStore({
|
||||
database: "llamaindex_node_test",
|
||||
...pgConfig,
|
||||
dimensions,
|
||||
schemaName,
|
||||
});
|
||||
@@ -4,14 +4,15 @@
|
||||
"version": "0.0.7",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"e2e": "node --import tsx --import ./mock-register.js --test ./node/*.e2e.ts",
|
||||
"e2e:nomock": "node --import tsx --test ./node/*.e2e.ts",
|
||||
"e2e:updatesnap": "UPDATE_SNAPSHOT=1 node --import tsx --test ./node/*.e2e.ts"
|
||||
"e2e": "node --import tsx --import ./mock-register.js --test ./node/**/*.e2e.ts",
|
||||
"e2e:nomock": "node --import tsx --test ./node/**/*.e2e.ts",
|
||||
"e2e:updatesnap": "UPDATE_SNAPSHOT=1 node --import tsx --test ./node/**/*.e2e.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^8.4.1",
|
||||
"@faker-js/faker": "^9.0.1",
|
||||
"@types/node": "^22.5.1",
|
||||
"consola": "^3.2.3",
|
||||
"dotenv": "^16.4.5",
|
||||
"llamaindex": "workspace:*",
|
||||
"tsx": "^4.19.0"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.6.2",
|
||||
"version": "0.6.4",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
@@ -33,8 +33,8 @@
|
||||
"@llamaindex/cloud": "workspace:*",
|
||||
"@llamaindex/core": "workspace:*",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@llamaindex/openai": "workspace:*",
|
||||
"@llamaindex/groq": "workspace:*",
|
||||
"@llamaindex/openai": "workspace:*",
|
||||
"@mistralai/mistralai": "^1.0.4",
|
||||
"@mixedbread-ai/sdk": "^2.2.11",
|
||||
"@pinecone-database/pinecone": "^3.0.2",
|
||||
@@ -43,7 +43,6 @@
|
||||
"@types/node": "^22.5.1",
|
||||
"@types/papaparse": "^5.3.14",
|
||||
"@types/pg": "^8.11.8",
|
||||
"@xenova/transformers": "^2.17.2",
|
||||
"@zilliz/milvus2-sdk-node": "^2.4.6",
|
||||
"ajv": "^8.17.1",
|
||||
"assemblyai": "^4.7.0",
|
||||
@@ -91,6 +90,7 @@
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@swc/cli": "^0.4.0",
|
||||
"@swc/core": "^1.7.22",
|
||||
"@xenova/transformers": "^2.17.2",
|
||||
"concurrently": "^8.2.2",
|
||||
"glob": "^11.0.0",
|
||||
"pg": "^8.12.0",
|
||||
|
||||
@@ -9,6 +9,8 @@ import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
|
||||
|
||||
/**
|
||||
* The ServiceContext is a collection of components that are used in different parts of the application.
|
||||
*
|
||||
* @deprecated This will no longer supported, please use `Settings` instead.
|
||||
*/
|
||||
export interface ServiceContext {
|
||||
llm: LLM;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
type NodeParser,
|
||||
SentenceSplitter,
|
||||
} from "@llamaindex/core/node-parser";
|
||||
import type { LoadTransformerEvent } from "@llamaindex/env";
|
||||
import { AsyncLocalStorage, getEnv } from "@llamaindex/env";
|
||||
import type { ServiceContext } from "./ServiceContext.js";
|
||||
import {
|
||||
@@ -20,6 +21,12 @@ import {
|
||||
withEmbeddedModel,
|
||||
} from "./internal/settings/EmbedModel.js";
|
||||
|
||||
declare module "@llamaindex/core/global" {
|
||||
interface LlamaIndexEventMaps {
|
||||
"load-transformers": LoadTransformerEvent;
|
||||
}
|
||||
}
|
||||
|
||||
export type PromptConfig = {
|
||||
llm?: string;
|
||||
lang?: string;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import type { Document, TransformComponent } from "@llamaindex/core/schema";
|
||||
import type { BaseRetriever } from "../Retriever.js";
|
||||
import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine.js";
|
||||
import type { BaseNodePostprocessor } from "../postprocessors/types.js";
|
||||
import type { BaseSynthesizer } from "../synthesizers/types.js";
|
||||
import type { QueryEngine } from "../types.js";
|
||||
import type { CloudRetrieveParams } from "./LlamaCloudRetriever.js";
|
||||
import { LlamaCloudRetriever } from "./LlamaCloudRetriever.js";
|
||||
import { getPipelineCreate } from "./config.js";
|
||||
@@ -300,7 +300,7 @@ export class LlamaCloudIndex {
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
} & CloudRetrieveParams,
|
||||
): QueryEngine {
|
||||
): BaseQueryEngine {
|
||||
const retriever = new LlamaCloudRetriever({
|
||||
...this.params,
|
||||
...params,
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
import { MultiModalEmbedding } from "@llamaindex/core/embeddings";
|
||||
import type { ImageType } from "@llamaindex/core/schema";
|
||||
import _ from "lodash";
|
||||
import { lazyLoadTransformers } from "../internal/deps/transformers.js";
|
||||
// only import type, to avoid bundling error
|
||||
import { loadTransformers } from "@llamaindex/env";
|
||||
import type {
|
||||
CLIPTextModelWithProjection,
|
||||
CLIPVisionModelWithProjection,
|
||||
PreTrainedTokenizer,
|
||||
Processor,
|
||||
} from "@xenova/transformers";
|
||||
import { Settings } from "../Settings.js";
|
||||
|
||||
async function readImage(input: ImageType) {
|
||||
const { RawImage } = await lazyLoadTransformers();
|
||||
const { RawImage } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (input instanceof Blob) {
|
||||
return await RawImage.fromBlob(input);
|
||||
} else if (_.isString(input) || input instanceof URL) {
|
||||
@@ -40,7 +49,15 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
}
|
||||
|
||||
async getTokenizer() {
|
||||
const { AutoTokenizer } = await lazyLoadTransformers();
|
||||
const { AutoTokenizer } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (!this.tokenizer) {
|
||||
this.tokenizer = await AutoTokenizer.from_pretrained(this.modelType);
|
||||
}
|
||||
@@ -48,7 +65,15 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
}
|
||||
|
||||
async getProcessor() {
|
||||
const { AutoProcessor } = await lazyLoadTransformers();
|
||||
const { AutoProcessor } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (!this.processor) {
|
||||
this.processor = await AutoProcessor.from_pretrained(this.modelType);
|
||||
}
|
||||
@@ -56,7 +81,17 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
}
|
||||
|
||||
async getVisionModel() {
|
||||
const { CLIPVisionModelWithProjection } = await lazyLoadTransformers();
|
||||
const { CLIPVisionModelWithProjection } = await loadTransformers(
|
||||
(transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (!this.visionModel) {
|
||||
this.visionModel = await CLIPVisionModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
@@ -67,7 +102,17 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
}
|
||||
|
||||
async getTextModel() {
|
||||
const { CLIPTextModelWithProjection } = await lazyLoadTransformers();
|
||||
const { CLIPTextModelWithProjection } = await loadTransformers(
|
||||
(transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (!this.textModel) {
|
||||
this.textModel = await CLIPTextModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { HfInference } from "@huggingface/inference";
|
||||
import { BaseEmbedding } from "@llamaindex/core/embeddings";
|
||||
import { lazyLoadTransformers } from "../internal/deps/transformers.js";
|
||||
import { loadTransformers } from "@llamaindex/env";
|
||||
import { Settings } from "../Settings.js";
|
||||
|
||||
export enum HuggingFaceEmbeddingModelType {
|
||||
XENOVA_ALL_MINILM_L6_V2 = "Xenova/all-MiniLM-L6-v2",
|
||||
@@ -33,7 +34,15 @@ export class HuggingFaceEmbedding extends BaseEmbedding {
|
||||
|
||||
async getExtractor() {
|
||||
if (!this.extractor) {
|
||||
const { pipeline } = await lazyLoadTransformers();
|
||||
const { pipeline } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
this.extractor = await pipeline("feature-extraction", this.modelType, {
|
||||
quantized: this.quantized,
|
||||
});
|
||||
|
||||
@@ -20,8 +20,9 @@ export type JinaEmbeddingRequest = {
|
||||
input: Array<{ text: string } | { url: string } | { bytes: string }>;
|
||||
model?: string;
|
||||
encoding_type?: EncodingType;
|
||||
task_type?: TaskType;
|
||||
task?: TaskType;
|
||||
dimensions?: number;
|
||||
late_chunking?: boolean;
|
||||
};
|
||||
|
||||
export type JinaEmbeddingResponse = {
|
||||
@@ -44,9 +45,10 @@ export class JinaAIEmbedding extends MultiModalEmbedding {
|
||||
apiKey: string;
|
||||
model: string;
|
||||
baseURL: string;
|
||||
taskType: TaskType | undefined;
|
||||
task?: TaskType | undefined;
|
||||
encodingType?: EncodingType | undefined;
|
||||
dimensions?: number | undefined;
|
||||
late_chunking?: boolean | undefined;
|
||||
|
||||
async getTextEmbedding(text: string): Promise<number[]> {
|
||||
const result = await this.getJinaEmbedding({ input: [{ text }] });
|
||||
@@ -87,8 +89,10 @@ export class JinaAIEmbedding extends MultiModalEmbedding {
|
||||
this.model = init?.model ?? "jina-embeddings-v3";
|
||||
this.baseURL = init?.baseURL ?? "https://api.jina.ai/v1/embeddings";
|
||||
init?.embedBatchSize && (this.embedBatchSize = init?.embedBatchSize);
|
||||
this.taskType = init?.taskType;
|
||||
this.task = init?.task;
|
||||
this.encodingType = init?.encodingType;
|
||||
this.dimensions = init?.dimensions;
|
||||
this.late_chunking = init?.late_chunking;
|
||||
}
|
||||
|
||||
private async getImageInput(
|
||||
@@ -125,8 +129,11 @@ export class JinaAIEmbedding extends MultiModalEmbedding {
|
||||
body: JSON.stringify({
|
||||
model: this.model,
|
||||
encoding_type: this.encodingType ?? "float",
|
||||
...(this.taskType && { task_type: this.taskType }),
|
||||
...(this.task && { task: this.task }),
|
||||
...(this.dimensions !== undefined && { dimensions: this.dimensions }),
|
||||
...(this.late_chunking !== undefined && {
|
||||
late_chunking: this.late_chunking,
|
||||
}),
|
||||
...params,
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -9,3 +9,5 @@ export * from "./MixedbreadAIEmbeddings.js";
|
||||
export { OllamaEmbedding } from "./OllamaEmbedding.js";
|
||||
export * from "./OpenAIEmbedding.js";
|
||||
export { TogetherEmbedding } from "./together.js";
|
||||
// ClipEmbedding might not work in non-node.js runtime, but it doesn't have side effects
|
||||
export { ClipEmbedding, ClipEmbeddingModelType } from "./ClipEmbedding.js";
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
type ModuleRecord,
|
||||
PromptMixin,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
|
||||
import type { EngineResponse } from "@llamaindex/core/schema";
|
||||
import {
|
||||
extractText,
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
} from "@llamaindex/core/utils";
|
||||
import type { ServiceContext } from "../../ServiceContext.js";
|
||||
import { llmFromSettingsOrContext } from "../../Settings.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type {
|
||||
ChatEngine,
|
||||
ChatEngineParamsNonStreaming,
|
||||
@@ -37,13 +37,13 @@ export class CondenseQuestionChatEngine
|
||||
extends PromptMixin
|
||||
implements ChatEngine
|
||||
{
|
||||
queryEngine: QueryEngine;
|
||||
queryEngine: BaseQueryEngine;
|
||||
chatHistory: BaseMemory;
|
||||
llm: LLM;
|
||||
condenseMessagePrompt: CondenseQuestionPrompt;
|
||||
|
||||
constructor(init: {
|
||||
queryEngine: QueryEngine;
|
||||
queryEngine: BaseQueryEngine;
|
||||
chatHistory: ChatMessage[];
|
||||
serviceContext?: ServiceContext;
|
||||
condenseMessagePrompt?: CondenseQuestionPrompt;
|
||||
@@ -114,10 +114,12 @@ export class CondenseQuestionChatEngine
|
||||
chatHistory.put({ content: message, role: "user" });
|
||||
|
||||
if (stream) {
|
||||
const stream = await this.queryEngine.query({
|
||||
query: condensedQuestion,
|
||||
stream: true,
|
||||
});
|
||||
const stream = await this.queryEngine.query(
|
||||
{
|
||||
query: condensedQuestion,
|
||||
},
|
||||
true,
|
||||
);
|
||||
return streamReducer({
|
||||
stream,
|
||||
initialValue: "",
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
PromptMixin,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import { MetadataMode, type NodeWithScore } from "@llamaindex/core/schema";
|
||||
import { createMessageContent } from "@llamaindex/core/utils";
|
||||
import type { BaseNodePostprocessor } from "../../postprocessors/index.js";
|
||||
import type { BaseRetriever } from "../../Retriever.js";
|
||||
import { createMessageContent } from "../../synthesizers/utils.js";
|
||||
import type { Context, ContextGenerator } from "./types.js";
|
||||
|
||||
export class DefaultContextGenerator
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import { PromptMixin } from "@llamaindex/core/prompts";
|
||||
import { EngineResponse, type NodeWithScore } from "@llamaindex/core/schema";
|
||||
import { wrapEventCaller } from "@llamaindex/core/utils";
|
||||
import { BaseQueryEngine } from "@llamaindex/core/query-engine";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import { getResponseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import { type NodeWithScore } from "@llamaindex/core/schema";
|
||||
import { extractText } from "@llamaindex/core/utils";
|
||||
import type { BaseNodePostprocessor } from "../../postprocessors/index.js";
|
||||
import type { BaseRetriever } from "../../Retriever.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/index.js";
|
||||
import { ResponseSynthesizer } from "../../synthesizers/index.js";
|
||||
import type {
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "../../types.js";
|
||||
|
||||
/**
|
||||
* A query engine that uses a retriever to query an index and then synthesizes the response.
|
||||
*/
|
||||
export class RetrieverQueryEngine extends PromptMixin implements QueryEngine {
|
||||
export class RetrieverQueryEngine extends BaseQueryEngine {
|
||||
retriever: BaseRetriever;
|
||||
responseSynthesizer: BaseSynthesizer;
|
||||
nodePostprocessors: BaseNodePostprocessor[];
|
||||
@@ -26,14 +21,36 @@ export class RetrieverQueryEngine extends PromptMixin implements QueryEngine {
|
||||
preFilters?: unknown,
|
||||
nodePostprocessors?: BaseNodePostprocessor[],
|
||||
) {
|
||||
super();
|
||||
super(async (strOrQueryBundle, stream) => {
|
||||
const nodesWithScore = await this.retrieve(
|
||||
typeof strOrQueryBundle === "string"
|
||||
? strOrQueryBundle
|
||||
: extractText(strOrQueryBundle),
|
||||
);
|
||||
if (stream) {
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query:
|
||||
typeof strOrQueryBundle === "string"
|
||||
? { query: strOrQueryBundle }
|
||||
: strOrQueryBundle,
|
||||
nodes: nodesWithScore,
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.responseSynthesizer.synthesize({
|
||||
query:
|
||||
typeof strOrQueryBundle === "string"
|
||||
? { query: strOrQueryBundle }
|
||||
: strOrQueryBundle,
|
||||
nodes: nodesWithScore,
|
||||
});
|
||||
});
|
||||
|
||||
this.retriever = retriever;
|
||||
this.responseSynthesizer =
|
||||
responseSynthesizer ||
|
||||
new ResponseSynthesizer({
|
||||
serviceContext: retriever.serviceContext,
|
||||
});
|
||||
responseSynthesizer || getResponseSynthesizer("compact");
|
||||
this.preFilters = preFilters;
|
||||
this.nodePostprocessors = nodePostprocessors || [];
|
||||
}
|
||||
@@ -71,29 +88,4 @@ export class RetrieverQueryEngine extends PromptMixin implements QueryEngine {
|
||||
|
||||
return await this.applyNodePostprocessors(nodes, query);
|
||||
}
|
||||
|
||||
query(
|
||||
params: QueryEngineParamsStreaming,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<EngineResponse>;
|
||||
@wrapEventCaller
|
||||
async query(
|
||||
params: QueryEngineParamsStreaming | QueryEngineParamsNonStreaming,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const { query, stream } = params;
|
||||
const nodesWithScore = await this.retrieve(query);
|
||||
if (stream) {
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query,
|
||||
nodesWithScore,
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.responseSynthesizer.synthesize({
|
||||
query,
|
||||
nodesWithScore,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { PromptMixin } from "@llamaindex/core/prompts";
|
||||
import type { QueryType } from "@llamaindex/core/query-engine";
|
||||
import {
|
||||
BaseQueryEngine,
|
||||
type QueryBundle,
|
||||
} from "@llamaindex/core/query-engine";
|
||||
import {
|
||||
BaseSynthesizer,
|
||||
getResponseSynthesizer,
|
||||
} from "@llamaindex/core/response-synthesizers";
|
||||
import { EngineResponse, type NodeWithScore } from "@llamaindex/core/schema";
|
||||
import { extractText } from "@llamaindex/core/utils";
|
||||
import type { ServiceContext } from "../../ServiceContext.js";
|
||||
import { llmFromSettingsOrContext } from "../../Settings.js";
|
||||
import type { BaseSelector } from "../../selectors/index.js";
|
||||
import { LLMSingleSelector } from "../../selectors/index.js";
|
||||
import { TreeSummarize } from "../../synthesizers/index.js";
|
||||
import type {
|
||||
QueryEngine,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
} from "../../types.js";
|
||||
|
||||
type RouterQueryEngineTool = {
|
||||
queryEngine: QueryEngine;
|
||||
queryEngine: BaseQueryEngine;
|
||||
description: string;
|
||||
};
|
||||
|
||||
@@ -23,59 +23,67 @@ type RouterQueryEngineMetadata = {
|
||||
};
|
||||
|
||||
async function combineResponses(
|
||||
summarizer: TreeSummarize,
|
||||
summarizer: BaseSynthesizer,
|
||||
responses: EngineResponse[],
|
||||
queryType: QueryType,
|
||||
queryBundle: QueryBundle,
|
||||
verbose: boolean = false,
|
||||
): Promise<EngineResponse> {
|
||||
if (verbose) {
|
||||
console.log("Combining responses from multiple query engines.");
|
||||
}
|
||||
|
||||
const responseStrs: string[] = [];
|
||||
const sourceNodes: NodeWithScore[] = [];
|
||||
|
||||
for (const response of responses) {
|
||||
if (response?.sourceNodes) {
|
||||
sourceNodes.push(...response.sourceNodes);
|
||||
}
|
||||
|
||||
responseStrs.push(extractText(response.message.content));
|
||||
}
|
||||
|
||||
const summary = await summarizer.getResponse({
|
||||
query: extractText(queryType),
|
||||
textChunks: responseStrs,
|
||||
return await summarizer.synthesize({
|
||||
query: queryBundle,
|
||||
nodes: sourceNodes,
|
||||
});
|
||||
|
||||
return EngineResponse.fromResponse(summary, false, sourceNodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A query engine that uses multiple query engines and selects the best one.
|
||||
*/
|
||||
export class RouterQueryEngine extends PromptMixin implements QueryEngine {
|
||||
export class RouterQueryEngine extends BaseQueryEngine {
|
||||
private selector: BaseSelector;
|
||||
private queryEngines: QueryEngine[];
|
||||
private queryEngines: BaseQueryEngine[];
|
||||
private metadatas: RouterQueryEngineMetadata[];
|
||||
private summarizer: TreeSummarize;
|
||||
private summarizer: BaseSynthesizer;
|
||||
private verbose: boolean;
|
||||
|
||||
constructor(init: {
|
||||
selector: BaseSelector;
|
||||
queryEngineTools: RouterQueryEngineTool[];
|
||||
serviceContext?: ServiceContext | undefined;
|
||||
summarizer?: TreeSummarize | undefined;
|
||||
summarizer?: BaseSynthesizer | undefined;
|
||||
verbose?: boolean | undefined;
|
||||
}) {
|
||||
super();
|
||||
super(async (strOrQueryBundle, stream) => {
|
||||
const response = await this.queryRoute(
|
||||
typeof strOrQueryBundle === "string"
|
||||
? { query: strOrQueryBundle }
|
||||
: strOrQueryBundle,
|
||||
);
|
||||
|
||||
if (stream) {
|
||||
throw new Error("Streaming is not supported yet.");
|
||||
}
|
||||
|
||||
return response;
|
||||
});
|
||||
|
||||
this.selector = init.selector;
|
||||
this.queryEngines = init.queryEngineTools.map((tool) => tool.queryEngine);
|
||||
this.metadatas = init.queryEngineTools.map((tool) => ({
|
||||
description: tool.description,
|
||||
}));
|
||||
this.summarizer = init.summarizer || new TreeSummarize(init.serviceContext);
|
||||
this.summarizer =
|
||||
init.summarizer || getResponseSynthesizer("tree_summarize");
|
||||
this.verbose = init.verbose ?? false;
|
||||
}
|
||||
|
||||
@@ -96,7 +104,7 @@ export class RouterQueryEngine extends PromptMixin implements QueryEngine {
|
||||
queryEngineTools: RouterQueryEngineTool[];
|
||||
selector?: BaseSelector;
|
||||
serviceContext?: ServiceContext;
|
||||
summarizer?: TreeSummarize;
|
||||
summarizer?: BaseSynthesizer;
|
||||
verbose?: boolean;
|
||||
}) {
|
||||
const serviceContext = init.serviceContext;
|
||||
@@ -114,25 +122,7 @@ export class RouterQueryEngine extends PromptMixin implements QueryEngine {
|
||||
});
|
||||
}
|
||||
|
||||
query(
|
||||
params: QueryEngineParamsStreaming,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<EngineResponse>;
|
||||
async query(
|
||||
params: QueryEngineParamsStreaming | QueryEngineParamsNonStreaming,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const { query, stream } = params;
|
||||
|
||||
const response = await this.queryRoute(query);
|
||||
|
||||
if (stream) {
|
||||
throw new Error("Streaming is not supported yet.");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async queryRoute(query: QueryType): Promise<EngineResponse> {
|
||||
private async queryRoute(query: QueryBundle): Promise<EngineResponse> {
|
||||
const result = await this.selector.select(this.metadatas, query);
|
||||
|
||||
if (result.selections.length > 1) {
|
||||
@@ -146,11 +136,7 @@ export class RouterQueryEngine extends PromptMixin implements QueryEngine {
|
||||
}
|
||||
|
||||
const selectedQueryEngine = this.queryEngines[engineInd.index]!;
|
||||
responses.push(
|
||||
await selectedQueryEngine.query({
|
||||
query: extractText(query),
|
||||
}),
|
||||
);
|
||||
responses.push(await selectedQueryEngine.query(query));
|
||||
}
|
||||
|
||||
if (responses.length > 1) {
|
||||
|
||||
@@ -1,29 +1,21 @@
|
||||
import {
|
||||
EngineResponse,
|
||||
TextNode,
|
||||
type NodeWithScore,
|
||||
} from "@llamaindex/core/schema";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import { getResponseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import { TextNode, type NodeWithScore } from "@llamaindex/core/schema";
|
||||
import { LLMQuestionGenerator } from "../../QuestionGenerator.js";
|
||||
import type { ServiceContext } from "../../ServiceContext.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/index.js";
|
||||
import {
|
||||
CompactAndRefine,
|
||||
ResponseSynthesizer,
|
||||
} from "../../synthesizers/index.js";
|
||||
|
||||
import type { BaseTool, ToolMetadata } from "@llamaindex/core/llms";
|
||||
import { PromptMixin, type PromptsRecord } from "@llamaindex/core/prompts";
|
||||
import type { BaseQueryEngine, QueryType } from "@llamaindex/core/query-engine";
|
||||
import { wrapEventCaller } from "@llamaindex/core/utils";
|
||||
import type { PromptsRecord } from "@llamaindex/core/prompts";
|
||||
import {
|
||||
BaseQueryEngine,
|
||||
type QueryBundle,
|
||||
} from "@llamaindex/core/query-engine";
|
||||
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 BaseQueryEngine {
|
||||
responseSynthesizer: BaseSynthesizer;
|
||||
questionGen: BaseQuestionGenerator;
|
||||
queryEngines: BaseTool[];
|
||||
@@ -34,11 +26,48 @@ export class SubQuestionQueryEngine
|
||||
responseSynthesizer: BaseSynthesizer;
|
||||
queryEngineTools: BaseTool[];
|
||||
}) {
|
||||
super();
|
||||
super(async (strOrQueryBundle, stream) => {
|
||||
let query: QueryBundle;
|
||||
if (typeof strOrQueryBundle === "string") {
|
||||
query = {
|
||||
query: strOrQueryBundle,
|
||||
};
|
||||
} else {
|
||||
query = strOrQueryBundle;
|
||||
}
|
||||
const subQuestions = await this.questionGen.generate(
|
||||
this.metadatas,
|
||||
strOrQueryBundle,
|
||||
);
|
||||
|
||||
const subQNodes = await Promise.all(
|
||||
subQuestions.map((subQ) => this.querySubQ(subQ)),
|
||||
);
|
||||
|
||||
const nodesWithScore: NodeWithScore[] = subQNodes.filter(
|
||||
(node) => node !== null,
|
||||
);
|
||||
if (stream) {
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query,
|
||||
nodes: nodesWithScore,
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query,
|
||||
nodes: nodesWithScore,
|
||||
},
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
this.questionGen = init.questionGen;
|
||||
this.responseSynthesizer =
|
||||
init.responseSynthesizer ?? new ResponseSynthesizer();
|
||||
init.responseSynthesizer ?? getResponseSynthesizer("compact");
|
||||
this.queryEngines = init.queryEngineTools;
|
||||
this.metadatas = init.queryEngineTools.map((tool) => tool.metadata);
|
||||
}
|
||||
@@ -62,15 +91,9 @@ export class SubQuestionQueryEngine
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
serviceContext?: ServiceContext;
|
||||
}) {
|
||||
const serviceContext = init.serviceContext;
|
||||
|
||||
const questionGen = init.questionGen ?? new LLMQuestionGenerator();
|
||||
const responseSynthesizer =
|
||||
init.responseSynthesizer ??
|
||||
new ResponseSynthesizer({
|
||||
responseBuilder: new CompactAndRefine(serviceContext),
|
||||
serviceContext,
|
||||
});
|
||||
init.responseSynthesizer ?? getResponseSynthesizer("compact");
|
||||
|
||||
return new SubQuestionQueryEngine({
|
||||
questionGen,
|
||||
@@ -79,40 +102,6 @@ export class SubQuestionQueryEngine
|
||||
});
|
||||
}
|
||||
|
||||
query(query: QueryType, stream: true): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(query: QueryType, stream?: false): Promise<EngineResponse>;
|
||||
@wrapEventCaller
|
||||
async query(
|
||||
query: QueryType,
|
||||
stream?: boolean,
|
||||
): Promise<EngineResponse | AsyncIterable<EngineResponse>> {
|
||||
const subQuestions = await this.questionGen.generate(this.metadatas, query);
|
||||
|
||||
const subQNodes = await Promise.all(
|
||||
subQuestions.map((subQ) => this.querySubQ(subQ)),
|
||||
);
|
||||
|
||||
const nodesWithScore = subQNodes
|
||||
.filter((node) => node !== null)
|
||||
.map((node) => node as NodeWithScore);
|
||||
if (stream) {
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query,
|
||||
nodesWithScore,
|
||||
},
|
||||
true,
|
||||
);
|
||||
}
|
||||
return this.responseSynthesizer.synthesize(
|
||||
{
|
||||
query,
|
||||
nodesWithScore,
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
private async querySubQ(subQ: SubQuestion): Promise<NodeWithScore | null> {
|
||||
try {
|
||||
const question = subQ.subQuestion;
|
||||
|
||||
@@ -33,6 +33,8 @@ export type {
|
||||
export * from "@llamaindex/core/indices";
|
||||
export * from "@llamaindex/core/llms";
|
||||
export * from "@llamaindex/core/prompts";
|
||||
export * from "@llamaindex/core/query-engine";
|
||||
export * from "@llamaindex/core/response-synthesizers";
|
||||
export * from "@llamaindex/core/schema";
|
||||
|
||||
declare module "@llamaindex/core/global" {
|
||||
@@ -69,6 +71,5 @@ export * from "./selectors/index.js";
|
||||
export * from "./ServiceContext.js";
|
||||
export { Settings } from "./Settings.js";
|
||||
export * from "./storage/StorageContext.js";
|
||||
export * from "./synthesizers/index.js";
|
||||
export * from "./tools/index.js";
|
||||
export * from "./types.js";
|
||||
|
||||
@@ -2,10 +2,6 @@ export * from "./index.edge.js";
|
||||
export * from "./readers/index.js";
|
||||
export * from "./storage/index.js";
|
||||
// Exports modules that doesn't support non-node.js runtime
|
||||
export {
|
||||
ClipEmbedding,
|
||||
ClipEmbeddingModelType,
|
||||
} from "./embeddings/ClipEmbedding.js";
|
||||
export {
|
||||
HuggingFaceEmbedding,
|
||||
HuggingFaceEmbeddingModelType,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import type { BaseNode, Document } from "@llamaindex/core/schema";
|
||||
import type { BaseRetriever } from "../Retriever.js";
|
||||
import type { ServiceContext } from "../ServiceContext.js";
|
||||
@@ -6,8 +8,6 @@ import { runTransformations } from "../ingestion/IngestionPipeline.js";
|
||||
import type { StorageContext } from "../storage/StorageContext.js";
|
||||
import type { BaseDocumentStore } from "../storage/docStore/types.js";
|
||||
import type { BaseIndexStore } from "../storage/indexStore/types.js";
|
||||
import type { BaseSynthesizer } from "../synthesizers/types.js";
|
||||
import type { QueryEngine } from "../types.js";
|
||||
import { IndexStruct } from "./IndexStruct.js";
|
||||
import { IndexStructType } from "./json-to-index-struct.js";
|
||||
|
||||
@@ -83,7 +83,7 @@ export abstract class BaseIndex<T> {
|
||||
abstract asQueryEngine(options?: {
|
||||
retriever?: BaseRetriever;
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
}): QueryEngine;
|
||||
}): BaseQueryEngine;
|
||||
|
||||
/**
|
||||
* Insert a document into the index.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import type {
|
||||
BaseNode,
|
||||
Document,
|
||||
@@ -12,8 +13,6 @@ import type { BaseNodePostprocessor } from "../../postprocessors/index.js";
|
||||
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 { QueryEngine } from "../../types.js";
|
||||
import type { BaseIndexInit } from "../BaseIndex.js";
|
||||
import { BaseIndex, KeywordTable } from "../BaseIndex.js";
|
||||
import { IndexStructType } from "../json-to-index-struct.js";
|
||||
@@ -30,6 +29,7 @@ import {
|
||||
type KeywordExtractPrompt,
|
||||
type QueryKeywordExtractPrompt,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import type { BaseQueryEngine } from "@llamaindex/core/query-engine";
|
||||
import { extractText } from "@llamaindex/core/utils";
|
||||
import { llmFromSettingsOrContext } from "../../Settings.js";
|
||||
|
||||
@@ -237,7 +237,7 @@ export class KeywordTableIndex extends BaseIndex<KeywordTable> {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
}): QueryEngine {
|
||||
}): BaseQueryEngine {
|
||||
const { retriever, responseSynthesizer } = options ?? {};
|
||||
return new RetrieverQueryEngine(
|
||||
retriever ?? this.asRetriever(),
|
||||
|
||||
@@ -2,6 +2,8 @@ import {
|
||||
type ChoiceSelectPrompt,
|
||||
defaultChoiceSelectPrompt,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import { getResponseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import type {
|
||||
BaseNode,
|
||||
Document,
|
||||
@@ -23,12 +25,6 @@ import type {
|
||||
BaseDocumentStore,
|
||||
RefDocInfo,
|
||||
} from "../../storage/docStore/types.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/index.js";
|
||||
import {
|
||||
CompactAndRefine,
|
||||
ResponseSynthesizer,
|
||||
} from "../../synthesizers/index.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";
|
||||
@@ -178,7 +174,7 @@ export class SummaryIndex extends BaseIndex<IndexList> {
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: unknown;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
}): QueryEngine & RetrieverQueryEngine {
|
||||
}): RetrieverQueryEngine {
|
||||
let { retriever, responseSynthesizer } = options ?? {};
|
||||
|
||||
if (!retriever) {
|
||||
@@ -186,11 +182,7 @@ export class SummaryIndex extends BaseIndex<IndexList> {
|
||||
}
|
||||
|
||||
if (!responseSynthesizer) {
|
||||
const responseBuilder = new CompactAndRefine(this.serviceContext);
|
||||
responseSynthesizer = new ResponseSynthesizer({
|
||||
serviceContext: this.serviceContext,
|
||||
responseBuilder,
|
||||
});
|
||||
responseSynthesizer = getResponseSynthesizer("compact");
|
||||
}
|
||||
|
||||
return new RetrieverQueryEngine(
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
} from "@llamaindex/core/embeddings";
|
||||
import { Settings } from "@llamaindex/core/global";
|
||||
import type { MessageContent } from "@llamaindex/core/llms";
|
||||
import type { BaseSynthesizer } from "@llamaindex/core/response-synthesizers";
|
||||
import {
|
||||
ImageNode,
|
||||
ModalityType,
|
||||
@@ -30,8 +31,6 @@ import type { BaseNodePostprocessor } from "../../postprocessors/types.js";
|
||||
import type { StorageContext } from "../../storage/StorageContext.js";
|
||||
import { storageContextFromDefaults } from "../../storage/StorageContext.js";
|
||||
import type { BaseIndexStore } from "../../storage/indexStore/types.js";
|
||||
import type { BaseSynthesizer } from "../../synthesizers/types.js";
|
||||
import type { QueryEngine } from "../../types.js";
|
||||
import type {
|
||||
MetadataFilters,
|
||||
VectorStore,
|
||||
@@ -288,7 +287,7 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
preFilters?: MetadataFilters;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
similarityTopK?: number;
|
||||
}): QueryEngine & RetrieverQueryEngine {
|
||||
}): RetrieverQueryEngine {
|
||||
const {
|
||||
retriever,
|
||||
responseSynthesizer,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
let transformer: typeof import("@xenova/transformers") | null = null;
|
||||
|
||||
export async function lazyLoadTransformers() {
|
||||
if (!transformer) {
|
||||
transformer = await import("@xenova/transformers");
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
if (typeof EdgeRuntime === "string") {
|
||||
// there is no local file system in the edge runtime
|
||||
transformer.env.allowLocalModels = false;
|
||||
}
|
||||
// fixme: handle cloudflare workers case here?
|
||||
return transformer;
|
||||
}
|
||||
@@ -11,12 +11,13 @@ import {
|
||||
type ToolCallLLMMessageOptions,
|
||||
} from "@llamaindex/core/llms";
|
||||
import { streamConverter, wrapLLMEvent } from "@llamaindex/core/utils";
|
||||
import { loadTransformers } from "@llamaindex/env";
|
||||
import type {
|
||||
PreTrainedModel,
|
||||
PreTrainedTokenizer,
|
||||
Tensor,
|
||||
} from "@xenova/transformers";
|
||||
import { lazyLoadTransformers } from "../internal/deps/transformers.js";
|
||||
import { Settings } from "../Settings.js";
|
||||
|
||||
// TODO workaround issue with @huggingface/inference@2.7.0
|
||||
interface HfInferenceOptions {
|
||||
@@ -225,7 +226,15 @@ export class HuggingFaceLLM extends BaseLLM {
|
||||
}
|
||||
|
||||
async getTokenizer() {
|
||||
const { AutoTokenizer } = await lazyLoadTransformers();
|
||||
const { AutoTokenizer } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (!this.tokenizer) {
|
||||
this.tokenizer = await AutoTokenizer.from_pretrained(this.tokenizerName);
|
||||
}
|
||||
@@ -233,7 +242,15 @@ export class HuggingFaceLLM extends BaseLLM {
|
||||
}
|
||||
|
||||
async getModel() {
|
||||
const { AutoModelForCausalLM } = await lazyLoadTransformers();
|
||||
const { AutoModelForCausalLM } = await loadTransformers((transformer) => {
|
||||
Settings.callbackManager.dispatchEvent(
|
||||
"load-transformers",
|
||||
{
|
||||
transformer,
|
||||
},
|
||||
true,
|
||||
);
|
||||
});
|
||||
if (!this.model) {
|
||||
this.model = await AutoModelForCausalLM.from_pretrained(this.modelName);
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
import {
|
||||
defaultTextQAPrompt,
|
||||
PromptMixin,
|
||||
type ModuleRecord,
|
||||
type TextQAPrompt,
|
||||
} from "@llamaindex/core/prompts";
|
||||
import { EngineResponse, MetadataMode } from "@llamaindex/core/schema";
|
||||
import { streamConverter } from "@llamaindex/core/utils";
|
||||
import type { ServiceContext } from "../ServiceContext.js";
|
||||
import { llmFromSettingsOrContext } from "../Settings.js";
|
||||
import type { BaseSynthesizer, SynthesizeQuery } from "./types.js";
|
||||
import { createMessageContent } from "./utils.js";
|
||||
|
||||
export class MultiModalResponseSynthesizer
|
||||
extends PromptMixin
|
||||
implements BaseSynthesizer
|
||||
{
|
||||
serviceContext?: ServiceContext | undefined;
|
||||
metadataMode: MetadataMode;
|
||||
textQATemplate: TextQAPrompt;
|
||||
|
||||
constructor({
|
||||
serviceContext,
|
||||
textQATemplate,
|
||||
metadataMode,
|
||||
}: Partial<MultiModalResponseSynthesizer> = {}) {
|
||||
super();
|
||||
|
||||
this.serviceContext = serviceContext;
|
||||
this.metadataMode = metadataMode ?? MetadataMode.NONE;
|
||||
this.textQATemplate = textQATemplate ?? defaultTextQAPrompt;
|
||||
}
|
||||
|
||||
protected _getPromptModules(): ModuleRecord {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected _getPrompts(): { textQATemplate: TextQAPrompt } {
|
||||
return {
|
||||
textQATemplate: this.textQATemplate,
|
||||
};
|
||||
}
|
||||
|
||||
protected _updatePrompts(promptsDict: {
|
||||
textQATemplate: TextQAPrompt;
|
||||
}): void {
|
||||
if (promptsDict.textQATemplate) {
|
||||
this.textQATemplate = promptsDict.textQATemplate;
|
||||
}
|
||||
}
|
||||
|
||||
synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
synthesize(query: SynthesizeQuery, stream?: false): Promise<EngineResponse>;
|
||||
async synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<EngineResponse> | EngineResponse> {
|
||||
const { nodesWithScore } = query;
|
||||
const nodes = nodesWithScore.map(({ node }) => node);
|
||||
const prompt = await createMessageContent(
|
||||
this.textQATemplate,
|
||||
nodes,
|
||||
// fixme: wtf type is this?
|
||||
// { query },
|
||||
{},
|
||||
this.metadataMode,
|
||||
);
|
||||
|
||||
const llm = llmFromSettingsOrContext(this.serviceContext);
|
||||
|
||||
if (stream) {
|
||||
const response = await llm.complete({
|
||||
prompt,
|
||||
stream,
|
||||
});
|
||||
return streamConverter(response, ({ text }) =>
|
||||
EngineResponse.fromResponse(text, true, nodesWithScore),
|
||||
);
|
||||
}
|
||||
const response = await llm.complete({
|
||||
prompt,
|
||||
});
|
||||
return EngineResponse.fromResponse(response.text, false, nodesWithScore);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import { PromptMixin, type PromptsRecord } from "@llamaindex/core/prompts";
|
||||
import { EngineResponse, MetadataMode } from "@llamaindex/core/schema";
|
||||
import { streamConverter } from "@llamaindex/core/utils";
|
||||
import type { ServiceContext } from "../ServiceContext.js";
|
||||
import { getResponseBuilder } from "./builders.js";
|
||||
import type {
|
||||
BaseSynthesizer,
|
||||
ResponseBuilder,
|
||||
SynthesizeQuery,
|
||||
} from "./types.js";
|
||||
|
||||
/**
|
||||
* A ResponseSynthesizer is used to generate a response from a query and a list of nodes.
|
||||
*/
|
||||
export class ResponseSynthesizer
|
||||
extends PromptMixin
|
||||
implements BaseSynthesizer
|
||||
{
|
||||
responseBuilder: ResponseBuilder;
|
||||
metadataMode: MetadataMode;
|
||||
|
||||
constructor({
|
||||
responseBuilder,
|
||||
serviceContext,
|
||||
metadataMode = MetadataMode.NONE,
|
||||
}: {
|
||||
responseBuilder?: ResponseBuilder | undefined;
|
||||
serviceContext?: ServiceContext | undefined;
|
||||
metadataMode?: MetadataMode | undefined;
|
||||
} = {}) {
|
||||
super();
|
||||
|
||||
this.responseBuilder =
|
||||
responseBuilder ?? getResponseBuilder(serviceContext);
|
||||
this.metadataMode = metadataMode;
|
||||
}
|
||||
|
||||
_getPromptModules() {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected _getPrompts() {
|
||||
const prompts = this.responseBuilder.getPrompts?.();
|
||||
return {
|
||||
...prompts,
|
||||
};
|
||||
}
|
||||
|
||||
protected _updatePrompts(promptsRecord: PromptsRecord): void {
|
||||
this.responseBuilder.updatePrompts?.(promptsRecord);
|
||||
}
|
||||
|
||||
synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
synthesize(query: SynthesizeQuery, stream?: false): Promise<EngineResponse>;
|
||||
async synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream?: boolean,
|
||||
): Promise<AsyncIterable<EngineResponse> | EngineResponse> {
|
||||
const { nodesWithScore } = query;
|
||||
const textChunks: string[] = nodesWithScore.map(({ node }) =>
|
||||
node.getContent(this.metadataMode),
|
||||
);
|
||||
if (stream) {
|
||||
const response = await this.responseBuilder.getResponse(
|
||||
{
|
||||
...query,
|
||||
textChunks,
|
||||
},
|
||||
true,
|
||||
);
|
||||
return streamConverter(response, (chunk) =>
|
||||
EngineResponse.fromResponse(chunk, true, nodesWithScore),
|
||||
);
|
||||
}
|
||||
const response = await this.responseBuilder.getResponse(
|
||||
{
|
||||
...query,
|
||||
textChunks,
|
||||
},
|
||||
false,
|
||||
);
|
||||
return EngineResponse.fromResponse(response, false, nodesWithScore);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export * from "./builders.js";
|
||||
export * from "./MultiModalResponseSynthesizer.js";
|
||||
export * from "./ResponseSynthesizer.js";
|
||||
export * from "./types.js";
|
||||
@@ -1,40 +0,0 @@
|
||||
import type { PromptMixin } from "@llamaindex/core/prompts";
|
||||
import type { QueryType } from "@llamaindex/core/query-engine";
|
||||
import { EngineResponse, type NodeWithScore } from "@llamaindex/core/schema";
|
||||
|
||||
export interface SynthesizeQuery {
|
||||
query: QueryType;
|
||||
nodesWithScore: NodeWithScore[];
|
||||
}
|
||||
|
||||
// todo(himself65): Move this to @llamaindex/core/schema
|
||||
/**
|
||||
* A BaseSynthesizer is used to generate a response from a query and a list of nodes.
|
||||
*/
|
||||
export interface BaseSynthesizer extends PromptMixin {
|
||||
synthesize(
|
||||
query: SynthesizeQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
synthesize(query: SynthesizeQuery, stream?: false): Promise<EngineResponse>;
|
||||
}
|
||||
|
||||
export interface ResponseBuilderQuery {
|
||||
query: QueryType;
|
||||
textChunks: string[];
|
||||
prevResponse?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A ResponseBuilder is used in a response synthesizer to generate a response from multiple response chunks.
|
||||
*/
|
||||
export interface ResponseBuilder extends PromptMixin {
|
||||
/**
|
||||
* Get the response from a query and a list of text chunks.
|
||||
*/
|
||||
getResponse(
|
||||
query: ResponseBuilderQuery,
|
||||
stream: true,
|
||||
): Promise<AsyncIterable<string>>;
|
||||
getResponse(query: ResponseBuilderQuery, stream?: false): Promise<string>;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
import type { MessageContentDetail } from "@llamaindex/core/llms";
|
||||
import type { BasePromptTemplate } from "@llamaindex/core/prompts";
|
||||
import {
|
||||
ImageNode,
|
||||
MetadataMode,
|
||||
ModalityType,
|
||||
splitNodesByType,
|
||||
type BaseNode,
|
||||
} from "@llamaindex/core/schema";
|
||||
import { imageToDataUrl } from "../internal/utils.js";
|
||||
|
||||
export async function createMessageContent(
|
||||
prompt: BasePromptTemplate,
|
||||
nodes: BaseNode[],
|
||||
extraParams: Record<string, string | undefined> = {},
|
||||
metadataMode: MetadataMode = MetadataMode.NONE,
|
||||
): Promise<MessageContentDetail[]> {
|
||||
const content: MessageContentDetail[] = [];
|
||||
const nodeMap = splitNodesByType(nodes);
|
||||
for (const type in nodeMap) {
|
||||
// for each retrieved modality type, create message content
|
||||
const nodes = nodeMap[type as ModalityType];
|
||||
if (nodes) {
|
||||
content.push(
|
||||
...(await createContentPerModality(
|
||||
prompt,
|
||||
type as ModalityType,
|
||||
nodes,
|
||||
extraParams,
|
||||
metadataMode,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
async function createContentPerModality(
|
||||
prompt: BasePromptTemplate,
|
||||
type: ModalityType,
|
||||
nodes: BaseNode[],
|
||||
extraParams: Record<string, string | undefined>,
|
||||
metadataMode: MetadataMode,
|
||||
): Promise<MessageContentDetail[]> {
|
||||
switch (type) {
|
||||
case ModalityType.TEXT:
|
||||
return [
|
||||
{
|
||||
type: "text",
|
||||
text: prompt.format({
|
||||
...extraParams,
|
||||
context: nodes.map((r) => r.getContent(metadataMode)).join("\n\n"),
|
||||
}),
|
||||
},
|
||||
];
|
||||
case ModalityType.IMAGE:
|
||||
const images: MessageContentDetail[] = await Promise.all(
|
||||
(nodes as ImageNode[]).map(async (node) => {
|
||||
return {
|
||||
type: "image_url",
|
||||
image_url: {
|
||||
url: await imageToDataUrl(node.image),
|
||||
},
|
||||
} satisfies MessageContentDetail;
|
||||
}),
|
||||
);
|
||||
return images;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -2,36 +2,6 @@
|
||||
* Top level types to avoid circular dependencies
|
||||
*/
|
||||
import type { ToolMetadata } from "@llamaindex/core/llms";
|
||||
import type { EngineResponse } from "@llamaindex/core/schema";
|
||||
|
||||
/**
|
||||
* Parameters for sending a query.
|
||||
*/
|
||||
export interface QueryEngineParamsBase {
|
||||
query: string;
|
||||
}
|
||||
|
||||
export interface QueryEngineParamsStreaming extends QueryEngineParamsBase {
|
||||
stream: true;
|
||||
}
|
||||
|
||||
export interface QueryEngineParamsNonStreaming extends QueryEngineParamsBase {
|
||||
stream?: false | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A query engine is a question answerer that can use one or more steps.
|
||||
*/
|
||||
export interface QueryEngine {
|
||||
/**
|
||||
* Query the query engine and get a response.
|
||||
* @param params
|
||||
*/
|
||||
query(
|
||||
params: QueryEngineParamsStreaming,
|
||||
): Promise<AsyncIterable<EngineResponse>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<EngineResponse>;
|
||||
}
|
||||
|
||||
/**
|
||||
* StructuredOutput is just a combo of the raw output and the parsed output.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user