mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-15 14:55:41 -04:00
Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93d1450fc1 | |||
| 27d55fde8c | |||
| 690399b04c | |||
| 65b84f1ab3 | |||
| 835acb89d0 | |||
| d9df9ea75c | |||
| 06874ffb69 | |||
| f0898a3930 | |||
| 7d50196d2f | |||
| f90f7fee64 | |||
| 3d860df873 | |||
| 2fe3a2b6a8 | |||
| eb3d4af204 | |||
| 0652352e92 | |||
| 103949513b | |||
| 9ba4547c4d | |||
| 4fea0adf43 | |||
| de070dbfa7 | |||
| 87eb72bdb2 | |||
| fe03aaae55 | |||
| 9ce7d3d648 | |||
| 0471407761 | |||
| e4b807a018 | |||
| 0a0ec37725 | |||
| 8abca5d818 | |||
| 3a29a8036b | |||
| e2b9b66f71 | |||
| bb66cb7e36 | |||
| 2159e77c9d | |||
| 3154f521d9 | |||
| fda8024607 |
@@ -36,3 +36,6 @@ jobs:
|
||||
working-directory: ./packages/core
|
||||
- name: Run Type Check
|
||||
run: pnpm run type-check
|
||||
- name: Run Circular Dependency Check
|
||||
run: pnpm run circular-check
|
||||
working-directory: ./packages/core
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm format
|
||||
pnpm lint
|
||||
npx lint-staged
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
pnpm test
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# docs
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3154f52: chore: add qdrant readme
|
||||
@@ -32,12 +32,12 @@ LlamaIndex.TS help you prepare the knowledge base with a suite of data connector
|
||||
|
||||

