Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cc1ee1deaa | ||
|
|
29bd038579 | ||
|
|
f6c4f86986 | ||
|
|
68183e9dce | ||
|
|
78ec91a3a9 | ||
|
|
c95d458e52 | ||
|
|
191ae3ec1e | ||
|
|
ab9598d00a | ||
|
|
0f8a2e624a | ||
|
|
d77e8da3f3 | ||
|
|
a27eeb3255 | ||
|
|
413ccb83e6 | ||
|
|
797bb567c6 | ||
|
|
f2a5dc40ee | ||
|
|
3979480532 | ||
|
|
76f1993e7a | ||
|
|
d783fa2b89 | ||
|
|
bbce18caac | ||
|
|
3ce2d8a656 | ||
|
|
a5c86a2f5c | ||
|
|
d18e533adf | ||
|
|
2b881aaad0 | ||
|
|
39cc07608f | ||
|
|
9894cfcced | ||
|
|
b5d80be037 | ||
|
|
b7870fbd9b | ||
|
|
36e6d486fc | ||
|
|
2d5dc84f1a | ||
|
|
b47405e1bd | ||
|
|
8b64deab40 | ||
|
|
c8846e0e93 | ||
|
|
7641cba01d | ||
|
|
4dc1785ef1 | ||
|
|
b2286f3e34 | ||
|
|
65a20aa457 | ||
|
|
d8a7d71344 | ||
|
|
bb490df9a6 | ||
|
|
cdfd6519c8 | ||
|
|
e8a2846449 | ||
|
|
d065cbf934 | ||
|
|
413b107b9a | ||
|
|
c336292346 | ||
|
|
adf50f1e81 | ||
|
|
636bc0a99d | ||
|
|
a7a61fae1d | ||
|
|
5ec12212e4 | ||
|
|
77c90a308e |
@@ -19,14 +19,23 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install poetry
|
||||
run: pip install poetry==1.4.2
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
version: 1.4.2
|
||||
virtualenvs-create: true
|
||||
virtualenvs-in-project: true
|
||||
- name: Load cached venv
|
||||
id: cached-poetry-dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: .venv
|
||||
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
|
||||
- name: Install dependencies
|
||||
run: poetry install --all-extras
|
||||
if: steps.cached-poetry-dependencies.outputs.cache-hit != 'true'
|
||||
- name: Lint with ruff
|
||||
run: make lint
|
||||
- name: Test with pytest
|
||||
run: make test
|
||||
- name: Generate coverage report
|
||||
- name: Run tests and generate coverage report
|
||||
run: make coverage
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
@@ -34,4 +43,3 @@ jobs:
|
||||
file: coverage.xml
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
|
||||
+7
-2
@@ -76,7 +76,7 @@ docs/_build/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
*.yaml
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
@@ -165,9 +165,14 @@ cython_debug/
|
||||
|
||||
# Database
|
||||
db
|
||||
test-db
|
||||
|
||||
.vscode
|
||||
/poetry.lock
|
||||
.idea/
|
||||
|
||||
.DS_Store
|
||||
|
||||
notebooks/*.yaml
|
||||
.ipynb_checkpoints/
|
||||
|
||||
!configs/*.yaml
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
# Contributing to embedchain
|
||||
|
||||
Let us make contributing easy, collaborative and fun.
|
||||
Let us make contribution easy, collaborative and fun.
|
||||
|
||||
## Submit your Contribution through PR
|
||||
|
||||
To make a contribution, follow the following steps:
|
||||
To make a contribution, follow these steps:
|
||||
|
||||
1. Fork and clone this repository
|
||||
2. Do the changes on your fork with dedicated feature branch `feature/f1`
|
||||
@@ -35,7 +35,7 @@ poetry shell
|
||||
|
||||
### 📌 Pre-commit
|
||||
|
||||
To ensure our standards, make sure to install pre-commit before star to contribute.
|
||||
To ensure our standards, make sure to install pre-commit before starting to contribute.
|
||||
|
||||
```bash
|
||||
pre-commit install
|
||||
@@ -51,7 +51,7 @@ make lint
|
||||
|
||||
Make sure that the linter does not report any errors or warnings before submitting a pull request.
|
||||
|
||||
### Code Format with `black`
|
||||
### Code Formatting with `black`
|
||||
|
||||
We use `black` to reformat the code by running the following command:
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ lint:
|
||||
poetry run ruff .
|
||||
|
||||
test:
|
||||
poetry run pytest
|
||||
poetry run pytest $(file)
|
||||
|
||||
coverage:
|
||||
poetry run pytest --cov=$(PROJECT_NAME) --cov-report=xml
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# embedchain
|
||||
|
||||
<a href="https://runacap.com/ross-index/q3-2023/" target="_blank" rel="noopener"><img style="width: 260px; height: 56px" src="https://runacap.com/wp-content/uploads/2023/10/ROSS_badge_black_Q3_2023.svg" alt="ROSS Index - Fastest Growing Open-Source Startups in Q3 2023 | Runa Capital" width="260" height="56"/></a>
|
||||
|
||||
[](https://pypi.org/project/embedchain/)
|
||||
[](https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw)
|
||||
[](https://discord.gg/CUU9FPhRNt)
|
||||
@@ -8,7 +10,7 @@
|
||||
[](https://colab.research.google.com/drive/138lMWhENGeEu7Q1-6lNbNTHGLZXBBz_B?usp=sharing)
|
||||
[](https://codecov.io/gh/embedchain/embedchain)
|
||||
|
||||
Embedchain is a framework to easily create LLM powered bots over any dataset. If you want a javascript version, check out [embedchain-js](https://github.com/embedchain/embedchain/tree/main/embedchain-js)
|
||||
Embedchain is a Data Platform for LLMs - load, index, retrieve, and sync any unstructured data. Using embedchain, you can easily create LLM powered apps over any data. If you want a javascript version, check out [embedchain-js](https://github.com/embedchain/embedchain/tree/main/embedchain-js)
|
||||
|
||||
## Community
|
||||
|
||||
@@ -38,17 +40,23 @@ The documentation for embedchain can be found at [docs.embedchain.ai](https://do
|
||||
|
||||
Embedchain empowers you to create ChatGPT like apps, on your own dynamic dataset.
|
||||
|
||||
### Data Types Supported
|
||||
### Data types supported
|
||||
|
||||
* Youtube video
|
||||
* PDF file
|
||||
* CSV file
|
||||
* Web page
|
||||
* MDX file
|
||||
* XML file
|
||||
* Sitemap
|
||||
* Doc file
|
||||
* Code documentation website loader
|
||||
* Notion and many more.
|
||||
* Notion
|
||||
* JSON file
|
||||
* OpenAPI specs
|
||||
* Code docs website
|
||||
* Unstructured file loader and many more
|
||||
|
||||
You can find the full list of data types on [our documentation](https://docs.embedchain.ai/data-sources/csv).
|
||||
You can find the full list of data types on [our documentation](https://docs.embedchain.ai/data-sources/).
|
||||
|
||||
### Queries
|
||||
|
||||
@@ -72,6 +80,34 @@ elon_bot.query("How many companies does Elon Musk run and name those?")
|
||||
# Answer: Elon Musk currently runs several companies. As of my knowledge, he is the CEO and lead designer of SpaceX, the CEO and product architect of Tesla, Inc., the CEO and founder of Neuralink, and the CEO and founder of The Boring Company. However, please note that this information may change over time, so it's always good to verify the latest updates.
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
| LLM | Google Colab | Replit |
|
||||
|--------------|---------------|----------|
|
||||
| OpenAI | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/openai.ipynb) | [](https://replit.com/@taranjeetio/openai#main.py) |
|
||||
| Anthropic | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/anthropic.ipynb) | [](https://replit.com/@taranjeetio/anthropic#main.py) |
|
||||
| Azure OpenAI | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/azure-openai.ipynb) | [](https://replit.com/@taranjeetio/azureopenai#main.py) |
|
||||
| VertexAI | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/vertex_ai.ipynb) | [](https://replit.com/@taranjeetio/vertexai#main.py) |
|
||||
| Cohere | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/cohere.ipynb) | [](https://replit.com/@taranjeetio/cohere#main.py) |
|
||||
| Hugging Face | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/hugging_face_hub.ipynb) | [](https://replit.com/@taranjeetio/huggingface#main.py) |
|
||||
| JinaChat | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/jina.ipynb) | [](https://replit.com/@taranjeetio/jina#main.py) |
|
||||
| GPT4All | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/gpt4all.ipynb) | [](https://replit.com/@taranjeetio/gpt4all#main.py) |
|
||||
| Llama2 | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/llama2.ipynb) | [](https://replit.com/@taranjeetio/llama2#main.py) |
|
||||
|
||||
| Embedding model | Google Colab | Replit |
|
||||
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| OpenAI | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/openai.ipynb) | [](https://replit.com/@taranjeetio/openai#main.py) |
|
||||
| VertexAI | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/vertex_ai.ipynb) | [](https://replit.com/@taranjeetio/vertexai#main.py) |
|
||||
| GPT4All | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/gpt4all.ipynb) | [](https://replit.com/@taranjeetio/gpt4all#main.py) |
|
||||
| Hugging Face | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/hugging_face_hub.ipynb) | [](https://replit.com/@taranjeetio/huggingface#main.py) |
|
||||
|
||||
| Vector DB | Google Colab | Replit |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| ChromaDB | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/chromadb.ipynb) | [](https://replit.com/@taranjeetio/chromadb#main.py) |
|
||||
| Elasticsearch | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/elasticsearch.ipynb) | [](https://replit.com/@taranjeetio/elasticsearchdb#main.py) |
|
||||
| Opensearch | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/opensearch.ipynb) | [](https://replit.com/@taranjeetio/opensearchdb#main.py) |
|
||||
| Pinecone | [](https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/pinecone.ipynb) | [](https://replit.com/@taranjeetio/pineconedb#main.py) |
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Please check out the issues on the repository, and feel free to open a pull request.
|
||||
@@ -94,7 +130,7 @@ If you utilize this repository, please consider citing it with:
|
||||
```
|
||||
@misc{embedchain,
|
||||
author = {Taranjeet Singh, Deshraj Yadav},
|
||||
title = {Embedchain: Framework to easily create LLM powered bots over any dataset},
|
||||
title = {Embedchain: Data platform for LLMs - load, index, retrieve, and sync any unstructured data},
|
||||
year = {2023},
|
||||
publisher = {GitHub},
|
||||
journal = {GitHub repository},
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
app:
|
||||
config:
|
||||
id: azure-openai-app
|
||||
|
||||
llm:
|
||||
provider: azure_openai
|
||||
model: gpt-35-turbo
|
||||
config:
|
||||
deployment_name: your_llm_deployment_name
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
stream: false
|
||||
|
||||
embedder:
|
||||
provider: azure_openai
|
||||
config:
|
||||
model: text-embedding-ada-002
|
||||
deployment_name: you_embedding_model_deployment_name
|
||||
@@ -25,7 +25,7 @@ llm:
|
||||
vectordb:
|
||||
provider: chroma
|
||||
config:
|
||||
collection_name: 'full-stack-app'
|
||||
collection_name: 'my-collection-name'
|
||||
dir: db
|
||||
allow_reset: true
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
llm:
|
||||
provider: gpt4all
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -9,5 +9,3 @@ llm:
|
||||
|
||||
embedder:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'all-MiniLM-L6-v2'
|
||||
|
||||
@@ -6,8 +6,8 @@ app:
|
||||
|
||||
llm:
|
||||
provider: gpt4all
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -23,5 +23,4 @@ vectordb:
|
||||
embedder:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'all-MiniLM-L6-v2'
|
||||
deployment_name: null
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
vectordb:
|
||||
provider: pinecone
|
||||
config:
|
||||
metric: cosine
|
||||
vector_dimension: 1536
|
||||
collection_name: my-pinecone-index
|
||||
@@ -0,0 +1,26 @@
|
||||
pipeline:
|
||||
config:
|
||||
name: Example pipeline
|
||||
id: pipeline-1 # Make sure that id is different every time you create a new pipeline
|
||||
|
||||
vectordb:
|
||||
provider: chroma
|
||||
config:
|
||||
collection_name: pipeline-1
|
||||
dir: db
|
||||
allow_reset: true
|
||||
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
stream: false
|
||||
|
||||
embedding_model:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'all-MiniLM-L6-v2'
|
||||
deployment_name: null
|
||||
@@ -0,0 +1,4 @@
|
||||
vectordb:
|
||||
provider: weaviate
|
||||
config:
|
||||
collection_name: my_weaviate_index
|
||||
@@ -13,8 +13,8 @@ app:
|
||||
|
||||
llm:
|
||||
provider: openai
|
||||
model: 'gpt-3.5-turbo'
|
||||
config:
|
||||
model: 'gpt-3.5-turbo'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
title: '🔍 Query configurations'
|
||||
---
|
||||
|
||||
## AppConfig
|
||||
|
||||
| option | description | type | default |
|
||||
|-----------|-----------------------|---------------------------------|------------------------|
|
||||
| log_level | log level | string | WARNING |
|
||||
| embedding_fn| embedding function | chromadb.utils.embedding_functions | \{text-embedding-ada-002\} |
|
||||
| db | vector database (experimental) | BaseVectorDB | ChromaDB |
|
||||
| collection_name | initial collection name for the database | string | embedchain_store |
|
||||
| collect_metrics | collect anonymous telemetry data to improve embedchain | boolean | true |
|
||||
|
||||
|
||||
## AddConfig
|
||||
|
||||
|option|description|type|default|
|
||||
|---|---|---|---|
|
||||
|chunker|chunker config|ChunkerConfig|Default values for chunker depends on the `data_type`. Please refer [ChunkerConfig](#chunker-config)|
|
||||
|loader|loader config|LoaderConfig|None|
|
||||
|
||||
Yes, you are passing `ChunkerConfig` to `AddConfig`, like so:
|
||||
|
||||
```python
|
||||
chunker_config = ChunkerConfig(chunk_size=100)
|
||||
add_config = AddConfig(chunker=chunker_config)
|
||||
app.add("lorem ipsum", config=add_config)
|
||||
```
|
||||
|
||||
### ChunkerConfig
|
||||
|
||||
|option|description|type|default|
|
||||
|---|---|---|---|
|
||||
|chunk_size|Maximum size of chunks to return|int|Default value for various `data_type` mentioned below|
|
||||
|chunk_overlap|Overlap in characters between chunks|int|Default value for various `data_type` mentioned below|
|
||||
|length_function|Function that measures the length of given chunks|typing.Callable|Default value for various `data_type` mentioned below|
|
||||
|
||||
Default values of chunker config parameters for different `data_type`:
|
||||
|
||||
|data_type|chunk_size|chunk_overlap|length_function|
|
||||
|---|---|---|---|
|
||||
|docx|1000|0|len|
|
||||
|text|300|0|len|
|
||||
|qna_pair|300|0|len|
|
||||
|web_page|500|0|len|
|
||||
|pdf_file|1000|0|len|
|
||||
|youtube_video|2000|0|len|
|
||||
|docs_site|500|50|len|
|
||||
|notion|300|0|len|
|
||||
|
||||
## BaseLlmConfig
|
||||
|
||||
|option|description|type|default|
|
||||
|---|---|---|---|
|
||||
|number_documents|Absolute number of documents to pull from the database as context.|int|1
|
||||
|template|custom template for prompt. If history is used with query, $history has to be included as well.|Template|Template("Use the following pieces of context to answer the query at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. \$context Query: \$query Helpful Answer:")|
|
||||
|model|name of the model used.|string|depends on app type|
|
||||
|temperature|Controls the randomness of the model's output. Higher values (closer to 1) make output more random, lower values make it more deterministic.|float|0|
|
||||
|max_tokens|Controls how many tokens are used. Exact implementation (whether it counts prompt and/or response) depends on the model.|int|1000|
|
||||
|top_p|Controls the diversity of words. Higher values (closer to 1) make word selection more diverse, lower values make words less diverse.|float|1|
|
||||
|history|include conversation history from your client or database.|any (recommendation: list[str])|None|
|
||||
|stream|control if response is streamed back to the user.|bool|False|
|
||||
|deployment_name|t.b.a.|str|None|
|
||||
|system_prompt|System prompt string. Unused if none.|str|None|
|
||||
|where|filter for context search.|dict|None|
|
||||
@@ -1,40 +0,0 @@
|
||||
---
|
||||
title: '🧪 Testing'
|
||||
---
|
||||
|
||||
## Methods for testing
|
||||
|
||||
### Dry Run
|
||||
|
||||
Before you consume valueable tokens, you should make sure that data chunks are properly created and the embedding you have done works and that it's receiving the correct document from the database.
|
||||
|
||||
- For `query` or `chat` method, you can add this to your script:
|
||||
|
||||
```python
|
||||
print(naval_chat_bot.query('Can you tell me who Naval Ravikant is?', dry_run=True))
|
||||
|
||||
'''
|
||||
Use the following pieces of context to answer the query at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
|
||||
Q: Who is Naval Ravikant?
|
||||
A: Naval Ravikant is an Indian-American entrepreneur and investor.
|
||||
Query: Can you tell me who Naval Ravikant is?
|
||||
Helpful Answer:
|
||||
'''
|
||||
```
|
||||
|
||||
_The embedding is confirmed to work as expected. It returns the right document, even if the question is asked slightly different. No prompt tokens have been consumed._
|
||||
|
||||
The dry run will still consume tokens to embed your query, but it is only **~1/15 of the prompt.**
|
||||
|
||||
|
||||
- For `add` method, you can add this to your script:
|
||||
|
||||
```python
|
||||
print(naval_chat_bot.add('https://navalmanack.s3.amazonaws.com/Eric-Jorgenson_The-Almanack-of-Naval-Ravikant_Final.pdf', dry_run=True))
|
||||
|
||||
'''
|
||||
{'chunks': ['THE ALMANACK OF NAVAL RAVIKANT', 'GETTING RICH IS NOT JUST ABOUT LUCK;', 'HAPPINESS IS NOT JUST A TRAIT WE ARE'], 'metadata': [{'source': 'C:\\Users\\Dev\\AppData\\Local\\Temp\\tmp3g5mjoiz\\tmp.pdf', 'page': 0, 'url': 'https://navalmanack.s3.amazonaws.com/Eric-Jorgenson_The-Almanack-of-Naval-Ravikant_Final.pdf', 'data_type': 'pdf_file'}, {'source': 'C:\\Users\\Dev\\AppData\\Local\\Temp\\tmp3g5mjoiz\\tmp.pdf', 'page': 2, 'url': 'https://navalmanack.s3.amazonaws.com/Eric-Jorgenson_The-Almanack-of-Naval-Ravikant_Final.pdf', 'data_type': 'pdf_file'}, {'source': 'C:\\Users\\Dev\\AppData\\Local\\Temp\\tmp3g5mjoiz\\tmp.pdf', 'page': 2, 'url': 'https://navalmanack.s3.amazonaws.com/Eric-Jorgenson_The-Almanack-of-Naval-Ravikant_Final.pdf', 'data_type': 'pdf_file'}], 'count': 7358, 'type': <DataType.PDF_FILE: 'pdf_file'>}
|
||||
|
||||
# less items to show for readability
|
||||
'''
|
||||
```
|
||||
@@ -1,118 +0,0 @@
|
||||
---
|
||||
title: '💾 Vector Database'
|
||||
---
|
||||
|
||||
We support `Chroma`, `Elasticsearch` and `OpenSearch` as vector databases.
|
||||
`Chroma` is used as a default database.
|
||||
|
||||
## Elasticsearch
|
||||
|
||||
### Minimal Example
|
||||
|
||||
In order to use `Elasticsearch` as vector database we need to use App type `CustomApp`.
|
||||
|
||||
1. Set the environment variables in a `.env` file.
|
||||
```
|
||||
OPENAI_API_KEY=sk-SECRETKEY
|
||||
ELASTICSEARCH_API_KEY=SECRETKEY==
|
||||
ELASTICSEARCH_URL=https://secret-domain.europe-west3.gcp.cloud.es.io:443
|
||||
```
|
||||
Please note that the key needs certain privileges. For testing you can just toggle off `restrict privileges` under `/app/management/security/api_keys/` in your web interface.
|
||||
|
||||
2. Load the app
|
||||
```python
|
||||
from embedchain import CustomApp
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.llm.openai import OpenAILlm
|
||||
from embedchain.vectordb.elasticsearch import ElasticsearchDB
|
||||
|
||||
es_app = CustomApp(
|
||||
llm=OpenAILlm(),
|
||||
embedder=OpenAIEmbedder(),
|
||||
db=ElasticsearchDB(),
|
||||
)
|
||||
```
|
||||
|
||||
### More custom settings
|
||||
|
||||
You can get a URL for elasticsearch in the cloud, or run it locally.
|
||||
The following example shows you how to configure embedchain to work with a locally running elasticsearch.
|
||||
|
||||
Instead of using an API key, we use http login credentials. The localhost url can be defined in .env or in the config.
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from embedchain import CustomApp
|
||||
from embedchain.config import CustomAppConfig, ElasticsearchDBConfig
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.llm.openai import OpenAILlm
|
||||
from embedchain.vectordb.elasticsearch import ElasticsearchDB
|
||||
|
||||
es_config = ElasticsearchDBConfig(
|
||||
# elasticsearch url or list of nodes url with different hosts and ports.
|
||||
es_url='https://localhost:9200',
|
||||
# pass named parameters supported by Python Elasticsearch client
|
||||
http_auth=("elastic", "secret"),
|
||||
ca_certs="~/binaries/elasticsearch-8.7.0/config/certs/http_ca.crt" # your cert path
|
||||
# verify_certs=False # Alternative, if you aren't using certs
|
||||
) # pass named parameters supported by elasticsearch-py
|
||||
|
||||
es_app = CustomApp(
|
||||
config=CustomAppConfig(log_level="INFO"),
|
||||
llm=OpenAILlm(),
|
||||
embedder=OpenAIEmbedder(),
|
||||
db=ElasticsearchDB(config=es_config),
|
||||
)
|
||||
```
|
||||
3. This should log your connection details to the console.
|
||||
4. Alternatively to a URL, you `ElasticsearchDBConfig` accepts `es_url` as a list of nodes url with different hosts and ports.
|
||||
5. Additionally we can pass named parameters supported by Python Elasticsearch client.
|
||||
|
||||
|
||||
## OpenSearch 🔍
|
||||
|
||||
To use OpenSearch as a vector database with a CustomApp, follow these simple steps:
|
||||
|
||||
1. Set the `OPENAI_API_KEY` environment variable:
|
||||
|
||||
```
|
||||
OPENAI_API_KEY=sk-xxxx
|
||||
```
|
||||
|
||||
2. Define the OpenSearch configuration in your Python code:
|
||||
|
||||
```python
|
||||
from embedchain import CustomApp
|
||||
from embedchain.config import OpenSearchDBConfig
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.llm.openai import OpenAILlm
|
||||
from embedchain.vectordb.opensearch import OpenSearchDB
|
||||
|
||||
opensearch_url = "https://localhost:9200"
|
||||
http_auth = ("username", "password")
|
||||
|
||||
db_config = OpenSearchDBConfig(
|
||||
opensearch_url=opensearch_url,
|
||||
http_auth=http_auth,
|
||||
collection_name="embedchain-app",
|
||||
use_ssl=True,
|
||||
timeout=30,
|
||||
)
|
||||
db = OpenSearchDB(config=db_config)
|
||||
```
|
||||
|
||||
2. Instantiate the app and add data:
|
||||
|
||||
```python
|
||||
app = CustomApp(llm=OpenAILlm(), embedder=OpenAIEmbedder(), db=db)
|
||||
app.add("https://en.wikipedia.org/wiki/Elon_Musk")
|
||||
app.add("https://www.forbes.com/profile/elon-musk")
|
||||
app.add("https://www.britannica.com/biography/Elon-Musk")
|
||||
```
|
||||
|
||||
3. You're all set! Start querying using the following command:
|
||||
|
||||
```python
|
||||
app.query("What is the net worth of Elon Musk?")
|
||||
```
|
||||
@@ -4,15 +4,25 @@ title: 🤝 Connect with Us
|
||||
|
||||
We believe in building a vibrant and supportive community around embedchain. There are various channels through which you can connect with us, stay updated, and contribute to the ongoing discussions:
|
||||
|
||||
|
||||
* Slack: Our Slack workspace provides a platform for more structured discussions and channels dedicated to different topics. Feel free to jump in and start contributing. [Join Slack](https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw).
|
||||
|
||||
* Discord: Join our Discord server to engage in real-time conversations with the community members and the project maintainers. It’s a great place to seek help and discuss anything related to the project. [Join Discord](https://discord.gg/CUU9FPhRNt).
|
||||
|
||||
* Twitter: Follow us on Twitter for the latest news, announcements, and highlights from our community. It’s also a quick way to reach out to us. [Follow @embedchain](https://twitter.com/embedchain).
|
||||
|
||||
* LinkedIn: Connect with us on LinkedIn to stay updated on official announcements, job openings, and professional networking opportunities within our community. [Follow Our Page](https://www.linkedin.com/company/embedchain/).
|
||||
|
||||
* Newsletter: Subscribe to our newsletter for a curated list of project updates, community contributions, and upcoming events. It’s a compact way to stay in the loop with what’s happening in our community. [Subscribe Now](https://embedchain.substack.com/).
|
||||
<CardGroup cols={3}>
|
||||
<Card title="Twitter" icon="twitter" href="https://twitter.com/embedchain">
|
||||
Follow us on Twitter
|
||||
</Card>
|
||||
<Card title="Slack" icon="slack" href="https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw" color="#4A154B">
|
||||
Join our slack community
|
||||
</Card>
|
||||
<Card title="Discord" icon="discord" href="https://discord.gg/6PzXDgEjG5" color="#7289DA">
|
||||
Join our discord community
|
||||
</Card>
|
||||
<Card title="LinkedIn" icon="linkedin" href="https://www.linkedin.com/company/embedchain/">
|
||||
Connect with us on LinkedIn
|
||||
</Card>
|
||||
<Card title="Schedule a call" icon="calendar" href="https://cal.com/taranjeetio/ec">
|
||||
Schedule a call with Embedchain founder
|
||||
</Card>
|
||||
<Card title="Newsletter" icon="message" href="https://embedchain.substack.com/">
|
||||
Subscribe to our newsletter
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
We look forward to connecting with you and seeing how we can create amazing things together!
|
||||
|
||||
@@ -8,6 +8,7 @@ Embedchain supports several embedding models from the following providers:
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="OpenAI" href="#openai"></Card>
|
||||
<Card title="Azure OpenAI" href="#azure-openai"></Card>
|
||||
<Card title="GPT4All" href="#gpt4all"></Card>
|
||||
<Card title="Hugging Face" href="#hugging-face"></Card>
|
||||
<Card title="Vertex AI" href="#vertex-ai"></Card>
|
||||
@@ -27,14 +28,14 @@ from embedchain import App
|
||||
|
||||
os.environ['OPENAI_API_KEY'] = 'xxx'
|
||||
|
||||
# load embedding model configuration from openai.yaml file
|
||||
app = App.from_config(yaml_path="openai.yaml")
|
||||
# load embedding model configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
|
||||
app.add("https://en.wikipedia.org/wiki/OpenAI")
|
||||
app.query("What is OpenAI?")
|
||||
```
|
||||
|
||||
```yaml openai.yaml
|
||||
```yaml config.yaml
|
||||
embedder:
|
||||
provider: openai
|
||||
config:
|
||||
@@ -43,6 +44,45 @@ embedder:
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Azure OpenAI
|
||||
|
||||
To use Azure OpenAI embedding model, you have to set some of the azure openai related environment variables as given in the code block below:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
import os
|
||||
from embedchain import App
|
||||
|
||||
os.environ["OPENAI_API_TYPE"] = "azure"
|
||||
os.environ["OPENAI_API_BASE"] = "https://xxx.openai.azure.com/"
|
||||
os.environ["OPENAI_API_KEY"] = "xxx"
|
||||
os.environ["OPENAI_API_VERSION"] = "xxx"
|
||||
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: azure_openai
|
||||
config:
|
||||
model: gpt-35-turbo
|
||||
deployment_name: your_llm_deployment_name
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
stream: false
|
||||
|
||||
embedder:
|
||||
provider: azure_openai
|
||||
config:
|
||||
model: text-embedding-ada-002
|
||||
deployment_name: you_embedding_model_deployment_name
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can find the list of models and deployment name on the [Azure OpenAI Platform](https://oai.azure.com/portal).
|
||||
|
||||
## GPT4ALL
|
||||
|
||||
GPT4All supports generating high quality embeddings of arbitrary length documents of text using a CPU optimized contrastively trained Sentence Transformer.
|
||||
@@ -52,15 +92,15 @@ GPT4All supports generating high quality embeddings of arbitrary length document
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load embedding model configuration from gpt4all.yaml file
|
||||
app = App.from_config(yaml_path="gpt4all.yaml")
|
||||
# load embedding model configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml gpt4all.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: gpt4all
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -68,8 +108,6 @@ llm:
|
||||
|
||||
embedder:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'all-MiniLM-L6-v2'
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
@@ -83,15 +121,15 @@ Hugging Face supports generating embeddings of arbitrary length documents of tex
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load embedding model configuration from huggingface.yaml file
|
||||
app = App.from_config(yaml_path="huggingface.yaml")
|
||||
# load embedding model configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml huggingface.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: huggingface
|
||||
model: 'google/flan-t5-xxl'
|
||||
config:
|
||||
model: 'google/flan-t5-xxl'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 0.5
|
||||
@@ -114,15 +152,15 @@ Embedchain supports Google's VertexAI embeddings model through a simple interfac
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load embedding model configuration from vertexai.yaml file
|
||||
app = App.from_config(yaml_path="vertexai.yaml")
|
||||
# load embedding model configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml vertexai.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: vertexai
|
||||
model: 'chat-bison'
|
||||
config:
|
||||
model: 'chat-bison'
|
||||
temperature: 0.5
|
||||
top_p: 0.5
|
||||
|
||||
|
||||
+87
-42
@@ -35,7 +35,7 @@ app.add("https://en.wikipedia.org/wiki/OpenAI")
|
||||
app.query("What is OpenAI?")
|
||||
```
|
||||
|
||||
If you are looking to configure the different parameters of the LLM, you can do so by loading the app using a [yaml config](https://github.com/embedchain/embedchain/blob/main/embedchain/yaml/chroma.yaml) file.
|
||||
If you are looking to configure the different parameters of the LLM, you can do so by loading the app using a [yaml config](https://github.com/embedchain/embedchain/blob/main/configs/chroma.yaml) file.
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
@@ -45,15 +45,15 @@ from embedchain import App
|
||||
|
||||
os.environ['OPENAI_API_KEY'] = 'xxx'
|
||||
|
||||
# load llm configuration from openai.yaml file
|
||||
app = App.from_config(yaml_path="openai.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml openai.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: openai
|
||||
model: 'gpt-3.5-turbo'
|
||||
config:
|
||||
model: 'gpt-3.5-turbo'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -65,7 +65,42 @@ llm:
|
||||
|
||||
## Azure OpenAI
|
||||
|
||||
_Coming soon_
|
||||
To use Azure OpenAI model, you have to set some of the azure openai related environment variables as given in the code block below:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
import os
|
||||
from embedchain import App
|
||||
|
||||
os.environ["OPENAI_API_TYPE"] = "azure"
|
||||
os.environ["OPENAI_API_BASE"] = "https://xxx.openai.azure.com/"
|
||||
os.environ["OPENAI_API_KEY"] = "xxx"
|
||||
os.environ["OPENAI_API_VERSION"] = "xxx"
|
||||
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: azure_openai
|
||||
config:
|
||||
model: gpt-35-turbo
|
||||
deployment_name: your_llm_deployment_name
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
stream: false
|
||||
|
||||
embedder:
|
||||
provider: azure_openai
|
||||
config:
|
||||
model: text-embedding-ada-002
|
||||
deployment_name: you_embedding_model_deployment_name
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
You can find the list of models and deployment name on the [Azure OpenAI Platform](https://oai.azure.com/portal).
|
||||
|
||||
## Anthropic
|
||||
|
||||
@@ -79,15 +114,15 @@ from embedchain import App
|
||||
|
||||
os.environ["ANTHROPIC_API_KEY"] = "xxx"
|
||||
|
||||
# load llm configuration from anthropic.yaml file
|
||||
app = App.from_config(yaml_path="anthropic.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml anthropic.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: anthropic
|
||||
model: 'claude-instant-1'
|
||||
config:
|
||||
model: 'claude-instant-1'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -96,15 +131,14 @@ llm:
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
<br />
|
||||
|
||||
<Tip>
|
||||
You may also have to set the `OPENAI_API_KEY` if you use the OpenAI's embedding model.
|
||||
</Tip>
|
||||
|
||||
|
||||
## Cohere
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[cohere]'
|
||||
```
|
||||
|
||||
Set the `COHERE_API_KEY` as environment variable which you can find on their [Account settings page](https://dashboard.cohere.com/api-keys).
|
||||
|
||||
Once you have the API key, you are all set to use it with Embedchain.
|
||||
@@ -117,15 +151,15 @@ from embedchain import App
|
||||
|
||||
os.environ["COHERE_API_KEY"] = "xxx"
|
||||
|
||||
# load llm configuration from cohere.yaml file
|
||||
app = App.from_config(yaml_path="cohere.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml cohere.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: cohere
|
||||
model: large
|
||||
config:
|
||||
model: large
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -135,6 +169,12 @@ llm:
|
||||
|
||||
## GPT4ALL
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[opensource]'
|
||||
```
|
||||
|
||||
GPT4all is a free-to-use, locally running, privacy-aware chatbot. No GPU or internet required. You can use this with Embedchain using the following code:
|
||||
|
||||
<CodeGroup>
|
||||
@@ -142,15 +182,15 @@ GPT4all is a free-to-use, locally running, privacy-aware chatbot. No GPU or inte
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load llm configuration from gpt4all.yaml file
|
||||
app = App.from_config(yaml_path="gpt4all.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml gpt4all.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: gpt4all
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -158,8 +198,6 @@ llm:
|
||||
|
||||
embedder:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'all-MiniLM-L6-v2'
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
@@ -177,11 +215,11 @@ import os
|
||||
from embedchain import App
|
||||
|
||||
os.environ["JINACHAT_API_KEY"] = "xxx"
|
||||
# load llm configuration from jina.yaml file
|
||||
app = App.from_config(yaml_path="jina.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml jina.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: jina
|
||||
config:
|
||||
@@ -195,6 +233,13 @@ llm:
|
||||
|
||||
## Hugging Face
|
||||
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[huggingface_hub]'
|
||||
```
|
||||
|
||||
First, set `HUGGINGFACE_ACCESS_TOKEN` in environment variable which you can obtain from [their platform](https://huggingface.co/settings/tokens).
|
||||
|
||||
Once you have the token, load the app using the config yaml file:
|
||||
@@ -207,15 +252,15 @@ from embedchain import App
|
||||
|
||||
os.environ["HUGGINGFACE_ACCESS_TOKEN"] = "xxx"
|
||||
|
||||
# load llm configuration from huggingface.yaml file
|
||||
app = App.from_config(yaml_path="huggingface.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml huggingface.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: huggingface
|
||||
model: 'google/flan-t5-xxl'
|
||||
config:
|
||||
model: 'google/flan-t5-xxl'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 0.5
|
||||
@@ -237,15 +282,15 @@ from embedchain import App
|
||||
|
||||
os.environ["REPLICATE_API_TOKEN"] = "xxx"
|
||||
|
||||
# load llm configuration from llama2.yaml file
|
||||
app = App.from_config(yaml_path="llama2.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml llama2.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: llama2
|
||||
model: 'a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5'
|
||||
config:
|
||||
model: 'a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 0.5
|
||||
@@ -262,15 +307,15 @@ Setup Google Cloud Platform application credentials by following the instruction
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load llm configuration from vertexai.yaml file
|
||||
app = App.from_config(yaml_path="vertexai.yaml")
|
||||
# load llm configuration from config.yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml vertexai.yaml
|
||||
```yaml config.yaml
|
||||
llm:
|
||||
provider: vertexai
|
||||
model: 'chat-bison'
|
||||
config:
|
||||
model: 'chat-bison'
|
||||
temperature: 0.5
|
||||
top_p: 0.5
|
||||
```
|
||||
|
||||
@@ -25,10 +25,10 @@ Utilizing a vector database alongside Embedchain is a seamless process. All you
|
||||
from embedchain import App
|
||||
|
||||
# load chroma configuration from yaml file
|
||||
app = App.from_config(yaml_path="chroma-config-1.yaml")
|
||||
app = App.from_config(yaml_path="config1.yaml")
|
||||
```
|
||||
|
||||
```yaml chroma-config-1.yaml
|
||||
```yaml config1.yaml
|
||||
vectordb:
|
||||
provider: chroma
|
||||
config:
|
||||
@@ -37,7 +37,7 @@ vectordb:
|
||||
allow_reset: true
|
||||
```
|
||||
|
||||
```yaml chroma-config-2.yaml
|
||||
```yaml config2.yaml
|
||||
vectordb:
|
||||
provider: chroma
|
||||
config:
|
||||
@@ -52,16 +52,22 @@ vectordb:
|
||||
|
||||
## Elasticsearch
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[elasticsearch]'
|
||||
```
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load elasticsearch configuration from yaml file
|
||||
app = App.from_config(yaml_path="elasticsearch.yaml")
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml elasticsearch.yaml
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: elasticsearch
|
||||
config:
|
||||
@@ -74,16 +80,22 @@ vectordb:
|
||||
|
||||
## OpenSearch
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[opensearch]'
|
||||
```
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load opensearch configuration from yaml file
|
||||
app = App.from_config(yaml_path="opensearch.yaml")
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml opensearch.yaml
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: opensearch
|
||||
config:
|
||||
@@ -101,16 +113,28 @@ vectordb:
|
||||
|
||||
## Zilliz
|
||||
|
||||
Install related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[milvus]'
|
||||
```
|
||||
|
||||
Set the Zilliz environment variables `ZILLIZ_CLOUD_URI` and `ZILLIZ_CLOUD_TOKEN` which you can find it on their [cloud platform](https://cloud.zilliz.com/).
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
import os
|
||||
from embedchain import App
|
||||
|
||||
os.environ['ZILLIZ_CLOUD_URI'] = 'https://xxx.zillizcloud.com'
|
||||
os.environ['ZILLIZ_CLOUD_TOKEN'] = 'xxx'
|
||||
|
||||
# load zilliz configuration from yaml file
|
||||
app = App.from_config(yaml_path="zilliz.yaml")
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml zilliz.yaml
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: zilliz
|
||||
config:
|
||||
@@ -129,14 +153,72 @@ _Coming soon_
|
||||
|
||||
## Pinecone
|
||||
|
||||
_Coming soon_
|
||||
Install pinecone related dependencies using the following command:
|
||||
|
||||
```bash
|
||||
pip install --upgrade 'embedchain[pinecone]'
|
||||
```
|
||||
|
||||
In order to use Pinecone as vector database, set the environment variables `PINECONE_API_KEY` and `PINECONE_ENV` which you can find on [Pinecone dashboard](https://app.pinecone.io/).
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load pinecone configuration from yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: pinecone
|
||||
config:
|
||||
metric: cosine
|
||||
vector_dimension: 1536
|
||||
collection_name: my-pinecone-index
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Qdrant
|
||||
|
||||
_Coming soon_
|
||||
In order to use Qdrant as a vector database, set the environment variables `QDRANT_URL` and `QDRANT_API_KEY` which you can find on [Qdrant Dashboard](https://cloud.qdrant.io/).
|
||||
|
||||
<CodeGroup>
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load qdrant configuration from yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: qdrant
|
||||
config:
|
||||
collection_name: my_qdrant_index
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Weaviate
|
||||
|
||||
_Coming soon_
|
||||
In order to use Weaviate as a vector database, set the environment variables `WEAVIATE_ENDPOINT` and `WEAVIATE_API_KEY` which you can find on [Weaviate dashboard](https://console.weaviate.cloud/dashboard).
|
||||
|
||||
<CodeGroup>
|
||||
```python main.py
|
||||
from embedchain import App
|
||||
|
||||
# load weaviate configuration from yaml file
|
||||
app = App.from_config(yaml_path="config.yaml")
|
||||
```
|
||||
|
||||
```yaml config.yaml
|
||||
vectordb:
|
||||
provider: weaviate
|
||||
config:
|
||||
collection_name: my_weaviate_index
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
<Snippet file="missing-vector-db-tip.mdx" />
|
||||
|
||||
@@ -35,12 +35,9 @@ embedchain is built on the following stack:
|
||||
|
||||
## Team
|
||||
|
||||
### Author
|
||||
### Authors
|
||||
|
||||
- Taranjeet Singh ([@taranjeetio](https://twitter.com/taranjeetio))
|
||||
|
||||
### Maintainer
|
||||
|
||||
- Deshraj Yadav ([@deshrajdry](https://twitter.com/taranjeetio))
|
||||
|
||||
### Citation
|
||||
@@ -49,8 +46,8 @@ If you utilize this repository, please consider citing it with:
|
||||
|
||||
```
|
||||
@misc{embedchain,
|
||||
author = {Taranjeet Singh},
|
||||
title = {Embechain: Framework to easily create LLM powered bots over any dataset},
|
||||
author = {Taranjeet Singh, Deshraj Yadav},
|
||||
title = {Embechain: Data platform for LLMs - Load, index, retrieve and sync any unstructured data},
|
||||
year = {2023},
|
||||
publisher = {GitHub},
|
||||
journal = {GitHub repository},
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: '📬 Gmail'
|
||||
---
|
||||
|
||||
To use GmailLoader you must install the extra dependencies with `pip install --upgrade embedchain[gmail]`.
|
||||
|
||||
The `source` must be a valid Gmail search query, you can refer `https://support.google.com/mail/answer/7190?hl=en` to build a query.
|
||||
|
||||
To load Gmail messages, you MUST use the data_type as `gmail`. Otherwise the source will be detected as simple `text`.
|
||||
|
||||
To use this you need to save `credentials.json` in the directory from where you will run the loader. Follow these steps to get the credentials
|
||||
|
||||
1. Go to the [Google Cloud Console](https://console.cloud.google.com/apis/credentials).
|
||||
2. Create a project if you don't have one already.
|
||||
3. Create an `OAuth Consent Screen` in the project. You may need to select the `external` option.
|
||||
4. Make sure the consent screen is published.
|
||||
5. Enable the [Gmail API](https://console.cloud.google.com/apis/api/gmail.googleapis.com)
|
||||
6. Create credentials from the `Credentials` tab.
|
||||
7. Select the type `OAuth Client ID`.
|
||||
8. Choose the application type `Web application`. As a name you can choose `embedchain` or any other name as per your use case.
|
||||
9. Add an authorized redirect URI for `http://localhost:8080/`.
|
||||
10. You can leave everything else at default, finish the creation.
|
||||
11. When you are done, a modal opens where you can download the details in `json` format.
|
||||
12. Put the `.json` file in your current directory and rename it to `credentials.json`
|
||||
|
||||
```python
|
||||
import os
|
||||
from embedchain.apps.app import App
|
||||
from embedchain.models.data_type import DataType
|
||||
app = App()
|
||||
|
||||
query = "to: me label:inbox"
|
||||
app.add(query, data_type=DataType.GMAIL)
|
||||
app.query("Summarize my email conversations")
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: '📃 JSON'
|
||||
---
|
||||
|
||||
To add any json file, use the data_type as `json`. `json` allows remote urls and conventional file paths. Headers are included for each line, so if you have an `age` column, `18` will be added as `age: 18`. Eg:
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from embedchain.apps.app import App
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "openai_api_key"
|
||||
|
||||
app = App()
|
||||
|
||||
response = app.query("What is the net worth of Elon Musk as of October 2023?")
|
||||
|
||||
print(response)
|
||||
"I'm sorry, but I don't have access to real-time information or future predictions. Therefore, I don't know the net worth of Elon Musk as of October 2023."
|
||||
|
||||
source_id = app.add("temp.json")
|
||||
|
||||
response = app.query("What is the net worth of Elon Musk as of October 2023?")
|
||||
|
||||
print(response)
|
||||
"As of October 2023, Elon Musk's net worth is $255.2 billion."
|
||||
```
|
||||
|
||||
```temp.json
|
||||
{
|
||||
"question": "What is your net worth, Elon Musk?",
|
||||
"answer": "As of October 2023, Elon Musk's net worth is $255.2 billion, making him one of the wealthiest individuals in the world."
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
title: '📓 Notion'
|
||||
---
|
||||
|
||||
To use notion you must install the extra dependencies with `pip install --upgrade embedchain[notion]`.
|
||||
To use notion you must install the extra dependencies with `pip install --upgrade embedchain[community]`.
|
||||
|
||||
To load a notion page, use the data_type as `notion`. Since it is hard to automatically detect, it is advised to specify the `data_type` when adding a notion document.
|
||||
The next argument must **end** with the `notion page id`. The id is a 32-character string. Eg:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
title: 🙌 OpenAPI
|
||||
---
|
||||
|
||||
To add any OpenAPI spec yaml file (currently the json file will be detected as JSON data type), use the data_type as 'openapi'. 'openapi' allows remote urls and conventional file paths. Headers are included for each line, so if you have an `age` column, `18` will be added as `age: 18`. Eg:
|
||||
|
||||
```python
|
||||
from embedchain.apps.app import App
|
||||
import os
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "sk-xxx"
|
||||
|
||||
app = App()
|
||||
|
||||
app.add("https://github.com/openai/openai-openapi/blob/master/openapi.yaml", data_type="openapi")
|
||||
# Or add using the local file path
|
||||
# app.add("configs/openai_openapi.yaml", data_type="openapi")
|
||||
|
||||
response = app.query("What can OpenAI API endpoint do? Can you list the things it can learn from?")
|
||||
# Answer: The OpenAI API endpoint allows users to interact with OpenAI's models and perform various tasks such as generating text, answering questions, summarizing documents, translating languages, and more. The specific capabilities and tasks that the API can learn from may vary depending on the models and features provided by OpenAI. For more detailed information, it is recommended to refer to the OpenAI API documentation at https://platform.openai.com/docs/api-reference.
|
||||
```
|
||||
|
||||
NOTE: The yaml file added to the App must have the required OpenAPI fields otherwise the adding OpenAPI spec will fail. Please refer to [OpenAPI Spec Doc](https://spec.openapis.org/oas/v3.1.0)
|
||||
@@ -6,6 +6,7 @@ Embedchain comes with built-in support for various data sources. We handle the c
|
||||
|
||||
<CardGroup cols={4}>
|
||||
<Card title="📊 csv" href="/data-sources/csv"></Card>
|
||||
<Card title="📃 JSON" href="/data-sources/json"></Card>
|
||||
<Card title="📚🌐 docs site" href="/data-sources/docs-site"></Card>
|
||||
<Card title="📄 docx" href="/data-sources/docx"></Card>
|
||||
<Card title="📝 mdx" href="/data-sources/mdx"></Card>
|
||||
@@ -16,7 +17,9 @@ Embedchain comes with built-in support for various data sources. We handle the c
|
||||
<Card title="📝 text" href="/data-sources/text"></Card>
|
||||
<Card title="🌐📄 web page" href="/data-sources/web-page"></Card>
|
||||
<Card title="🧾 xml" href="/data-sources/xml"></Card>
|
||||
<Card title="🙌 OpenAPI" href="/data-sources/openapi"></Card>
|
||||
<Card title="🎥📺 youtube video" href="/data-sources/youtube-video"></Card>
|
||||
<Card title="📬 Gmail" href="/data-sources/gmail"></Card>
|
||||
</CardGroup>
|
||||
|
||||
<br/ >
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
title: '🌍 API Server'
|
||||
---
|
||||
|
||||
The API Server based on Flask integrates the `embedchain` package, offering endpoints to add, query, and chat to engage in conversations with a chatbot using JSON requests.
|
||||
The API server example can be found [here](https://github.com/embedchain/embedchain/tree/main/examples/api_server).
|
||||
|
||||
It is a Flask based server that integrates the `embedchain` package, offering endpoints to add, query, and chat to engage in conversations with a chatbot using JSON requests.
|
||||
|
||||
### 🐳 Docker Setup
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
title: '🌐 Full Stack'
|
||||
---
|
||||
|
||||
The Full Stack app example can be found [here](https://github.com/embedchain/embedchain/tree/main/examples/full_stack).
|
||||
|
||||
This guide will help you setup the full stack app on your local machine.
|
||||
|
||||
### 🐳 Docker Setup
|
||||
|
||||
- To setup full stack app using docker, run the following command inside this folder using your terminal.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
---
|
||||
title: 🔎 Examples
|
||||
description: 'Collection of Google colab notebook and Replit links for users'
|
||||
---
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>LLM</th>
|
||||
<th>Google Colab</th>
|
||||
<th>Replit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="align-middle">OpenAI</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/openai.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/openai#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Anthropic</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/anthropic.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/anthropic#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Azure OpenAI</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/azure-openai.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/azureopenai#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">VertexAI</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/vertex_ai.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/vertexai#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Cohere</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/cohere.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/cohere#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Hugging Face</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/hugging_face_hub.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/huggingface#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">JinaChat</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/jina.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/jina#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">GPT4All</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/gpt4all.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/gpt4all#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Llama2</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/llama2.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/llama2#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Embedding model</th>
|
||||
<th>Google Colab</th>
|
||||
<th>Replit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="align-middle">OpenAI</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/openai.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/openai#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">VertexAI</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/vertex_ai.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/vertexai#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">GPT4All</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/gpt4all.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/gpt4all#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Hugging Face</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/hugging_face_hub.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/huggingface#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Vector DB</th>
|
||||
<th>Google Colab</th>
|
||||
<th>Replit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="align-middle">ChromaDB</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/chromadb.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/chromadb#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Elasticsearch</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/elasticsearch.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/elasticsearchdb#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Opensearch</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/opensearch.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/opensearchdb#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="align-middle">Pinecone</td>
|
||||
<td className="align-middle"><a target="_blank" href="https://colab.research.google.com/github/embedchain/embedchain/blob/main/notebooks/pinecone.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" noZoom alt="Open In Colab"/></a></td>
|
||||
<td className="align-middle"><a target="_blank" href="https://replit.com/@taranjeetio/pineconedb#main.py"><img src="https://replit.com/badge?caption=Try%20with%20Replit&variant=small" noZoom alt="Try with Replit Badge"/></a></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -20,8 +20,8 @@ app = App.from_config(yaml_path="gpt4.yaml")
|
||||
```yaml gpt4.yaml
|
||||
llm:
|
||||
provider: openai
|
||||
model: 'gpt-4'
|
||||
config:
|
||||
model: 'gpt-4'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -47,8 +47,8 @@ app = App.from_config(yaml_path="opensource.yaml")
|
||||
```yaml opensource.yaml
|
||||
llm:
|
||||
provider: gpt4all
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: 📚 Introduction
|
||||
description: '📝 Embedchain is a framework to easily create LLM powered apps on your data.'
|
||||
description: '📝 Embedchain is a Data Platform for LLMs - load, index, retrieve, and sync any unstructured data'
|
||||
---
|
||||
|
||||
## 🤔 What is Embedchain?
|
||||
@@ -27,9 +27,6 @@ naval_bot.add(("Who is Naval Ravikant?", "Naval Ravikant is an Indian-American e
|
||||
|
||||
naval_bot.query("What unique capacity does Naval argue humans possess when it comes to understanding explanations or concepts?")
|
||||
# Answer: Naval argues that humans possess the unique capacity to understand explanations or concepts to the maximum extent possible in this physical reality.
|
||||
|
||||
# Ask questions with specific context
|
||||
naval_bot.query("What unique capacity does Naval argue humans possess when it comes to understanding explanations or concepts?", where={'chapter': 'philosophy'})
|
||||
```
|
||||
|
||||
## 🚀 How it works?
|
||||
|
||||
@@ -3,6 +3,8 @@ title: '🚀 Quickstart'
|
||||
description: '💡 Start building LLM powered apps under 30 seconds'
|
||||
---
|
||||
|
||||
Embedchain is a Data Platform for LLMs - load, index, retrieve, and sync any unstructured data. Using embedchain, you can easily create LLM powered apps over any data.
|
||||
|
||||
Install embedchain python package:
|
||||
|
||||
```bash
|
||||
@@ -20,9 +22,11 @@ app = App()
|
||||
</Step>
|
||||
<Step title="🗃️ Add data sources">
|
||||
```python
|
||||
# Embed online resources
|
||||
# Add different data sources
|
||||
elon_bot.add("https://en.wikipedia.org/wiki/Elon_Musk")
|
||||
elon_bot.add("https://www.forbes.com/profile/elon-musk")
|
||||
# You can also add local data sources such as pdf, csv files etc.
|
||||
# elon_bot.add("/path/to/file.pdf")
|
||||
```
|
||||
</Step>
|
||||
<Step title="💬 Query or chat on your data and get answers">
|
||||
@@ -42,9 +46,11 @@ from embedchain import App
|
||||
os.environ["OPENAI_API_KEY"] = "xxx"
|
||||
elon_bot = App()
|
||||
|
||||
# Embed online resources
|
||||
# Add different data sources
|
||||
elon_bot.add("https://en.wikipedia.org/wiki/Elon_Musk")
|
||||
elon_bot.add("https://www.forbes.com/profile/elon-musk")
|
||||
# You can also add local data sources such as pdf, csv files etc.
|
||||
# elon_bot.add("/path/to/file.pdf")
|
||||
|
||||
response = elon_bot.query("What is the net worth of Elon Musk today?")
|
||||
print(response)
|
||||
|
||||
+7
-1
@@ -32,7 +32,7 @@
|
||||
"navigation": [
|
||||
{
|
||||
"group": "Get started",
|
||||
"pages": ["get-started/quickstart", "get-started/introduction", "get-started/faq"]
|
||||
"pages": ["get-started/quickstart", "get-started/introduction", "get-started/faq", "get-started/examples"]
|
||||
},
|
||||
{
|
||||
"group": "Components",
|
||||
@@ -46,6 +46,7 @@
|
||||
"group": "Supported data sources",
|
||||
"pages": [
|
||||
"data-sources/csv",
|
||||
"data-sources/json",
|
||||
"data-sources/docs-site",
|
||||
"data-sources/docx",
|
||||
"data-sources/mdx",
|
||||
@@ -55,6 +56,7 @@
|
||||
"data-sources/sitemap",
|
||||
"data-sources/text",
|
||||
"data-sources/web-page",
|
||||
"data-sources/openapi",
|
||||
"data-sources/youtube-video"
|
||||
]
|
||||
},
|
||||
@@ -69,6 +71,10 @@
|
||||
"group": "Examples",
|
||||
"pages": ["examples/full_stack", "examples/api_server", "examples/discord_bot", "examples/slack_bot", "examples/telegram_bot", "examples/whatsapp_bot", "examples/poe_bot"]
|
||||
},
|
||||
{
|
||||
"group": "Pipelines",
|
||||
"pages": ["pipelines/quickstart"]
|
||||
},
|
||||
{
|
||||
"group": "Community",
|
||||
"pages": [
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: '🚀 Pipelines'
|
||||
description: '💡 Start building LLM powered data pipelines in 1 minute'
|
||||
---
|
||||
|
||||
Embedchain lets you build data pipelines on your own data sources and deploy it in production in less than a minute. It can load, index, retrieve, and sync any unstructured data.
|
||||
|
||||
Install embedchain python package:
|
||||
|
||||
```bash
|
||||
pip install embedchain
|
||||
```
|
||||
|
||||
Creating a pipeline involves 3 steps:
|
||||
|
||||
<Steps>
|
||||
<Step title="⚙️ Import pipeline instance">
|
||||
```python
|
||||
from embedchain import Pipeline
|
||||
p = Pipeline(name="Elon Musk")
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step title="🗃️ Add data sources">
|
||||
```python
|
||||
# Add different data sources
|
||||
p.add("https://en.wikipedia.org/wiki/Elon_Musk")
|
||||
p.add("https://www.forbes.com/profile/elon-musk")
|
||||
# You can also add local data sources such as pdf, csv files etc.
|
||||
# p.add("/path/to/file.pdf")
|
||||
```
|
||||
</Step>
|
||||
<Step title="💬 Deploy your pipeline to Embedchain platform">
|
||||
```python
|
||||
p.deploy()
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
That's it. Now, head to the [Embedchain platform](https://app.embedchain.ai) and your pipeline is available there. Make sure to set the `OPENAI_API_KEY` 🔑 environment variable in the code.
|
||||
|
||||
After you deploy your pipeline to Embedchain platform, you can still add more data sources and update the pipeline multiple times.
|
||||
|
||||
Here is a Google Colab notebook for you to get started: [](https://colab.research.google.com/drive/1YVXaBO4yqlHZY4ho67GCJ6aD4CHNiScD?usp=sharing)
|
||||
@@ -3,9 +3,6 @@ import importlib.metadata
|
||||
__version__ = importlib.metadata.version(__package__ or __name__)
|
||||
|
||||
from embedchain.apps.app import App # noqa: F401
|
||||
from embedchain.apps.custom_app import CustomApp # noqa: F401
|
||||
from embedchain.apps.Llama2App import Llama2App # noqa: F401
|
||||
from embedchain.apps.open_source_app import OpenSourceApp # noqa: F401
|
||||
from embedchain.apps.person_app import (PersonApp, # noqa: F401
|
||||
PersonOpenSourceApp)
|
||||
from embedchain.client import Client # noqa: F401
|
||||
from embedchain.pipeline import Pipeline # noqa: F401
|
||||
from embedchain.vectordb.chroma import ChromaDB # noqa: F401
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from embedchain.apps.app import App
|
||||
from embedchain.config import CustomAppConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.llama2 import Llama2Llm
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class Llama2App(App):
|
||||
"""
|
||||
The EmbedChain Llama2App class.
|
||||
|
||||
Methods:
|
||||
add(source, data_type): adds the data from the given URL to the vector db.
|
||||
query(query): finds answer to the given query using vector database and LLM.
|
||||
chat(query): finds answer to the given query using vector database and LLM, with conversation history.
|
||||
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
"""
|
||||
|
||||
def __init__(self, config: CustomAppConfig = None, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
|
||||
:param config: CustomAppConfig instance to load as configuration. Optional.
|
||||
:param system_prompt: System prompt string. Optional.
|
||||
"""
|
||||
logging.warning(
|
||||
"DEPRECATION WARNING: Please use `App` instead of `Llama2App`. "
|
||||
"`Llama2App` will be removed in a future release. "
|
||||
"Please refer to https://docs.embedchain.ai/advanced/app_types#llama2app for instructions."
|
||||
)
|
||||
|
||||
super().__init__(config=config, llm=Llama2Llm(), system_prompt=system_prompt)
|
||||
@@ -1,63 +0,0 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from embedchain.apps.app import App
|
||||
from embedchain.config import CustomAppConfig
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class CustomApp(App):
|
||||
"""
|
||||
Embedchain's custom app allows for most flexibility.
|
||||
|
||||
You can craft your own mix of various LLMs, vector databases and embedding model/functions.
|
||||
|
||||
Methods:
|
||||
add(source, data_type): adds the data from the given URL to the vector db.
|
||||
query(query): finds answer to the given query using vector database and LLM.
|
||||
chat(query): finds answer to the given query using vector database and LLM, with conversation history.
|
||||
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: Optional[CustomAppConfig] = None,
|
||||
llm: BaseLlm = None,
|
||||
db: BaseVectorDB = None,
|
||||
embedder: BaseEmbedder = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initialize a new `CustomApp` instance. You have to choose a LLM, database and embedder.
|
||||
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
|
||||
:param config: Config for the app instance. This is the most basic configuration,
|
||||
that does not fall into the LLM, database or embedder category, defaults to None
|
||||
:type config: Optional[CustomAppConfig], optional
|
||||
:param llm: LLM Class instance. example: `from embedchain.llm.openai import OpenAILlm`, defaults to None
|
||||
:type llm: BaseLlm
|
||||
:param db: The database to use for storing and retrieving embeddings,
|
||||
example: `from embedchain.vectordb.chroma_db import ChromaDb`, defaults to None
|
||||
:type db: BaseVectorDB
|
||||
:param embedder: The embedder (embedding model and function) use to calculate embeddings.
|
||||
example: `from embedchain.embedder.gpt4all_embedder import GPT4AllEmbedder`, defaults to None
|
||||
:type embedder: BaseEmbedder
|
||||
:param system_prompt: System prompt that will be provided to the LLM as such, defaults to None
|
||||
:type system_prompt: Optional[str], optional
|
||||
:raises ValueError: LLM, database or embedder has not been defined.
|
||||
:raises TypeError: LLM, database or embedder is not a valid class instance.
|
||||
"""
|
||||
logging.warning(
|
||||
"DEPRECATION WARNING: Please use `App` instead of `CustomApp`. "
|
||||
"`CustomApp` will be removed in a future release. "
|
||||
"Please refer to https://docs.embedchain.ai/advanced/app_types#opensourceapp for instructions."
|
||||
)
|
||||
super().__init__(config=config, llm=llm, db=db, embedder=embedder, system_prompt=system_prompt)
|
||||
@@ -1,71 +0,0 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from embedchain.apps.app import App
|
||||
from embedchain.config import (BaseLlmConfig, ChromaDbConfig,
|
||||
OpenSourceAppConfig)
|
||||
from embedchain.embedder.gpt4all import GPT4AllEmbedder
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.gpt4all import GPT4ALLLlm
|
||||
from embedchain.vectordb.chroma import ChromaDB
|
||||
|
||||
gpt4all_model = None
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class OpenSourceApp(App):
|
||||
"""
|
||||
The embedchain Open Source App.
|
||||
Comes preconfigured with the best open source LLM, embedding model, database.
|
||||
|
||||
Methods:
|
||||
add(source, data_type): adds the data from the given URL to the vector db.
|
||||
query(query): finds answer to the given query using vector database and LLM.
|
||||
chat(query): finds answer to the given query using vector database and LLM, with conversation history.
|
||||
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: OpenSourceAppConfig = None,
|
||||
llm_config: BaseLlmConfig = None,
|
||||
chromadb_config: Optional[ChromaDbConfig] = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initialize a new `CustomApp` instance.
|
||||
Since it's opinionated you don't have to choose a LLM, database and embedder.
|
||||
However, you can configure those.
|
||||
|
||||
.. deprecated:: 0.0.64
|
||||
Use `App` instead.
|
||||
|
||||
:param config: Config for the app instance. This is the most basic configuration,
|
||||
that does not fall into the LLM, database or embedder category, defaults to None
|
||||
:type config: OpenSourceAppConfig, optional
|
||||
:param llm_config: Allows you to configure the LLM, e.g. how many documents to return.
|
||||
example: `from embedchain.config import BaseLlmConfig`, defaults to None
|
||||
:type llm_config: BaseLlmConfig, optional
|
||||
:param chromadb_config: Allows you to configure the open source database,
|
||||
example: `from embedchain.config import ChromaDbConfig`, defaults to None
|
||||
:type chromadb_config: Optional[ChromaDbConfig], optional
|
||||
:param system_prompt: System prompt that will be provided to the LLM as such.
|
||||
Please don't use for the time being, as it's not supported., defaults to None
|
||||
:type system_prompt: Optional[str], optional
|
||||
:raises TypeError: `OpenSourceAppConfig` or `BaseLlmConfig` invalid.
|
||||
"""
|
||||
logging.warning(
|
||||
"DEPRECATION WARNING: Please use `App` instead of `OpenSourceApp`."
|
||||
"`OpenSourceApp` will be removed in a future release."
|
||||
"Please refer to https://docs.embedchain.ai/advanced/app_types#customapp for instructions."
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
config=config,
|
||||
llm=GPT4ALLLlm(config=llm_config),
|
||||
db=ChromaDB(config=chromadb_config),
|
||||
embedder=GPT4AllEmbedder(),
|
||||
system_prompt=system_prompt,
|
||||
)
|
||||
@@ -1,94 +0,0 @@
|
||||
from string import Template
|
||||
|
||||
from embedchain.apps.app import App
|
||||
from embedchain.apps.open_source_app import OpenSourceApp
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.config.apps.base_app_config import BaseAppConfig
|
||||
from embedchain.config.llm.base import (DEFAULT_PROMPT,
|
||||
DEFAULT_PROMPT_WITH_HISTORY)
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class EmbedChainPersonApp:
|
||||
"""
|
||||
Base class to create a person bot.
|
||||
This bot behaves and speaks like a person.
|
||||
|
||||
:param person: name of the person, better if its a well known person.
|
||||
:param config: BaseAppConfig instance to load as configuration.
|
||||
"""
|
||||
|
||||
def __init__(self, person: str, config: BaseAppConfig = None):
|
||||
"""Initialize a new person app
|
||||
|
||||
:param person: Name of the person that's imitated.
|
||||
:type person: str
|
||||
:param config: Configuration class instance, defaults to None
|
||||
:type config: BaseAppConfig, optional
|
||||
"""
|
||||
self.person = person
|
||||
self.person_prompt = f"You are {person}. Whatever you say, you will always say in {person} style." # noqa:E501
|
||||
super().__init__(config)
|
||||
|
||||
def add_person_template_to_config(self, default_prompt: str, config: BaseLlmConfig = None):
|
||||
"""
|
||||
This method checks if the config object contains a prompt template
|
||||
if yes it adds the person prompt to it and return the updated config
|
||||
else it creates a config object with the default prompt added to the person prompt
|
||||
|
||||
:param default_prompt: it is the default prompt for query or chat methods
|
||||
:type default_prompt: str
|
||||
:param config: _description_, defaults to None
|
||||
:type config: BaseLlmConfig, optional
|
||||
:return: The `ChatConfig` instance to use as configuration options.
|
||||
:rtype: _type_
|
||||
"""
|
||||
template = Template(self.person_prompt + " " + default_prompt)
|
||||
|
||||
if config:
|
||||
if config.template:
|
||||
# Add person prompt to custom user template
|
||||
config.template = Template(self.person_prompt + " " + config.template.template)
|
||||
else:
|
||||
# If no user template is present, use person prompt with the default template
|
||||
config.template = template
|
||||
else:
|
||||
# if no config is present at all, initialize the config with person prompt and default template
|
||||
config = BaseLlmConfig(
|
||||
template=template,
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class PersonApp(EmbedChainPersonApp, App):
|
||||
"""
|
||||
The Person app.
|
||||
Extends functionality from EmbedChainPersonApp and App
|
||||
"""
|
||||
|
||||
def query(self, input_query, config: BaseLlmConfig = None, dry_run=False):
|
||||
config = self.add_person_template_to_config(DEFAULT_PROMPT, config, where=None)
|
||||
return super().query(input_query, config, dry_run, where=None)
|
||||
|
||||
def chat(self, input_query, config: BaseLlmConfig = None, dry_run=False, where=None):
|
||||
config = self.add_person_template_to_config(DEFAULT_PROMPT_WITH_HISTORY, config)
|
||||
return super().chat(input_query, config, dry_run, where)
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class PersonOpenSourceApp(EmbedChainPersonApp, OpenSourceApp):
|
||||
"""
|
||||
The Person app.
|
||||
Extends functionality from EmbedChainPersonApp and OpenSourceApp
|
||||
"""
|
||||
|
||||
def query(self, input_query, config: BaseLlmConfig = None, dry_run=False):
|
||||
config = self.add_person_template_to_config(DEFAULT_PROMPT, config)
|
||||
return super().query(input_query, config, dry_run)
|
||||
|
||||
def chat(self, input_query, config: BaseLlmConfig = None, dry_run=False):
|
||||
config = self.add_person_template_to_config(DEFAULT_PROMPT_WITH_HISTORY, config)
|
||||
return super().chat(input_query, config, dry_run)
|
||||
@@ -44,6 +44,7 @@ class BaseChunker(JSONSerializable):
|
||||
|
||||
for chunk in chunks:
|
||||
chunk_id = hashlib.sha256((chunk + url).encode()).hexdigest()
|
||||
chunk_id = f"{app_id}--{chunk_id}" if app_id is not None else chunk_id
|
||||
if idMap.get(chunk_id) is None:
|
||||
idMap[chunk_id] = True
|
||||
chunk_ids.append(chunk_id)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from typing import Optional
|
||||
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config.add_config import ChunkerConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class GmailChunker(BaseChunker):
|
||||
"""Chunker for gmail."""
|
||||
|
||||
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||
if config is None:
|
||||
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=config.chunk_size,
|
||||
chunk_overlap=config.chunk_overlap,
|
||||
length_function=config.length_function,
|
||||
)
|
||||
super().__init__(text_splitter)
|
||||
@@ -0,0 +1,22 @@
|
||||
from typing import Optional
|
||||
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config.add_config import ChunkerConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class JSONChunker(BaseChunker):
|
||||
"""Chunker for json."""
|
||||
|
||||
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||
if config is None:
|
||||
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=config.chunk_size,
|
||||
chunk_overlap=config.chunk_overlap,
|
||||
length_function=config.length_function,
|
||||
)
|
||||
super().__init__(text_splitter)
|
||||
@@ -0,0 +1,18 @@
|
||||
from typing import Optional
|
||||
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config.add_config import ChunkerConfig
|
||||
|
||||
|
||||
class OpenAPIChunker(BaseChunker):
|
||||
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||
if config is None:
|
||||
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=config.chunk_size,
|
||||
chunk_overlap=config.chunk_overlap,
|
||||
length_function=config.length_function,
|
||||
)
|
||||
super().__init__(text_splitter)
|
||||
@@ -0,0 +1,22 @@
|
||||
from typing import Optional
|
||||
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config.add_config import ChunkerConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class UnstructuredFileChunker(BaseChunker):
|
||||
"""Chunker for Unstructured file."""
|
||||
|
||||
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||
if config is None:
|
||||
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||
text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=config.chunk_size,
|
||||
chunk_overlap=config.chunk_overlap,
|
||||
length_function=config.length_function,
|
||||
)
|
||||
super().__init__(text_splitter)
|
||||
@@ -0,0 +1,102 @@
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
|
||||
import requests
|
||||
|
||||
from embedchain.embedchain import CONFIG_DIR, CONFIG_FILE
|
||||
|
||||
|
||||
class Client:
|
||||
def __init__(self, api_key=None, host="https://apiv2.embedchain.ai"):
|
||||
self.config_data = self.load_config()
|
||||
self.host = host
|
||||
|
||||
if api_key:
|
||||
if self.check(api_key):
|
||||
self.api_key = api_key
|
||||
self.save()
|
||||
else:
|
||||
raise ValueError(
|
||||
"Invalid API key provided. You can find your API key on https://app.embedchain.ai/settings/keys."
|
||||
)
|
||||
else:
|
||||
if "api_key" in self.config_data:
|
||||
self.api_key = self.config_data["api_key"]
|
||||
logging.info("API key loaded successfully!")
|
||||
else:
|
||||
raise ValueError(
|
||||
"You are not logged in. Please obtain an API key from https://app.embedchain.ai/settings/keys/"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def setup_dir(self):
|
||||
"""
|
||||
Loads the user id from the config file if it exists, otherwise generates a new
|
||||
one and saves it to the config file.
|
||||
|
||||
:return: user id
|
||||
:rtype: str
|
||||
"""
|
||||
if not os.path.exists(CONFIG_DIR):
|
||||
os.makedirs(CONFIG_DIR)
|
||||
|
||||
if os.path.exists(CONFIG_FILE):
|
||||
with open(CONFIG_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
if "user_id" in data:
|
||||
return data["user_id"]
|
||||
|
||||
u_id = str(uuid.uuid4())
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
json.dump({"user_id": u_id}, f)
|
||||
|
||||
@classmethod
|
||||
def load_config(cls):
|
||||
if not os.path.exists(CONFIG_FILE):
|
||||
cls.setup_dir()
|
||||
|
||||
with open(CONFIG_FILE, "r") as config_file:
|
||||
return json.load(config_file)
|
||||
|
||||
def save(self):
|
||||
self.config_data["api_key"] = self.api_key
|
||||
with open(CONFIG_FILE, "w") as config_file:
|
||||
json.dump(self.config_data, config_file, indent=4)
|
||||
|
||||
logging.info("API key saved successfully!")
|
||||
|
||||
def clear(self):
|
||||
if "api_key" in self.config_data:
|
||||
del self.config_data["api_key"]
|
||||
with open(CONFIG_FILE, "w") as config_file:
|
||||
json.dump(self.config_data, config_file, indent=4)
|
||||
self.api_key = None
|
||||
logging.info("API key deleted successfully!")
|
||||
else:
|
||||
logging.warning("API key not found in the configuration file.")
|
||||
|
||||
def update(self, api_key):
|
||||
if self.check(api_key):
|
||||
self.api_key = api_key
|
||||
self.save()
|
||||
logging.info("API key updated successfully!")
|
||||
else:
|
||||
logging.warning("Invalid API key provided. API key not updated.")
|
||||
|
||||
def check(self, api_key):
|
||||
validation_url = f"{self.host}/api/v1/accounts/api_keys/validate/"
|
||||
response = requests.post(validation_url, headers={"Authorization": f"Token {api_key}"})
|
||||
if response.status_code == 200:
|
||||
return True
|
||||
else:
|
||||
logging.warning(f"Response from API: {response.text}")
|
||||
logging.warning("Invalid API key. Unable to validate.")
|
||||
return False
|
||||
|
||||
def get(self):
|
||||
return self.api_key
|
||||
|
||||
def __str__(self):
|
||||
return self.api_key
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
from .add_config import AddConfig, ChunkerConfig
|
||||
from .apps.app_config import AppConfig
|
||||
from .apps.custom_app_config import CustomAppConfig
|
||||
from .apps.open_source_app_config import OpenSourceAppConfig
|
||||
from .base_config import BaseConfig
|
||||
from .embedder.base import BaseEmbedderConfig
|
||||
from .embedder.base import BaseEmbedderConfig as EmbedderConfig
|
||||
from .llm.base import BaseLlmConfig
|
||||
from .pipeline_config import PipelineConfig
|
||||
from .vectordb.chroma import ChromaDbConfig
|
||||
from .vectordb.elasticsearch import ElasticsearchDBConfig
|
||||
from .vectordb.opensearch import OpenSearchDBConfig
|
||||
|
||||
@@ -8,7 +8,7 @@ from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
class BaseAppConfig(BaseConfig, JSONSerializable):
|
||||
"""
|
||||
Parent config to initialize an instance of `App`, `OpenSourceApp` or `CustomApp`.
|
||||
Parent config to initialize an instance of `App`.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
from .base_app_config import BaseAppConfig
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class OpenSourceAppConfig(BaseAppConfig):
|
||||
"""
|
||||
Config to initialize an embedchain custom `OpenSourceApp` instance, with extra config options.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
log_level: str = "WARNING",
|
||||
id: Optional[str] = None,
|
||||
collect_metrics: Optional[bool] = None,
|
||||
model: str = "orca-mini-3b.ggmlv3.q4_0.bin",
|
||||
collection_name: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initializes a configuration class instance for an Open Source App.
|
||||
|
||||
:param log_level: Debug level ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], defaults to "WARNING"
|
||||
:type log_level: str, optional
|
||||
:param id: ID of the app. Document metadata will have this id., defaults to None
|
||||
:type id: Optional[str], optional
|
||||
:param collect_metrics: Send anonymous telemetry to improve embedchain, defaults to True
|
||||
:type collect_metrics: Optional[bool], optional
|
||||
:param model: GPT4ALL uses the model to instantiate the class.
|
||||
Unlike `App`, it has to be provided before querying, defaults to "orca-mini-3b.ggmlv3.q4_0.bin"
|
||||
:type model: str, optional
|
||||
:param collection_name: Default collection name. It's recommended to use app.db.set_collection_name() instead,
|
||||
defaults to None
|
||||
:type collection_name: Optional[str], optional
|
||||
"""
|
||||
self.model = model or "orca-mini-3b.ggmlv3.q4_0.bin"
|
||||
|
||||
super().__init__(log_level=log_level, id=id, collect_metrics=collect_metrics, collection_name=collection_name)
|
||||
+10
-18
@@ -1,17 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
from .base_app_config import BaseAppConfig
|
||||
|
||||
load_dotenv()
|
||||
from .apps.base_app_config import BaseAppConfig
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class CustomAppConfig(BaseAppConfig):
|
||||
class PipelineConfig(BaseAppConfig):
|
||||
"""
|
||||
Config to initialize an embedchain custom `App` instance, with extra config options.
|
||||
"""
|
||||
@@ -19,20 +14,16 @@ class CustomAppConfig(BaseAppConfig):
|
||||
def __init__(
|
||||
self,
|
||||
log_level: str = "WARNING",
|
||||
db: Optional[BaseVectorDB] = None,
|
||||
id: Optional[str] = None,
|
||||
collect_metrics: Optional[bool] = None,
|
||||
collection_name: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
collect_metrics: Optional[bool] = False,
|
||||
):
|
||||
"""
|
||||
Initializes a configuration class instance for an Custom App.
|
||||
Most of the configuration is done in the `CustomApp` class itself.
|
||||
Initializes a configuration class instance for an App. This is the simplest form of an embedchain app.
|
||||
Most of the configuration is done in the `App` class itself.
|
||||
|
||||
:param log_level: Debug level ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], defaults to "WARNING"
|
||||
:type log_level: str, optional
|
||||
:param db: A database class. It is recommended to set this directly in the `CustomApp` class, not this config,
|
||||
defaults to None
|
||||
:type db: Optional[BaseVectorDB], optional
|
||||
:param id: ID of the app. Document metadata will have this id., defaults to None
|
||||
:type id: Optional[str], optional
|
||||
:param collect_metrics: Send anonymous telemetry to improve embedchain, defaults to True
|
||||
@@ -41,6 +32,7 @@ class CustomAppConfig(BaseAppConfig):
|
||||
defaults to None
|
||||
:type collection_name: Optional[str], optional
|
||||
"""
|
||||
super().__init__(
|
||||
log_level=log_level, db=db, id=id, collect_metrics=collect_metrics, collection_name=collection_name
|
||||
)
|
||||
self._setup_logging(log_level)
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.collect_metrics = collect_metrics
|
||||
@@ -0,0 +1,20 @@
|
||||
from typing import Dict, Optional
|
||||
|
||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class PineconeDBConfig(BaseVectorDbConfig):
|
||||
def __init__(
|
||||
self,
|
||||
collection_name: Optional[str] = None,
|
||||
dir: Optional[str] = None,
|
||||
vector_dimension: int = 1536,
|
||||
metric: Optional[str] = "cosine",
|
||||
**extra_params: Dict[str, any],
|
||||
):
|
||||
self.metric = metric
|
||||
self.vector_dimension = vector_dimension
|
||||
self.extra_params = extra_params
|
||||
super().__init__(collection_name=collection_name, dir=dir)
|
||||
@@ -0,0 +1,44 @@
|
||||
from typing import Dict, Optional
|
||||
|
||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class QdrantDBConfig(BaseVectorDbConfig):
|
||||
"""
|
||||
Config to initialize an qdrant client.
|
||||
:param url. qdrant url or list of nodes url to be used for connection
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
collection_name: Optional[str] = None,
|
||||
dir: Optional[str] = None,
|
||||
hnsw_config: Optional[Dict[str, any]] = None,
|
||||
quantization_config: Optional[Dict[str, any]] = None,
|
||||
on_disk: Optional[bool] = None,
|
||||
**extra_params: Dict[str, any],
|
||||
):
|
||||
"""
|
||||
Initializes a configuration class instance for a qdrant client.
|
||||
|
||||
:param collection_name: Default name for the collection, defaults to None
|
||||
:type collection_name: Optional[str], optional
|
||||
:param dir: Path to the database directory, where the database is stored, defaults to None
|
||||
:type dir: Optional[str], optional
|
||||
:param hnsw_config: Params for HNSW index
|
||||
:type hnsw_config: Optional[Dict[str, any]], defaults to None
|
||||
:param quantization_config: Params for quantization, if None - quantization will be disabled
|
||||
:type quantization_config: Optional[Dict[str, any]], defaults to None
|
||||
:param on_disk: If true - point`s payload will not be stored in memory.
|
||||
It will be read from the disk every time it is requested.
|
||||
This setting saves RAM by (slightly) increasing the response time.
|
||||
Note: those payload values that are involved in filtering and are indexed - remain in RAM.
|
||||
:type on_disk: bool, optional, defaults to None
|
||||
"""
|
||||
self.hnsw_config = hnsw_config
|
||||
self.quantization_config = quantization_config
|
||||
self.on_disk = on_disk
|
||||
self.extra_params = extra_params
|
||||
super().__init__(collection_name=collection_name, dir=dir)
|
||||
@@ -0,0 +1,16 @@
|
||||
from typing import Dict, Optional
|
||||
|
||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class WeaviateDBConfig(BaseVectorDbConfig):
|
||||
def __init__(
|
||||
self,
|
||||
collection_name: Optional[str] = None,
|
||||
dir: Optional[str] = None,
|
||||
**extra_params: Dict[str, any],
|
||||
):
|
||||
self.extra_params = extra_params
|
||||
super().__init__(collection_name=collection_name, dir=dir)
|
||||
@@ -1,14 +1,18 @@
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.chunkers.docs_site import DocsSiteChunker
|
||||
from embedchain.chunkers.docx_file import DocxFileChunker
|
||||
from embedchain.chunkers.gmail import GmailChunker
|
||||
from embedchain.chunkers.images import ImagesChunker
|
||||
from embedchain.chunkers.json import JSONChunker
|
||||
from embedchain.chunkers.mdx import MdxChunker
|
||||
from embedchain.chunkers.notion import NotionChunker
|
||||
from embedchain.chunkers.openapi import OpenAPIChunker
|
||||
from embedchain.chunkers.pdf_file import PdfFileChunker
|
||||
from embedchain.chunkers.qna_pair import QnaPairChunker
|
||||
from embedchain.chunkers.sitemap import SitemapChunker
|
||||
from embedchain.chunkers.table import TableChunker
|
||||
from embedchain.chunkers.text import TextChunker
|
||||
from embedchain.chunkers.unstructured_file import UnstructuredFileChunker
|
||||
from embedchain.chunkers.web_page import WebPageChunker
|
||||
from embedchain.chunkers.xml import XmlChunker
|
||||
from embedchain.chunkers.youtube_video import YoutubeVideoChunker
|
||||
@@ -19,12 +23,16 @@ from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.loaders.csv import CsvLoader
|
||||
from embedchain.loaders.docs_site_loader import DocsSiteLoader
|
||||
from embedchain.loaders.docx_file import DocxFileLoader
|
||||
from embedchain.loaders.gmail import GmailLoader
|
||||
from embedchain.loaders.images import ImagesLoader
|
||||
from embedchain.loaders.json import JSONLoader
|
||||
from embedchain.loaders.local_qna_pair import LocalQnaPairLoader
|
||||
from embedchain.loaders.local_text import LocalTextLoader
|
||||
from embedchain.loaders.mdx import MdxLoader
|
||||
from embedchain.loaders.openapi import OpenAPILoader
|
||||
from embedchain.loaders.pdf_file import PdfFileLoader
|
||||
from embedchain.loaders.sitemap import SitemapLoader
|
||||
from embedchain.loaders.unstructured_file import UnstructuredLoader
|
||||
from embedchain.loaders.web_page import WebPageLoader
|
||||
from embedchain.loaders.xml import XmlLoader
|
||||
from embedchain.loaders.youtube_video import YoutubeVideoLoader
|
||||
@@ -75,6 +83,10 @@ class DataFormatter(JSONSerializable):
|
||||
DataType.CSV: CsvLoader,
|
||||
DataType.MDX: MdxLoader,
|
||||
DataType.IMAGES: ImagesLoader,
|
||||
DataType.UNSTRUCTURED: UnstructuredLoader,
|
||||
DataType.JSON: JSONLoader,
|
||||
DataType.OPENAPI: OpenAPILoader,
|
||||
DataType.GMAIL: GmailLoader,
|
||||
}
|
||||
lazy_loaders = {DataType.NOTION}
|
||||
if data_type in loaders:
|
||||
@@ -116,6 +128,10 @@ class DataFormatter(JSONSerializable):
|
||||
DataType.MDX: MdxChunker,
|
||||
DataType.IMAGES: ImagesChunker,
|
||||
DataType.XML: XmlChunker,
|
||||
DataType.UNSTRUCTURED: UnstructuredFileChunker,
|
||||
DataType.JSON: JSONChunker,
|
||||
DataType.OPENAPI: OpenAPIChunker,
|
||||
DataType.GMAIL: GmailChunker,
|
||||
}
|
||||
if data_type in chunker_classes:
|
||||
chunker_class: type = chunker_classes[data_type]
|
||||
|
||||
+66
-17
@@ -3,6 +3,7 @@ import importlib.metadata
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
import threading
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
@@ -32,6 +33,7 @@ ABS_PATH = os.getcwd()
|
||||
HOME_DIR = str(Path.home())
|
||||
CONFIG_DIR = os.path.join(HOME_DIR, ".embedchain")
|
||||
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")
|
||||
SQLITE_PATH = os.path.join(CONFIG_DIR, "embedchain.db")
|
||||
|
||||
|
||||
class EmbedChain(JSONSerializable):
|
||||
@@ -89,6 +91,27 @@ class EmbedChain(JSONSerializable):
|
||||
# Send anonymous telemetry
|
||||
self.s_id = self.config.id if self.config.id else str(uuid.uuid4())
|
||||
self.u_id = self._load_or_generate_user_id()
|
||||
|
||||
# Establish a connection to the SQLite database
|
||||
self.connection = sqlite3.connect(SQLITE_PATH)
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
# Create the 'data_sources' table if it doesn't exist
|
||||
self.cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS data_sources (
|
||||
pipeline_id TEXT,
|
||||
hash TEXT,
|
||||
type TEXT,
|
||||
value TEXT,
|
||||
metadata TEXT,
|
||||
is_uploaded INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (pipeline_id, hash)
|
||||
)
|
||||
"""
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
# NOTE: Uncomment the next two lines when running tests to see if any test fires a telemetry event.
|
||||
# if (self.config.collect_metrics):
|
||||
# raise ConnectionRefusedError("Collection of metrics should not be allowed.")
|
||||
@@ -163,7 +186,7 @@ class EmbedChain(JSONSerializable):
|
||||
:raises ValueError: Invalid data type
|
||||
:param dry_run: Optional. A dry run displays the chunks to ensure that the loader and chunker work as intended.
|
||||
deafaults to False
|
||||
:return: source_id, a md5-hash of the source, in hexadecimal representation.
|
||||
:return: source_hash, a md5-hash of the source, in hexadecimal representation.
|
||||
:rtype: str
|
||||
"""
|
||||
if config is None:
|
||||
@@ -192,18 +215,40 @@ class EmbedChain(JSONSerializable):
|
||||
if not data_type:
|
||||
data_type = detect_datatype(source)
|
||||
|
||||
# `source_id` is the hash of the source argument
|
||||
# `source_hash` is the md5 hash of the source argument
|
||||
hash_object = hashlib.md5(str(source).encode("utf-8"))
|
||||
source_id = hash_object.hexdigest()
|
||||
source_hash = hash_object.hexdigest()
|
||||
|
||||
# Check if the data hash already exists, if so, skip the addition
|
||||
self.cursor.execute(
|
||||
"SELECT 1 FROM data_sources WHERE hash = ? AND pipeline_id = ?", (source_hash, self.config.id)
|
||||
)
|
||||
existing_data = self.cursor.fetchone()
|
||||
|
||||
if existing_data:
|
||||
print(f"Data with hash {source_hash} already exists. Skipping addition.")
|
||||
return source_hash
|
||||
|
||||
data_formatter = DataFormatter(data_type, config)
|
||||
self.user_asks.append([source, data_type.value, metadata])
|
||||
documents, metadatas, _ids, new_chunks = self.load_and_embed(
|
||||
data_formatter.loader, data_formatter.chunker, source, metadata, source_id, dry_run
|
||||
data_formatter.loader, data_formatter.chunker, source, metadata, source_hash, dry_run
|
||||
)
|
||||
if data_type in {DataType.DOCS_SITE}:
|
||||
self.is_docs_site_instance = True
|
||||
|
||||
# Insert the data into the 'data' table
|
||||
self.cursor.execute(
|
||||
"""
|
||||
INSERT INTO data_sources (hash, pipeline_id, type, value, metadata)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
""",
|
||||
(source_hash, self.config.id, data_type.value, str(source), json.dumps(metadata)),
|
||||
)
|
||||
|
||||
# Commit the transaction
|
||||
self.connection.commit()
|
||||
|
||||
if dry_run:
|
||||
data_chunks_info = {"chunks": documents, "metadata": metadatas, "count": len(documents), "type": data_type}
|
||||
logging.debug(f"Dry run info : {data_chunks_info}")
|
||||
@@ -218,7 +263,7 @@ class EmbedChain(JSONSerializable):
|
||||
thread_telemetry = threading.Thread(target=self._send_telemetry_event, args=("add", extra_metadata))
|
||||
thread_telemetry.start()
|
||||
|
||||
return source_id
|
||||
return source_hash
|
||||
|
||||
def add_local(
|
||||
self,
|
||||
@@ -245,7 +290,7 @@ class EmbedChain(JSONSerializable):
|
||||
:param config: The `AddConfig` instance to use as configuration options., defaults to None
|
||||
:type config: Optional[AddConfig], optional
|
||||
:raises ValueError: Invalid data type
|
||||
:return: source_id, a md5-hash of the source, in hexadecimal representation.
|
||||
:return: source_hash, a md5-hash of the source, in hexadecimal representation.
|
||||
:rtype: str
|
||||
"""
|
||||
logging.warning(
|
||||
@@ -313,7 +358,7 @@ class EmbedChain(JSONSerializable):
|
||||
chunker: BaseChunker,
|
||||
src: Any,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
source_id: Optional[str] = None,
|
||||
source_hash: Optional[str] = None,
|
||||
dry_run=False,
|
||||
):
|
||||
"""
|
||||
@@ -324,7 +369,7 @@ class EmbedChain(JSONSerializable):
|
||||
:param src: The data to be handled by the loader. Can be a URL for
|
||||
remote sources or local content for local loaders.
|
||||
:param metadata: Optional. Metadata associated with the data source.
|
||||
:param source_id: Hexadecimal hash of the source.
|
||||
:param source_hash: Hexadecimal hash of the source.
|
||||
:param dry_run: Optional. A dry run returns chunks and doesn't update DB.
|
||||
:type dry_run: bool, defaults to False
|
||||
:return: (List) documents (embedded text), (List) metadata, (list) ids, (int) number of chunks
|
||||
@@ -339,7 +384,6 @@ class EmbedChain(JSONSerializable):
|
||||
metadatas = embeddings_data["metadatas"]
|
||||
ids = embeddings_data["ids"]
|
||||
new_doc_id = embeddings_data["doc_id"]
|
||||
|
||||
if existing_doc_id and existing_doc_id == new_doc_id:
|
||||
print("Doc content has not changed. Skipping creating chunks and embeddings")
|
||||
return [], [], [], 0
|
||||
@@ -351,12 +395,15 @@ class EmbedChain(JSONSerializable):
|
||||
|
||||
# get existing ids, and discard doc if any common id exist.
|
||||
where = {"url": src}
|
||||
# if data type is qna_pair, we check for question
|
||||
if chunker.data_type == DataType.QNA_PAIR:
|
||||
where = {"question": src[0]}
|
||||
|
||||
if self.config.id is not None:
|
||||
where["app_id"] = self.config.id
|
||||
|
||||
db_result = self.db.get(ids=ids, where=where) # optional filter
|
||||
existing_ids = set(db_result["ids"])
|
||||
|
||||
if len(existing_ids):
|
||||
data_dict = {id: (doc, meta) for id, doc, meta in zip(ids, documents, metadatas)}
|
||||
data_dict = {id: value for id, value in data_dict.items() if id not in existing_ids}
|
||||
@@ -380,7 +427,7 @@ class EmbedChain(JSONSerializable):
|
||||
m["app_id"] = self.config.id
|
||||
|
||||
# Add hashed source
|
||||
m["hash"] = source_id
|
||||
m["hash"] = source_hash
|
||||
|
||||
# Note: Metadata is the function argument
|
||||
if metadata:
|
||||
@@ -404,6 +451,7 @@ class EmbedChain(JSONSerializable):
|
||||
skip_embedding=(chunker.data_type == DataType.IMAGES),
|
||||
)
|
||||
count_new_chunks = self.db.count() - chunks_before_addition
|
||||
|
||||
print((f"Successfully saved {src} ({chunker.data_type}). New chunks count: {count_new_chunks}"))
|
||||
return list(documents), metadatas, ids, count_new_chunks
|
||||
|
||||
@@ -432,7 +480,6 @@ class EmbedChain(JSONSerializable):
|
||||
:rtype: List[str]
|
||||
"""
|
||||
query_config = config or self.llm.config
|
||||
|
||||
if where is not None:
|
||||
where = where
|
||||
elif query_config is not None and query_config.where is not None:
|
||||
@@ -453,14 +500,17 @@ class EmbedChain(JSONSerializable):
|
||||
|
||||
db_query = ClipProcessor.get_text_features(query=input_query)
|
||||
|
||||
contents = self.db.query(
|
||||
contexts = self.db.query(
|
||||
input_query=db_query,
|
||||
n_results=query_config.number_documents,
|
||||
where=where,
|
||||
skip_embedding=(hasattr(config, "query_type") and config.query_type == "Images"),
|
||||
)
|
||||
|
||||
return contents
|
||||
if len(contexts) > 0 and isinstance(contexts[0], tuple):
|
||||
contexts = list(map(lambda x: x[0], contexts))
|
||||
|
||||
return contexts
|
||||
|
||||
def query(self, input_query: str, config: BaseLlmConfig = None, dry_run=False, where: Optional[Dict] = None) -> str:
|
||||
"""
|
||||
@@ -557,15 +607,14 @@ class EmbedChain(JSONSerializable):
|
||||
"""
|
||||
Resets the database. Deletes all embeddings irreversibly.
|
||||
`App` does not have to be reinitialized after using this method.
|
||||
|
||||
DEPRECATED IN FAVOR OF `db.reset()`
|
||||
"""
|
||||
# Send anonymous telemetry
|
||||
thread_telemetry = threading.Thread(target=self._send_telemetry_event, args=("reset",))
|
||||
thread_telemetry.start()
|
||||
|
||||
logging.warning("DEPRECATION WARNING: Please use `app.db.reset()` instead of `App.reset()`.")
|
||||
self.db.reset()
|
||||
self.cursor.execute("DELETE FROM data_sources WHERE pipeline_id = ?", (self.config.id,))
|
||||
self.connection.commit()
|
||||
|
||||
@retry(stop=stop_after_attempt(3), wait=wait_fixed(1))
|
||||
def _send_telemetry_event(self, method: str, extra_metadata: Optional[dict] = None):
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from chromadb.utils import embedding_functions
|
||||
|
||||
from embedchain.config import BaseEmbedderConfig
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.models import VectorDimensions
|
||||
@@ -9,12 +7,13 @@ from embedchain.models import VectorDimensions
|
||||
|
||||
class GPT4AllEmbedder(BaseEmbedder):
|
||||
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
||||
# Note: We could use langchains GPT4ALL embedding, but it's not available in all versions.
|
||||
super().__init__(config=config)
|
||||
if self.config.model is None:
|
||||
self.config.model = "all-MiniLM-L6-v2"
|
||||
|
||||
embedding_fn = embedding_functions.SentenceTransformerEmbeddingFunction(model_name=self.config.model)
|
||||
from langchain.embeddings import \
|
||||
GPT4AllEmbeddings as LangchainGPT4AllEmbeddings
|
||||
|
||||
embeddings = LangchainGPT4AllEmbeddings()
|
||||
embedding_fn = BaseEmbedder._langchain_default_concept(embeddings)
|
||||
self.set_embedding_fn(embedding_fn=embedding_fn)
|
||||
|
||||
vector_dimension = VectorDimensions.GPT4ALL.value
|
||||
|
||||
+12
-1
@@ -41,13 +41,16 @@ class LlmFactory:
|
||||
|
||||
class EmbedderFactory:
|
||||
provider_to_class = {
|
||||
"azure_openai": "embedchain.embedder.openai.OpenAIEmbedder",
|
||||
"gpt4all": "embedchain.embedder.gpt4all.GPT4AllEmbedder",
|
||||
"huggingface": "embedchain.embedder.huggingface.HuggingFaceEmbedder",
|
||||
"vertexai": "embedchain.embedder.vertexai.VertexAIEmbedder",
|
||||
"openai": "embedchain.embedder.openai.OpenAIEmbedder",
|
||||
"vertexai": "embedchain.embedder.vertexai.VertexAIEmbedder",
|
||||
}
|
||||
provider_to_config_class = {
|
||||
"azure_openai": "embedchain.config.embedder.base.BaseEmbedderConfig",
|
||||
"openai": "embedchain.config.embedder.base.BaseEmbedderConfig",
|
||||
"gpt4all": "embedchain.config.embedder.base.BaseEmbedderConfig",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
@@ -69,11 +72,19 @@ class VectorDBFactory:
|
||||
"chroma": "embedchain.vectordb.chroma.ChromaDB",
|
||||
"elasticsearch": "embedchain.vectordb.elasticsearch.ElasticsearchDB",
|
||||
"opensearch": "embedchain.vectordb.opensearch.OpenSearchDB",
|
||||
"pinecone": "embedchain.vectordb.pinecone.PineconeDB",
|
||||
"qdrant": "embedchain.vectordb.qdrant.QdrantDB",
|
||||
"weaviate": "embedchain.vectordb.weaviate.WeaviateDB",
|
||||
"zilliz": "embedchain.vectordb.zilliz.ZillizVectorDB",
|
||||
}
|
||||
provider_to_config_class = {
|
||||
"chroma": "embedchain.config.vectordb.chroma.ChromaDbConfig",
|
||||
"elasticsearch": "embedchain.config.vectordb.elasticsearch.ElasticsearchDBConfig",
|
||||
"opensearch": "embedchain.config.vectordb.opensearch.OpenSearchDBConfig",
|
||||
"pinecone": "embedchain.config.vectordb.pinecone.PineconeDBConfig",
|
||||
"qdrant": "embedchain.config.vectordb.qdrant.QdrantDBConfig",
|
||||
"weaviate": "embedchain.config.vectordb.weaviate.WeaviateDBConfig",
|
||||
"zilliz": "embedchain.config.vectordb.zilliz.ZillizDBConfig",
|
||||
}
|
||||
|
||||
@classmethod
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
@@ -9,6 +10,8 @@ from embedchain.llm.base import BaseLlm
|
||||
@register_deserializable
|
||||
class AnthropicLlm(BaseLlm):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
if "ANTHROPIC_API_KEY" not in os.environ:
|
||||
raise ValueError("Please set the ANTHROPIC_API_KEY environment variable.")
|
||||
super().__init__(config=config)
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
@@ -18,7 +21,9 @@ class AnthropicLlm(BaseLlm):
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
from langchain.chat_models import ChatAnthropic
|
||||
|
||||
chat = ChatAnthropic(temperature=config.temperature, model=config.model)
|
||||
chat = ChatAnthropic(
|
||||
anthropic_api_key=os.environ["ANTHROPIC_API_KEY"], temperature=config.temperature, model=config.model
|
||||
)
|
||||
|
||||
if config.max_tokens and config.max_tokens != 1000:
|
||||
logging.warning("Config option `max_tokens` is not supported by this model.")
|
||||
|
||||
@@ -129,8 +129,12 @@ class BaseLlm(JSONSerializable):
|
||||
:return: Search results
|
||||
:rtype: Unknown
|
||||
"""
|
||||
from langchain.tools import DuckDuckGoSearchRun
|
||||
|
||||
try:
|
||||
from langchain.tools import DuckDuckGoSearchRun
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'Searching requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
search = DuckDuckGoSearchRun()
|
||||
logging.info(f"Access search to get answers for {input_query}")
|
||||
return search.run(input_query)
|
||||
@@ -202,7 +206,6 @@ class BaseLlm(JSONSerializable):
|
||||
k["web_search_result"] = self.access_search_and_get_results(input_query)
|
||||
prompt = self.generate_prompt(input_query, contexts, **k)
|
||||
logging.info(f"Prompt: {prompt}")
|
||||
|
||||
if dry_run:
|
||||
return prompt
|
||||
|
||||
|
||||
+22
-11
@@ -1,5 +1,8 @@
|
||||
from typing import Iterable, Optional, Union
|
||||
|
||||
from langchain.callbacks.stdout import StdOutCallbackHandler
|
||||
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.base import BaseLlm
|
||||
@@ -12,6 +15,7 @@ class GPT4ALLLlm(BaseLlm):
|
||||
if self.config.model is None:
|
||||
self.config.model = "orca-mini-3b.ggmlv3.q4_0.bin"
|
||||
self.instance = GPT4ALLLlm._get_instance(self.config.model)
|
||||
self.instance.streaming = self.config.stream
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
return self._get_answer(prompt=prompt, config=self.config)
|
||||
@@ -19,13 +23,13 @@ class GPT4ALLLlm(BaseLlm):
|
||||
@staticmethod
|
||||
def _get_instance(model):
|
||||
try:
|
||||
from gpt4all import GPT4All
|
||||
from langchain.llms.gpt4all import GPT4All as LangchainGPT4All
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError(
|
||||
"The GPT4All python package is not installed. Please install it with `pip install --upgrade embedchain[opensource]`" # noqa E501
|
||||
) from None
|
||||
|
||||
return GPT4All(model_name=model)
|
||||
return LangchainGPT4All(model=model, allow_download=True)
|
||||
|
||||
def _get_answer(self, prompt: str, config: BaseLlmConfig) -> Union[str, Iterable]:
|
||||
if config.model and config.model != self.config.model:
|
||||
@@ -33,14 +37,21 @@ class GPT4ALLLlm(BaseLlm):
|
||||
"GPT4ALLLlm does not support switching models at runtime. Please create a new app instance."
|
||||
)
|
||||
|
||||
messages = []
|
||||
if config.system_prompt:
|
||||
raise ValueError("GPT4ALLLlm does not support `system_prompt`")
|
||||
messages.append(config.system_prompt)
|
||||
messages.append(prompt)
|
||||
kwargs = {
|
||||
"temp": config.temperature,
|
||||
"max_tokens": config.max_tokens,
|
||||
}
|
||||
if config.top_p:
|
||||
kwargs["top_p"] = config.top_p
|
||||
|
||||
response = self.instance.generate(
|
||||
prompt=prompt,
|
||||
streaming=config.stream,
|
||||
top_p=config.top_p,
|
||||
max_tokens=config.max_tokens,
|
||||
temp=config.temperature,
|
||||
)
|
||||
return response
|
||||
callbacks = [StreamingStdOutCallbackHandler()] if config.stream else [StdOutCallbackHandler()]
|
||||
|
||||
response = self.instance.generate(prompts=messages, callbacks=callbacks, **kwargs)
|
||||
answer = ""
|
||||
for generations in response.generations:
|
||||
answer += " ".join(map(lambda generation: generation.text, generations))
|
||||
return answer
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import importlib
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
@@ -11,6 +12,13 @@ from embedchain.llm.base import BaseLlm
|
||||
@register_deserializable
|
||||
class Llama2Llm(BaseLlm):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
try:
|
||||
importlib.import_module("replicate")
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError(
|
||||
"The required dependencies for Llama2 are not installed."
|
||||
'Please install with `pip install --upgrade "embedchain[llama2]"`'
|
||||
) from None
|
||||
if "REPLICATE_API_TOKEN" not in os.environ:
|
||||
raise ValueError("Please set the REPLICATE_API_TOKEN environment variable.")
|
||||
|
||||
@@ -31,7 +39,7 @@ class Llama2Llm(BaseLlm):
|
||||
def get_llm_model_answer(self, prompt):
|
||||
# TODO: Move the model and other inputs into config
|
||||
if self.config.system_prompt:
|
||||
raise ValueError("Llama2App does not support `system_prompt`")
|
||||
raise ValueError("Llama2 does not support `system_prompt`")
|
||||
llm = Replicate(
|
||||
model=self.config.model,
|
||||
input={
|
||||
|
||||
@@ -13,13 +13,9 @@ class OpenAILlm(BaseLlm):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
super().__init__(config=config)
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
def get_llm_model_answer(self, prompt) -> str:
|
||||
response = OpenAILlm._get_answer(prompt, self.config)
|
||||
|
||||
if self.config.stream:
|
||||
return response
|
||||
else:
|
||||
return response.content
|
||||
return response
|
||||
|
||||
def _get_answer(prompt: str, config: BaseLlmConfig) -> str:
|
||||
messages = []
|
||||
@@ -41,4 +37,4 @@ class OpenAILlm(BaseLlm):
|
||||
chat = ChatOpenAI(**kwargs, streaming=config.stream, callbacks=[StreamingStdOutCallbackHandler()])
|
||||
else:
|
||||
chat = ChatOpenAI(**kwargs)
|
||||
return chat(messages)
|
||||
return chat(messages).content
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import importlib
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
@@ -9,6 +10,13 @@ from embedchain.llm.base import BaseLlm
|
||||
@register_deserializable
|
||||
class VertexAILlm(BaseLlm):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
try:
|
||||
importlib.import_module("vertexai")
|
||||
except ModuleNotFoundError:
|
||||
raise ModuleNotFoundError(
|
||||
"The required dependencies for VertexAI are not installed."
|
||||
'Please install with `pip install --upgrade "embedchain[vertexai]"`'
|
||||
) from None
|
||||
super().__init__(config=config)
|
||||
|
||||
def get_llm_model_answer(self, prompt):
|
||||
|
||||
@@ -3,7 +3,14 @@ import logging
|
||||
from urllib.parse import urljoin, urlparse
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
try:
|
||||
from bs4 import BeautifulSoup
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'DocsSite requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
|
||||
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import hashlib
|
||||
|
||||
from langchain.document_loaders import Docx2txtLoader
|
||||
|
||||
try:
|
||||
from langchain.document_loaders import Docx2txtLoader
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'Docx file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import quopri
|
||||
from textwrap import dedent
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
try:
|
||||
from llama_hub.gmail.base import GmailReader
|
||||
except ImportError:
|
||||
raise ImportError("Gmail requires extra dependencies. Install with `pip install embedchain[gmail]`") from None
|
||||
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.utils import clean_string
|
||||
|
||||
|
||||
def get_header(text: str, header: str) -> str:
|
||||
start_string_position = text.find(header)
|
||||
pos_start = text.find(":", start_string_position) + 1
|
||||
pos_end = text.find("\n", pos_start)
|
||||
header = text[pos_start:pos_end]
|
||||
return header.strip()
|
||||
|
||||
|
||||
class GmailLoader(BaseLoader):
|
||||
def load_data(self, query):
|
||||
"""Load data from gmail."""
|
||||
if not os.path.isfile("credentials.json"):
|
||||
raise FileNotFoundError(
|
||||
"You must download the valid credentials file from your google \
|
||||
dev account. Refer this `https://cloud.google.com/docs/authentication/api-keys`"
|
||||
)
|
||||
|
||||
loader = GmailReader(query=query, service=None, results_per_page=20)
|
||||
documents = loader.load_data()
|
||||
logging.info(f"Gmail Loader: {len(documents)} mails found for query- {query}")
|
||||
|
||||
data = []
|
||||
data_contents = []
|
||||
logging.info(f"Gmail Loader: {len(documents)} mails found")
|
||||
for document in documents:
|
||||
original_size = len(document.text)
|
||||
|
||||
snippet = document.metadata.get("snippet")
|
||||
meta_data = {
|
||||
"url": document.metadata.get("id"),
|
||||
"date": get_header(document.text, "Date"),
|
||||
"subject": get_header(document.text, "Subject"),
|
||||
"from": get_header(document.text, "From"),
|
||||
"to": get_header(document.text, "To"),
|
||||
"search_query": query,
|
||||
}
|
||||
|
||||
# Decode
|
||||
decoded_bytes = quopri.decodestring(document.text)
|
||||
decoded_str = decoded_bytes.decode("utf-8", errors="replace")
|
||||
|
||||
# Slice
|
||||
mail_start = decoded_str.find("<!DOCTYPE")
|
||||
email_data = decoded_str[mail_start:]
|
||||
|
||||
# Web Page HTML Processing
|
||||
soup = BeautifulSoup(email_data, "html.parser")
|
||||
|
||||
tags_to_exclude = [
|
||||
"nav",
|
||||
"aside",
|
||||
"form",
|
||||
"header",
|
||||
"noscript",
|
||||
"svg",
|
||||
"canvas",
|
||||
"footer",
|
||||
"script",
|
||||
"style",
|
||||
]
|
||||
|
||||
for tag in soup(tags_to_exclude):
|
||||
tag.decompose()
|
||||
|
||||
ids_to_exclude = ["sidebar", "main-navigation", "menu-main-menu"]
|
||||
for id in ids_to_exclude:
|
||||
tags = soup.find_all(id=id)
|
||||
for tag in tags:
|
||||
tag.decompose()
|
||||
|
||||
classes_to_exclude = [
|
||||
"elementor-location-header",
|
||||
"navbar-header",
|
||||
"nav",
|
||||
"header-sidebar-wrapper",
|
||||
"blog-sidebar-wrapper",
|
||||
"related-posts",
|
||||
]
|
||||
|
||||
for class_name in classes_to_exclude:
|
||||
tags = soup.find_all(class_=class_name)
|
||||
for tag in tags:
|
||||
tag.decompose()
|
||||
|
||||
content = soup.get_text()
|
||||
content = clean_string(content)
|
||||
|
||||
cleaned_size = len(content)
|
||||
if original_size != 0:
|
||||
logging.info(
|
||||
f"[{id}] Cleaned page size: {cleaned_size} characters, down from {original_size} (shrunk: {original_size-cleaned_size} chars, {round((1-(cleaned_size/original_size)) * 100, 2)}%)" # noqa:E501
|
||||
)
|
||||
|
||||
result = f"""
|
||||
email from '{meta_data.get('from')}' to '{meta_data.get('to')}'
|
||||
subject: {meta_data.get('subject')}
|
||||
date: {meta_data.get('date')}
|
||||
preview: {snippet}
|
||||
content: f{content}
|
||||
"""
|
||||
data_content = dedent(result)
|
||||
data.append({"content": data_content, "meta_data": meta_data})
|
||||
data_contents.append(data_content)
|
||||
doc_id = hashlib.sha256((query + ", ".join(data_contents)).encode()).hexdigest()
|
||||
response_data = {"doc_id": doc_id, "data": data}
|
||||
return response_data
|
||||
@@ -0,0 +1,24 @@
|
||||
import hashlib
|
||||
|
||||
from langchain.document_loaders.json_loader import \
|
||||
JSONLoader as LangchainJSONLoader
|
||||
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
langchain_json_jq_schema = 'to_entries | map("\(.key): \(.value|tostring)") | .[]'
|
||||
|
||||
|
||||
class JSONLoader(BaseLoader):
|
||||
@staticmethod
|
||||
def load_data(content):
|
||||
"""Load a json file. Each data point is a key value pair."""
|
||||
data = []
|
||||
data_content = []
|
||||
loader = LangchainJSONLoader(content, text_content=False, jq_schema=langchain_json_jq_schema)
|
||||
docs = loader.load()
|
||||
for doc in docs:
|
||||
meta_data = doc.metadata
|
||||
data.append({"content": doc.page_content, "meta_data": {"url": content, "row": meta_data["seq_num"]}})
|
||||
data_content.append(doc.page_content)
|
||||
doc_id = hashlib.sha256((content + ", ".join(data_content)).encode()).hexdigest()
|
||||
return {"doc_id": doc_id, "data": data}
|
||||
@@ -0,0 +1,42 @@
|
||||
import hashlib
|
||||
from io import StringIO
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
import yaml
|
||||
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
|
||||
class OpenAPILoader(BaseLoader):
|
||||
@staticmethod
|
||||
def _get_file_content(content):
|
||||
url = urlparse(content)
|
||||
if all([url.scheme, url.netloc]) and url.scheme not in ["file", "http", "https"]:
|
||||
raise ValueError("Not a valid URL.")
|
||||
|
||||
if url.scheme in ["http", "https"]:
|
||||
response = requests.get(content)
|
||||
response.raise_for_status()
|
||||
return StringIO(response.text)
|
||||
elif url.scheme == "file":
|
||||
path = url.path
|
||||
return open(path)
|
||||
else:
|
||||
return open(content)
|
||||
|
||||
@staticmethod
|
||||
def load_data(content):
|
||||
"""Load yaml file of openapi. Each pair is a document."""
|
||||
data = []
|
||||
file_path = content
|
||||
data_content = []
|
||||
with OpenAPILoader._get_file_content(content=content) as file:
|
||||
yaml_data = yaml.load(file, Loader=yaml.Loader)
|
||||
for i, (key, value) in enumerate(yaml_data.items()):
|
||||
string_data = f"{key}: {value}"
|
||||
meta_data = {"url": file_path, "row": i + 1}
|
||||
data.append({"content": string_data, "meta_data": meta_data})
|
||||
data_content.append(string_data)
|
||||
doc_id = hashlib.sha256((content + ", ".join(data_content)).encode()).hexdigest()
|
||||
return {"doc_id": doc_id, "data": data}
|
||||
@@ -1,7 +1,11 @@
|
||||
import hashlib
|
||||
|
||||
from langchain.document_loaders import PyPDFLoader
|
||||
|
||||
try:
|
||||
from langchain.document_loaders import PyPDFLoader
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'PDF File requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.utils import clean_string
|
||||
|
||||
@@ -2,8 +2,14 @@ import hashlib
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.builder import ParserRejectedMarkup
|
||||
|
||||
try:
|
||||
from bs4 import BeautifulSoup
|
||||
from bs4.builder import ParserRejectedMarkup
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'Sitemap requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import hashlib
|
||||
|
||||
try:
|
||||
from langchain.document_loaders import UnstructuredFileLoader
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'PDF File requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.utils import clean_string
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class UnstructuredLoader(BaseLoader):
|
||||
def load_data(self, url):
|
||||
"""Load data from a Unstructured file."""
|
||||
loader = UnstructuredFileLoader(url)
|
||||
data = []
|
||||
all_content = []
|
||||
pages = loader.load_and_split()
|
||||
if not len(pages):
|
||||
raise ValueError("No data found")
|
||||
for page in pages:
|
||||
content = page.page_content
|
||||
content = clean_string(content)
|
||||
meta_data = page.metadata
|
||||
meta_data["url"] = url
|
||||
data.append(
|
||||
{
|
||||
"content": content,
|
||||
"meta_data": meta_data,
|
||||
}
|
||||
)
|
||||
all_content.append(content)
|
||||
doc_id = hashlib.sha256((" ".join(all_content) + url).encode()).hexdigest()
|
||||
return {
|
||||
"doc_id": doc_id,
|
||||
"data": data,
|
||||
}
|
||||
@@ -2,7 +2,13 @@ import hashlib
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
try:
|
||||
from bs4 import BeautifulSoup
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'Webpage requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import hashlib
|
||||
|
||||
from langchain.document_loaders import UnstructuredXMLLoader
|
||||
|
||||
try:
|
||||
from langchain.document_loaders import UnstructuredXMLLoader
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'XML file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.utils import clean_string
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import hashlib
|
||||
|
||||
from langchain.document_loaders import YoutubeLoader
|
||||
|
||||
try:
|
||||
from langchain.document_loaders import YoutubeLoader
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
'YouTube video requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||
) from None
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
from embedchain.utils import clean_string
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
from .embedding_functions import EmbeddingFunctions # noqa: F401
|
||||
from .providers import Providers # noqa: F401
|
||||
from .vector_databases import VectorDatabases # noqa: F401
|
||||
from .vector_dimensions import VectorDimensions # noqa: F401
|
||||
|
||||
@@ -25,6 +25,10 @@ class IndirectDataType(Enum):
|
||||
CSV = "csv"
|
||||
MDX = "mdx"
|
||||
IMAGES = "images"
|
||||
UNSTRUCTURED = "unstructured"
|
||||
JSON = "json"
|
||||
OPENAPI = "openapi"
|
||||
GMAIL = "gmail"
|
||||
|
||||
|
||||
class SpecialDataType(Enum):
|
||||
@@ -49,3 +53,7 @@ class DataType(Enum):
|
||||
MDX = IndirectDataType.MDX.value
|
||||
QNA_PAIR = SpecialDataType.QNA_PAIR.value
|
||||
IMAGES = IndirectDataType.IMAGES.value
|
||||
UNSTRUCTURED = IndirectDataType.UNSTRUCTURED.value
|
||||
JSON = IndirectDataType.JSON.value
|
||||
OPENAPI = IndirectDataType.OPENAPI.value
|
||||
GMAIL = IndirectDataType.GMAIL.value
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class VectorDatabases(Enum):
|
||||
CHROMADB = "CHROMADB"
|
||||
ELASTICSEARCH = "ELASTICSEARCH"
|
||||
OPENSEARCH = "OPENSEARCH"
|
||||
ZILLIZ = "ZILLIZ"
|
||||
@@ -0,0 +1,387 @@
|
||||
import ast
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
import uuid
|
||||
|
||||
import requests
|
||||
import yaml
|
||||
from fastapi import FastAPI, HTTPException
|
||||
|
||||
from embedchain import Client
|
||||
from embedchain.config import PipelineConfig
|
||||
from embedchain.embedchain import CONFIG_DIR, EmbedChain
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.llm.openai import OpenAILlm
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
from embedchain.vectordb.chroma import ChromaDB
|
||||
|
||||
SQLITE_PATH = os.path.join(CONFIG_DIR, "embedchain.db")
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class Pipeline(EmbedChain):
|
||||
"""
|
||||
EmbedChain pipeline lets you create a LLM powered app for your unstructured
|
||||
data by defining a pipeline with your chosen data source, embedding model,
|
||||
and vector database.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
id: str = None,
|
||||
name: str = None,
|
||||
config: PipelineConfig = None,
|
||||
db: BaseVectorDB = None,
|
||||
embedding_model: BaseEmbedder = None,
|
||||
llm: BaseLlm = None,
|
||||
yaml_path: str = None,
|
||||
log_level=logging.INFO,
|
||||
auto_deploy: bool = False,
|
||||
):
|
||||
"""
|
||||
Initialize a new `App` instance.
|
||||
|
||||
:param config: Configuration for the pipeline, defaults to None
|
||||
:type config: PipelineConfig, optional
|
||||
:param db: The database to use for storing and retrieving embeddings, defaults to None
|
||||
:type db: BaseVectorDB, optional
|
||||
:param embedding_model: The embedding model used to calculate embeddings, defaults to None
|
||||
:type embedding_model: BaseEmbedder, optional
|
||||
:param llm: The LLM model used to calculate embeddings, defaults to None
|
||||
:type llm: BaseLlm, optional
|
||||
:param yaml_path: Path to the YAML configuration file, defaults to None
|
||||
:type yaml_path: str, optional
|
||||
:param log_level: Log level to use, defaults to logging.INFO
|
||||
:type log_level: int, optional
|
||||
:param auto_deploy: Whether to deploy the pipeline automatically, defaults to False
|
||||
:type auto_deploy: bool, optional
|
||||
:raises Exception: If an error occurs while creating the pipeline
|
||||
"""
|
||||
if id and yaml_path:
|
||||
raise Exception("Cannot provide both id and config. Please provide only one of them.")
|
||||
|
||||
if id and name:
|
||||
raise Exception("Cannot provide both id and name. Please provide only one of them.")
|
||||
|
||||
if name and config:
|
||||
raise Exception("Cannot provide both name and config. Please provide only one of them.")
|
||||
|
||||
logging.basicConfig(level=log_level, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
self.auto_deploy = auto_deploy
|
||||
|
||||
# Store the yaml config as an attribute to be able to send it
|
||||
self.yaml_config = None
|
||||
self.client = None
|
||||
# pipeline_id from the backend
|
||||
self.id = None
|
||||
|
||||
self.config = config or PipelineConfig()
|
||||
self.name = self.config.name
|
||||
|
||||
self.config.id = self.local_id = str(uuid.uuid4()) if self.config.id is None else self.config.id
|
||||
|
||||
if yaml_path:
|
||||
with open(yaml_path, "r") as file:
|
||||
config_data = yaml.safe_load(file)
|
||||
self.yaml_config = config_data
|
||||
|
||||
if id is not None:
|
||||
# Init client first since user is trying to fetch the pipeline
|
||||
# details from the platform
|
||||
self._init_client()
|
||||
pipeline_details = self._get_pipeline(id)
|
||||
self.config.id = self.local_id = pipeline_details["metadata"]["local_id"]
|
||||
self.id = id
|
||||
|
||||
if name is not None:
|
||||
self.name = name
|
||||
|
||||
self.embedding_model = embedding_model or OpenAIEmbedder()
|
||||
self.db = db or ChromaDB()
|
||||
self.llm = llm or OpenAILlm()
|
||||
self._init_db()
|
||||
|
||||
# setup user id and directory
|
||||
self.u_id = self._load_or_generate_user_id()
|
||||
|
||||
# Establish a connection to the SQLite database
|
||||
self.connection = sqlite3.connect(SQLITE_PATH)
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
# Create the 'data_sources' table if it doesn't exist
|
||||
self.cursor.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS data_sources (
|
||||
pipeline_id TEXT,
|
||||
hash TEXT,
|
||||
type TEXT,
|
||||
value TEXT,
|
||||
metadata TEXT,
|
||||
is_uploaded INTEGER DEFAULT 0,
|
||||
PRIMARY KEY (pipeline_id, hash)
|
||||
)
|
||||
"""
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
self.user_asks = [] # legacy defaults
|
||||
if self.auto_deploy:
|
||||
self.deploy()
|
||||
|
||||
def _init_db(self):
|
||||
"""
|
||||
Initialize the database.
|
||||
"""
|
||||
self.db._set_embedder(self.embedding_model)
|
||||
self.db._initialize()
|
||||
self.db.set_collection_name(self.db.config.collection_name)
|
||||
|
||||
def _init_client(self):
|
||||
"""
|
||||
Initialize the client.
|
||||
"""
|
||||
config = Client.load_config()
|
||||
if config.get("api_key"):
|
||||
self.client = Client()
|
||||
else:
|
||||
api_key = input(
|
||||
"🔑 Enter your Embedchain API key. You can find the API key at https://app.embedchain.ai/settings/keys/ \n" # noqa: E501
|
||||
)
|
||||
self.client = Client(api_key=api_key)
|
||||
|
||||
def _get_pipeline(self, id):
|
||||
"""
|
||||
Get existing pipeline
|
||||
"""
|
||||
print("🛠️ Fetching pipeline details from the platform...")
|
||||
url = f"{self.client.host}/api/v1/pipelines/{id}/cli/"
|
||||
r = requests.get(
|
||||
url,
|
||||
headers={"Authorization": f"Token {self.client.api_key}"},
|
||||
)
|
||||
if r.status_code == 404:
|
||||
raise Exception(f"❌ Pipeline with id {id} not found!")
|
||||
|
||||
print(
|
||||
f"🎉 Pipeline loaded successfully! Pipeline url: https://app.embedchain.ai/pipelines/{r.json()['id']}\n" # noqa: E501
|
||||
)
|
||||
return r.json()
|
||||
|
||||
def _create_pipeline(self):
|
||||
"""
|
||||
Create a pipeline on the platform.
|
||||
"""
|
||||
print("🛠️ Creating pipeline on the platform...")
|
||||
# self.yaml_config is a dict. Pass it inside the key 'yaml_config' to the backend
|
||||
payload = {
|
||||
"yaml_config": json.dumps(self.yaml_config),
|
||||
"name": self.name,
|
||||
"local_id": self.local_id,
|
||||
}
|
||||
url = f"{self.client.host}/api/v1/pipelines/cli/create/"
|
||||
r = requests.post(
|
||||
url,
|
||||
json=payload,
|
||||
headers={"Authorization": f"Token {self.client.api_key}"},
|
||||
)
|
||||
if r.status_code not in [200, 201]:
|
||||
raise Exception(f"❌ Error occurred while creating pipeline. API response: {r.text}")
|
||||
|
||||
if r.status_code == 200:
|
||||
print(
|
||||
f"🎉🎉🎉 Existing pipeline found! View your pipeline: https://app.embedchain.ai/pipelines/{r.json()['id']}\n" # noqa: E501
|
||||
) # noqa: E501
|
||||
elif r.status_code == 201:
|
||||
print(
|
||||
f"🎉🎉🎉 Pipeline created successfully! View your pipeline: https://app.embedchain.ai/pipelines/{r.json()['id']}\n" # noqa: E501
|
||||
)
|
||||
return r.json()
|
||||
|
||||
def _get_presigned_url(self, data_type, data_value):
|
||||
payload = {"data_type": data_type, "data_value": data_value}
|
||||
r = requests.post(
|
||||
f"{self.client.host}/api/v1/pipelines/{self.id}/cli/presigned_url/",
|
||||
json=payload,
|
||||
headers={"Authorization": f"Token {self.client.api_key}"},
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
def search(self, query, num_documents=3):
|
||||
"""
|
||||
Search for similar documents related to the query in the vector database.
|
||||
"""
|
||||
# TODO: Search will call the endpoint rather than fetching the data from the db itself when deploy=True.
|
||||
if self.id is None:
|
||||
where = {"app_id": self.local_id}
|
||||
return self.db.query(
|
||||
query,
|
||||
n_results=num_documents,
|
||||
where=where,
|
||||
skip_embedding=False,
|
||||
)
|
||||
else:
|
||||
# Make API call to the backend to get the results
|
||||
NotImplementedError("Search is not implemented yet for the prod mode.")
|
||||
|
||||
def _upload_file_to_presigned_url(self, presigned_url, file_path):
|
||||
try:
|
||||
with open(file_path, "rb") as file:
|
||||
response = requests.put(presigned_url, data=file)
|
||||
response.raise_for_status()
|
||||
return response.status_code == 200
|
||||
except Exception as e:
|
||||
self.logger.exception(f"Error occurred during file upload: {str(e)}")
|
||||
print("❌ Error occurred during file upload!")
|
||||
return False
|
||||
|
||||
def _upload_data_to_pipeline(self, data_type, data_value, metadata=None):
|
||||
payload = {
|
||||
"data_type": data_type,
|
||||
"data_value": data_value,
|
||||
"metadata": metadata,
|
||||
}
|
||||
try:
|
||||
self._send_api_request(f"/api/v1/pipelines/{self.id}/cli/add/", payload)
|
||||
# print the local file path if user tries to upload a local file
|
||||
printed_value = metadata.get("file_path") if metadata.get("file_path") else data_value
|
||||
print(f"✅ Data of type: {data_type}, value: {printed_value} added successfully.")
|
||||
except Exception as e:
|
||||
print(f"❌ Error occurred during data upload for type {data_type}!. Error: {str(e)}")
|
||||
|
||||
def _send_api_request(self, endpoint, payload):
|
||||
url = f"{self.client.host}{endpoint}"
|
||||
headers = {"Authorization": f"Token {self.client.api_key}"}
|
||||
response = requests.post(url, json=payload, headers=headers)
|
||||
response.raise_for_status()
|
||||
return response
|
||||
|
||||
def _process_and_upload_data(self, data_hash, data_type, data_value):
|
||||
if os.path.isabs(data_value):
|
||||
presigned_url_data = self._get_presigned_url(data_type, data_value)
|
||||
presigned_url = presigned_url_data["presigned_url"]
|
||||
s3_key = presigned_url_data["s3_key"]
|
||||
if self._upload_file_to_presigned_url(presigned_url, file_path=data_value):
|
||||
metadata = {"file_path": data_value, "s3_key": s3_key}
|
||||
data_value = presigned_url
|
||||
else:
|
||||
self.logger.error(f"File upload failed for hash: {data_hash}")
|
||||
return False
|
||||
else:
|
||||
if data_type == "qna_pair":
|
||||
data_value = list(ast.literal_eval(data_value))
|
||||
metadata = {}
|
||||
|
||||
try:
|
||||
self._upload_data_to_pipeline(data_type, data_value, metadata)
|
||||
self._mark_data_as_uploaded(data_hash)
|
||||
return True
|
||||
except Exception:
|
||||
print(f"❌ Error occurred during data upload for hash {data_hash}!")
|
||||
return False
|
||||
|
||||
def _mark_data_as_uploaded(self, data_hash):
|
||||
self.cursor.execute(
|
||||
"UPDATE data_sources SET is_uploaded = 1 WHERE hash = ? AND pipeline_id = ?",
|
||||
(data_hash, self.local_id),
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
def deploy(self):
|
||||
if self.client is None:
|
||||
self._init_client()
|
||||
|
||||
pipeline_data = self._create_pipeline()
|
||||
self.id = pipeline_data["id"]
|
||||
|
||||
results = self.cursor.execute(
|
||||
"SELECT * FROM data_sources WHERE pipeline_id = ? AND is_uploaded = 0", (self.local_id,) # noqa:E501
|
||||
).fetchall()
|
||||
|
||||
if len(results) > 0:
|
||||
print("🛠️ Adding data to your pipeline...")
|
||||
for result in results:
|
||||
data_hash, data_type, data_value = result[1], result[2], result[3]
|
||||
self._process_and_upload_data(data_hash, data_type, data_value)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, yaml_path: str, auto_deploy: bool = False):
|
||||
"""
|
||||
Instantiate a Pipeline object from a YAML configuration file.
|
||||
|
||||
:param yaml_path: Path to the YAML configuration file.
|
||||
:type yaml_path: str
|
||||
:param auto_deploy: Whether to deploy the pipeline automatically, defaults to False
|
||||
:type auto_deploy: bool, optional
|
||||
:return: An instance of the Pipeline class.
|
||||
:rtype: Pipeline
|
||||
"""
|
||||
with open(yaml_path, "r") as file:
|
||||
config_data = yaml.safe_load(file)
|
||||
|
||||
pipeline_config_data = config_data.get("pipeline", {}).get("config", {})
|
||||
db_config_data = config_data.get("vectordb", {})
|
||||
embedding_model_config_data = config_data.get("embedding_model", {})
|
||||
llm_config_data = config_data.get("llm", {})
|
||||
|
||||
pipeline_config = PipelineConfig(**pipeline_config_data)
|
||||
|
||||
db_provider = db_config_data.get("provider", "chroma")
|
||||
db = VectorDBFactory.create(db_provider, db_config_data.get("config", {}))
|
||||
|
||||
if llm_config_data:
|
||||
llm_provider = llm_config_data.get("provider", "openai")
|
||||
llm = LlmFactory.create(llm_provider, llm_config_data.get("config", {}))
|
||||
else:
|
||||
llm = None
|
||||
|
||||
embedding_model_provider = embedding_model_config_data.get("provider", "openai")
|
||||
embedding_model = EmbedderFactory.create(
|
||||
embedding_model_provider, embedding_model_config_data.get("config", {})
|
||||
)
|
||||
return cls(
|
||||
config=pipeline_config,
|
||||
llm=llm,
|
||||
db=db,
|
||||
embedding_model=embedding_model,
|
||||
yaml_path=yaml_path,
|
||||
auto_deploy=auto_deploy,
|
||||
)
|
||||
|
||||
def start(self, host="0.0.0.0", port=8000):
|
||||
app = FastAPI()
|
||||
|
||||
@app.post("/add")
|
||||
async def add_document(data_value: str, data_type: str = None):
|
||||
"""
|
||||
Add a document to the pipeline.
|
||||
"""
|
||||
try:
|
||||
document = {"data_value": data_value, "data_type": data_type}
|
||||
self.add(document)
|
||||
return {"message": "Document added successfully"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/query")
|
||||
async def query_documents(query: str, num_documents: int = 3):
|
||||
"""
|
||||
Query for similar documents in the pipeline.
|
||||
"""
|
||||
try:
|
||||
results = self.search(query, num_documents)
|
||||
return results
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
import uvicorn
|
||||
|
||||
uvicorn.run(app, host=host, port=port)
|
||||
@@ -115,6 +115,13 @@ def detect_datatype(source: Any) -> DataType:
|
||||
"""
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import requests
|
||||
import yaml
|
||||
|
||||
def is_openapi_yaml(yaml_content):
|
||||
# currently the following two fields are required in openapi spec yaml config
|
||||
return "openapi" in yaml_content and "info" in yaml_content
|
||||
|
||||
try:
|
||||
if not isinstance(source, str):
|
||||
raise ValueError("Source is not a string and thus cannot be a URL.")
|
||||
@@ -155,6 +162,35 @@ def detect_datatype(source: Any) -> DataType:
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `docx`.")
|
||||
return DataType.DOCX
|
||||
|
||||
if url.path.endswith(".yaml"):
|
||||
try:
|
||||
response = requests.get(source)
|
||||
response.raise_for_status()
|
||||
try:
|
||||
yaml_content = yaml.safe_load(response.text)
|
||||
except yaml.YAMLError as exc:
|
||||
logging.error(f"Error parsing YAML: {exc}")
|
||||
raise TypeError(f"Not a valid data type. Error loading YAML: {exc}")
|
||||
|
||||
if is_openapi_yaml(yaml_content):
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `openapi`.")
|
||||
return DataType.OPENAPI
|
||||
else:
|
||||
logging.error(
|
||||
f"Source of `{formatted_source}` does not contain all the required \
|
||||
fields of OpenAPI yaml. Check 'https://spec.openapis.org/oas/v3.1.0'"
|
||||
)
|
||||
raise TypeError(
|
||||
"Not a valid data type. Check 'https://spec.openapis.org/oas/v3.1.0', \
|
||||
make sure you have all the required fields in YAML config data"
|
||||
)
|
||||
except requests.exceptions.RequestException as e:
|
||||
logging.error(f"Error fetching URL {formatted_source}: {e}")
|
||||
|
||||
if url.path.endswith(".json"):
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `json_file`.")
|
||||
return DataType.JSON
|
||||
|
||||
if "docs" in url.netloc or ("docs" in url.path and url.scheme != "file"):
|
||||
# `docs_site` detection via path is not accepted for local filesystem URIs,
|
||||
# because that would mean all paths that contain `docs` are now doc sites, which is too aggressive.
|
||||
@@ -194,6 +230,26 @@ def detect_datatype(source: Any) -> DataType:
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `xml`.")
|
||||
return DataType.XML
|
||||
|
||||
if source.endswith(".yaml"):
|
||||
with open(source, "r") as file:
|
||||
yaml_content = yaml.safe_load(file)
|
||||
if is_openapi_yaml(yaml_content):
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `openapi`.")
|
||||
return DataType.OPENAPI
|
||||
else:
|
||||
logging.error(
|
||||
f"Source of `{formatted_source}` does not contain all the required \
|
||||
fields of OpenAPI yaml. Check 'https://spec.openapis.org/oas/v3.1.0'"
|
||||
)
|
||||
raise ValueError(
|
||||
"Invalid YAML data. Check 'https://spec.openapis.org/oas/v3.1.0', \
|
||||
make sure to add all the required params"
|
||||
)
|
||||
|
||||
if source.endswith(".json"):
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `json`.")
|
||||
return DataType.JSON
|
||||
|
||||
# If the source is a valid file, that's not detectable as a type, an error is raised.
|
||||
# It does not fallback to text.
|
||||
raise ValueError(
|
||||
@@ -203,6 +259,8 @@ def detect_datatype(source: Any) -> DataType:
|
||||
else:
|
||||
# Source is not a URL.
|
||||
|
||||
# TODO: check if source is gmail query
|
||||
|
||||
# Use text as final fallback.
|
||||
logging.debug(f"Source of `{formatted_source}` detected as `text`.")
|
||||
return DataType.TEXT
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
from chromadb import Collection, QueryResult
|
||||
from langchain.docstore.document import Document
|
||||
@@ -25,6 +25,8 @@ except RuntimeError:
|
||||
class ChromaDB(BaseVectorDB):
|
||||
"""Vector database using ChromaDB."""
|
||||
|
||||
BATCH_SIZE = 100
|
||||
|
||||
def __init__(self, config: Optional[ChromaDbConfig] = None):
|
||||
"""Initialize a new ChromaDB instance
|
||||
|
||||
@@ -123,10 +125,6 @@ class ChromaDB(BaseVectorDB):
|
||||
args["limit"] = limit
|
||||
return self.collection.get(**args)
|
||||
|
||||
def get_advanced(self, where):
|
||||
where_clause = self._generate_where_clause(where)
|
||||
return self.collection.get(where=where_clause, limit=1)
|
||||
|
||||
def add(
|
||||
self,
|
||||
embeddings: List[List[float]],
|
||||
@@ -149,10 +147,31 @@ class ChromaDB(BaseVectorDB):
|
||||
:param skip_embedding: Optional. If True, then the embeddings are assumed to be already generated.
|
||||
:type skip_embedding: bool
|
||||
"""
|
||||
if skip_embedding:
|
||||
self.collection.add(embeddings=embeddings, documents=documents, metadatas=metadatas, ids=ids)
|
||||
else:
|
||||
self.collection.add(documents=documents, metadatas=metadatas, ids=ids)
|
||||
size = len(documents)
|
||||
if skip_embedding and (embeddings is None or len(embeddings) != len(documents)):
|
||||
raise ValueError("Cannot add documents to chromadb with inconsistent embeddings")
|
||||
|
||||
if len(documents) != size or len(metadatas) != size or len(ids) != size:
|
||||
raise ValueError(
|
||||
"Cannot add documents to chromadb with inconsistent sizes. Documents size: {}, Metadata size: {},"
|
||||
" Ids size: {}".format(len(documents), len(metadatas), len(ids))
|
||||
)
|
||||
|
||||
for i in range(0, len(documents), self.BATCH_SIZE):
|
||||
print("Inserting batches from {} to {} in chromadb".format(i, min(len(documents), i + self.BATCH_SIZE)))
|
||||
if skip_embedding:
|
||||
self.collection.add(
|
||||
embeddings=embeddings[i : i + self.BATCH_SIZE],
|
||||
documents=documents[i : i + self.BATCH_SIZE],
|
||||
metadatas=metadatas[i : i + self.BATCH_SIZE],
|
||||
ids=ids[i : i + self.BATCH_SIZE],
|
||||
)
|
||||
else:
|
||||
self.collection.add(
|
||||
documents=documents[i : i + self.BATCH_SIZE],
|
||||
metadatas=metadatas[i : i + self.BATCH_SIZE],
|
||||
ids=ids[i : i + self.BATCH_SIZE],
|
||||
)
|
||||
|
||||
def _format_result(self, results: QueryResult) -> list[tuple[Document, float]]:
|
||||
"""
|
||||
@@ -172,7 +191,9 @@ class ChromaDB(BaseVectorDB):
|
||||
)
|
||||
]
|
||||
|
||||
def query(self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool) -> List[str]:
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
Query contents from vector database based on vector similarity
|
||||
|
||||
@@ -185,8 +206,8 @@ class ChromaDB(BaseVectorDB):
|
||||
:param skip_embedding: Optional. If True, then the input_query is assumed to be already embedded.
|
||||
:type skip_embedding: bool
|
||||
:raises InvalidDimensionException: Dimensions do not match.
|
||||
:return: The content of the document that matched your query.
|
||||
:rtype: List[str]
|
||||
:return: The content of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
try:
|
||||
if skip_embedding:
|
||||
@@ -208,11 +229,18 @@ class ChromaDB(BaseVectorDB):
|
||||
except InvalidDimensionException as e:
|
||||
raise InvalidDimensionException(
|
||||
e.message()
|
||||
+ ". This is commonly a side-effect when an embedding function, different from the one used to add the embeddings, is used to retrieve an embedding from the database." # noqa E501
|
||||
+ ". This is commonly a side-effect when an embedding function, different from the one used to add the"
|
||||
" embeddings, is used to retrieve an embedding from the database."
|
||||
) from None
|
||||
results_formatted = self._format_result(result)
|
||||
contents = [result[0].page_content for result in results_formatted]
|
||||
return contents
|
||||
contexts = []
|
||||
for result in results_formatted:
|
||||
context = result[0].page_content
|
||||
metadata = result[0].metadata
|
||||
source = metadata["url"]
|
||||
doc_id = metadata["doc_id"]
|
||||
contexts.append((context, source, doc_id))
|
||||
return contexts
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
"""
|
||||
@@ -242,9 +270,9 @@ class ChromaDB(BaseVectorDB):
|
||||
"""
|
||||
Resets the database. Deletes all embeddings irreversibly.
|
||||
"""
|
||||
# Delete all data from the database
|
||||
# Delete all data from the collection
|
||||
try:
|
||||
self.client.reset()
|
||||
self.client.delete_collection(self.config.collection_name)
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
"For safety reasons, resetting is disabled. "
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
from elasticsearch import Elasticsearch
|
||||
@@ -74,9 +74,7 @@ class ElasticsearchDB(BaseVectorDB):
|
||||
def _get_or_create_collection(self, name):
|
||||
"""Note: nothing to return here. Discuss later"""
|
||||
|
||||
def get(
|
||||
self, ids: Optional[List[str]] = None, where: Optional[Dict[str, any]] = None, limit: Optional[int] = None
|
||||
) -> Set[str]:
|
||||
def get(self, ids: Optional[List[str]] = None, where: Optional[Dict[str, any]] = None, limit: Optional[int] = None):
|
||||
"""
|
||||
Get existing doc ids present in vector database
|
||||
|
||||
@@ -137,7 +135,9 @@ class ElasticsearchDB(BaseVectorDB):
|
||||
bulk(self.client, docs)
|
||||
self.client.indices.refresh(index=self._get_index())
|
||||
|
||||
def query(self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool) -> List[str]:
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
query contents from vector data base based on vector similarity
|
||||
|
||||
@@ -149,8 +149,9 @@ class ElasticsearchDB(BaseVectorDB):
|
||||
:type where: Dict[str, any]
|
||||
:param skip_embedding: Optional. If True, then the input_query is assumed to be already embedded.
|
||||
:type skip_embedding: bool
|
||||
:return: Database contents that are the result of the query
|
||||
:rtype: List[str]
|
||||
:return: The context of the document that matched your query, url of the source, doc_id
|
||||
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
if skip_embedding:
|
||||
query_vector = input_query
|
||||
@@ -158,6 +159,7 @@ class ElasticsearchDB(BaseVectorDB):
|
||||
input_query_vector = self.embedder.embedding_fn(input_query)
|
||||
query_vector = input_query_vector[0]
|
||||
|
||||
# `https://www.elastic.co/guide/en/elasticsearch/reference/7.17/query-dsl-script-score-query.html`
|
||||
query = {
|
||||
"script_score": {
|
||||
"query": {"bool": {"must": [{"exists": {"field": "text"}}]}},
|
||||
@@ -169,11 +171,17 @@ class ElasticsearchDB(BaseVectorDB):
|
||||
}
|
||||
if "app_id" in where:
|
||||
app_id = where["app_id"]
|
||||
query["script_score"]["query"]["bool"]["must"] = [{"term": {"metadata.app_id": app_id}}]
|
||||
_source = ["text"]
|
||||
query["script_score"]["query"] = {"match": {"metadata.app_id": app_id}}
|
||||
_source = ["text", "metadata.url", "metadata.doc_id"]
|
||||
response = self.client.search(index=self._get_index(), query=query, _source=_source, size=n_results)
|
||||
docs = response["hits"]["hits"]
|
||||
contents = [doc["_source"]["text"] for doc in docs]
|
||||
contents = []
|
||||
for doc in docs:
|
||||
context = doc["_source"]["text"]
|
||||
metadata = doc["_source"]["metadata"]
|
||||
source = metadata["url"]
|
||||
doc_id = metadata["doc_id"]
|
||||
contents.append(tuple((context, source, doc_id)))
|
||||
return contents
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Dict, List, Optional, Set
|
||||
from typing import Dict, List, Optional, Set, Tuple
|
||||
|
||||
try:
|
||||
from opensearchpy import OpenSearch
|
||||
@@ -145,7 +145,9 @@ class OpenSearchDB(BaseVectorDB):
|
||||
bulk(self.client, docs)
|
||||
self.client.indices.refresh(index=self._get_index())
|
||||
|
||||
def query(self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool) -> List[str]:
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
query contents from vector data base based on vector similarity
|
||||
|
||||
@@ -157,8 +159,8 @@ class OpenSearchDB(BaseVectorDB):
|
||||
:type where: Dict[str, any]
|
||||
:param skip_embedding: Optional. If True, then the input_query is assumed to be already embedded.
|
||||
:type skip_embedding: bool
|
||||
:return: Database contents that are the result of the query
|
||||
:rtype: List[str]
|
||||
:return: The content of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
# TODO(rupeshbansal, deshraj): Add support for skip embeddings here if already exists
|
||||
embeddings = OpenAIEmbeddings()
|
||||
@@ -185,7 +187,13 @@ class OpenSearchDB(BaseVectorDB):
|
||||
pre_filter=pre_filter,
|
||||
k=n_results,
|
||||
)
|
||||
contents = [doc.page_content for doc in docs]
|
||||
|
||||
contents = []
|
||||
for doc in docs:
|
||||
context = doc.page_content
|
||||
source = doc.metadata["url"]
|
||||
doc_id = doc.metadata["doc_id"]
|
||||
contents.append(tuple((context, source, doc_id)))
|
||||
return contents
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
import os
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
import pinecone
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Pinecone requires extra dependencies. Install with `pip install --upgrade 'embedchain[pinecone]'`"
|
||||
) from None
|
||||
|
||||
from embedchain.config.vectordb.pinecone import PineconeDBConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class PineconeDB(BaseVectorDB):
|
||||
"""
|
||||
Pinecone as vector database
|
||||
"""
|
||||
|
||||
BATCH_SIZE = 100
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: Optional[PineconeDBConfig] = None,
|
||||
):
|
||||
"""Pinecone as vector database.
|
||||
|
||||
:param config: Pinecone database config, defaults to None
|
||||
:type config: PineconeDBConfig, optional
|
||||
:raises ValueError: No config provided
|
||||
"""
|
||||
if config is None:
|
||||
self.config = PineconeDBConfig()
|
||||
else:
|
||||
if not isinstance(config, PineconeDBConfig):
|
||||
raise TypeError(
|
||||
"config is not a `PineconeDBConfig` instance. "
|
||||
"Please make sure the type is right and that you are passing an instance."
|
||||
)
|
||||
self.config = config
|
||||
self.client = self._setup_pinecone_index()
|
||||
# Call parent init here because embedder is needed
|
||||
super().__init__(config=self.config)
|
||||
|
||||
def _initialize(self):
|
||||
"""
|
||||
This method is needed because `embedder` attribute needs to be set externally before it can be initialized.
|
||||
"""
|
||||
if not self.embedder:
|
||||
raise ValueError("Embedder not set. Please set an embedder with `set_embedder` before initialization.")
|
||||
|
||||
# Loads the Pinecone index or creates it if not present.
|
||||
def _setup_pinecone_index(self):
|
||||
pinecone.init(
|
||||
api_key=os.environ.get("PINECONE_API_KEY"),
|
||||
environment=os.environ.get("PINECONE_ENV"),
|
||||
**self.config.extra_params,
|
||||
)
|
||||
self.index_name = self._get_index_name()
|
||||
indexes = pinecone.list_indexes()
|
||||
if indexes is None or self.index_name not in indexes:
|
||||
pinecone.create_index(
|
||||
name=self.index_name, metric=self.config.metric, dimension=self.config.vector_dimension
|
||||
)
|
||||
return pinecone.Index(self.index_name)
|
||||
|
||||
def get(self, ids: Optional[List[str]] = None, where: Optional[Dict[str, any]] = None, limit: Optional[int] = None):
|
||||
"""
|
||||
Get existing doc ids present in vector database
|
||||
|
||||
:param ids: _list of doc ids to check for existence
|
||||
:type ids: List[str]
|
||||
:param where: to filter data
|
||||
:type where: Dict[str, any]
|
||||
:return: ids
|
||||
:rtype: Set[str]
|
||||
"""
|
||||
existing_ids = list()
|
||||
if ids is not None:
|
||||
for i in range(0, len(ids), 1000):
|
||||
result = self.client.fetch(ids=ids[i : i + 1000])
|
||||
batch_existing_ids = list(result.get("vectors").keys())
|
||||
existing_ids.extend(batch_existing_ids)
|
||||
return {"ids": existing_ids}
|
||||
|
||||
def add(
|
||||
self,
|
||||
embeddings: List[List[float]],
|
||||
documents: List[str],
|
||||
metadatas: List[object],
|
||||
ids: List[str],
|
||||
skip_embedding: bool,
|
||||
):
|
||||
"""add data in vector database
|
||||
|
||||
:param documents: list of texts to add
|
||||
:type documents: List[str]
|
||||
:param metadatas: list of metadata associated with docs
|
||||
:type metadatas: List[object]
|
||||
:param ids: ids of docs
|
||||
:type ids: List[str]
|
||||
"""
|
||||
docs = []
|
||||
print("Adding documents to Pinecone...")
|
||||
|
||||
embeddings = self.embedder.embedding_fn(documents)
|
||||
for id, text, metadata, embedding in zip(ids, documents, metadatas, embeddings):
|
||||
docs.append(
|
||||
{
|
||||
"id": id,
|
||||
"values": embedding,
|
||||
"metadata": {**metadata, "text": text},
|
||||
}
|
||||
)
|
||||
|
||||
for i in range(0, len(docs), self.BATCH_SIZE):
|
||||
self.client.upsert(docs[i : i + self.BATCH_SIZE])
|
||||
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
query contents from vector database based on vector similarity
|
||||
:param input_query: list of query string
|
||||
:type input_query: List[str]
|
||||
:param n_results: no of similar documents to fetch from database
|
||||
:type n_results: int
|
||||
:param where: Optional. to filter data
|
||||
:type where: Dict[str, any]
|
||||
:param skip_embedding: Optional. if True, input_query is already embedded
|
||||
:type skip_embedding: bool
|
||||
:return: The content of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
if not skip_embedding:
|
||||
query_vector = self.embedder.embedding_fn([input_query])[0]
|
||||
else:
|
||||
query_vector = input_query
|
||||
data = self.client.query(vector=query_vector, filter=where, top_k=n_results, include_metadata=True)
|
||||
contents = []
|
||||
for doc in data["matches"]:
|
||||
metadata = doc["metadata"]
|
||||
context = metadata["text"]
|
||||
source = metadata["url"]
|
||||
doc_id = metadata["doc_id"]
|
||||
contents.append(tuple((context, source, doc_id)))
|
||||
return contents
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
"""
|
||||
Set the name of the collection. A collection is an isolated space for vectors.
|
||||
|
||||
:param name: Name of the collection.
|
||||
:type name: str
|
||||
"""
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("Collection name must be a string")
|
||||
self.config.collection_name = name
|
||||
|
||||
def count(self) -> int:
|
||||
"""
|
||||
Count number of documents/chunks embedded in the database.
|
||||
|
||||
:return: number of documents
|
||||
:rtype: int
|
||||
"""
|
||||
return self.client.describe_index_stats()["total_vector_count"]
|
||||
|
||||
def _get_or_create_db(self):
|
||||
"""Called during initialization"""
|
||||
return self.client
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the database. Deletes all embeddings irreversibly.
|
||||
"""
|
||||
# Delete all data from the database
|
||||
pinecone.delete_index(self.index_name)
|
||||
self._setup_pinecone_index()
|
||||
|
||||
# Pinecone only allows alphanumeric characters and "-" in the index name
|
||||
def _get_index_name(self) -> str:
|
||||
"""Get the Pinecone index for a collection
|
||||
|
||||
:return: Pinecone index
|
||||
:rtype: str
|
||||
"""
|
||||
return f"{self.config.collection_name}-{self.config.vector_dimension}".lower().replace("_", "-")
|
||||
@@ -0,0 +1,232 @@
|
||||
import copy
|
||||
import os
|
||||
import uuid
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
from qdrant_client import QdrantClient
|
||||
from qdrant_client.http import models
|
||||
from qdrant_client.http.models import Batch
|
||||
from qdrant_client.models import Distance, VectorParams
|
||||
except ImportError:
|
||||
raise ImportError("Qdrant requires extra dependencies. Install with `pip install embedchain[qdrant]`") from None
|
||||
|
||||
from embedchain.config.vectordb.qdrant import QdrantDBConfig
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
|
||||
class QdrantDB(BaseVectorDB):
|
||||
"""
|
||||
Qdrant as vector database
|
||||
"""
|
||||
|
||||
BATCH_SIZE = 10
|
||||
|
||||
def __init__(self, config: QdrantDBConfig = None):
|
||||
"""
|
||||
Qdrant as vector database
|
||||
:param config. Qdrant database config to be used for connection
|
||||
"""
|
||||
if config is None:
|
||||
config = QdrantDBConfig()
|
||||
else:
|
||||
if not isinstance(config, QdrantDBConfig):
|
||||
raise TypeError(
|
||||
"config is not a `QdrantDBConfig` instance. "
|
||||
"Please make sure the type is right and that you are passing an instance."
|
||||
)
|
||||
self.config = config
|
||||
self.client = QdrantClient(url=os.getenv("QDRANT_URL"), api_key=os.getenv("QDRANT_API_KEY"))
|
||||
# Call parent init here because embedder is needed
|
||||
super().__init__(config=self.config)
|
||||
|
||||
def _initialize(self):
|
||||
"""
|
||||
This method is needed because `embedder` attribute needs to be set externally before it can be initialized.
|
||||
"""
|
||||
if not self.embedder:
|
||||
raise ValueError("Embedder not set. Please set an embedder with `set_embedder` before initialization.")
|
||||
|
||||
self.collection_name = self._get_or_create_collection()
|
||||
self.metadata_keys = {"data_type", "doc_id", "url", "hash", "app_id", "text"}
|
||||
all_collections = self.client.get_collections()
|
||||
collection_names = [collection.name for collection in all_collections.collections]
|
||||
if self.collection_name not in collection_names:
|
||||
self.client.recreate_collection(
|
||||
collection_name=self.collection_name,
|
||||
vectors_config=VectorParams(
|
||||
size=self.embedder.vector_dimension,
|
||||
distance=Distance.COSINE,
|
||||
hnsw_config=self.config.hnsw_config,
|
||||
quantization_config=self.config.quantization_config,
|
||||
on_disk=self.config.on_disk,
|
||||
),
|
||||
)
|
||||
|
||||
def _get_or_create_db(self):
|
||||
return self.client
|
||||
|
||||
def _get_or_create_collection(self):
|
||||
return f"{self.config.collection_name}-{self.embedder.vector_dimension}".lower().replace("_", "-")
|
||||
|
||||
def get(self, ids: Optional[List[str]] = None, where: Optional[Dict[str, any]] = None, limit: Optional[int] = None):
|
||||
"""
|
||||
Get existing doc ids present in vector database
|
||||
|
||||
:param ids: _list of doc ids to check for existence
|
||||
:type ids: List[str]
|
||||
:param where: to filter data
|
||||
:type where: Dict[str, any]
|
||||
:param limit: The number of entries to be fetched
|
||||
:type limit: Optional int, defaults to None
|
||||
:return: All the existing IDs
|
||||
:rtype: Set[str]
|
||||
"""
|
||||
if ids is None or len(ids) == 0:
|
||||
return {"ids": []}
|
||||
|
||||
keys = set(where.keys() if where is not None else set())
|
||||
|
||||
qdrant_must_filters = [
|
||||
models.FieldCondition(
|
||||
key="identifier",
|
||||
match=models.MatchAny(
|
||||
any=ids,
|
||||
),
|
||||
)
|
||||
]
|
||||
if len(keys.intersection(self.metadata_keys)) != 0:
|
||||
for key in keys.intersection(self.metadata_keys):
|
||||
qdrant_must_filters.append(
|
||||
models.FieldCondition(
|
||||
key="metadata.{}".format(key),
|
||||
match=models.MatchValue(
|
||||
value=where.get(key),
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
offset = 0
|
||||
existing_ids = []
|
||||
while offset is not None:
|
||||
response = self.client.scroll(
|
||||
collection_name=self.collection_name,
|
||||
scroll_filter=models.Filter(must=qdrant_must_filters),
|
||||
offset=offset,
|
||||
limit=self.BATCH_SIZE,
|
||||
)
|
||||
offset = response[1]
|
||||
for doc in response[0]:
|
||||
existing_ids.append(doc.payload["identifier"])
|
||||
return {"ids": existing_ids}
|
||||
|
||||
def add(
|
||||
self,
|
||||
embeddings: List[List[float]],
|
||||
documents: List[str],
|
||||
metadatas: List[object],
|
||||
ids: List[str],
|
||||
skip_embedding: bool,
|
||||
):
|
||||
"""add data in vector database
|
||||
:param embeddings: list of embeddings for the corresponding documents to be added
|
||||
:type documents: List[List[float]]
|
||||
:param documents: list of texts to add
|
||||
:type documents: List[str]
|
||||
:param metadatas: list of metadata associated with docs
|
||||
:type metadatas: List[object]
|
||||
:param ids: ids of docs
|
||||
:type ids: List[str]
|
||||
:param skip_embedding: A boolean flag indicating if the embedding for the documents to be added is to be
|
||||
generated or not
|
||||
:type skip_embedding: bool
|
||||
"""
|
||||
if not skip_embedding:
|
||||
embeddings = self.embedder.embedding_fn(documents)
|
||||
|
||||
payloads = []
|
||||
qdrant_ids = []
|
||||
for id, document, metadata in zip(ids, documents, metadatas):
|
||||
metadata["text"] = document
|
||||
qdrant_ids.append(str(uuid.uuid4()))
|
||||
payloads.append({"identifier": id, "text": document, "metadata": copy.deepcopy(metadata)})
|
||||
for i in range(0, len(qdrant_ids), self.BATCH_SIZE):
|
||||
self.client.upsert(
|
||||
collection_name=self.collection_name,
|
||||
points=Batch(
|
||||
ids=qdrant_ids[i : i + self.BATCH_SIZE],
|
||||
payloads=payloads[i : i + self.BATCH_SIZE],
|
||||
vectors=embeddings[i : i + self.BATCH_SIZE],
|
||||
),
|
||||
)
|
||||
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
query contents from vector database based on vector similarity
|
||||
:param input_query: list of query string
|
||||
:type input_query: List[str]
|
||||
:param n_results: no of similar documents to fetch from database
|
||||
:type n_results: int
|
||||
:param where: Optional. to filter data
|
||||
:type where: Dict[str, any]
|
||||
:param skip_embedding: A boolean flag indicating if the embedding for the documents to be added is to be
|
||||
generated or not
|
||||
:type skip_embedding: bool
|
||||
:return: The context of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
if not skip_embedding:
|
||||
query_vector = self.embedder.embedding_fn([input_query])[0]
|
||||
else:
|
||||
query_vector = input_query
|
||||
|
||||
keys = set(where.keys() if where is not None else set())
|
||||
|
||||
qdrant_must_filters = []
|
||||
if len(keys.intersection(self.metadata_keys)) != 0:
|
||||
for key in keys.intersection(self.metadata_keys):
|
||||
qdrant_must_filters.append(
|
||||
models.FieldCondition(
|
||||
key="payload.metadata.{}".format(key),
|
||||
match=models.MatchValue(
|
||||
value=where.get(key),
|
||||
),
|
||||
)
|
||||
)
|
||||
results = self.client.search(
|
||||
collection_name=self.collection_name,
|
||||
query_filter=models.Filter(must=qdrant_must_filters),
|
||||
query_vector=query_vector,
|
||||
limit=n_results,
|
||||
)
|
||||
|
||||
response = []
|
||||
for result in results:
|
||||
context = result.payload["text"]
|
||||
metadata = result.payload["metadata"]
|
||||
source = metadata["url"]
|
||||
doc_id = metadata["doc_id"]
|
||||
response.append(tuple((context, source, doc_id)))
|
||||
return response
|
||||
|
||||
def count(self) -> int:
|
||||
response = self.client.get_collection(collection_name=self.collection_name)
|
||||
return response.points_count
|
||||
|
||||
def reset(self):
|
||||
self.client.delete_collection(collection_name=self.collection_name)
|
||||
self._initialize()
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
"""
|
||||
Set the name of the collection. A collection is an isolated space for vectors.
|
||||
|
||||
:param name: Name of the collection.
|
||||
:type name: str
|
||||
"""
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("Collection name must be a string")
|
||||
self.config.collection_name = name
|
||||
self.collection_name = self._get_or_create_collection()
|
||||
@@ -0,0 +1,297 @@
|
||||
import copy
|
||||
import os
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
import weaviate
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"Weaviate requires extra dependencies. Install with `pip install --upgrade 'embedchain[weaviate]'`"
|
||||
) from None
|
||||
|
||||
from embedchain.config.vectordb.weaviate import WeaviateDBConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
|
||||
@register_deserializable
|
||||
class WeaviateDB(BaseVectorDB):
|
||||
"""
|
||||
Weaviate as vector database
|
||||
"""
|
||||
|
||||
BATCH_SIZE = 100
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: Optional[WeaviateDBConfig] = None,
|
||||
):
|
||||
"""Weaviate as vector database.
|
||||
:param config: Weaviate database config, defaults to None
|
||||
:type config: WeaviateDBConfig, optional
|
||||
:raises ValueError: No config provided
|
||||
"""
|
||||
if config is None:
|
||||
self.config = WeaviateDBConfig()
|
||||
else:
|
||||
if not isinstance(config, WeaviateDBConfig):
|
||||
raise TypeError(
|
||||
"config is not a `WeaviateDBConfig` instance. "
|
||||
"Please make sure the type is right and that you are passing an instance."
|
||||
)
|
||||
self.config = config
|
||||
self.client = weaviate.Client(
|
||||
url=os.environ.get("WEAVIATE_ENDPOINT"),
|
||||
auth_client_secret=weaviate.AuthApiKey(api_key=os.environ.get("WEAVIATE_API_KEY")),
|
||||
**self.config.extra_params,
|
||||
)
|
||||
|
||||
# Call parent init here because embedder is needed
|
||||
super().__init__(config=self.config)
|
||||
|
||||
def _initialize(self):
|
||||
"""
|
||||
This method is needed because `embedder` attribute needs to be set externally before it can be initialized.
|
||||
"""
|
||||
|
||||
if not self.embedder:
|
||||
raise ValueError("Embedder not set. Please set an embedder with `set_embedder` before initialization.")
|
||||
|
||||
self.index_name = self._get_index_name()
|
||||
self.metadata_keys = {"data_type", "doc_id", "url", "hash", "app_id", "text"}
|
||||
if not self.client.schema.exists(self.index_name):
|
||||
# id is a reserved field in Weaviate, hence we had to change the name of the id field to identifier
|
||||
# The none vectorizer is crucial as we have our own custom embedding function
|
||||
class_obj = {
|
||||
"classes": [
|
||||
{
|
||||
"class": self.index_name,
|
||||
"vectorizer": "none",
|
||||
"properties": [
|
||||
{
|
||||
"name": "identifier",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "text",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "metadata",
|
||||
"dataType": [self.index_name + "_metadata"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"class": self.index_name + "_metadata",
|
||||
"vectorizer": "none",
|
||||
"properties": [
|
||||
{
|
||||
"name": "data_type",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "doc_id",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "url",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "hash",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "app_id",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
{
|
||||
"name": "text",
|
||||
"dataType": ["text"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
self.client.schema.create(class_obj)
|
||||
|
||||
def get(self, ids: Optional[List[str]] = None, where: Optional[Dict[str, any]] = None, limit: Optional[int] = None):
|
||||
"""
|
||||
Get existing doc ids present in vector database
|
||||
:param ids: _list of doc ids to check for existance
|
||||
:type ids: List[str]
|
||||
:param where: to filter data
|
||||
:type where: Dict[str, any]
|
||||
:return: ids
|
||||
:rtype: Set[str]
|
||||
"""
|
||||
|
||||
if ids is None or len(ids) == 0:
|
||||
return {"ids": []}
|
||||
|
||||
existing_ids = []
|
||||
cursor = None
|
||||
has_iterated_once = False
|
||||
while cursor is not None or not has_iterated_once:
|
||||
has_iterated_once = True
|
||||
results = self._query_with_cursor(
|
||||
self.client.query.get(self.index_name, ["identifier"])
|
||||
.with_additional(["id"])
|
||||
.with_limit(self.BATCH_SIZE),
|
||||
cursor,
|
||||
)
|
||||
fetched_results = results["data"]["Get"].get(self.index_name, [])
|
||||
if len(fetched_results) == 0:
|
||||
break
|
||||
for result in fetched_results:
|
||||
existing_ids.append(result["identifier"])
|
||||
cursor = result["_additional"]["id"]
|
||||
|
||||
return {"ids": existing_ids}
|
||||
|
||||
def add(
|
||||
self,
|
||||
embeddings: List[List[float]],
|
||||
documents: List[str],
|
||||
metadatas: List[object],
|
||||
ids: List[str],
|
||||
skip_embedding: bool,
|
||||
):
|
||||
"""add data in vector database
|
||||
:param embeddings: list of embeddings for the corresponding documents to be added
|
||||
:type documents: List[List[float]]
|
||||
:param documents: list of texts to add
|
||||
:type documents: List[str]
|
||||
:param metadatas: list of metadata associated with docs
|
||||
:type metadatas: List[object]
|
||||
:param ids: ids of docs
|
||||
:type ids: List[str]
|
||||
:param skip_embedding: A boolean flag indicating if the embedding for the documents to be added is to be
|
||||
generated or not
|
||||
:type skip_embedding: bool
|
||||
"""
|
||||
|
||||
print("Adding documents to Weaviate...")
|
||||
if not skip_embedding:
|
||||
embeddings = self.embedder.embedding_fn(documents)
|
||||
self.client.batch.configure(batch_size=self.BATCH_SIZE, timeout_retries=3) # Configure batch
|
||||
with self.client.batch as batch: # Initialize a batch process
|
||||
for id, text, metadata, embedding in zip(ids, documents, metadatas, embeddings):
|
||||
doc = {"identifier": id, "text": text}
|
||||
updated_metadata = {"text": text}
|
||||
if metadata is not None:
|
||||
updated_metadata.update(**metadata)
|
||||
|
||||
obj_uuid = batch.add_data_object(
|
||||
data_object=copy.deepcopy(doc), class_name=self.index_name, vector=embedding
|
||||
)
|
||||
metadata_uuid = batch.add_data_object(
|
||||
data_object=copy.deepcopy(updated_metadata),
|
||||
class_name=self.index_name + "_metadata",
|
||||
vector=embedding,
|
||||
)
|
||||
batch.add_reference(obj_uuid, self.index_name, "metadata", metadata_uuid, self.index_name + "_metadata")
|
||||
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
query contents from vector database based on vector similarity
|
||||
:param input_query: list of query string
|
||||
:type input_query: List[str]
|
||||
:param n_results: no of similar documents to fetch from database
|
||||
:type n_results: int
|
||||
:param where: Optional. to filter data
|
||||
:type where: Dict[str, any]
|
||||
:param skip_embedding: A boolean flag indicating if the embedding for the documents to be added is to be
|
||||
generated or not
|
||||
:type skip_embedding: bool
|
||||
:return: The context of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
if not skip_embedding:
|
||||
query_vector = self.embedder.embedding_fn([input_query])[0]
|
||||
else:
|
||||
query_vector = input_query
|
||||
keys = set(where.keys() if where is not None else set())
|
||||
data_fields = ["text"]
|
||||
if len(keys.intersection(self.metadata_keys)) != 0:
|
||||
weaviate_where_operands = []
|
||||
for key in keys:
|
||||
if key in self.metadata_keys:
|
||||
weaviate_where_operands.append(
|
||||
{
|
||||
"path": ["metadata", self.index_name + "_metadata", key],
|
||||
"operator": "Equal",
|
||||
"valueText": where.get(key),
|
||||
}
|
||||
)
|
||||
if len(weaviate_where_operands) == 1:
|
||||
weaviate_where_clause = weaviate_where_operands[0]
|
||||
else:
|
||||
weaviate_where_clause = {"operator": "And", "operands": weaviate_where_operands}
|
||||
|
||||
results = (
|
||||
self.client.query.get(self.index_name, data_fields)
|
||||
.with_where(weaviate_where_clause)
|
||||
.with_near_vector({"vector": query_vector})
|
||||
.with_limit(n_results)
|
||||
.do()
|
||||
)
|
||||
else:
|
||||
results = (
|
||||
self.client.query.get(self.index_name, data_fields)
|
||||
.with_near_vector({"vector": query_vector})
|
||||
.with_limit(n_results)
|
||||
.do()
|
||||
)
|
||||
contexts = results["data"]["Get"].get(self.index_name)
|
||||
return contexts
|
||||
|
||||
def set_collection_name(self, name: str):
|
||||
"""
|
||||
Set the name of the collection. A collection is an isolated space for vectors.
|
||||
:param name: Name of the collection.
|
||||
:type name: str
|
||||
"""
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("Collection name must be a string")
|
||||
self.config.collection_name = name
|
||||
|
||||
def count(self) -> int:
|
||||
"""
|
||||
Count number of documents/chunks embedded in the database.
|
||||
:return: number of documents
|
||||
:rtype: int
|
||||
"""
|
||||
data = self.client.query.aggregate(self.index_name).with_meta_count().do()
|
||||
return data["data"]["Aggregate"].get(self.index_name)[0]["meta"]["count"]
|
||||
|
||||
def _get_or_create_db(self):
|
||||
"""Called during initialization"""
|
||||
return self.client
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the database. Deletes all embeddings irreversibly.
|
||||
"""
|
||||
# Delete all data from the database
|
||||
self.client.batch.delete_objects(
|
||||
self.index_name, where={"path": ["identifier"], "operator": "Like", "valueText": ".*"}
|
||||
)
|
||||
|
||||
# Weaviate internally by default capitalizes the class name
|
||||
def _get_index_name(self) -> str:
|
||||
"""Get the Weaviate index for a collection
|
||||
:return: Weaviate index
|
||||
:rtype: str
|
||||
"""
|
||||
return f"{self.config.collection_name}_{self.embedder.vector_dimension}".capitalize()
|
||||
|
||||
def _query_with_cursor(self, query, cursor):
|
||||
if cursor is not None:
|
||||
query.with_after(cursor)
|
||||
results = query.do()
|
||||
return results
|
||||
@@ -1,4 +1,5 @@
|
||||
from typing import Dict, List, Optional
|
||||
import logging
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from embedchain.config import ZillizDBConfig
|
||||
from embedchain.helper.json_serializable import register_deserializable
|
||||
@@ -61,6 +62,7 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
:type name: str
|
||||
"""
|
||||
if utility.has_collection(name):
|
||||
logging.info(f"[ZillizDB]: found an existing collection {name}, make sure the auto-id is disabled.")
|
||||
self.collection = Collection(name)
|
||||
else:
|
||||
fields = [
|
||||
@@ -124,7 +126,9 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
self.collection.flush()
|
||||
self.client.flush(self.config.collection_name)
|
||||
|
||||
def query(self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool) -> List[str]:
|
||||
def query(
|
||||
self, input_query: List[str], n_results: int, where: Dict[str, any], skip_embedding: bool
|
||||
) -> List[Tuple[str, str, str]]:
|
||||
"""
|
||||
Query contents from vector data base based on vector similarity
|
||||
|
||||
@@ -135,8 +139,8 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
:param where: to filter data
|
||||
:type where: str
|
||||
:raises InvalidDimensionException: Dimensions do not match.
|
||||
:return: The content of the document that matched your query.
|
||||
:rtype: List[str]
|
||||
:return: The context of the document that matched your query, url of the source, doc_id
|
||||
:rtype: List[Tuple[str,str,str]]
|
||||
"""
|
||||
|
||||
if self.collection.is_empty:
|
||||
@@ -145,13 +149,14 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
if not isinstance(where, str):
|
||||
where = None
|
||||
|
||||
output_fields = ["text", "url", "doc_id"]
|
||||
if skip_embedding:
|
||||
query_vector = input_query
|
||||
query_result = self.client.search(
|
||||
collection_name=self.config.collection_name,
|
||||
data=query_vector,
|
||||
limit=n_results,
|
||||
output_fields=["text"],
|
||||
output_fields=output_fields,
|
||||
)
|
||||
|
||||
else:
|
||||
@@ -162,13 +167,16 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
collection_name=self.config.collection_name,
|
||||
data=[query_vector],
|
||||
limit=n_results,
|
||||
output_fields=["text"],
|
||||
output_fields=output_fields,
|
||||
)
|
||||
|
||||
doc_list = []
|
||||
for query in query_result:
|
||||
doc_list.append(query[0]["entity"]["text"])
|
||||
|
||||
data = query[0]["entity"]
|
||||
context = data["text"]
|
||||
source = data["url"]
|
||||
doc_id = data["doc_id"]
|
||||
doc_list.append(tuple((context, source, doc_id)))
|
||||
return doc_list
|
||||
|
||||
def count(self) -> int:
|
||||
|
||||
@@ -8,4 +8,9 @@ COPY . .
|
||||
|
||||
EXPOSE 5000
|
||||
|
||||
CMD ["python", "api_server.py"]
|
||||
ENV FLASK_APP=api_server.py
|
||||
|
||||
ENV FLASK_RUN_EXTRA_FILES=/usr/src/api/*
|
||||
ENV FLASK_ENV=development
|
||||
|
||||
CMD ["flask", "run", "--host=0.0.0.0", "--reload"]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import logging
|
||||
|
||||
from flask import Flask, jsonify, request
|
||||
|
||||
from embedchain import App
|
||||
@@ -5,11 +7,6 @@ from embedchain import App
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
def initialize_chat_bot():
|
||||
global chat_bot
|
||||
chat_bot = App()
|
||||
|
||||
|
||||
@app.route("/add", methods=["POST"])
|
||||
def add():
|
||||
data = request.get_json()
|
||||
@@ -17,9 +14,10 @@ def add():
|
||||
url_or_text = data.get("url_or_text")
|
||||
if data_type and url_or_text:
|
||||
try:
|
||||
chat_bot.add(data_type, url_or_text)
|
||||
App().add(url_or_text, data_type=data_type)
|
||||
return jsonify({"data": f"Added {data_type}: {url_or_text}"}), 200
|
||||
except Exception:
|
||||
logging.exception(f"Failed to add {data_type=}: {url_or_text=}")
|
||||
return jsonify({"error": f"Failed to add {data_type}: {url_or_text}"}), 500
|
||||
return jsonify({"error": "Invalid request. Please provide 'data_type' and 'url_or_text' in JSON format."}), 400
|
||||
|
||||
@@ -30,9 +28,10 @@ def query():
|
||||
question = data.get("question")
|
||||
if question:
|
||||
try:
|
||||
response = chat_bot.query(question)
|
||||
response = App().query(question)
|
||||
return jsonify({"data": response}), 200
|
||||
except Exception:
|
||||
logging.exception(f"Failed to query {question=}")
|
||||
return jsonify({"error": "An error occurred. Please try again!"}), 500
|
||||
return jsonify({"error": "Invalid request. Please provide 'question' in JSON format."}), 400
|
||||
|
||||
@@ -43,13 +42,13 @@ def chat():
|
||||
question = data.get("question")
|
||||
if question:
|
||||
try:
|
||||
response = chat_bot.chat(question)
|
||||
response = App().chat(question)
|
||||
return jsonify({"data": response}), 200
|
||||
except Exception:
|
||||
logging.exception(f"Failed to chat {question=}")
|
||||
return jsonify({"error": "An error occurred. Please try again!"}), 500
|
||||
return jsonify({"error": "Invalid request. Please provide 'question' in JSON format."}), 400
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
initialize_chat_bot()
|
||||
app.run(host="0.0.0.0", port=5000, debug=False)
|
||||
|
||||
@@ -10,4 +10,6 @@ services:
|
||||
env_file:
|
||||
- variables.env
|
||||
ports:
|
||||
- "5000:5000"
|
||||
- "5000:5000"
|
||||
volumes:
|
||||
- .:/usr/src/api
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
flask==2.3.2
|
||||
embedchain==0.0.58
|
||||
embedchain[dataloaders]==0.0.78
|
||||
@@ -28,7 +28,7 @@ export default function Home() {
|
||||
Welcome to Embedchain Playground
|
||||
</h1>
|
||||
<p className="mb-6 text-lg font-normal text-gray-500 lg:text-xl">
|
||||
embedchain is a framework to easily create LLM powered bots over any
|
||||
Embedchain is a Data Platform for LLMs - Load, index, retrieve, and sync any unstructured data
|
||||
dataset
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using Anthropic with Embedchain\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "efdce0dc-fb30-4e01-f5a8-ef1a7f4e8c09"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set Anthropic related environment variables\n",
|
||||
"\n",
|
||||
"You can find `OPENAI_API_KEY` on your [OpenAI dashboard](https://platform.openai.com/account/api-keys) and `ANTHROPIC_API_KEY` on your [Anthropic dashboard](https://console.anthropic.com/account/keys)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\"\n",
|
||||
"os.environ[\"ANTHROPIC_API_KEY\"] = \"xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: anthropic\n",
|
||||
" config:\n",
|
||||
" model: 'claude-instant-1'\n",
|
||||
" temperature: 0.5\n",
|
||||
" top_p: 1\n",
|
||||
" stream: false\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('anthropic.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Amzxk3m-i3tD"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"anthropic.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 52
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "dc17baec-39b5-4dc8-bd42-f2aad92697eb"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 391
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "3d1cb7ce-969e-4dad-d48c-b818b7447cc0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "63ab5e89",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Cookbook for using Azure OpenAI with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e32a0265",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b80ff15a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ac982a56",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-2: Set Azure OpenAI related environment variables\n",
|
||||
"\n",
|
||||
"You can find these env variables on your Azure OpenAI dashboard."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e0a36133",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_TYPE\"] = \"azure\"\n",
|
||||
"os.environ[\"OPENAI_API_BASE\"] = \"https://xxx.openai.azure.com/\"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"xxx\"\n",
|
||||
"os.environ[\"OPENAI_API_VERSION\"] = \"xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7d7b554e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b9f52fc5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: azure_openai\n",
|
||||
" model: gpt-35-turbo\n",
|
||||
" config:\n",
|
||||
" deployment_name: ec_openai_azure\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 1\n",
|
||||
" stream: false\n",
|
||||
"\n",
|
||||
"embedder:\n",
|
||||
" provider: azure_openai\n",
|
||||
" config:\n",
|
||||
" model: text-embedding-ada-002\n",
|
||||
" deployment_name: ec_embeddings_ada_002\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('azure_openai.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "98a11130",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1ee9bdd9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"azure_openai.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "554dc97b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "686ae765",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ccc7d421",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "27868a7d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e1f2ead5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.4"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Cookbook for using ChromaDB with Embedchain"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "-NbXjAdlh0vJ"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-2: Set OpenAI environment variables\n",
|
||||
"\n",
|
||||
"You can find this env variable on your [OpenAI dashboard](https://platform.openai.com/account/api-keys)."
|
||||
],
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\""
|
||||
],
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-3: Define your Vector Database config"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"vectordb:\n",
|
||||
" provider: chroma\n",
|
||||
" config:\n",
|
||||
" collection_name: 'my-collection'\n",
|
||||
" # CHANGE THE BELOW TWO LINES!\n",
|
||||
" # pass remote database variables - host and port\n",
|
||||
" host: your-chromadb-url.com\n",
|
||||
" port: 5200\n",
|
||||
" allow_reset: true\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('chromadb.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"chromadb.yaml\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Amzxk3m-i3tD"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Sn_0rx9QjIY9"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "cvIK7dWRjN_f"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using Cohere with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "fae77912-4e6a-4c78-fcb7-fbbe46f7a9c7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set Cohere related environment variables and install the dependencies\n",
|
||||
"\n",
|
||||
"You can find `OPENAI_API_KEY` on your [OpenAI dashboard](https://platform.openai.com/account/api-keys) and `COHERE_API_KEY` key on your [Cohere dashboard](https://dashboard.cohere.com/api-keys)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000
|
||||
},
|
||||
"id": "S5jTywPZNtrj",
|
||||
"outputId": "4a23c813-c9e5-4b6c-e3d9-b41e4fdbc54d"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain[cohere]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\"\n",
|
||||
"os.environ[\"COHERE_API_KEY\"] = \"xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: cohere\n",
|
||||
" config:\n",
|
||||
" model: gptd-instruct-tft\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 1\n",
|
||||
" stream: false\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('cohere.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 321
|
||||
},
|
||||
"id": "Amzxk3m-i3tD",
|
||||
"outputId": "afe8afde-5cb8-46bc-c541-3ad26cc3fa6e"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"cohere.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 176
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "2f2718a4-3b7e-4844-fd46-3e0857653ca0"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "79e873c8-9594-45da-f5a3-0a893511267f"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Cookbook for using ElasticSearchDB with Embedchain"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "-NbXjAdlh0vJ"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-2: Set OpenAI environment variables and install the dependencies.\n",
|
||||
"\n",
|
||||
"You can find this env variable on your [OpenAI dashboard](https://platform.openai.com/account/api-keys). Now lets install the dependencies needed for Elasticsearch."
|
||||
],
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"!pip install --upgrade 'embedchain[elasticsearch]'"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "-MUFRfxV7Jk7"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\""
|
||||
],
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-3: Define your Vector Database config"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"vectordb:\n",
|
||||
" provider: elasticsearch\n",
|
||||
" config:\n",
|
||||
" collection_name: 'es-index'\n",
|
||||
" es_url: your-elasticsearch-url.com\n",
|
||||
" allow_reset: true\n",
|
||||
" api_key: xxx\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('elasticsearch.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"elasticsearch.yaml\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Amzxk3m-i3tD"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Sn_0rx9QjIY9"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "cvIK7dWRjN_f"
|
||||
},
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using GPT4All with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "077fa470-b51f-4c29-8c22-9c5f0a9cef47"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set GPT4ALL related environment variables and install dependencies\n",
|
||||
"\n",
|
||||
"GPT4All is free for all and doesn't require any API Key to use it. Just import the dependencies."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "dGOE4u3dC6at",
|
||||
"outputId": "c1c0087b-3f14-49fa-fb86-a4a3391ba14c"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install --upgrade embedchain[opensource]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from embedchain import App"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: gpt4all\n",
|
||||
" config:\n",
|
||||
" model: 'orca-mini-3b.ggmlv3.q4_0.bin'\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 1\n",
|
||||
" stream: false\n",
|
||||
"\n",
|
||||
"embedder:\n",
|
||||
" provider: gpt4all\n",
|
||||
" config:\n",
|
||||
" model: 'all-MiniLM-L6-v2'\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('gpt4all.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "Amzxk3m-i3tD",
|
||||
"outputId": "775db99b-e217-47db-f87f-788495d86f26"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"gpt4all.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 52
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "c6514f17-3cb2-4fbc-c80d-79b3a311ff30"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 480
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "c74f356a-d2fb-426d-b36c-d84911397338"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using Hugging Face Hub with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "35ddc904-8067-44cf-dcc9-3c8b4cd29989"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set Hugging Face Hub related environment variables and install dependencies\n",
|
||||
"\n",
|
||||
"You can find your `HUGGINGFACE_ACCESS_TOKEN` key on your [Hugging Face Hub dashboard](https://huggingface.co/settings/tokens) and install the dependencies"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "VfDNZJCqNfqo",
|
||||
"outputId": "34894d35-7142-42ee-8564-2e9f718afcbb"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain[huggingface-hub]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "SCNT8khqcR3G",
|
||||
"outputId": "b789ee77-ef50-4330-8ac6-5da645dc36d6"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain[opensource]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"HUGGINGFACE_ACCESS_TOKEN\"] = \"hf_xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: huggingface\n",
|
||||
" config:\n",
|
||||
" model: 'google/flan-t5-xxl'\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 0.8\n",
|
||||
" stream: false\n",
|
||||
"\n",
|
||||
"embedder:\n",
|
||||
" provider: huggingface\n",
|
||||
" config:\n",
|
||||
" model: 'sentence-transformers/all-mpnet-base-v2'\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('huggingface.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Amzxk3m-i3tD"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"huggingface.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 70
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "3c2a803a-3a93-4b0d-a6ae-17ae3c96c3c2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "47a89d1c-b322-495c-822a-6c2ecef894d2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "HvZVn6gU5xB_"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using JinaChat with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 1000
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "69cb79a6-c758-4656-ccf7-9f3105c81d16"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set JinaChat related environment variables\n",
|
||||
"\n",
|
||||
"You can find `OPENAI_API_KEY` on your [OpenAI dashboard](https://platform.openai.com/account/api-keys) and `JINACHAT_API_KEY` key on your [Chat Jina dashboard](https://chat.jina.ai/api)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\"\n",
|
||||
"os.environ[\"JINACHAT_API_KEY\"] = \"xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: jina\n",
|
||||
" config:\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 1\n",
|
||||
" stream: false\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('jina.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 321
|
||||
},
|
||||
"id": "Amzxk3m-i3tD",
|
||||
"outputId": "8d00da74-5f73-49bb-b868-dcf1c375ac85"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"jina.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 52
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "10eeacc7-9263-448e-876d-002af897ebe5"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "7dc7212f-a0e9-43c8-f119-f595ba79b4b7"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b02n_zJ_hl3d"
|
||||
},
|
||||
"source": [
|
||||
"## Cookbook for using LLAMA2 with Embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "gyJ6ui2vhtMY"
|
||||
},
|
||||
"source": [
|
||||
"### Step-1: Install embedchain package"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"id": "-NbXjAdlh0vJ",
|
||||
"outputId": "86a4a9b2-4ed6-431c-da6f-c3eacb390f42"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "nGnpSYAAh2bQ"
|
||||
},
|
||||
"source": [
|
||||
"### Step-2: Set LLAMA2 related environment variables and install dependencies\n",
|
||||
"\n",
|
||||
"You can find `OPENAI_API_KEY` on your [OpenAI dashboard](https://platform.openai.com/account/api-keys) and `REPLICATE_API_TOKEN` key on your [Replicate dashboard](https://replicate.com/account/api-tokens). Now lets install the dependencies for LLAMA2."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "qoBUbocNtUUD"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!pip install embedchain[llama2]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "0fBdQ9GAiRvK"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"from embedchain import App\n",
|
||||
"\n",
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"sk-xxx\"\n",
|
||||
"os.environ[\"REPLICATE_API_TOKEN\"] = \"xxx\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Ns6RhPfbiitr"
|
||||
},
|
||||
"source": [
|
||||
"### Step-3: Define your llm and embedding model config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "S9CkxVjriotB"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"config = \"\"\"\n",
|
||||
"llm:\n",
|
||||
" provider: llama2\n",
|
||||
" config:\n",
|
||||
" model: 'a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5'\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 0.5\n",
|
||||
" stream: false\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"# Write the multi-line string to a YAML file\n",
|
||||
"with open('llama2.yaml', 'w') as file:\n",
|
||||
" file.write(config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "PGt6uPLIi1CS"
|
||||
},
|
||||
"source": [
|
||||
"### Step-4 Create embedchain app based on the config"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "Amzxk3m-i3tD"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app = App.from_config(yaml_path=\"llama2.yaml\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "XNXv4yZwi7ef"
|
||||
},
|
||||
"source": [
|
||||
"### Step-5: Add data sources to your app"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 52
|
||||
},
|
||||
"id": "Sn_0rx9QjIY9",
|
||||
"outputId": "ba158e9c-0f16-4c6b-a876-7543120985a2"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"app.add(\"https://www.forbes.com/profile/elon-musk\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "_7W6fDeAjMAP"
|
||||
},
|
||||
"source": [
|
||||
"### Step-6: All set. Now start asking questions related to your data"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/",
|
||||
"height": 599
|
||||
},
|
||||
"id": "cvIK7dWRjN_f",
|
||||
"outputId": "e2d11a25-a2ed-4034-ec6a-e8a5986c89ae"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"while(True):\n",
|
||||
" question = input(\"Enter question: \")\n",
|
||||
" if question in ['q', 'exit', 'quit']:\n",
|
||||
" break\n",
|
||||
" answer = app.query(question)\n",
|
||||
" print(answer)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"provenance": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "python"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user