|
||||
|
||||
[**Data Loaders**](./modules/high_level/data_loader.md):
|
||||
[**Data Loaders**](../modules/data_loader.md):
|
||||
A data connector (i.e. `Reader`) ingest data from different data sources and data formats into a simple `Document` representation (text and simple metadata).
|
||||
|
||||
[**Documents / Nodes**](./modules/high_level/documents_and_nodes.md): A `Document` is a generic container around any data source - for instance, a PDF, an API output, or retrieved data from a database. A `Node` is the atomic unit of data in LlamaIndex and represents a "chunk" of a source `Document`. It's a rich representation that includes metadata and relationships (to other nodes) to enable accurate and expressive retrieval operations.
|
||||
[**Documents / Nodes**](../modules/documents_and_nodes.md): A `Document` is a generic container around any data source - for instance, a PDF, an API output, or retrieved data from a database. A `Node` is the atomic unit of data in LlamaIndex and represents a "chunk" of a source `Document`. It's a rich representation that includes metadata and relationships (to other nodes) to enable accurate and expressive retrieval operations.
|
||||
|
||||
[**Data Indexes**](./modules/high_level/data_index.md):
|
||||
[**Data Indexes**](../modules/data_index.md):
|
||||
Once you've ingested your data, LlamaIndex helps you index data into a format that's easy to retrieve.
|
||||
|
||||
Under the hood, LlamaIndex parses the raw documents into intermediate representations, calculates vector embeddings, and stores your data in-memory or to disk.
|
||||
@@ -60,19 +60,19 @@ These building blocks can be customized to reflect ranking preferences, as well
|
||||
|
||||
#### Building Blocks
|
||||
|
||||
[**Retrievers**](./modules/low_level/retriever.md):
|
||||
[**Retrievers**](../modules/retriever.md):
|
||||
A retriever defines how to efficiently retrieve relevant context from a knowledge base (i.e. index) when given a query.
|
||||
The specific retrieval logic differs for difference indices, the most popular being dense retrieval against a vector index.
|
||||
|
||||
[**Response Synthesizers**](./modules/low_level/response_synthesizer.md):
|
||||
[**Response Synthesizers**](../modules/response_synthesizer.md):
|
||||
A response synthesizer generates a response from an LLM, using a user query and a given set of retrieved text chunks.
|
||||
|
||||
#### Pipelines
|
||||
|
||||
[**Query Engines**](./modules/high_level/query_engine.md):
|
||||
[**Query Engines**](../modules/query_engine.md):
|
||||
A query engine is an end-to-end pipeline that allow you to ask question over your data.
|
||||
It takes in a natural language query, and returns a response, along with reference context retrieved and passed to the LLM.
|
||||
|
||||
[**Chat Engines**](./modules/high_level/chat_engine.md):
|
||||
[**Chat Engines**](../modules/chat_engine.md):
|
||||
A chat engine is an end-to-end pipeline for having a conversation with your data
|
||||
(multiple back-and-forth instead of a single question & answer).
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Index
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Reader / Loader
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
label: "Document / Nodes"
|
||||
position: 0
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Documents and Nodes
|
||||
@@ -0,0 +1,45 @@
|
||||
# Metadata Extraction Usage Pattern
|
||||
|
||||
You can use LLMs to automate metadata extraction with our `Metadata Extractor` modules.
|
||||
|
||||
Our metadata extractor modules include the following "feature extractors":
|
||||
|
||||
- `SummaryExtractor` - automatically extracts a summary over a set of Nodes
|
||||
- `QuestionsAnsweredExtractor` - extracts a set of questions that each Node can answer
|
||||
- `TitleExtractor` - extracts a title over the context of each Node by document and combine them
|
||||
- `KeywordExtractor` - extracts keywords over the context of each Node
|
||||
|
||||
Then you can chain the `Metadata Extractors` with the `IngestionPipeline` to extract metadata from a set of documents.
|
||||
|
||||
```ts
|
||||
import {
|
||||
IngestionPipeline,
|
||||
TitleExtractor,
|
||||
QuestionsAnsweredExtractor,
|
||||
Document,
|
||||
OpenAI,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const pipeline = new IngestionPipeline({
|
||||
transformations: [
|
||||
new TitleExtractor(),
|
||||
new QuestionsAnsweredExtractor({
|
||||
questions: 5,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const nodes = await pipeline.run({
|
||||
documents: [
|
||||
new Document({ text: "I am 10 years old. John is 20 years old." }),
|
||||
],
|
||||
});
|
||||
|
||||
for (const node of nodes) {
|
||||
console.log(node.metadata);
|
||||
}
|
||||
}
|
||||
|
||||
main().then(() => console.log("done"));
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Embedding
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
# Core Modules
|
||||
|
||||
LlamaIndex.TS offers several core modules, seperated into high-level modules for quickly getting started, and low-level modules for customizing key components as you need.
|
||||
|
||||
## High-Level Modules
|
||||
|
||||
- [**Document**](./high_level/documents_and_nodes.md): A document represents a text file, PDF file or other contiguous piece of data.
|
||||
|
||||
- [**Node**](./high_level/documents_and_nodes.md): The basic data building block. Most commonly, these are parts of the document split into manageable pieces that are small enough to be fed into an embedding model and LLM.
|
||||
|
||||
- [**Reader/Loader**](./high_level/data_loader.md): A reader or loader is something that takes in a document in the real world and transforms into a Document class that can then be used in your Index and queries. We currently support plain text files and PDFs with many many more to come.
|
||||
|
||||
- [**Indexes**](./high_level/data_index.md): indexes store the Nodes and the embeddings of those nodes.
|
||||
|
||||
- [**QueryEngine**](./high_level/query_engine.md): Query engines are what generate the query you put in and give you back the result. Query engines generally combine a pre-built prompt with selected nodes from your Index to give the LLM the context it needs to answer your query.
|
||||
|
||||
- [**ChatEngine**](./high_level/chat_engine.md): A ChatEngine helps you build a chatbot that will interact with your Indexes.
|
||||
|
||||
## Low Level Module
|
||||
|
||||
- [**LLM**](./low_level/llm.md): The LLM class is a unified interface over a large language model provider such as OpenAI GPT-4, Anthropic Claude, or Meta LLaMA. You can subclass it to write a connector to your own large language model.
|
||||
|
||||
- [**Embedding**](./low_level/embedding.md): An embedding is represented as a vector of floating point numbers. OpenAI's text-embedding-ada-002 is our default embedding model and each embedding it generates consists of 1,536 floating point numbers. Another popular embedding model is BERT which uses 768 floating point numbers to represent each Node. We provide a number of utilities to work with embeddings including 3 similarity calculation options and Maximum Marginal Relevance
|
||||
|
||||
- [**TextSplitter/NodeParser**](./low_level/node_parser.md): Text splitting strategies are incredibly important to the overall efficacy of the embedding search. Currently, while we do have a default, there's no one size fits all solution. Depending on the source documents, you may want to use different splitting sizes and strategies. Currently we support spliltting by fixed size, splitting by fixed size with overlapping sections, splitting by sentence, and splitting by paragraph. The text splitter is used by the NodeParser when splitting `Document`s into `Node`s.
|
||||
|
||||
- [**Retriever**](./low_level/retriever.md): The Retriever is what actually chooses the Nodes to retrieve from the index. Here, you may wish to try retrieving more or fewer Nodes per query, changing your similarity function, or creating your own retriever for each individual use case in your application. For example, you may wish to have a separate retriever for code content vs. text content.
|
||||
|
||||
- [**ResponseSynthesizer**](./low_level/response_synthesizer.md): The ResponseSynthesizer is responsible for taking a query string, and using a list of `Node`s to generate a response. This can take many forms, like iterating over all the context and refining an answer, or building a tree of summaries and returning the root summary.
|
||||
|
||||
- [**Storage**](./low_level/storage.md): At some point you're going to want to store your indexes, data and vectors instead of re-running the embedding models every time. IndexStore, DocStore, VectorStore, and KVStore are abstractions that let you do that. Combined, they form the StorageContext. Currently, we allow you to persist your embeddings in files on the filesystem (or a virtual in memory file system), but we are also actively adding integrations to Vector Databases.
|
||||
@@ -0,0 +1,2 @@
|
||||
label: "Ingestion Pipeline"
|
||||
position: 2
|
||||
@@ -0,0 +1,99 @@
|
||||
# Ingestion Pipeline
|
||||
|
||||
An `IngestionPipeline` uses a concept of `Transformations` that are applied to input data.
|
||||
These `Transformations` are applied to your input data, and the resulting nodes are either returned or inserted into a vector database (if given).
|
||||
|
||||
## Usage Pattern
|
||||
|
||||
The simplest usage is to instantiate an IngestionPipeline like so:
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Document,
|
||||
IngestionPipeline,
|
||||
MetadataMode,
|
||||
OpenAIEmbedding,
|
||||
TitleExtractor,
|
||||
SimpleNodeParser,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
const pipeline = new IngestionPipeline({
|
||||
transformations: [
|
||||
new SimpleNodeParser({ chunkSize: 1024, chunkOverlap: 20 }),
|
||||
new TitleExtractor(),
|
||||
new OpenAIEmbedding(),
|
||||
],
|
||||
});
|
||||
|
||||
// run the pipeline
|
||||
const nodes = await pipeline.run({ documents: [document] });
|
||||
|
||||
// print out the result of the pipeline run
|
||||
for (const node of nodes) {
|
||||
console.log(node.getContent(MetadataMode.NONE));
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
## Connecting to Vector Databases
|
||||
|
||||
When running an ingestion pipeline, you can also chose to automatically insert the resulting nodes into a remote vector store.
|
||||
|
||||
Then, you can construct an index from that vector store later on.
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Document,
|
||||
IngestionPipeline,
|
||||
MetadataMode,
|
||||
OpenAIEmbedding,
|
||||
TitleExtractor,
|
||||
SimpleNodeParser,
|
||||
QdrantVectorStore,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
const vectorStore = new QdrantVectorStore({
|
||||
host: "http://localhost:6333",
|
||||
});
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
const pipeline = new IngestionPipeline({
|
||||
transformations: [
|
||||
new SimpleNodeParser({ chunkSize: 1024, chunkOverlap: 20 }),
|
||||
new TitleExtractor(),
|
||||
new OpenAIEmbedding(),
|
||||
],
|
||||
vectorStore,
|
||||
});
|
||||
|
||||
// run the pipeline
|
||||
const nodes = await pipeline.run({ documents: [document] });
|
||||
|
||||
// create an index
|
||||
const index = VectorStoreIndex.fromVectorStore(vectorStore);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
@@ -0,0 +1,77 @@
|
||||
# Transformations
|
||||
|
||||
A transformation is something that takes a list of nodes as an input, and returns a list of nodes. Each component that implements the Transformatio class has both a `transform` definition responsible for transforming the nodes
|
||||
|
||||
Currently, the following components are Transformation objects:
|
||||
|
||||
- [SimpleNodeParser](../../api/classes/SimpleNodeParser.md)
|
||||
- [MetadataExtractor](../documents_and_nodes/metadata_extraction.md)
|
||||
- Embeddings
|
||||
|
||||
## Usage Pattern
|
||||
|
||||
While transformations are best used with with an IngestionPipeline, they can also be used directly.
|
||||
|
||||
```ts
|
||||
import { SimpleNodeParser, TitleExtractor, Document } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
let nodes = new SimpleNodeParser().getNodesFromDocuments([
|
||||
new Document({ text: "I am 10 years old. John is 20 years old." }),
|
||||
]);
|
||||
|
||||
const titleExtractor = new TitleExtractor();
|
||||
|
||||
nodes = await titleExtractor.transform(nodes);
|
||||
|
||||
for (const node of nodes) {
|
||||
console.log(node.getContent(MetadataMode.NONE));
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
## Custom Transformations
|
||||
|
||||
You can implement any transformation yourself by implementing the `TransformerComponent`.
|
||||
|
||||
The following custom transformation will remove any special characters or punctutaion in text.
|
||||
|
||||
```ts
|
||||
import { TransformerComponent, Node } from "llamaindex";
|
||||
|
||||
class RemoveSpecialCharacters extends TransformerComponent {
|
||||
async transform(nodes: Node[]): Promise<Node[]> {
|
||||
for (const node of nodes) {
|
||||
node.text = node.text.replace(/[^\w\s]/gi, "");
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These can then be used directly or in any IngestionPipeline.
|
||||
|
||||
```ts
|
||||
import { IngestionPipeline, Document } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const pipeline = new IngestionPipeline({
|
||||
transformations: [new RemoveSpecialCharacters()],
|
||||
});
|
||||
|
||||
const nodes = await pipeline.run({
|
||||
documents: [
|
||||
new Document({ text: "I am 10 years old. John is 20 years old." }),
|
||||
],
|
||||
});
|
||||
|
||||
for (const node of nodes) {
|
||||
console.log(node.getContent(MetadataMode.NONE));
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# LLM
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# QueryEngine
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
label: "Vector Stores"
|
||||
position: 1
|
||||
@@ -0,0 +1,86 @@
|
||||
# Qdrant Vector Store
|
||||
|
||||
To run this example, you need to have a Qdrant instance running. You can run it with Docker:
|
||||
|
||||
```bash
|
||||
docker pull qdrant/qdrant
|
||||
docker run -p 6333:6333 qdrant/qdrant
|
||||
```
|
||||
|
||||
## Importing the modules
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
import { Document, VectorStoreIndex, QdrantVectorStore } from "llamaindex";
|
||||
```
|
||||
|
||||
## Load the documents
|
||||
|
||||
```ts
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
```
|
||||
|
||||
## Setup Qdrant
|
||||
|
||||
```ts
|
||||
const vectorStore = new QdrantVectorStore({
|
||||
url: "http://localhost:6333",
|
||||
});
|
||||
```
|
||||
|
||||
## Setup the index
|
||||
|
||||
```ts
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
vectorStore,
|
||||
});
|
||||
```
|
||||
|
||||
## Query the index
|
||||
|
||||
```ts
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
```
|
||||
|
||||
## Full code
|
||||
|
||||
```ts
|
||||
import fs from "node:fs/promises";
|
||||
import { Document, VectorStoreIndex, QdrantVectorStore } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
const vectorStore = new QdrantVectorStore({
|
||||
url: "http://localhost:6333",
|
||||
});
|
||||
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
vectorStore,
|
||||
});
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.0",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
@@ -15,8 +15,8 @@
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.1.0",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^3.1.0",
|
||||
"@docusaurus/core": "^3.1.1",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^3.1.1",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"clsx": "^2.1.0",
|
||||
"postcss": "^8.4.33",
|
||||
@@ -27,11 +27,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.1.0",
|
||||
"@docusaurus/preset-classic": "^3.1.0",
|
||||
"@docusaurus/theme-classic": "^3.1.0",
|
||||
"@docusaurus/types": "^3.1.0",
|
||||
"@docusaurus/preset-classic": "^3.1.1",
|
||||
"@docusaurus/theme-classic": "^3.1.1",
|
||||
"@docusaurus/types": "^3.1.1",
|
||||
"@tsconfig/docusaurus": "^2.0.2",
|
||||
"@types/node": "^18.19.6",
|
||||
"@types/node": "^18.19.10",
|
||||
"docusaurus-plugin-typedoc": "^0.22.0",
|
||||
"typedoc": "^0.25.7",
|
||||
"typedoc-plugin-markdown": "^3.17.1",
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# simple
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5a765aa]
|
||||
- llamaindex@0.0.5
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c65d671]
|
||||
- llamaindex@0.0.4
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ca9410f]
|
||||
- llamaindex@0.0.3
|
||||
@@ -16,7 +16,10 @@ import {
|
||||
|
||||
console.log(nodes);
|
||||
|
||||
const keywordExtractor = new KeywordExtractor(openaiLLM, 5);
|
||||
const keywordExtractor = new KeywordExtractor({
|
||||
llm: openaiLLM,
|
||||
keywords: 5,
|
||||
});
|
||||
|
||||
const nodesWithKeywordMetadata = await keywordExtractor.processNodes(nodes);
|
||||
|
||||
|
||||
@@ -19,10 +19,10 @@ import {
|
||||
}),
|
||||
]);
|
||||
|
||||
const questionsAnsweredExtractor = new QuestionsAnsweredExtractor(
|
||||
openaiLLM,
|
||||
5,
|
||||
);
|
||||
const questionsAnsweredExtractor = new QuestionsAnsweredExtractor({
|
||||
llm: openaiLLM,
|
||||
questions: 5,
|
||||
});
|
||||
|
||||
const nodesWithQuestionsMetadata =
|
||||
await questionsAnsweredExtractor.processNodes(nodes);
|
||||
|
||||
@@ -16,7 +16,9 @@ import {
|
||||
}),
|
||||
]);
|
||||
|
||||
const summaryExtractor = new SummaryExtractor(openaiLLM);
|
||||
const summaryExtractor = new SummaryExtractor({
|
||||
llm: openaiLLM,
|
||||
});
|
||||
|
||||
const nodesWithSummaryMetadata = await summaryExtractor.processNodes(nodes);
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ import { Document, OpenAI, SimpleNodeParser, TitleExtractor } from "llamaindex";
|
||||
}),
|
||||
]);
|
||||
|
||||
const titleExtractor = new TitleExtractor(openaiLLM, 1);
|
||||
const titleExtractor = new TitleExtractor({
|
||||
llm: openaiLLM,
|
||||
nodes: 5,
|
||||
});
|
||||
|
||||
const nodesWithTitledMetadata = await titleExtractor.processNodes(nodes);
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
{
|
||||
"name": "examples",
|
||||
"private": true,
|
||||
"version": "0.0.3",
|
||||
"dependencies": {
|
||||
"@datastax/astra-db-ts": "^0.1.2",
|
||||
"@datastax/astra-db-ts": "^0.1.4",
|
||||
"@notionhq/client": "^2.2.14",
|
||||
"@pinecone-database/pinecone": "^1.1.2",
|
||||
"chromadb": "^1.7.3",
|
||||
"@pinecone-database/pinecone": "^1.1.3",
|
||||
"chromadb": "^1.8.1",
|
||||
"commander": "^11.1.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"dotenv": "^16.4.1",
|
||||
"llamaindex": "latest",
|
||||
"mongodb": "^6.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.18.6",
|
||||
"ts-node": "^10.9.1"
|
||||
"@types/node": "^18.19.10",
|
||||
"ts-node": "^10.9.2"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint ."
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
import {
|
||||
Document,
|
||||
OpenAIEmbedding,
|
||||
VectorStoreIndex,
|
||||
serviceContextFromDefaults,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await fs.readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Create service context and specify text-embedding-3-large
|
||||
const embedModel = new OpenAIEmbedding({
|
||||
model: "text-embedding-3-large",
|
||||
dimensions: 1024,
|
||||
});
|
||||
const serviceContext = serviceContextFromDefaults({ embedModel });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments([document], {
|
||||
serviceContext,
|
||||
});
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
+6
-6
@@ -8,7 +8,7 @@
|
||||
"format": "prettier --ignore-unknown --cache --check .",
|
||||
"format:write": "prettier --ignore-unknown --write .",
|
||||
"lint": "turbo run lint",
|
||||
"prepare": "husky install",
|
||||
"prepare": "husky",
|
||||
"test": "turbo run test",
|
||||
"type-check": "tsc -b --diagnostics",
|
||||
"release": "pnpm run build:release && changeset publish",
|
||||
@@ -18,20 +18,20 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.1",
|
||||
"@turbo/gen": "^1.11.2",
|
||||
"@turbo/gen": "^1.11.3",
|
||||
"@types/jest": "^29.5.11",
|
||||
"eslint": "^8.56.0",
|
||||
"eslint-config-custom": "workspace:*",
|
||||
"husky": "^8.0.3",
|
||||
"husky": "^9.0.6",
|
||||
"jest": "^29.7.0",
|
||||
"lint-staged": "^15.2.0",
|
||||
"prettier": "^3.2.4",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"ts-jest": "^29.1.1",
|
||||
"turbo": "^1.11.2",
|
||||
"ts-jest": "^29.1.2",
|
||||
"turbo": "^1.11.3",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"packageManager": "pnpm@8.10.5+sha256.a4bd9bb7b48214bbfcd95f264bd75bb70d100e5d4b58808f5cd6ab40c6ac21c5",
|
||||
"packageManager": "pnpm@8.14.3+sha256.2d0363bb6c314daa67087ef07743eea1ba2e2d360c835e8fec6b5575e4ed9484",
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"trim": "1.0.1",
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9ce7d3d: update dependencies
|
||||
- 7d50196: fix: output target causes not implemented error
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- e4b807a: fix: invalid package.json
|
||||
|
||||
## 0.1.1
|
||||
|
||||
No changes for this release.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 3154f52: chore: add qdrant readme
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- bb66cb7: add new OpenAI embeddings (with dimension reduction support)
|
||||
|
||||
## 0.0.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fda8024: revert: export conditions not working with moduleResolution `node`
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
# LlamaIndex.TS
|
||||
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://discord.com/invite/eN6D2HQ4aX)
|
||||
|
||||
LlamaIndex is a data framework for your LLM application.
|
||||
|
||||
Use your own data with large language models (LLMs, OpenAI ChatGPT and others) in Typescript and Javascript.
|
||||
|
||||
Documentation: https://ts.llamaindex.ai/
|
||||
|
||||
## What is LlamaIndex.TS?
|
||||
|
||||
LlamaIndex.TS aims to be a lightweight, easy to use set of libraries to help you integrate large language models into your applications with your own data.
|
||||
|
||||
## Getting started with an example:
|
||||
|
||||
LlamaIndex.TS requires Node v18 or higher. You can download it from https://nodejs.org or use https://nvm.sh (our preferred option).
|
||||
|
||||
In a new folder:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-......" # Replace with your key from https://platform.openai.com/account/api-keys
|
||||
pnpm init
|
||||
pnpm install typescript
|
||||
pnpm exec tsc --init # if needed
|
||||
pnpm install llamaindex
|
||||
pnpm install @types/node
|
||||
```
|
||||
|
||||
Create the file example.ts
|
||||
|
||||
```ts
|
||||
// example.ts
|
||||
import fs from "fs/promises";
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load essay from abramov.txt in Node
|
||||
const essay = await fs.readFile(
|
||||
"node_modules/llamaindex/examples/abramov.txt",
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// Query the index
|
||||
const queryEngine = index.asQueryEngine();
|
||||
const response = await queryEngine.query(
|
||||
"What did the author do in college?",
|
||||
);
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
}
|
||||
|
||||
main();
|
||||
```
|
||||
|
||||
Then you can run it using
|
||||
|
||||
```bash
|
||||
pnpx ts-node example.ts
|
||||
```
|
||||
|
||||
## Playground
|
||||
|
||||
Check out our NextJS playground at https://llama-playground.vercel.app/. The source is available at https://github.com/run-llama/ts-playground
|
||||
|
||||
## Core concepts for getting started:
|
||||
|
||||
- [Document](/packages/core/src/Node.ts): A document represents a text file, PDF file or other contiguous piece of data.
|
||||
|
||||
- [Node](/packages/core/src/Node.ts): The basic data building block. Most commonly, these are parts of the document split into manageable pieces that are small enough to be fed into an embedding model and LLM.
|
||||
|
||||
- [Embedding](/packages/core/src/Embedding.ts): Embeddings are sets of floating point numbers which represent the data in a Node. By comparing the similarity of embeddings, we can derive an understanding of the similarity of two pieces of data. One use case is to compare the embedding of a question with the embeddings of our Nodes to see which Nodes may contain the data needed to answer that quesiton.
|
||||
|
||||
- [Indices](/packages/core/src/indices/): Indices store the Nodes and the embeddings of those nodes. QueryEngines retrieve Nodes from these Indices using embedding similarity.
|
||||
|
||||
- [QueryEngine](/packages/core/src/QueryEngine.ts): Query engines are what generate the query you put in and give you back the result. Query engines generally combine a pre-built prompt with selected Nodes from your Index to give the LLM the context it needs to answer your query.
|
||||
|
||||
- [ChatEngine](/packages/core/src/ChatEngine.ts): A ChatEngine helps you build a chatbot that will interact with your Indices.
|
||||
|
||||
- [SimplePrompt](/packages/core/src/Prompt.ts): A simple standardized function call definition that takes in inputs and formats them in a template literal. SimplePrompts can be specialized using currying and combined using other SimplePrompt functions.
|
||||
|
||||
## Note: NextJS:
|
||||
|
||||
If you're using NextJS App Router, you'll need to use the NodeJS runtime (default) and add the following config to your next.config.js to have it use imports/exports in the same way Node does.
|
||||
|
||||
```js
|
||||
export const runtime = "nodejs"; // default
|
||||
```
|
||||
|
||||
```js
|
||||
// next.config.js
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
webpack: (config) => {
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
sharp$: false,
|
||||
"onnxruntime-node$": false,
|
||||
};
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
```
|
||||
|
||||
## Supported LLMs:
|
||||
|
||||
- OpenAI GPT-3.5-turbo and GPT-4
|
||||
- Anthropic Claude Instant and Claude 2
|
||||
- Llama2 Chat LLMs (70B, 13B, and 7B parameters)
|
||||
- MistralAI Chat LLMs
|
||||
|
||||
## Contributing:
|
||||
|
||||
We are in the very early days of LlamaIndex.TS. If you’re interested in hacking on it with us check out our [contributing guide](/CONTRIBUTING.md)
|
||||
|
||||
## Bugs? Questions?
|
||||
|
||||
Please join our Discord! https://discord.com/invite/eN6D2HQ4aX
|
||||
@@ -2,5 +2,5 @@
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
testPathIgnorePatterns: ["/lib/"],
|
||||
testPathIgnorePatterns: ["/lib/", "/node_modules/", "/dist/"],
|
||||
};
|
||||
|
||||
+25
-153
@@ -1,16 +1,17 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.0.50",
|
||||
"private": true,
|
||||
"version": "0.1.3",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.9.1",
|
||||
"@datastax/astra-db-ts": "^0.1.2",
|
||||
"@mistralai/mistralai": "^0.0.7",
|
||||
"@anthropic-ai/sdk": "^0.12.4",
|
||||
"@datastax/astra-db-ts": "^0.1.4",
|
||||
"@mistralai/mistralai": "^0.0.10",
|
||||
"@notionhq/client": "^2.2.14",
|
||||
"@pinecone-database/pinecone": "^1.1.2",
|
||||
"@pinecone-database/pinecone": "^1.1.3",
|
||||
"@qdrant/js-client-rest": "^1.7.0",
|
||||
"@xenova/transformers": "^2.10.0",
|
||||
"assemblyai": "^4.0.0",
|
||||
"@xenova/transformers": "^2.14.1",
|
||||
"assemblyai": "^4.2.1",
|
||||
"chromadb": "~1.7.3",
|
||||
"file-type": "^18.7.0",
|
||||
"js-tiktoken": "^1.0.8",
|
||||
@@ -19,26 +20,28 @@
|
||||
"md-utils-ts": "^2.0.0",
|
||||
"mongodb": "^6.3.0",
|
||||
"notion-md-crawler": "^0.0.2",
|
||||
"openai": "^4.20.1",
|
||||
"openai": "^4.26.0",
|
||||
"papaparse": "^5.4.1",
|
||||
"pathe": "^1.1.2",
|
||||
"pdfjs-dist": "4.0.269",
|
||||
"pg": "^8.11.3",
|
||||
"pgvector": "^0.1.5",
|
||||
"pgvector": "^0.1.7",
|
||||
"portkey-ai": "^0.1.16",
|
||||
"rake-modified": "^1.0.8",
|
||||
"replicate": "^0.21.1",
|
||||
"string-strip-html": "^13.4.3",
|
||||
"replicate": "^0.25.2",
|
||||
"string-strip-html": "^13.4.5",
|
||||
"wink-nlp": "^1.14.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@types/edit-json-file": "^1.7.3",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "^18.19.6",
|
||||
"@types/node": "^18.19.10",
|
||||
"@types/papaparse": "^5.3.14",
|
||||
"@types/pg": "^8.10.9",
|
||||
"bunchee": "^4.4.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"bunchee": "^4.4.2",
|
||||
"edit-json-file": "^1.8.0",
|
||||
"madge": "^6.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
@@ -50,154 +53,19 @@
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.mts",
|
||||
"edge-light": "./dist/index.edge-light.mjs",
|
||||
"import": "./dist/index.mjs",
|
||||
"edge-light": "./dist/index.edge-light.mjs",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"./env": {
|
||||
"types": "./dist/env.d.mts",
|
||||
"edge-light": "./dist/env.edge-light.mjs",
|
||||
"import": "./dist/env.mjs",
|
||||
"edge-light": "./dist/env.edge-light.mjs",
|
||||
"require": "./dist/env.js"
|
||||
},
|
||||
"./storage/FileSystem": {
|
||||
"types": "./dist/storage/FileSystem.d.mts",
|
||||
"edge-light": "./dist/storage/FileSystem.edge-light.mjs",
|
||||
"import": "./dist/storage/FileSystem.mjs",
|
||||
"require": "./dist/storage/FileSystem.js"
|
||||
},
|
||||
"./ChatHistory": {
|
||||
"types": "./dist/ChatHistory.d.mts",
|
||||
"import": "./dist/ChatHistory.mjs",
|
||||
"require": "./dist/ChatHistory.js"
|
||||
},
|
||||
"./constants": {
|
||||
"types": "./dist/constants.d.mts",
|
||||
"import": "./dist/constants.mjs",
|
||||
"require": "./dist/constants.js"
|
||||
},
|
||||
"./GlobalsHelper": {
|
||||
"types": "./dist/GlobalsHelper.d.mts",
|
||||
"import": "./dist/GlobalsHelper.mjs",
|
||||
"require": "./dist/GlobalsHelper.js"
|
||||
},
|
||||
"./Node": {
|
||||
"types": "./dist/Node.d.mts",
|
||||
"import": "./dist/Node.mjs",
|
||||
"require": "./dist/Node.js"
|
||||
},
|
||||
"./OutputParser": {
|
||||
"types": "./dist/OutputParser.d.mts",
|
||||
"import": "./dist/OutputParser.mjs",
|
||||
"require": "./dist/OutputParser.js"
|
||||
},
|
||||
"./Prompt": {
|
||||
"types": "./dist/Prompt.d.mts",
|
||||
"import": "./dist/Prompt.mjs",
|
||||
"require": "./dist/Prompt.js"
|
||||
},
|
||||
"./PromptHelper": {
|
||||
"types": "./dist/PromptHelper.d.mts",
|
||||
"import": "./dist/PromptHelper.mjs",
|
||||
"require": "./dist/PromptHelper.js"
|
||||
},
|
||||
"./QueryEngine": {
|
||||
"types": "./dist/QueryEngine.d.mts",
|
||||
"import": "./dist/QueryEngine.mjs",
|
||||
"require": "./dist/QueryEngine.js"
|
||||
},
|
||||
"./QuestionGenerator": {
|
||||
"types": "./dist/QuestionGenerator.d.mts",
|
||||
"import": "./dist/QuestionGenerator.mjs",
|
||||
"require": "./dist/QuestionGenerator.js"
|
||||
},
|
||||
"./Response": {
|
||||
"types": "./dist/Response.d.mts",
|
||||
"import": "./dist/Response.mjs",
|
||||
"require": "./dist/Response.js"
|
||||
},
|
||||
"./Retriever": {
|
||||
"types": "./dist/Retriever.d.mts",
|
||||
"import": "./dist/Retriever.mjs",
|
||||
"require": "./dist/Retriever.js"
|
||||
},
|
||||
"./ServiceContext": {
|
||||
"types": "./dist/ServiceContext.d.mts",
|
||||
"import": "./dist/ServiceContext.mjs",
|
||||
"require": "./dist/ServiceContext.js"
|
||||
},
|
||||
"./TextSplitter": {
|
||||
"types": "./dist/TextSplitter.d.mts",
|
||||
"import": "./dist/TextSplitter.mjs",
|
||||
"require": "./dist/TextSplitter.js"
|
||||
},
|
||||
"./Tool": {
|
||||
"types": "./dist/Tool.d.mts",
|
||||
"import": "./dist/Tool.mjs",
|
||||
"require": "./dist/Tool.js"
|
||||
},
|
||||
"./readers/AssemblyAI": {
|
||||
"types": "./dist/readers/AssemblyAI.d.mts",
|
||||
"import": "./dist/readers/AssemblyAI.mjs",
|
||||
"require": "./dist/readers/AssemblyAI.js"
|
||||
},
|
||||
"./readers/base": {
|
||||
"types": "./dist/readers/base.d.mts",
|
||||
"import": "./dist/readers/base.mjs",
|
||||
"require": "./dist/readers/base.js"
|
||||
},
|
||||
"./readers/CSVReader": {
|
||||
"types": "./dist/readers/CSVReader.d.mts",
|
||||
"import": "./dist/readers/CSVReader.mjs",
|
||||
"require": "./dist/readers/CSVReader.js"
|
||||
},
|
||||
"./readers/DocxReader": {
|
||||
"types": "./dist/readers/DocxReader.d.mts",
|
||||
"import": "./dist/readers/DocxReader.mjs",
|
||||
"require": "./dist/readers/DocxReader.js"
|
||||
},
|
||||
"./readers/HTMLReader": {
|
||||
"types": "./dist/readers/HTMLReader.d.mts",
|
||||
"import": "./dist/readers/HTMLReader.mjs",
|
||||
"require": "./dist/readers/HTMLReader.js"
|
||||
},
|
||||
"./readers/ImageReader": {
|
||||
"types": "./dist/readers/ImageReader.d.mts",
|
||||
"import": "./dist/readers/ImageReader.mjs",
|
||||
"require": "./dist/readers/ImageReader.js"
|
||||
},
|
||||
"./readers/MarkdownReader": {
|
||||
"types": "./dist/readers/MarkdownReader.d.mts",
|
||||
"import": "./dist/readers/MarkdownReader.mjs",
|
||||
"require": "./dist/readers/MarkdownReader.js"
|
||||
},
|
||||
"./readers/NotionReader": {
|
||||
"types": "./dist/readers/NotionReader.d.mts",
|
||||
"import": "./dist/readers/NotionReader.mjs",
|
||||
"require": "./dist/readers/NotionReader.js"
|
||||
},
|
||||
"./readers/PDFReader": {
|
||||
"types": "./dist/readers/PDFReader.d.mts",
|
||||
"import": "./dist/readers/PDFReader.mjs",
|
||||
"require": "./dist/readers/PDFReader.js"
|
||||
},
|
||||
"./readers/SimpleDirectoryReader": {
|
||||
"types": "./dist/readers/SimpleDirectoryReader.d.mts",
|
||||
"import": "./dist/readers/SimpleDirectoryReader.mjs",
|
||||
"require": "./dist/readers/SimpleDirectoryReader.js"
|
||||
},
|
||||
"./readers/SimpleMongoReader": {
|
||||
"types": "./dist/readers/SimpleMongoReader.d.mts",
|
||||
"import": "./dist/readers/SimpleMongoReader.mjs",
|
||||
"require": "./dist/readers/SimpleMongoReader.js"
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"examples",
|
||||
"src",
|
||||
"types",
|
||||
"CHANGELOG.md"
|
||||
"**"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -208,7 +76,11 @@
|
||||
"lint": "eslint .",
|
||||
"test": "jest",
|
||||
"build": "bunchee",
|
||||
"postbuild": "pnpm run copy && pnpm run modify-package-json",
|
||||
"copy": "cp -r package.json CHANGELOG.md ../../README.md ../../LICENSE examples src dist/",
|
||||
"modify-package-json": "node ./scripts/modify-package-json.mjs",
|
||||
"prepublish": "pnpm run modify-package-json && echo \"please cd ./dist and run pnpm publish\" && exit 1",
|
||||
"dev": "bunchee -w",
|
||||
"circular-check": "madge --circular ./src/*.ts"
|
||||
"circular-check": "madge -c ./src/index.ts"
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* This script is used to modify the package.json file in the dist folder
|
||||
* so that it can be published to npm.
|
||||
*/
|
||||
import editJsonFile from "edit-json-file";
|
||||
import fs from "node:fs/promises";
|
||||
|
||||
{
|
||||
await fs.copyFile("./package.json", "./dist/package.json");
|
||||
const file = editJsonFile("./dist/package.json");
|
||||
|
||||
file.unset("scripts");
|
||||
file.unset("private");
|
||||
await new Promise((resolve) => file.save(resolve));
|
||||
}
|
||||
{
|
||||
const packageJson = await fs.readFile("./dist/package.json", "utf8");
|
||||
const modifiedPackageJson = packageJson.replaceAll("./dist/", "./");
|
||||
await fs.writeFile(
|
||||
"./dist/package.json",
|
||||
JSON.stringify(JSON.parse(modifiedPackageJson), null, 2),
|
||||
"utf8",
|
||||
);
|
||||
}
|
||||
@@ -1,20 +1,4 @@
|
||||
import { SubQuestion } from "./QuestionGenerator";
|
||||
|
||||
/**
|
||||
* An OutputParser is used to extract structured data from the raw output of the LLM.
|
||||
*/
|
||||
export interface BaseOutputParser<T> {
|
||||
parse(output: string): T;
|
||||
format(output: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* StructuredOutput is just a combo of the raw output and the parsed output.
|
||||
*/
|
||||
export interface StructuredOutput<T> {
|
||||
rawOutput: string;
|
||||
parsedOutput: T;
|
||||
}
|
||||
import { BaseOutputParser, StructuredOutput, SubQuestion } from "./types";
|
||||
|
||||
/**
|
||||
* Error class for output parsing. Due to the nature of LLMs, anytime we use LLM
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ChatMessage } from "./llm/types";
|
||||
import { SubQuestion } from "./QuestionGenerator";
|
||||
import { ToolMetadata } from "./Tool";
|
||||
import { SubQuestion, ToolMetadata } from "./types";
|
||||
|
||||
/**
|
||||
* A SimplePrompt is a function that takes a dictionary of inputs and returns a string.
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { NodeWithScore, TextNode } from "./Node";
|
||||
import {
|
||||
BaseQuestionGenerator,
|
||||
LLMQuestionGenerator,
|
||||
SubQuestion,
|
||||
} from "./QuestionGenerator";
|
||||
import { LLMQuestionGenerator } from "./QuestionGenerator";
|
||||
import { Response } from "./Response";
|
||||
import { BaseRetriever } from "./Retriever";
|
||||
import { ServiceContext, serviceContextFromDefaults } from "./ServiceContext";
|
||||
import { QueryEngineTool, ToolMetadata } from "./Tool";
|
||||
import { Event } from "./callbacks/CallbackManager";
|
||||
import { randomUUID } from "./env";
|
||||
import { BaseNodePostprocessor } from "./postprocessors";
|
||||
@@ -16,34 +11,15 @@ import {
|
||||
CompactAndRefine,
|
||||
ResponseSynthesizer,
|
||||
} from "./synthesizers";
|
||||
|
||||
/**
|
||||
* Parameters for sending a query.
|
||||
*/
|
||||
export interface QueryEngineParamsBase {
|
||||
query: string;
|
||||
parentEvent?: Event;
|
||||
}
|
||||
|
||||
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 BaseQueryEngine {
|
||||
/**
|
||||
* Query the query engine and get a response.
|
||||
* @param params
|
||||
*/
|
||||
query(params: QueryEngineParamsStreaming): Promise<AsyncIterable<Response>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<Response>;
|
||||
}
|
||||
import {
|
||||
BaseQueryEngine,
|
||||
BaseQuestionGenerator,
|
||||
QueryEngineParamsNonStreaming,
|
||||
QueryEngineParamsStreaming,
|
||||
QueryEngineTool,
|
||||
SubQuestion,
|
||||
ToolMetadata,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* A query engine that uses a retriever to query an index and then synthesizes the response.
|
||||
|
||||
@@ -1,28 +1,18 @@
|
||||
import {
|
||||
BaseOutputParser,
|
||||
StructuredOutput,
|
||||
SubQuestionOutputParser,
|
||||
} from "./OutputParser";
|
||||
import { SubQuestionOutputParser } from "./OutputParser";
|
||||
import {
|
||||
SubQuestionPrompt,
|
||||
buildToolsText,
|
||||
defaultSubQuestionPrompt,
|
||||
} from "./Prompt";
|
||||
import { ToolMetadata } from "./Tool";
|
||||
import { OpenAI } from "./llm/LLM";
|
||||
import { LLM } from "./llm/types";
|
||||
|
||||
export interface SubQuestion {
|
||||
subQuestion: string;
|
||||
toolName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* QuestionGenerators generate new questions for the LLM using tools and a user query.
|
||||
*/
|
||||
export interface BaseQuestionGenerator {
|
||||
generate(tools: ToolMetadata[], query: string): Promise<SubQuestion[]>;
|
||||
}
|
||||
import {
|
||||
BaseOutputParser,
|
||||
BaseQuestionGenerator,
|
||||
StructuredOutput,
|
||||
SubQuestion,
|
||||
ToolMetadata,
|
||||
} from "./types";
|
||||
|
||||
/**
|
||||
* LLMQuestionGenerator uses the LLM to generate new questions for the LLM using tools and a user query.
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import { BaseQueryEngine } from "./QueryEngine";
|
||||
|
||||
export interface ToolMetadata {
|
||||
description: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple Tool interface. Likely to change.
|
||||
*/
|
||||
export interface BaseTool {
|
||||
metadata: ToolMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Tool that uses a QueryEngine.
|
||||
*/
|
||||
export interface QueryEngineTool extends BaseTool {
|
||||
queryEngine: BaseQueryEngine;
|
||||
}
|
||||
@@ -6,6 +6,4 @@ export const DEFAULT_CHUNK_OVERLAP = 20;
|
||||
export const DEFAULT_CHUNK_OVERLAP_RATIO = 0.1;
|
||||
export const DEFAULT_SIMILARITY_TOP_K = 2;
|
||||
|
||||
// NOTE: for text-embedding-ada-002
|
||||
export const DEFAULT_EMBEDDING_DIM = 1536;
|
||||
export const DEFAULT_PADDING = 5;
|
||||
|
||||
@@ -6,31 +6,58 @@ import {
|
||||
getAzureModel,
|
||||
shouldUseAzure,
|
||||
} from "../llm/azure";
|
||||
import { OpenAISession, getOpenAISession } from "../llm/openai";
|
||||
import { OpenAISession, getOpenAISession } from "../llm/open_ai";
|
||||
import { BaseEmbedding } from "./types";
|
||||
|
||||
export enum OpenAIEmbeddingModelType {
|
||||
TEXT_EMBED_ADA_002 = "text-embedding-ada-002",
|
||||
}
|
||||
export const ALL_OPENAI_EMBEDDING_MODELS = {
|
||||
"text-embedding-ada-002": {
|
||||
dimensions: 1536,
|
||||
maxTokens: 8191,
|
||||
},
|
||||
"text-embedding-3-small": {
|
||||
dimensions: 1536,
|
||||
dimensionOptions: [512, 1536],
|
||||
maxTokens: 8191,
|
||||
},
|
||||
"text-embedding-3-large": {
|
||||
dimensions: 3072,
|
||||
dimensionOptions: [256, 1024, 3072],
|
||||
maxTokens: 8191,
|
||||
},
|
||||
};
|
||||
|
||||
export class OpenAIEmbedding extends BaseEmbedding {
|
||||
model: OpenAIEmbeddingModelType | string;
|
||||
/** embeddding model. defaults to "text-embedding-ada-002" */
|
||||
model: string;
|
||||
/** number of dimensions of the resulting vector, for models that support choosing fewer dimensions. undefined will default to model default */
|
||||
dimensions: number | undefined;
|
||||
|
||||
// OpenAI session params
|
||||
|
||||
/** api key */
|
||||
apiKey?: string = undefined;
|
||||
/** maximum number of retries, default 10 */
|
||||
maxRetries: number;
|
||||
/** timeout in ms, default 60 seconds */
|
||||
timeout?: number;
|
||||
/** other session options for OpenAI */
|
||||
additionalSessionOptions?: Omit<
|
||||
Partial<OpenAIClientOptions>,
|
||||
"apiKey" | "maxRetries" | "timeout"
|
||||
>;
|
||||
|
||||
/** session object */
|
||||
session: OpenAISession;
|
||||
|
||||
/**
|
||||
* OpenAI Embedding
|
||||
* @param init - initial parameters
|
||||
*/
|
||||
constructor(init?: Partial<OpenAIEmbedding> & { azure?: AzureOpenAIConfig }) {
|
||||
super();
|
||||
|
||||
this.model = init?.model ?? OpenAIEmbeddingModelType.TEXT_EMBED_ADA_002;
|
||||
this.model = init?.model ?? "text-embedding-ada-002";
|
||||
this.dimensions = init?.dimensions; // if no dimensions provided, will be undefined/not sent to OpenAI
|
||||
|
||||
this.maxRetries = init?.maxRetries ?? 10;
|
||||
this.timeout = init?.timeout ?? 60 * 1000; // Default is 60 seconds
|
||||
@@ -76,6 +103,7 @@ export class OpenAIEmbedding extends BaseEmbedding {
|
||||
private async getOpenAIEmbedding(input: string) {
|
||||
const { data } = await this.session.openai.embeddings.create({
|
||||
model: this.model,
|
||||
dimensions: this.dimensions, // only sent to OpenAI if set by user
|
||||
input,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
import { BaseNode, MetadataMode } from "../Node";
|
||||
import { TransformComponent } from "../ingestion";
|
||||
import { similarity } from "./utils";
|
||||
|
||||
/**
|
||||
* Similarity type
|
||||
* Default is cosine similarity. Dot product and negative Euclidean distance are also supported.
|
||||
*/
|
||||
export enum SimilarityType {
|
||||
DEFAULT = "cosine",
|
||||
DOT_PRODUCT = "dot_product",
|
||||
EUCLIDEAN = "euclidean",
|
||||
}
|
||||
import { SimilarityType, similarity } from "./utils";
|
||||
|
||||
export abstract class BaseEmbedding implements TransformComponent {
|
||||
similarity(
|
||||
|
||||
@@ -2,8 +2,17 @@ import _ from "lodash";
|
||||
import { ImageType } from "../Node";
|
||||
import { DEFAULT_SIMILARITY_TOP_K } from "../constants";
|
||||
import { defaultFS } from "../env";
|
||||
import { VectorStoreQueryMode } from "../storage";
|
||||
import { SimilarityType } from "./types";
|
||||
import { VectorStoreQueryMode } from "../storage/vectorStore/types";
|
||||
|
||||
/**
|
||||
* Similarity type
|
||||
* Default is cosine similarity. Dot product and negative Euclidean distance are also supported.
|
||||
*/
|
||||
export enum SimilarityType {
|
||||
DEFAULT = "cosine",
|
||||
DOT_PRODUCT = "dot_product",
|
||||
EUCLIDEAN = "euclidean",
|
||||
}
|
||||
|
||||
/**
|
||||
* The similarity between two embeddings.
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
defaultCondenseQuestionPrompt,
|
||||
messagesToHistoryStr,
|
||||
} from "../../Prompt";
|
||||
import { BaseQueryEngine } from "../../QueryEngine";
|
||||
import { Response } from "../../Response";
|
||||
import {
|
||||
ServiceContext,
|
||||
@@ -12,6 +11,7 @@ import {
|
||||
} from "../../ServiceContext";
|
||||
import { ChatMessage, LLM } from "../../llm";
|
||||
import { extractText, streamReducer } from "../../llm/utils";
|
||||
import { BaseQueryEngine } from "../../types";
|
||||
import {
|
||||
ChatEngine,
|
||||
ChatEngineParamsNonStreaming,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BaseNode, MetadataMode, TextNode } from "../Node";
|
||||
import { LLM } from "../llm";
|
||||
import { LLM, OpenAI } from "../llm";
|
||||
import {
|
||||
defaultKeywordExtractorPromptTemplate,
|
||||
defaultQuestionAnswerPromptTemplate,
|
||||
@@ -11,6 +11,11 @@ import { BaseExtractor } from "./types";
|
||||
|
||||
const STRIP_REGEX = /(\r\n|\n|\r)/gm;
|
||||
|
||||
type KeywordExtractArgs = {
|
||||
llm?: LLM;
|
||||
keywords?: number;
|
||||
};
|
||||
|
||||
type ExtractKeyword = {
|
||||
excerptKeywords: string;
|
||||
};
|
||||
@@ -38,12 +43,14 @@ export class KeywordExtractor extends BaseExtractor {
|
||||
* @param {number} keywords Number of keywords to extract.
|
||||
* @throws {Error} If keywords is less than 1.
|
||||
*/
|
||||
constructor(llm: LLM, keywords: number = 5) {
|
||||
if (keywords < 1) throw new Error("Keywords must be greater than 0");
|
||||
constructor(options?: KeywordExtractArgs) {
|
||||
if (options?.keywords && options.keywords < 1)
|
||||
throw new Error("Keywords must be greater than 0");
|
||||
|
||||
super();
|
||||
this.llm = llm;
|
||||
this.keywords = keywords;
|
||||
|
||||
this.llm = options?.llm ?? new OpenAI();
|
||||
this.keywords = options?.keywords ?? 5;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,6 +88,13 @@ export class KeywordExtractor extends BaseExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
type TitleExtractorsArgs = {
|
||||
llm?: LLM;
|
||||
nodes?: number;
|
||||
nodeTemplate?: string;
|
||||
combineTemplate?: string;
|
||||
};
|
||||
|
||||
type ExtractTitle = {
|
||||
documentTitle: string;
|
||||
};
|
||||
@@ -128,20 +142,16 @@ export class TitleExtractor extends BaseExtractor {
|
||||
* @param {string} node_template The prompt template to use for the title extractor.
|
||||
* @param {string} combine_template The prompt template to merge title with..
|
||||
*/
|
||||
constructor(
|
||||
llm: LLM,
|
||||
nodes: number = 5,
|
||||
node_template?: string,
|
||||
combine_template?: string,
|
||||
) {
|
||||
constructor(options?: TitleExtractorsArgs) {
|
||||
super();
|
||||
|
||||
this.llm = llm;
|
||||
this.nodes = nodes;
|
||||
this.llm = options?.llm ?? new OpenAI();
|
||||
this.nodes = options?.nodes ?? 5;
|
||||
|
||||
this.nodeTemplate = node_template ?? defaultTitleExtractorPromptTemplate();
|
||||
this.nodeTemplate =
|
||||
options?.nodeTemplate ?? defaultTitleExtractorPromptTemplate();
|
||||
this.combineTemplate =
|
||||
combine_template ?? defaultTitleCombinePromptTemplate();
|
||||
options?.combineTemplate ?? defaultTitleCombinePromptTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,6 +207,13 @@ export class TitleExtractor extends BaseExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
type QuestionAnswerExtractArgs = {
|
||||
llm?: LLM;
|
||||
questions?: number;
|
||||
promptTemplate?: string;
|
||||
embeddingOnly?: boolean;
|
||||
};
|
||||
|
||||
type ExtractQuestion = {
|
||||
questionsThisExcerptCanAnswer: string;
|
||||
};
|
||||
@@ -238,25 +255,21 @@ export class QuestionsAnsweredExtractor extends BaseExtractor {
|
||||
* @param {string} promptTemplate The prompt template to use for the question extractor.
|
||||
* @param {boolean} embeddingOnly Wheter to use metadata for embeddings only.
|
||||
*/
|
||||
constructor(
|
||||
llm: LLM,
|
||||
questions: number = 5,
|
||||
promptTemplate?: string,
|
||||
embeddingOnly: boolean = false,
|
||||
) {
|
||||
if (questions < 1) throw new Error("Questions must be greater than 0");
|
||||
constructor(options?: QuestionAnswerExtractArgs) {
|
||||
if (options?.questions && options.questions < 1)
|
||||
throw new Error("Questions must be greater than 0");
|
||||
|
||||
super();
|
||||
|
||||
this.llm = llm;
|
||||
this.questions = questions;
|
||||
this.llm = options?.llm ?? new OpenAI();
|
||||
this.questions = options?.questions ?? 5;
|
||||
this.promptTemplate =
|
||||
promptTemplate ??
|
||||
options?.promptTemplate ??
|
||||
defaultQuestionAnswerPromptTemplate({
|
||||
numQuestions: questions,
|
||||
numQuestions: this.questions,
|
||||
contextStr: "",
|
||||
});
|
||||
this.embeddingOnly = embeddingOnly;
|
||||
this.embeddingOnly = options?.embeddingOnly ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -303,6 +316,12 @@ export class QuestionsAnsweredExtractor extends BaseExtractor {
|
||||
}
|
||||
}
|
||||
|
||||
type SummaryExtractArgs = {
|
||||
llm?: LLM;
|
||||
summaries?: string[];
|
||||
promptTemplate?: string;
|
||||
};
|
||||
|
||||
type ExtractSummary = {
|
||||
sectionSummary: string;
|
||||
prevSectionSummary: string;
|
||||
@@ -335,24 +354,25 @@ export class SummaryExtractor extends BaseExtractor {
|
||||
private _prevSummary: boolean;
|
||||
private _nextSummary: boolean;
|
||||
|
||||
constructor(
|
||||
llm: LLM,
|
||||
summaries: string[] = ["self"],
|
||||
promptTemplate?: string,
|
||||
) {
|
||||
if (!summaries.some((s) => ["self", "prev", "next"].includes(s)))
|
||||
constructor(options?: SummaryExtractArgs) {
|
||||
const summaries = options?.summaries ?? ["self"];
|
||||
|
||||
if (
|
||||
summaries &&
|
||||
!summaries.some((s) => ["self", "prev", "next"].includes(s))
|
||||
)
|
||||
throw new Error("Summaries must be one of 'self', 'prev', 'next'");
|
||||
|
||||
super();
|
||||
|
||||
this.llm = llm;
|
||||
this.llm = options?.llm ?? new OpenAI();
|
||||
this.summaries = summaries;
|
||||
this.promptTemplate =
|
||||
promptTemplate ?? defaultSummaryExtractorPromptTemplate();
|
||||
options?.promptTemplate ?? defaultSummaryExtractorPromptTemplate();
|
||||
|
||||
this._selfSummary = summaries.includes("self");
|
||||
this._prevSummary = summaries.includes("prev");
|
||||
this._nextSummary = summaries.includes("next");
|
||||
this._selfSummary = summaries?.includes("self") ?? false;
|
||||
this._prevSummary = summaries?.includes("prev") ?? false;
|
||||
this._nextSummary = summaries?.includes("next") ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,3 +4,4 @@ export {
|
||||
SummaryExtractor,
|
||||
TitleExtractor,
|
||||
} from "./MetadataExtractors";
|
||||
export { BaseExtractor } from "./types";
|
||||
|
||||
@@ -46,7 +46,10 @@ export abstract class BaseExtractor implements TransformComponent {
|
||||
let curMetadataList = await this.extract(newNodes);
|
||||
|
||||
for (let idx in newNodes) {
|
||||
newNodes[idx].metadata = curMetadataList[idx];
|
||||
newNodes[idx].metadata = {
|
||||
...newNodes[idx].metadata,
|
||||
...curMetadataList[idx],
|
||||
};
|
||||
}
|
||||
|
||||
for (let idx in newNodes) {
|
||||
|
||||
@@ -10,7 +10,6 @@ export * from "./Response";
|
||||
export * from "./Retriever";
|
||||
export * from "./ServiceContext";
|
||||
export * from "./TextSplitter";
|
||||
export * from "./Tool";
|
||||
export * from "./callbacks/CallbackManager";
|
||||
export * from "./constants";
|
||||
export * from "./embeddings";
|
||||
@@ -21,7 +20,7 @@ export * from "./ingestion";
|
||||
export * from "./llm";
|
||||
export * from "./nodeParsers";
|
||||
export * from "./postprocessors";
|
||||
export * from "./readers/AssemblyAI";
|
||||
export * from "./readers/AssemblyAIReader";
|
||||
export * from "./readers/CSVReader";
|
||||
export * from "./readers/DocxReader";
|
||||
export * from "./readers/HTMLReader";
|
||||
@@ -33,3 +32,4 @@ export * from "./readers/SimpleMongoReader";
|
||||
export * from "./readers/base";
|
||||
export * from "./storage";
|
||||
export * from "./synthesizers";
|
||||
export type * from "./types";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BaseNode, Document, jsonToNode } from "../Node";
|
||||
import { BaseQueryEngine } from "../QueryEngine";
|
||||
import { BaseRetriever } from "../Retriever";
|
||||
import { ServiceContext } from "../ServiceContext";
|
||||
import { randomUUID } from "../env";
|
||||
@@ -8,6 +7,7 @@ import { BaseDocumentStore } from "../storage/docStore/types";
|
||||
import { BaseIndexStore } from "../storage/indexStore/types";
|
||||
import { VectorStore } from "../storage/vectorStore/types";
|
||||
import { BaseSynthesizer } from "../synthesizers";
|
||||
import { BaseQueryEngine } from "../types";
|
||||
|
||||
/**
|
||||
* The underlying structure of each index.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BaseNode, Document, MetadataMode } from "../../Node";
|
||||
import { defaultKeywordExtractPrompt } from "../../Prompt";
|
||||
import { BaseQueryEngine, RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { BaseRetriever } from "../../Retriever";
|
||||
import {
|
||||
ServiceContext,
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
storageContextFromDefaults,
|
||||
} from "../../storage";
|
||||
import { BaseSynthesizer } from "../../synthesizers";
|
||||
import { BaseQueryEngine } from "../../types";
|
||||
import {
|
||||
BaseIndex,
|
||||
BaseIndexInit,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import _ from "lodash";
|
||||
import { BaseNode, Document } from "../../Node";
|
||||
import { BaseQueryEngine, RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { BaseRetriever } from "../../Retriever";
|
||||
import {
|
||||
ServiceContext,
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
CompactAndRefine,
|
||||
ResponseSynthesizer,
|
||||
} from "../../synthesizers";
|
||||
import { BaseQueryEngine } from "../../types";
|
||||
import {
|
||||
BaseIndex,
|
||||
BaseIndexInit,
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
ObjectType,
|
||||
splitNodesByType,
|
||||
} from "../../Node";
|
||||
import { BaseQueryEngine, RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { RetrieverQueryEngine } from "../../QueryEngine";
|
||||
import { BaseRetriever } from "../../Retriever";
|
||||
import {
|
||||
ServiceContext,
|
||||
@@ -26,6 +26,7 @@ import {
|
||||
storageContextFromDefaults,
|
||||
} from "../../storage";
|
||||
import { BaseSynthesizer } from "../../synthesizers";
|
||||
import { BaseQueryEngine } from "../../types";
|
||||
import {
|
||||
BaseIndex,
|
||||
BaseIndexInit,
|
||||
|
||||
@@ -25,9 +25,9 @@ import {
|
||||
shouldUseAzure,
|
||||
} from "./azure";
|
||||
import { BaseLLM } from "./base";
|
||||
import { OpenAISession, getOpenAISession } from "./openai";
|
||||
import { OpenAISession, getOpenAISession } from "./open_ai";
|
||||
import { PortkeySession, getPortkeySession } from "./portkey";
|
||||
import { ReplicateSession } from "./replicate";
|
||||
import { ReplicateSession } from "./replicate_ai";
|
||||
import {
|
||||
ChatMessage,
|
||||
ChatResponse,
|
||||
@@ -41,14 +41,21 @@ import {
|
||||
export const GPT4_MODELS = {
|
||||
"gpt-4": { contextWindow: 8192 },
|
||||
"gpt-4-32k": { contextWindow: 32768 },
|
||||
"gpt-4-32k-0613": { contextWindow: 32768 },
|
||||
"gpt-4-turbo-preview": { contextWindow: 128000 },
|
||||
"gpt-4-1106-preview": { contextWindow: 128000 },
|
||||
"gpt-4-vision-preview": { contextWindow: 8192 },
|
||||
"gpt-4-0125-preview": { contextWindow: 128000 },
|
||||
"gpt-4-vision-preview": { contextWindow: 128000 },
|
||||
};
|
||||
|
||||
// NOTE we don't currently support gpt-3.5-turbo-instruct and don't plan to in the near future
|
||||
export const GPT35_MODELS = {
|
||||
"gpt-3.5-turbo": { contextWindow: 4096 },
|
||||
"gpt-3.5-turbo-0613": { contextWindow: 4096 },
|
||||
"gpt-3.5-turbo-16k": { contextWindow: 16384 },
|
||||
"gpt-3.5-turbo-16k-0613": { contextWindow: 16384 },
|
||||
"gpt-3.5-turbo-1106": { contextWindow: 16384 },
|
||||
"gpt-3.5-turbo-0125": { contextWindow: 16384 },
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,14 @@ const ALL_AZURE_OPENAI_CHAT_MODELS = {
|
||||
},
|
||||
"gpt-4": { contextWindow: 8192, openAIModel: "gpt-4" },
|
||||
"gpt-4-32k": { contextWindow: 32768, openAIModel: "gpt-4-32k" },
|
||||
"gpt-4-vision-preview": {
|
||||
contextWindow: 128000,
|
||||
openAIModel: "gpt-4-vision-preview",
|
||||
},
|
||||
"gpt-4-1106-preview": {
|
||||
contextWindow: 128000,
|
||||
openAIModel: "gpt-4-1106-preview",
|
||||
},
|
||||
};
|
||||
|
||||
const ALL_AZURE_OPENAI_EMBEDDING_MODELS = {
|
||||
@@ -25,13 +33,29 @@ const ALL_AZURE_OPENAI_EMBEDDING_MODELS = {
|
||||
openAIModel: "text-embedding-ada-002",
|
||||
maxTokens: 8191,
|
||||
},
|
||||
"text-embedding-3-small": {
|
||||
dimensions: 1536,
|
||||
dimensionOptions: [512, 1536],
|
||||
openAIModel: "text-embedding-3-small",
|
||||
maxTokens: 8191,
|
||||
},
|
||||
"text-embedding-3-large": {
|
||||
dimensions: 3072,
|
||||
dimensionOptions: [256, 1024, 3072],
|
||||
openAIModel: "text-embedding-3-large",
|
||||
maxTokens: 8191,
|
||||
},
|
||||
};
|
||||
|
||||
const ALL_AZURE_API_VERSIONS = [
|
||||
"2022-12-01",
|
||||
"2023-05-15",
|
||||
"2023-06-01-preview",
|
||||
"2023-07-01-preview",
|
||||
"2023-03-15-preview", // retiring 2024-04-02
|
||||
"2023-06-01-preview", // retiring 2024-04-02
|
||||
"2023-07-01-preview", // retiring 2024-04-02
|
||||
"2023-08-01-preview", // retiring 2024-04-02
|
||||
"2023-09-01-preview",
|
||||
"2023-12-01-preview",
|
||||
];
|
||||
|
||||
const DEFAULT_API_VERSION = "2023-05-15";
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
export * from "./LLM";
|
||||
export * from "./mistral";
|
||||
export {
|
||||
ALL_AVAILABLE_MISTRAL_MODELS,
|
||||
MistralAI,
|
||||
MistralAISession,
|
||||
} from "./mistral";
|
||||
export { Ollama } from "./ollama";
|
||||
export * from "./open_ai";
|
||||
export { TogetherLLM } from "./together";
|
||||
export * from "./types";
|
||||
|
||||
@@ -28,5 +28,3 @@ export function getReplicateSession(replicateKey: string | null = null) {
|
||||
|
||||
return defaultReplicateSession;
|
||||
}
|
||||
|
||||
export * from "openai";
|
||||
@@ -20,6 +20,7 @@ export class PGVectorStore implements VectorStore {
|
||||
private schemaName: string = PGVECTOR_SCHEMA;
|
||||
private tableName: string = PGVECTOR_TABLE;
|
||||
private connectionString: string | undefined = undefined;
|
||||
private dimensions: number = 1536;
|
||||
|
||||
private db?: pg.Client;
|
||||
|
||||
@@ -38,15 +39,18 @@ export class PGVectorStore implements VectorStore {
|
||||
* @param {string} config.schemaName - The name of the schema (optional). Defaults to PGVECTOR_SCHEMA.
|
||||
* @param {string} config.tableName - The name of the table (optional). Defaults to PGVECTOR_TABLE.
|
||||
* @param {string} config.connectionString - The connection string (optional).
|
||||
* @param {number} config.dimensions - The dimensions of the embedding model.
|
||||
*/
|
||||
constructor(config?: {
|
||||
schemaName?: string;
|
||||
tableName?: string;
|
||||
connectionString?: string;
|
||||
dimensions?: number;
|
||||
}) {
|
||||
this.schemaName = config?.schemaName ?? PGVECTOR_SCHEMA;
|
||||
this.tableName = config?.tableName ?? PGVECTOR_TABLE;
|
||||
this.connectionString = config?.connectionString;
|
||||
this.dimensions = config?.dimensions ?? 1536;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +112,7 @@ export class PGVectorStore implements VectorStore {
|
||||
collection VARCHAR,
|
||||
document TEXT,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
embeddings VECTOR(1536)
|
||||
embeddings VECTOR(${this.dimensions})
|
||||
)`;
|
||||
await db.query(tbl);
|
||||
|
||||
|
||||
@@ -54,11 +54,9 @@ export class QdrantVectorStore implements VectorStore {
|
||||
apiKey,
|
||||
batchSize,
|
||||
}: QdrantParams) {
|
||||
if (!client && (!url || !apiKey)) {
|
||||
if (!url || !apiKey || !collectionName) {
|
||||
throw new Error(
|
||||
"QdrantVectorStore requires url, apiKey and collectionName",
|
||||
);
|
||||
if (!client && !url) {
|
||||
if (!url || !collectionName) {
|
||||
throw new Error("QdrantVectorStore requires url and collectionName");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
getTopKEmbeddings,
|
||||
getTopKEmbeddingsLearner,
|
||||
getTopKMMREmbeddings,
|
||||
} from "../../embeddings";
|
||||
} from "../../embeddings/utils";
|
||||
import { defaultFS, path } from "../../env";
|
||||
import { GenericFileSystem, exists } from "../FileSystem";
|
||||
import { DEFAULT_PERSIST_DIR } from "../constants";
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ResponseSynthesizer, SimpleResponseBuilder } from "../synthesizers";
|
||||
import { mockEmbeddingModel, mockLlmGeneration } from "./utility/mockOpenAI";
|
||||
|
||||
// Mock the OpenAI getOpenAISession function during testing
|
||||
jest.mock("../llm/openai", () => {
|
||||
jest.mock("../llm/open_ai", () => {
|
||||
return {
|
||||
getOpenAISession: jest.fn().mockImplementation(() => null),
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from "./utility/mockOpenAI";
|
||||
|
||||
// Mock the OpenAI getOpenAISession function during testing
|
||||
jest.mock("../llm/openai", () => {
|
||||
jest.mock("../llm/open_ai", () => {
|
||||
return {
|
||||
getOpenAISession: jest.fn().mockImplementation(() => null),
|
||||
};
|
||||
@@ -75,7 +75,10 @@ describe("[MetadataExtractor]: Extractors should populate the metadata", () => {
|
||||
new Document({ text: DEFAULT_LLM_TEXT_OUTPUT }),
|
||||
]);
|
||||
|
||||
const keywordExtractor = new KeywordExtractor(serviceContext.llm, 5);
|
||||
const keywordExtractor = new KeywordExtractor({
|
||||
llm: serviceContext.llm,
|
||||
keywords: 5,
|
||||
});
|
||||
|
||||
const nodesWithKeywordMetadata = await keywordExtractor.processNodes(nodes);
|
||||
|
||||
@@ -91,7 +94,10 @@ describe("[MetadataExtractor]: Extractors should populate the metadata", () => {
|
||||
new Document({ text: DEFAULT_LLM_TEXT_OUTPUT }),
|
||||
]);
|
||||
|
||||
const titleExtractor = new TitleExtractor(serviceContext.llm, 5);
|
||||
const titleExtractor = new TitleExtractor({
|
||||
llm: serviceContext.llm,
|
||||
nodes: 5,
|
||||
});
|
||||
|
||||
const nodesWithKeywordMetadata = await titleExtractor.processNodes(nodes);
|
||||
|
||||
@@ -107,10 +113,10 @@ describe("[MetadataExtractor]: Extractors should populate the metadata", () => {
|
||||
new Document({ text: DEFAULT_LLM_TEXT_OUTPUT }),
|
||||
]);
|
||||
|
||||
const questionsAnsweredExtractor = new QuestionsAnsweredExtractor(
|
||||
serviceContext.llm,
|
||||
5,
|
||||
);
|
||||
const questionsAnsweredExtractor = new QuestionsAnsweredExtractor({
|
||||
llm: serviceContext.llm,
|
||||
questions: 5,
|
||||
});
|
||||
|
||||
const nodesWithKeywordMetadata =
|
||||
await questionsAnsweredExtractor.processNodes(nodes);
|
||||
@@ -127,7 +133,9 @@ describe("[MetadataExtractor]: Extractors should populate the metadata", () => {
|
||||
new Document({ text: DEFAULT_LLM_TEXT_OUTPUT }),
|
||||
]);
|
||||
|
||||
const summaryExtractor = new SummaryExtractor(serviceContext.llm);
|
||||
const summaryExtractor = new SummaryExtractor({
|
||||
llm: serviceContext.llm,
|
||||
});
|
||||
|
||||
const nodesWithKeywordMetadata = await summaryExtractor.processNodes(nodes);
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Top level types to avoid circular dependencies
|
||||
*/
|
||||
|
||||
import { Event } from "./callbacks/CallbackManager";
|
||||
import { Response } from "./Response";
|
||||
|
||||
/**
|
||||
* Parameters for sending a query.
|
||||
*/
|
||||
export interface QueryEngineParamsBase {
|
||||
query: string;
|
||||
parentEvent?: Event;
|
||||
}
|
||||
|
||||
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 BaseQueryEngine {
|
||||
/**
|
||||
* Query the query engine and get a response.
|
||||
* @param params
|
||||
*/
|
||||
query(params: QueryEngineParamsStreaming): Promise<AsyncIterable<Response>>;
|
||||
query(params: QueryEngineParamsNonStreaming): Promise<Response>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple Tool interface. Likely to change.
|
||||
*/
|
||||
export interface BaseTool {
|
||||
metadata: ToolMetadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* A Tool that uses a QueryEngine.
|
||||
*/
|
||||
export interface QueryEngineTool extends BaseTool {
|
||||
queryEngine: BaseQueryEngine;
|
||||
}
|
||||
|
||||
export interface SubQuestion {
|
||||
subQuestion: string;
|
||||
toolName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* An OutputParser is used to extract structured data from the raw output of the LLM.
|
||||
*/
|
||||
export interface BaseOutputParser<T> {
|
||||
parse(output: string): T;
|
||||
|
||||
format(output: string): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* StructuredOutput is just a combo of the raw output and the parsed output.
|
||||
*/
|
||||
export interface StructuredOutput<T> {
|
||||
rawOutput: string;
|
||||
parsedOutput: T;
|
||||
}
|
||||
|
||||
export interface ToolMetadata {
|
||||
description: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* QuestionGenerators generate new questions for the LLM using tools and a user query.
|
||||
*/
|
||||
export interface BaseQuestionGenerator {
|
||||
generate(tools: ToolMetadata[], query: string): Promise<SubQuestion[]>;
|
||||
}
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
declare module "@mistralai/mistralai" {
|
||||
export = MistralClient;
|
||||
}
|
||||
@@ -1,5 +1,18 @@
|
||||
# create-llama
|
||||
|
||||
## 0.0.20
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 27d55fd: Add an option to provide an URL and chat with the website data
|
||||
|
||||
## 0.0.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 3a29a80: Add node_modules to gitignore in Express backends
|
||||
- fe03aaa: feat: generate llama pack example
|
||||
|
||||
## 0.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -32,10 +32,11 @@ export async function createApp({
|
||||
openAiKey,
|
||||
model,
|
||||
communityProjectPath,
|
||||
llamapack,
|
||||
vectorDb,
|
||||
externalPort,
|
||||
postInstallAction,
|
||||
contextFile,
|
||||
dataSource,
|
||||
}: InstallAppArgs): Promise<void> {
|
||||
const root = path.resolve(appPath);
|
||||
|
||||
@@ -75,10 +76,11 @@ export async function createApp({
|
||||
openAiKey,
|
||||
model,
|
||||
communityProjectPath,
|
||||
llamapack,
|
||||
vectorDb,
|
||||
externalPort,
|
||||
postInstallAction,
|
||||
contextFile,
|
||||
dataSource,
|
||||
};
|
||||
|
||||
if (frontend) {
|
||||
|
||||
@@ -28,10 +28,6 @@ for (const templateType of templateTypes) {
|
||||
// nextjs doesn't support simple templates - skip tests
|
||||
continue;
|
||||
}
|
||||
if (templateEngine === "context") {
|
||||
// we don't test context templates because it needs OPEN_AI_KEY
|
||||
continue;
|
||||
}
|
||||
const appType: AppType =
|
||||
templateFramework === "express" || templateFramework === "fastapi"
|
||||
? templateType === "simple"
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
export const COMMUNITY_OWNER = "run-llama";
|
||||
export const COMMUNITY_REPO = "create_llama_projects";
|
||||
export const LLAMA_PACK_OWNER = "run-llama";
|
||||
export const LLAMA_PACK_REPO = "llama-hub";
|
||||
export const LLAMA_HUB_FOLDER_PATH = `${LLAMA_PACK_OWNER}/${LLAMA_PACK_REPO}/main/llama_hub`;
|
||||
export const LLAMA_PACK_CONFIG_PATH = `${LLAMA_HUB_FOLDER_PATH}/llama_packs/library.json`;
|
||||
|
||||
@@ -7,14 +7,16 @@ import { cyan } from "picocolors";
|
||||
|
||||
import { COMMUNITY_OWNER, COMMUNITY_REPO } from "./constant";
|
||||
import { PackageManager } from "./get-pkg-manager";
|
||||
import { installLlamapackProject } from "./llama-pack";
|
||||
import { isHavingPoetryLockFile, tryPoetryRun } from "./poetry";
|
||||
import { installPythonTemplate } from "./python";
|
||||
import { downloadAndExtractRepo } from "./repo";
|
||||
import {
|
||||
InstallTemplateArgs,
|
||||
TemplateEngine,
|
||||
TemplateDataSource,
|
||||
TemplateFramework,
|
||||
TemplateVectorDB,
|
||||
WebSourceConfig,
|
||||
} from "./types";
|
||||
import { installTSTemplate } from "./typescript";
|
||||
|
||||
@@ -25,6 +27,7 @@ const createEnvLocalFile = async (
|
||||
vectorDb?: TemplateVectorDB;
|
||||
model?: string;
|
||||
framework?: TemplateFramework;
|
||||
dataSource?: TemplateDataSource;
|
||||
},
|
||||
) => {
|
||||
const envFileName = ".env";
|
||||
@@ -57,48 +60,30 @@ const createEnvLocalFile = async (
|
||||
}
|
||||
}
|
||||
|
||||
switch (opts?.dataSource?.type) {
|
||||
case "web": {
|
||||
let webConfig = opts?.dataSource.config as WebSourceConfig;
|
||||
content += `# web loader config\n`;
|
||||
content += `BASE_URL=${webConfig.baseUrl}\n`;
|
||||
content += `URL_PREFIX=${webConfig.baseUrl}\n`;
|
||||
content += `MAX_DEPTH=${webConfig.depth}\n`;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (content) {
|
||||
await fs.writeFile(path.join(root, envFileName), content);
|
||||
console.log(`Created '${envFileName}' file. Please check the settings.`);
|
||||
}
|
||||
};
|
||||
|
||||
const copyTestData = async (
|
||||
root: string,
|
||||
const installDependencies = async (
|
||||
framework: TemplateFramework,
|
||||
packageManager?: PackageManager,
|
||||
engine?: TemplateEngine,
|
||||
openAiKey?: string,
|
||||
vectorDb?: TemplateVectorDB,
|
||||
contextFile?: string,
|
||||
// eslint-disable-next-line max-params
|
||||
) => {
|
||||
if (engine === "context") {
|
||||
const destPath = path.join(root, "data");
|
||||
if (contextFile) {
|
||||
console.log(`\nCopying provided file to ${cyan(destPath)}\n`);
|
||||
await fs.mkdir(destPath, { recursive: true });
|
||||
await fs.copyFile(
|
||||
contextFile,
|
||||
path.join(destPath, path.basename(contextFile)),
|
||||
);
|
||||
} else {
|
||||
const srcPath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"templates",
|
||||
"components",
|
||||
"data",
|
||||
);
|
||||
console.log(`\nCopying test data to ${cyan(destPath)}\n`);
|
||||
await copy("**", destPath, {
|
||||
parents: true,
|
||||
cwd: srcPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (packageManager && engine === "context") {
|
||||
if (packageManager) {
|
||||
const runGenerate = `${cyan(
|
||||
framework === "fastapi"
|
||||
? "poetry run python app/engine/generate.py"
|
||||
@@ -130,6 +115,31 @@ const copyTestData = async (
|
||||
}
|
||||
};
|
||||
|
||||
const copyTestData = async (root: string, contextFile?: string) => {
|
||||
const destPath = path.join(root, "data");
|
||||
if (contextFile) {
|
||||
console.log(`\nCopying provided file to ${cyan(destPath)}\n`);
|
||||
await fs.mkdir(destPath, { recursive: true });
|
||||
await fs.copyFile(
|
||||
contextFile,
|
||||
path.join(destPath, path.basename(contextFile)),
|
||||
);
|
||||
} else {
|
||||
const srcPath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"templates",
|
||||
"components",
|
||||
"data",
|
||||
);
|
||||
console.log(`\nCopying test data to ${cyan(destPath)}\n`);
|
||||
await copy("**", destPath, {
|
||||
parents: true,
|
||||
cwd: srcPath,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const installCommunityProject = async ({
|
||||
root,
|
||||
communityProjectPath,
|
||||
@@ -153,6 +163,11 @@ export const installTemplate = async (
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.template === "llamapack" && props.llamapack) {
|
||||
await installLlamapackProject(props);
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.framework === "fastapi") {
|
||||
await installPythonTemplate(props);
|
||||
} else {
|
||||
@@ -168,18 +183,21 @@ export const installTemplate = async (
|
||||
vectorDb: props.vectorDb,
|
||||
model: props.model,
|
||||
framework: props.framework,
|
||||
dataSource: props.dataSource,
|
||||
});
|
||||
|
||||
// Copy test pdf file
|
||||
await copyTestData(
|
||||
props.root,
|
||||
props.framework,
|
||||
props.packageManager,
|
||||
props.engine,
|
||||
props.openAiKey,
|
||||
props.vectorDb,
|
||||
props.contextFile,
|
||||
);
|
||||
if (props.engine === "context") {
|
||||
if (props.dataSource?.type === "file") {
|
||||
// Copy test pdf file
|
||||
await copyTestData(props.root, props.framework);
|
||||
}
|
||||
installDependencies(
|
||||
props.framework,
|
||||
props.packageManager,
|
||||
props.openAiKey,
|
||||
props.vectorDb,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// this is a frontend for a full-stack app, create .env file with model information
|
||||
const content = `MODEL=${props.model}\nNEXT_PUBLIC_MODEL=${props.model}\n`;
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import { LLAMA_HUB_FOLDER_PATH, LLAMA_PACK_CONFIG_PATH } from "./constant";
|
||||
import { copy } from "./copy";
|
||||
import { installPythonDependencies } from "./python";
|
||||
import { getRepoRawContent } from "./repo";
|
||||
import { InstallTemplateArgs } from "./types";
|
||||
|
||||
export async function getAvailableLlamapackOptions(): Promise<
|
||||
{
|
||||
name: string;
|
||||
folderPath: string;
|
||||
example: boolean | undefined;
|
||||
}[]
|
||||
> {
|
||||
const libraryJsonRaw = await getRepoRawContent(LLAMA_PACK_CONFIG_PATH);
|
||||
const libraryJson = JSON.parse(libraryJsonRaw);
|
||||
const llamapackKeys = Object.keys(libraryJson);
|
||||
return llamapackKeys
|
||||
.map((key) => ({
|
||||
name: key,
|
||||
folderPath: libraryJson[key].id,
|
||||
example: libraryJson[key].example,
|
||||
}))
|
||||
.filter((item) => !!item.example);
|
||||
}
|
||||
|
||||
const copyLlamapackEmptyProject = async ({
|
||||
root,
|
||||
}: Pick<InstallTemplateArgs, "root">) => {
|
||||
const templatePath = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"templates/components/sample-projects/llamapack",
|
||||
);
|
||||
await copy("**", root, {
|
||||
parents: true,
|
||||
cwd: templatePath,
|
||||
});
|
||||
};
|
||||
|
||||
const copyData = async ({
|
||||
root,
|
||||
}: Pick<InstallTemplateArgs, "root" | "llamapack">) => {
|
||||
const dataPath = path.join(__dirname, "..", "templates/components/data");
|
||||
await copy("**", path.join(root, "data"), {
|
||||
parents: true,
|
||||
cwd: dataPath,
|
||||
});
|
||||
};
|
||||
|
||||
const installLlamapackExample = async ({
|
||||
root,
|
||||
llamapack,
|
||||
}: Pick<InstallTemplateArgs, "root" | "llamapack">) => {
|
||||
const exampleFileName = "example.py";
|
||||
const readmeFileName = "README.md";
|
||||
const exampleFilePath = `${LLAMA_HUB_FOLDER_PATH}/${llamapack}/${exampleFileName}`;
|
||||
const readmeFilePath = `${LLAMA_HUB_FOLDER_PATH}/${llamapack}/${readmeFileName}`;
|
||||
|
||||
// Download example.py from llamapack and save to root
|
||||
const exampleContent = await getRepoRawContent(exampleFilePath);
|
||||
await fs.writeFile(path.join(root, exampleFileName), exampleContent);
|
||||
|
||||
// Download README.md from llamapack and combine with README-template.md,
|
||||
// save to root and then delete template file
|
||||
const readmeContent = await getRepoRawContent(readmeFilePath);
|
||||
const readmeTemplateContent = await fs.readFile(
|
||||
path.join(root, "README-template.md"),
|
||||
"utf-8",
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(root, readmeFileName),
|
||||
`${readmeContent}\n${readmeTemplateContent}`,
|
||||
);
|
||||
await fs.unlink(path.join(root, "README-template.md"));
|
||||
};
|
||||
|
||||
export const installLlamapackProject = async ({
|
||||
root,
|
||||
llamapack,
|
||||
postInstallAction,
|
||||
}: Pick<InstallTemplateArgs, "root" | "llamapack" | "postInstallAction">) => {
|
||||
console.log("\nInstalling Llamapack project:", llamapack!);
|
||||
await copyLlamapackEmptyProject({ root });
|
||||
await copyData({ root });
|
||||
await installLlamapackExample({ root, llamapack });
|
||||
if (postInstallAction !== "none") {
|
||||
installPythonDependencies({ noRoot: true });
|
||||
}
|
||||
};
|
||||
@@ -10,9 +10,11 @@ export function isPoetryAvailable(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function tryPoetryInstall(): boolean {
|
||||
export function tryPoetryInstall(noRoot: boolean): boolean {
|
||||
try {
|
||||
execSync("poetry install", { stdio: "inherit" });
|
||||
execSync(`poetry install${noRoot ? " --no-root" : ""}`, {
|
||||
stdio: "inherit",
|
||||
});
|
||||
return true;
|
||||
} catch (_) {}
|
||||
return false;
|
||||
|
||||
@@ -92,12 +92,14 @@ export const addDependencies = async (
|
||||
}
|
||||
};
|
||||
|
||||
export const installPythonDependencies = (root: string) => {
|
||||
export const installPythonDependencies = (
|
||||
{ noRoot }: { noRoot: boolean } = { noRoot: false },
|
||||
) => {
|
||||
if (isPoetryAvailable()) {
|
||||
console.log(
|
||||
`Installing python dependencies using poetry. This may take a while...`,
|
||||
);
|
||||
const installSuccessful = tryPoetryInstall();
|
||||
const installSuccessful = tryPoetryInstall(noRoot);
|
||||
if (!installSuccessful) {
|
||||
console.error(
|
||||
red("Install failed. Please install dependencies manually."),
|
||||
@@ -124,6 +126,7 @@ export const installPythonTemplate = async ({
|
||||
framework,
|
||||
engine,
|
||||
vectorDb,
|
||||
dataSource,
|
||||
postInstallAction,
|
||||
}: Pick<
|
||||
InstallTemplateArgs,
|
||||
@@ -132,6 +135,7 @@ export const installPythonTemplate = async ({
|
||||
| "template"
|
||||
| "engine"
|
||||
| "vectorDb"
|
||||
| "dataSource"
|
||||
| "postInstallAction"
|
||||
>) => {
|
||||
console.log("\nInitializing Python project with template:", template, "\n");
|
||||
@@ -171,16 +175,30 @@ export const installPythonTemplate = async ({
|
||||
"python",
|
||||
vectorDb || "none",
|
||||
);
|
||||
const enginePath = path.join(root, "app", "engine");
|
||||
|
||||
await copy("**", path.join(root, "app", "engine"), {
|
||||
parents: true,
|
||||
cwd: VectorDBPath,
|
||||
});
|
||||
if (dataSource?.type !== "none" && dataSource?.type !== undefined) {
|
||||
const loaderPath = path.join(
|
||||
compPath,
|
||||
"loaders",
|
||||
"python",
|
||||
dataSource.type,
|
||||
);
|
||||
await copy("**", enginePath, {
|
||||
parents: true,
|
||||
cwd: loaderPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const addOnDependencies = getAdditionalDependencies(vectorDb);
|
||||
await addDependencies(root, addOnDependencies);
|
||||
|
||||
if (postInstallAction !== "none") {
|
||||
installPythonDependencies(root);
|
||||
installPythonDependencies();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,3 +61,11 @@ export async function getRepoRootFolders(
|
||||
const folders = data.filter((item) => item.type === "dir");
|
||||
return folders.map((item) => item.name);
|
||||
}
|
||||
|
||||
export async function getRepoRawContent(repoFilePath: string) {
|
||||
const url = `https://raw.githubusercontent.com/${repoFilePath}`;
|
||||
const response = await got(url, {
|
||||
responseType: "text",
|
||||
});
|
||||
return response.body;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
import { PackageManager } from "../helpers/get-pkg-manager";
|
||||
|
||||
export type TemplateType = "simple" | "streaming" | "community";
|
||||
export type TemplateType = "simple" | "streaming" | "community" | "llamapack";
|
||||
export type TemplateFramework = "nextjs" | "express" | "fastapi";
|
||||
export type TemplateEngine = "simple" | "context";
|
||||
export type TemplateUI = "html" | "shadcn";
|
||||
export type TemplateVectorDB = "none" | "mongo" | "pg";
|
||||
export type TemplatePostInstallAction = "none" | "dependencies" | "runApp";
|
||||
export type TemplateDataSource = {
|
||||
type: "none" | "file" | "web";
|
||||
config: TemplateDataSourceConfig;
|
||||
};
|
||||
export type FileSourceConfig = {
|
||||
contextFile?: string;
|
||||
};
|
||||
export type WebSourceConfig = {
|
||||
baseUrl?: string;
|
||||
depth?: number;
|
||||
};
|
||||
export type TemplateDataSourceConfig = FileSourceConfig | WebSourceConfig;
|
||||
|
||||
export interface InstallTemplateArgs {
|
||||
appName: string;
|
||||
@@ -15,14 +27,15 @@ export interface InstallTemplateArgs {
|
||||
template: TemplateType;
|
||||
framework: TemplateFramework;
|
||||
engine: TemplateEngine;
|
||||
contextFile?: string;
|
||||
ui: TemplateUI;
|
||||
dataSource?: TemplateDataSource;
|
||||
eslint: boolean;
|
||||
customApiPath?: string;
|
||||
openAiKey?: string;
|
||||
forBackend?: string;
|
||||
model: string;
|
||||
communityProjectPath?: string;
|
||||
llamapack?: string;
|
||||
vectorDb?: TemplateVectorDB;
|
||||
externalPort?: number;
|
||||
postInstallAction?: TemplatePostInstallAction;
|
||||
|
||||
@@ -237,10 +237,11 @@ async function run(): Promise<void> {
|
||||
openAiKey: program.openAiKey,
|
||||
model: program.model,
|
||||
communityProjectPath: program.communityProjectPath,
|
||||
llamapack: program.llamapack,
|
||||
vectorDb: program.vectorDb,
|
||||
externalPort: program.externalPort,
|
||||
postInstallAction: program.postInstallAction,
|
||||
contextFile: program.contextFile,
|
||||
dataSource: program.dataSource,
|
||||
});
|
||||
conf.set("preferences", preferences);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-llama",
|
||||
"version": "0.0.18",
|
||||
"version": "0.0.20",
|
||||
"keywords": [
|
||||
"rag",
|
||||
"llamaindex",
|
||||
@@ -29,11 +29,11 @@
|
||||
"prepublishOnly": "cd ../../ && pnpm run build:release"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.40.0",
|
||||
"@playwright/test": "^1.41.1",
|
||||
"@types/async-retry": "1.4.2",
|
||||
"@types/ci-info": "2.0.0",
|
||||
"@types/cross-spawn": "6.0.0",
|
||||
"@types/node": "^20.9.0",
|
||||
"@types/node": "^20.11.7",
|
||||
"@types/prompts": "2.0.1",
|
||||
"@types/tar": "6.1.5",
|
||||
"@types/validate-npm-package-name": "3.0.0",
|
||||
@@ -49,7 +49,7 @@
|
||||
"picocolors": "1.0.0",
|
||||
"prompts": "2.1.0",
|
||||
"rimraf": "^5.0.5",
|
||||
"smol-toml": "^1.1.3",
|
||||
"smol-toml": "^1.1.4",
|
||||
"tar": "6.1.15",
|
||||
"terminal-link": "^3.0.0",
|
||||
"update-check": "1.5.4",
|
||||
|
||||
@@ -7,6 +7,7 @@ import prompts from "prompts";
|
||||
import { InstallAppArgs } from "./create-app";
|
||||
import { TemplateFramework } from "./helpers";
|
||||
import { COMMUNITY_OWNER, COMMUNITY_REPO } from "./helpers/constant";
|
||||
import { getAvailableLlamapackOptions } from "./helpers/llama-pack";
|
||||
import { getRepoRootFolders } from "./helpers/repo";
|
||||
|
||||
export type QuestionArgs = Omit<InstallAppArgs, "appPath" | "packageManager">;
|
||||
@@ -37,7 +38,12 @@ const defaults: QuestionArgs = {
|
||||
openAiKey: "",
|
||||
model: "gpt-3.5-turbo",
|
||||
communityProjectPath: "",
|
||||
llamapack: "",
|
||||
postInstallAction: "dependencies",
|
||||
dataSource: {
|
||||
type: "none",
|
||||
config: {},
|
||||
},
|
||||
};
|
||||
|
||||
const handlers = {
|
||||
@@ -129,6 +135,48 @@ export const askQuestions = async (
|
||||
field: K,
|
||||
): QuestionArgs[K] => preferences[field] ?? defaults[field];
|
||||
|
||||
// Ask for next action after installation
|
||||
async function askPostInstallAction() {
|
||||
if (program.postInstallAction === undefined) {
|
||||
if (ciInfo.isCI) {
|
||||
program.postInstallAction = getPrefOrDefault("postInstallAction");
|
||||
} else {
|
||||
let actionChoices = [
|
||||
{
|
||||
title: "Just generate code (~1 sec)",
|
||||
value: "none",
|
||||
},
|
||||
{
|
||||
title: "Generate code and install dependencies (~2 min)",
|
||||
value: "dependencies",
|
||||
},
|
||||
];
|
||||
|
||||
const hasOpenAiKey = program.openAiKey || process.env["OPENAI_API_KEY"];
|
||||
if (program.vectorDb === "none" && hasOpenAiKey) {
|
||||
actionChoices.push({
|
||||
title:
|
||||
"Generate code, install dependencies, and run the app (~2 min)",
|
||||
value: "runApp",
|
||||
});
|
||||
}
|
||||
|
||||
const { action } = await prompts(
|
||||
{
|
||||
type: "select",
|
||||
name: "action",
|
||||
message: "How would you like to proceed?",
|
||||
choices: actionChoices,
|
||||
initial: 1,
|
||||
},
|
||||
handlers,
|
||||
);
|
||||
|
||||
program.postInstallAction = action;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!program.template) {
|
||||
if (ciInfo.isCI) {
|
||||
program.template = getPrefOrDefault("template");
|
||||
@@ -148,6 +196,10 @@ export const askQuestions = async (
|
||||
title: `Community template from ${styledRepo}`,
|
||||
value: "community",
|
||||
},
|
||||
{
|
||||
title: "Example using a LlamaPack",
|
||||
value: "llamapack",
|
||||
},
|
||||
],
|
||||
initial: 1,
|
||||
},
|
||||
@@ -181,6 +233,27 @@ export const askQuestions = async (
|
||||
return; // early return - no further questions needed for community projects
|
||||
}
|
||||
|
||||
if (program.template === "llamapack") {
|
||||
const availableLlamaPacks = await getAvailableLlamapackOptions();
|
||||
const { llamapack } = await prompts(
|
||||
{
|
||||
type: "select",
|
||||
name: "llamapack",
|
||||
message: "Select LlamaPack",
|
||||
choices: availableLlamaPacks.map((pack) => ({
|
||||
title: pack.name,
|
||||
value: pack.folderPath,
|
||||
})),
|
||||
initial: 0,
|
||||
},
|
||||
handlers,
|
||||
);
|
||||
program.llamapack = llamapack;
|
||||
preferences.llamapack = llamapack;
|
||||
await askPostInstallAction();
|
||||
return; // early return - no further questions needed for llamapack projects
|
||||
}
|
||||
|
||||
if (!program.framework) {
|
||||
if (ciInfo.isCI) {
|
||||
program.framework = getPrefOrDefault("framework");
|
||||
@@ -309,6 +382,9 @@ export const askQuestions = async (
|
||||
if (process.platform === "win32" || process.platform === "darwin") {
|
||||
choices.push({ title: "Use a local PDF file", value: "localFile" });
|
||||
}
|
||||
if (program.framework === "fastapi") {
|
||||
choices.push({ title: "Use website content", value: "web" });
|
||||
}
|
||||
|
||||
const { dataSource } = await prompts(
|
||||
{
|
||||
@@ -320,20 +396,47 @@ export const askQuestions = async (
|
||||
},
|
||||
handlers,
|
||||
);
|
||||
switch (dataSource) {
|
||||
case "simple":
|
||||
program.engine = "simple";
|
||||
break;
|
||||
case "exampleFile":
|
||||
program.engine = "context";
|
||||
break;
|
||||
case "localFile":
|
||||
program.engine = "context";
|
||||
// If the user selected the "pdf" option, ask them to select a file
|
||||
program.contextFile = await selectPDFFile();
|
||||
break;
|
||||
// Initialize with default config
|
||||
program.dataSource = getPrefOrDefault("dataSource");
|
||||
if (program.dataSource) {
|
||||
switch (dataSource) {
|
||||
case "simple":
|
||||
program.engine = "simple";
|
||||
break;
|
||||
case "exampleFile":
|
||||
program.engine = "context";
|
||||
break;
|
||||
case "localFile":
|
||||
program.engine = "context";
|
||||
program.dataSource.type = "file";
|
||||
// If the user selected the "pdf" option, ask them to select a file
|
||||
program.dataSource.config = {
|
||||
contextFile: await selectPDFFile(),
|
||||
};
|
||||
break;
|
||||
case "web":
|
||||
program.engine = "context";
|
||||
program.dataSource.type = "web";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (program.dataSource?.type === "web" && program.framework === "fastapi") {
|
||||
const { baseUrl } = await prompts(
|
||||
{
|
||||
type: "text",
|
||||
name: "baseUrl",
|
||||
message: "Please provide base URL of the website:",
|
||||
initial: "https://ts.llamaindex.ai/modules/",
|
||||
},
|
||||
handlers,
|
||||
);
|
||||
program.dataSource.config = {
|
||||
baseUrl: baseUrl,
|
||||
depth: 2,
|
||||
};
|
||||
}
|
||||
if (program.engine !== "simple" && !program.vectorDb) {
|
||||
if (ciInfo.isCI) {
|
||||
program.vectorDb = getPrefOrDefault("vectorDb");
|
||||
@@ -386,45 +489,7 @@ export const askQuestions = async (
|
||||
}
|
||||
}
|
||||
|
||||
// Ask for next action after installation
|
||||
if (program.postInstallAction === undefined) {
|
||||
if (ciInfo.isCI) {
|
||||
program.postInstallAction = getPrefOrDefault("postInstallAction");
|
||||
} else {
|
||||
let actionChoices = [
|
||||
{
|
||||
title: "Just generate code (~1 sec)",
|
||||
value: "none",
|
||||
},
|
||||
{
|
||||
title: "Generate code and install dependencies (~2 min)",
|
||||
value: "dependencies",
|
||||
},
|
||||
];
|
||||
|
||||
const hasOpenAiKey = program.openAiKey || process.env["OPENAI_API_KEY"];
|
||||
if (program.vectorDb === "none" && hasOpenAiKey) {
|
||||
actionChoices.push({
|
||||
title:
|
||||
"Generate code, install dependencies, and run the app (~2 min)",
|
||||
value: "runApp",
|
||||
});
|
||||
}
|
||||
|
||||
const { action } = await prompts(
|
||||
{
|
||||
type: "select",
|
||||
name: "action",
|
||||
message: "How would you like to proceed?",
|
||||
choices: actionChoices,
|
||||
initial: 1,
|
||||
},
|
||||
handlers,
|
||||
);
|
||||
|
||||
program.postInstallAction = action;
|
||||
}
|
||||
}
|
||||
await askPostInstallAction();
|
||||
|
||||
// TODO: consider using zod to validate the input (doesn't work like this as not every option is required)
|
||||
// templateUISchema.parse(program.ui);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import os
|
||||
from app.engine.constants import DATA_DIR
|
||||
from llama_index import VectorStoreIndex, download_loader
|
||||
from llama_index import SimpleDirectoryReader
|
||||
|
||||
|
||||
def get_documents():
|
||||
return SimpleDirectoryReader(DATA_DIR).load_data()
|
||||
@@ -0,0 +1,15 @@
|
||||
import os
|
||||
from llama_index import VectorStoreIndex, download_loader
|
||||
|
||||
|
||||
def get_documents():
|
||||
WholeSiteReader = download_loader("WholeSiteReader")
|
||||
|
||||
# Initialize the scraper with a prefix URL and maximum depth
|
||||
scraper = WholeSiteReader(
|
||||
prefix=os.environ.get("URL_PREFIX"), max_depth=int(os.environ.get("MAX_DEPTH"))
|
||||
)
|
||||
# Start scraping from a base URL
|
||||
documents = scraper.load_data(base_url=os.environ.get("BASE_URL"))
|
||||
|
||||
return documents
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
---
|
||||
|
||||
## Quickstart
|
||||
|
||||
1. Check above instructions for setting up your environment and export required environment variables
|
||||
For example, if you are using bash, you can run the following command to set up OpenAI API key
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=your_api_key
|
||||
```
|
||||
|
||||
2. Run the example
|
||||
|
||||
```
|
||||
poetry run python example.py
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
[tool.poetry]
|
||||
name = "app"
|
||||
version = "0.1.0"
|
||||
description = "Llama Pack Example"
|
||||
authors = ["Marcus Schiesser <mail@marcusschiesser.de>"]
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.11,<3.12"
|
||||
llama-index = "^0.9.19"
|
||||
python-dotenv = "^1.0.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -7,6 +7,7 @@ from llama_index.vector_stores import MongoDBAtlasVectorSearch
|
||||
|
||||
from app.engine.constants import DATA_DIR
|
||||
from app.engine.context import create_service_context
|
||||
from app.engine.loader import get_documents
|
||||
|
||||
|
||||
from llama_index import (
|
||||
@@ -22,7 +23,7 @@ logger = logging.getLogger()
|
||||
def generate_datasource(service_context):
|
||||
logger.info("Creating new index")
|
||||
# load the documents and create the index
|
||||
documents = SimpleDirectoryReader(DATA_DIR).load_data()
|
||||
documents = get_documents()
|
||||
store = MongoDBAtlasVectorSearch(
|
||||
db_name=os.environ["MONGODB_DATABASE"],
|
||||
collection_name=os.environ["MONGODB_VECTORS"],
|
||||
|
||||
@@ -4,6 +4,7 @@ from dotenv import load_dotenv
|
||||
|
||||
from app.engine.constants import DATA_DIR, STORAGE_DIR
|
||||
from app.engine.context import create_service_context
|
||||
from app.engine.loader import get_documents
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -19,7 +20,7 @@ logger = logging.getLogger()
|
||||
def generate_datasource(service_context):
|
||||
logger.info("Creating new index")
|
||||
# load the documents and create the index
|
||||
documents = SimpleDirectoryReader(DATA_DIR).load_data()
|
||||
documents = get_documents()
|
||||
index = VectorStoreIndex.from_documents(documents, service_context=service_context)
|
||||
# store it for later
|
||||
index.storage_context.persist(STORAGE_DIR)
|
||||
|
||||
@@ -6,6 +6,7 @@ import logging
|
||||
from app.engine.constants import DATA_DIR
|
||||
from app.engine.context import create_service_context
|
||||
from app.engine.utils import init_pg_vector_store_from_env
|
||||
from app.engine.loader import get_documents
|
||||
|
||||
from llama_index import (
|
||||
SimpleDirectoryReader,
|
||||
@@ -20,7 +21,7 @@ logger = logging.getLogger()
|
||||
def generate_datasource(service_context):
|
||||
logger.info("Creating new index")
|
||||
# load the documents and create the index
|
||||
documents = SimpleDirectoryReader(DATA_DIR).load_data()
|
||||
documents = get_documents()
|
||||
store = init_pg_vector_store_from_env()
|
||||
storage_context = StorageContext.from_defaults(vector_store=store)
|
||||
VectorStoreIndex.from_documents(
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# local env files
|
||||
.env
|
||||
node_modules/
|
||||
@@ -1,2 +1,3 @@
|
||||
# local env files
|
||||
.env
|
||||
node_modules/
|
||||
@@ -5,15 +5,15 @@
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eslint-config-next": "^13.4.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-turbo": "^1.9.3",
|
||||
"eslint-config-next": "^13.5.6",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-config-turbo": "^1.11.3",
|
||||
"eslint-plugin-react": "7.28.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"devDependencies": {
|
||||
"next": "^13.4.10"
|
||||
"next": "^13.5.6"
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1970
-1887
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user