Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1364975396 | |||
| deaa7f50f8 | |||
| 744ab5156f | |||
| c45413969a | |||
| b314e5e080 | |||
| 17129e2eaa | |||
| 654fd8d74c | |||
| 9d3568ef75 | |||
| 14712cac88 | |||
| 0d568c758b | |||
| 7c6b88c7c5 | |||
| 32c93be46e | |||
| 7de8d85199 | |||
| f7dd65a3de | |||
| d8cdbe0041 | |||
| 2b8b6d3ea9 | |||
| 936c7e389f | |||
| 6864b4207b | |||
| 98eb5b54be | |||
| 3332e6e236 | |||
| 0533da72d7 | |||
| a1de238716 | |||
| f0d112254b | |||
| 830a7397ef | |||
| 5428765329 |
@@ -1,74 +1,64 @@
|
||||
# embedchain
|
||||
<p align="center">
|
||||
<img src="docs/logo/dark.svg" width="400px" alt="Embedchain Logo">
|
||||
</p>
|
||||
|
||||
<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>
|
||||
<p align="center">
|
||||
<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>
|
||||
</p>
|
||||
|
||||
[](https://pypi.org/project/embedchain/)
|
||||
[](https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw)
|
||||
[](https://discord.gg/CUU9FPhRNt)
|
||||
[](https://twitter.com/embedchain)
|
||||
[](https://embedchain.substack.com/)
|
||||
[](https://colab.research.google.com/drive/138lMWhENGeEu7Q1-6lNbNTHGLZXBBz_B?usp=sharing)
|
||||
[](https://codecov.io/gh/embedchain/embedchain)
|
||||
<p align="center">
|
||||
<a href="https://pypi.org/project/embedchain/">
|
||||
<img src="https://img.shields.io/pypi/v/embedchain" alt="PyPI">
|
||||
</a>
|
||||
<a href="https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw">
|
||||
<img src="https://img.shields.io/badge/slack-embedchain-brightgreen.svg?logo=slack" alt="Slack">
|
||||
</a>
|
||||
<a href="https://discord.gg/CUU9FPhRNt">
|
||||
<img src="https://dcbadge.vercel.app/api/server/6PzXDgEjG5?style=flat" alt="Discord">
|
||||
</a>
|
||||
<a href="https://twitter.com/embedchain">
|
||||
<img src="https://img.shields.io/twitter/follow/embedchain" alt="Twitter">
|
||||
</a>
|
||||
<a href="https://embedchain.substack.com/">
|
||||
<img src="https://img.shields.io/badge/Substack-%23006f5c.svg?logo=substack" alt="Substack">
|
||||
</a>
|
||||
<a href="https://colab.research.google.com/drive/138lMWhENGeEu7Q1-6lNbNTHGLZXBBz_B?usp=sharing">
|
||||
<img src="https://camo.githubusercontent.com/84f0493939e0c4de4e6dbe113251b4bfb5353e57134ffd9fcab6b8714514d4d1/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667" alt="Open in Colab">
|
||||
</a>
|
||||
<a href="https://codecov.io/gh/embedchain/embedchain">
|
||||
<img src="https://codecov.io/gh/embedchain/embedchain/graph/badge.svg?token=EMRRHZXW1Q" alt="codecov">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
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)
|
||||
<hr />
|
||||
|
||||
## Community
|
||||
|
||||
* Join embedchain community on slack by accepting [this invite](https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw)
|
||||
|
||||
## 🤝 Schedule a 1-on-1 Session
|
||||
|
||||
Book a [1-on-1 Session](https://cal.com/taranjeetio/ec) with Taranjeet, the founder, to discuss any issues, provide feedback, or explore how we can improve Embedchain for you.
|
||||
## What is Embedchain?
|
||||
Embedchain is a Data Platform for Large Language Models (LLMs). Seamlessly load, index, retrieve, and sync unstructured data to build dynamic, LLM-powered applications. Check out [embedchain-js](https://github.com/embedchain/embedchain/tree/main/embedchain-js) for a JavaScript implementation.
|
||||
|
||||
## 🔧 Quick install
|
||||
|
||||
### Python API
|
||||
```bash
|
||||
pip install --upgrade embedchain
|
||||
```
|
||||
|
||||
To run Embedchain as a REST API server run the following command:
|
||||
### REST API
|
||||
You can also run Embedchain as a REST API server using the following command:
|
||||
|
||||
```bash
|
||||
docker run -d --name embedchain -p 8080:8080 embedchain/rest-api:latest
|
||||
docker run --name embedchain -p 8080:8080 embedchain/rest-api:latest
|
||||
```
|
||||
|
||||
Navigate to http://0.0.0.0:8080/docs to interact with the API.
|
||||
Then, navigate to http://0.0.0.0:8080/docs to interact with the API.
|
||||
|
||||
## 🔍 Demo
|
||||
## 🔍 Usage and Demo
|
||||
|
||||
Try out embedchain in your browser:
|
||||
<!-- Demo GIF or Image -->
|
||||
<p align="center">
|
||||
<img src="docs/images/cover.gif" width="900px" alt="Embedchain Demo">
|
||||
</p>
|
||||
|
||||
[](https://colab.research.google.com/drive/17ON1LPonnXAtLaZEebnOktstB_1cJJmh?usp=sharing)
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
The documentation for embedchain can be found at [docs.embedchain.ai](https://docs.embedchain.ai).
|
||||
|
||||
## 💻 Usage
|
||||
|
||||
Embedchain empowers you to create ChatGPT like apps, on your own dynamic dataset.
|
||||
|
||||
### Data types supported
|
||||
|
||||
* Youtube video
|
||||
* PDF file
|
||||
* CSV file
|
||||
* Web page
|
||||
* MDX file
|
||||
* XML file
|
||||
* Sitemap
|
||||
* Doc file
|
||||
* 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/).
|
||||
|
||||
### Queries
|
||||
|
||||
For example, you can use Embedchain to create an Elon Musk bot using the following code:
|
||||
For example, you can create an Elon Musk bot using the following code:
|
||||
|
||||
```python
|
||||
import os
|
||||
@@ -99,35 +89,27 @@ app.deploy()
|
||||
# ✅ Data of type: web_page, value: https://www.forbes.com/profile/elon-musk added successfully.
|
||||
```
|
||||
|
||||
## Examples
|
||||
You can also try it in your browser with Google Colab:
|
||||
|
||||
| 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) |
|
||||
[](https://colab.research.google.com/drive/17ON1LPonnXAtLaZEebnOktstB_1cJJmh?usp=sharing)
|
||||
|
||||
| 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) |
|
||||
## 📖 Documentation
|
||||
Comprehensive guides and API documentation are available to help you get the most out of Embedchain:
|
||||
|
||||
| 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) |
|
||||
- [Getting Started](https://docs.embedchain.ai/get-started/quickstart)
|
||||
- [Introduction](https://docs.embedchain.ai/get-started/introduction#what-is-embedchain)
|
||||
- [Examples](https://docs.embedchain.ai/get-started/examples)
|
||||
- [Supported data types](https://docs.embedchain.ai/data-sources/)
|
||||
|
||||
## 🤝 Contributing
|
||||
## 🔗 Join the Community
|
||||
|
||||
Connect with fellow developers and users by joining our [Slack Workspace](https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw). Dive into discussions, ask questions, and share your experiences.
|
||||
|
||||
## 🤝 Schedule a 1-on-1 Session
|
||||
|
||||
Book a [1-on-1 Session](https://cal.com/taranjeetio/ec) with Taranjeet, the founder, to discuss any issues, provide feedback, or explore how we can improve Embedchain for you.
|
||||
|
||||
## 🌐 Contributing
|
||||
|
||||
Contributions are welcome! Please check out the issues on the repository, and feel free to open a pull request.
|
||||
For more information, please see the [contributing guidelines](CONTRIBUTING.md).
|
||||
|
||||
+1
-1
@@ -23,4 +23,4 @@ embedder:
|
||||
provider: openai
|
||||
config:
|
||||
model: 'text-embedding-ada-002'
|
||||
deployment_name: null
|
||||
deployment_name: 'test-deployment'
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
chunker:
|
||||
chunk_size: 100
|
||||
chunk_overlap: 20
|
||||
length_function: 'len'
|
||||
@@ -2,6 +2,11 @@ app:
|
||||
config:
|
||||
id: 'full-stack-app'
|
||||
|
||||
chunker:
|
||||
chunk_size: 100
|
||||
chunk_overlap: 20
|
||||
length_function: 'len'
|
||||
|
||||
llm:
|
||||
provider: openai
|
||||
config:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
app:
|
||||
config:
|
||||
id: 'my-app'
|
||||
log_level: 'WARN'
|
||||
log_level: 'WARNING'
|
||||
collect_metrics: true
|
||||
collection_name: 'my-app'
|
||||
|
||||
@@ -30,4 +30,4 @@ embedder:
|
||||
provider: openai
|
||||
config:
|
||||
model: 'text-embedding-ada-002'
|
||||
deployment_name: null
|
||||
deployment_name: 'my-app'
|
||||
|
||||
@@ -7,7 +7,7 @@ app:
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
@@ -23,4 +23,4 @@ vectordb:
|
||||
embedder:
|
||||
provider: gpt4all
|
||||
config:
|
||||
deployment_name: null
|
||||
deployment_name: 'test-deployment'
|
||||
|
||||
@@ -13,7 +13,7 @@ vectordb:
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<Tip>
|
||||
If you can't find the specific data source, please feel free to request through one of the following channels and help us prioritize.
|
||||
<p>If you can't find the specific data source, please feel free to request through one of the following channels and help us prioritize.</p>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Slack" icon="slack" href="https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw" color="#4A154B">
|
||||
@@ -15,4 +14,3 @@ If you can't find the specific data source, please feel free to request through
|
||||
Schedule a call with Embedchain founder
|
||||
</Card>
|
||||
</CardGroup>
|
||||
</Tip>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<Tip>
|
||||
If you can't find the specific LLM you need, no need to fret. We're continuously expanding our support for additional LLMs, and you can help us prioritize by opening an issue on our GitHub or simply reaching out to us on our Slack or Discord community.
|
||||
<p>If you can't find the specific LLM you need, no need to fret. We're continuously expanding our support for additional LLMs, and you can help us prioritize by opening an issue on our GitHub or simply reaching out to us on our Slack or Discord community.</p>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Slack" icon="slack" href="https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw" color="#4A154B">
|
||||
@@ -15,4 +14,3 @@ If you can't find the specific LLM you need, no need to fret. We're continuously
|
||||
Schedule a call with Embedchain founder
|
||||
</Card>
|
||||
</CardGroup>
|
||||
</Tip>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<Tip>
|
||||
If you can't find the specific vector database, please feel free to request through one of the following channels and help us prioritize.
|
||||
|
||||
|
||||
<p>If you can't find the specific vector database, please feel free to request through one of the following channels and help us prioritize.</p>
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Slack" icon="slack" href="https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw" color="#4A154B">
|
||||
@@ -15,4 +16,3 @@ If you can't find the specific vector database, please feel free to request thro
|
||||
Schedule a call with Embedchain founder
|
||||
</Card>
|
||||
</CardGroup>
|
||||
</Tip>
|
||||
|
||||
@@ -11,6 +11,11 @@ app:
|
||||
config:
|
||||
id: 'full-stack-app'
|
||||
|
||||
chunker:
|
||||
chunk_size: 100
|
||||
chunk_overlap: 20
|
||||
length_function: 'len'
|
||||
|
||||
llm:
|
||||
provider: openai
|
||||
config:
|
||||
@@ -49,7 +54,11 @@ Alright, let's dive into what each key means in the yaml config above:
|
||||
1. `app` Section:
|
||||
- `config`:
|
||||
- `id` (String): The ID or name of your full-stack application.
|
||||
2. `llm` Section:
|
||||
2. `chunker` Section:
|
||||
- `chunk_size` (Integer): The size of each chunk of text that is sent to the language model.
|
||||
- `chunk_overlap` (Integer): The amount of overlap between each chunk of text.
|
||||
- `length_function` (String): The function used to calculate the length of each chunk of text. In this case, it's set to 'len'. You can also use any function import directly as a string here.
|
||||
3. `llm` Section:
|
||||
- `provider` (String): The provider for the language model, which is set to 'openai'. You can find the full list of llm providers in [our docs](/components/llms).
|
||||
- `model` (String): The specific model being used, 'gpt-3.5-turbo'.
|
||||
- `config`:
|
||||
@@ -59,13 +68,13 @@ Alright, let's dive into what each key means in the yaml config above:
|
||||
- `stream` (Boolean): Controls if the response is streamed back to the user (set to false).
|
||||
- `template` (String): A custom template for the prompt that the model uses to generate responses.
|
||||
- `system_prompt` (String): A system prompt for the model to follow when generating responses, in this case, it's set to the style of William Shakespeare.
|
||||
3. `vectordb` Section:
|
||||
4. `vectordb` Section:
|
||||
- `provider` (String): The provider for the vector database, set to 'chroma'. You can find the full list of vector database providers in [our docs](/components/vector-databases).
|
||||
- `config`:
|
||||
- `collection_name` (String): The initial collection name for the database, set to 'full-stack-app'.
|
||||
- `dir` (String): The directory for the database, set to 'db'.
|
||||
- `allow_reset` (Boolean): Indicates whether resetting the database is allowed, set to true.
|
||||
4. `embedder` Section:
|
||||
5. `embedder` Section:
|
||||
- `provider` (String): The provider for the embedder, set to 'openai'. You can find the full list of embedding model providers in [our docs](/components/embedding-models).
|
||||
- `config`:
|
||||
- `model` (String): The specific model used for text embedding, 'text-embedding-ada-002'.
|
||||
|
||||
@@ -100,7 +100,7 @@ app = App.from_config(yaml_path="config.yaml")
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -190,7 +190,7 @@ app = App.from_config(yaml_path="config.yaml")
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -138,7 +138,7 @@ app = App.from_config(yaml_path="config.yaml")
|
||||
vectordb:
|
||||
provider: zilliz
|
||||
config:
|
||||
collection_name: 'zilliz-app'
|
||||
collection_name: 'zilliz_app'
|
||||
uri: https://xxxx.api.gcp-region.zillizcloud.com
|
||||
token: xxx
|
||||
vector_dim: 1536
|
||||
|
||||
@@ -24,12 +24,11 @@ To use this you need to save `credentials.json` in the directory from where you
|
||||
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
|
||||
from embedchain import Pipeline as App
|
||||
|
||||
app = App()
|
||||
|
||||
query = "to: me label:inbox"
|
||||
app.add(query, data_type=DataType.GMAIL)
|
||||
gmail_filter = "to: me label:inbox"
|
||||
app.add(gmail_filter, data_type="gmail")
|
||||
app.query("Summarize my email conversations")
|
||||
```
|
||||
+17
-26
@@ -2,52 +2,43 @@
|
||||
title: '📃 JSON'
|
||||
---
|
||||
|
||||
To add any json file, use the data_type as `json`. Headers are included for each line, so if you have an `age` column, `18` will be added as `age: 18`. Eg:
|
||||
To add any json file, use the data_type as `json`. Headers are included for each line, so for example if you have a json like `{"age": 18}`, then it will be added as `age: 18`.
|
||||
|
||||
Here are the supported sources for loading `json`:
|
||||
|
||||
```
|
||||
1. URL - valid url to json file that ends with ".json" extension.
|
||||
2. Local file - valid url to local json file that ends with ".json" extension.
|
||||
3. String - valid json string (e.g. - app.add('{"foo": "bar"}'))
|
||||
```
|
||||
|
||||
If you would like to add other data structures (e.x. list, dict etc.), do:
|
||||
```
|
||||
import json
|
||||
a = {"foo": "bar"}
|
||||
valid_json_string_data = json.dumps(a, indent=0)
|
||||
<Tip>
|
||||
If you would like to add other data structures (e.g. list, dict etc.), convert it to a valid json first using `json.dumps()` function.
|
||||
</Tip>
|
||||
|
||||
b = [{"foo": "bar"}]
|
||||
valid_json_string_data = json.dumps(b, indent=0)
|
||||
```
|
||||
Example:
|
||||
```
|
||||
import os
|
||||
## Example
|
||||
|
||||
from embedchain.apps.app import App
|
||||
<CodeGroup>
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "openai_api_key"
|
||||
```python python
|
||||
from embedchain import Pipeline as App
|
||||
|
||||
app = App()
|
||||
|
||||
response = app.query("What is the net worth of Elon Musk as of October 2023?")
|
||||
# Add json file
|
||||
app.add("temp.json")
|
||||
|
||||
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
|
||||
app.query("What is the net worth of Elon Musk as of October 2023?")
|
||||
# As of October 2023, Elon Musk's net worth is $255.2 billion.
|
||||
```
|
||||
|
||||
|
||||
```json 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."
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
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:
|
||||
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.
|
||||
|
||||
```python
|
||||
from embedchain.apps.app import App
|
||||
import os
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "sk-xxx"
|
||||
from embedchain import Pipeline as App
|
||||
|
||||
app = App()
|
||||
|
||||
@@ -16,8 +13,10 @@ app.add("https://github.com/openai/openai-openapi/blob/master/openapi.yaml", dat
|
||||
# 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?")
|
||||
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)
|
||||
<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)
|
||||
</Note>
|
||||
@@ -20,6 +20,7 @@ Embedchain comes with built-in support for various data sources. We handle the c
|
||||
<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>
|
||||
<Card title="🐘 Postgres" href="/data-sources/postgres"></Card>
|
||||
</CardGroup>
|
||||
|
||||
<br/ >
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
title: '🐘 Postgres'
|
||||
---
|
||||
|
||||
1. Setup the Postgres loader by configuring the postgres db.
|
||||
```Python
|
||||
from embedchain.loaders.postgres import PostgresLoader
|
||||
|
||||
config = {
|
||||
"host": "host_address",
|
||||
"port": "port_number",
|
||||
"dbname": "database_name",
|
||||
"user": "username",
|
||||
"password": "password",
|
||||
}
|
||||
|
||||
"""
|
||||
config = {
|
||||
"url": "your_postgres_url"
|
||||
}
|
||||
"""
|
||||
|
||||
postgres_loader = PostgresLoader(config=config)
|
||||
|
||||
```
|
||||
|
||||
You can either setup the loader by passing the postgresql url or by providing the config data.
|
||||
For more details on how to setup with valid url and config, check postgres [documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING:~:text=34.1.1.%C2%A0Connection%20Strings-,%23,-Several%20libpq%20functions).
|
||||
|
||||
NOTE: if you provide the `url` field in config, all other fields will be ignored.
|
||||
|
||||
2. Once you setup the loader, you can create an app and load data using the above postgres loader
|
||||
```Python
|
||||
import os
|
||||
from embedchain.pipeline import Pipeline as App
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "sk-xxx"
|
||||
|
||||
app = App()
|
||||
|
||||
question = "What is Elon Musk's networth?"
|
||||
response = app.query(question)
|
||||
# Answer: As of September 2021, Elon Musk's net worth is estimated to be around $250 billion, making him one of the wealthiest individuals in the world. However, please note that net worth can fluctuate over time due to various factors such as stock market changes and business ventures.
|
||||
|
||||
app.add("SELECT * FROM table_name;", data_type='postgres', loader=postgres_loader)
|
||||
# Adds `(1, 'What is your net worth, Elon Musk?', "As of October 2023, Elon Musk's net worth is $255.2 billion.")`
|
||||
|
||||
response = app.query(question)
|
||||
# Answer: As of October 2023, Elon Musk's net worth is $255.2 billion.
|
||||
```
|
||||
|
||||
NOTE: The `add` function of the app will accept any executable query to load data. DO NOT pass the `CREATE`, `INSERT` queries in `add` function as they will result in not adding any data, so it is pointless.
|
||||
|
||||
3. We automatically create a chunker to chunk your postgres data, however if you wish to provide your own chunker class. Here is how you can do that:
|
||||
```Python
|
||||
|
||||
from embedchain.chunkers.postgres import PostgresChunker
|
||||
from embedchain.config.add_config import ChunkerConfig
|
||||
|
||||
postgres_chunker_config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||
postgres_chunker = PostgresChunker(config=postgres_chunker_config)
|
||||
|
||||
app.add("SELECT * FROM table_name;", data_type='postgres', loader=postgres_loader, chunker=postgres_chunker)
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: '🤖 Discord Bot'
|
||||
title: "🤖 Discord Bot"
|
||||
---
|
||||
|
||||
### 🔑 Keys Setup
|
||||
@@ -12,9 +12,11 @@ title: '🤖 Discord Bot'
|
||||
- On the left sidebar, click on `OAuth2` and go to `General`.
|
||||
- Set `Authorization Method` to `In-app Authorization`. Under `Scopes` select `bot`.
|
||||
- Under `Bot Permissions` allow the following and then click on `Save Changes`.
|
||||
|
||||
```text
|
||||
Send Messages (under Text Permissions)
|
||||
```
|
||||
|
||||
- Now under `OAuth2` and go to `URL Generator`. Under `Scopes` select `bot`.
|
||||
- Under `Bot Permissions` set the same permissions as above.
|
||||
- Now scroll down and copy the `Generated URL`. Paste it in a browser window and select the Server where you want to add the bot.
|
||||
@@ -23,40 +25,46 @@ Send Messages (under Text Permissions)
|
||||
|
||||
### Take the bot online
|
||||
|
||||
1. Install embedchain python package:
|
||||
<Tabs>
|
||||
<Tab title="docker">
|
||||
```bash
|
||||
docker run --name discord-bot -e OPENAI_API_KEY=sk-xxx -e DISCORD_BOT_TOKEN=xxx -p 8080:8080 embedchain/discord-bot:latest
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="python">
|
||||
```bash
|
||||
pip install --upgrade "embedchain[discord]"
|
||||
|
||||
```bash
|
||||
pip install --upgrade "embedchain[discord]"
|
||||
```
|
||||
python -m embedchain.bots.discord
|
||||
|
||||
2. Launch your Discord bot:
|
||||
|
||||
|
||||
```bash
|
||||
python -m embedchain.bots.discord
|
||||
```
|
||||
|
||||
If you prefer to see the question and not only the answer, run it with
|
||||
|
||||
```bash
|
||||
python -m embedchain.bots.discord --include-question
|
||||
```
|
||||
# or if you prefer to see the question and not only the answer, run it with
|
||||
python -m embedchain.bots.discord --include-question
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### 🚀 Usage Instructions
|
||||
|
||||
- Go to the server where you have added your bot.
|
||||

|
||||
- You can add data sources to the bot using the slash command:
|
||||
|
||||
```text
|
||||
/add <data_type> <url_or_text>
|
||||
/ec add <data_type> <url_or_text>
|
||||
```
|
||||
|
||||
- You can ask your queries from the bot using the slash command:
|
||||
|
||||
```text
|
||||
/query <question>
|
||||
/ec query <question>
|
||||
```
|
||||
|
||||
- You can chat with the bot using the slash command:
|
||||
|
||||
```text
|
||||
/chat <question>
|
||||
/ec chat <question>
|
||||
```
|
||||
|
||||
📝 Note: To use the bot privately, you can message the bot directly by right clicking the bot and selecting `Message`.
|
||||
|
||||
🎉 Happy Chatting! 🎉
|
||||
|
||||
@@ -8,14 +8,45 @@ 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.
|
||||
- Create a `docker-compose.yml` file and paste the following code in it.
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
backend:
|
||||
container_name: embedchain-backend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: backend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
frontend:
|
||||
container_name: embedchain-frontend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: frontend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- "backend"
|
||||
```
|
||||
|
||||
- Run the following command,
|
||||
|
||||
```bash
|
||||
docker-compose up --build
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
📝 Note: The build command might take a while to install all the packages depending on your system resources.
|
||||
|
||||

|
||||
|
||||
### 🚀 Usage Instructions
|
||||
|
||||
- Go to [http://localhost:3000/](http://localhost:3000/) in your browser to view the dashboard.
|
||||
|
||||
@@ -1,21 +1,46 @@
|
||||
---
|
||||
title: '📱 Telegram Bot'
|
||||
title: "📱 Telegram Bot"
|
||||
---
|
||||
|
||||
### 🖼️ Template Setup
|
||||
|
||||
- Fork [this](https://replit.com/@taranjeetio/EC-Telegram-Bot-Template?v=1#README.md) replit template.
|
||||
- Set your `OPENAI_API_KEY` in Secrets.
|
||||
- Open the Telegram app and search for the `BotFather` user.
|
||||
- Start a chat with BotFather and use the `/newbot` command to create a new bot.
|
||||
- Follow the instructions to choose a name and username for your bot.
|
||||
- Once the bot is created, BotFather will provide you with a unique token for your bot.
|
||||
- Set this token as `TELEGRAM_BOT_TOKEN` in Secrets.
|
||||
|
||||
<Tabs>
|
||||
<Tab title="docker">
|
||||
```bash
|
||||
docker run --name telegram-bot -e OPENAI_API_KEY=sk-xxx -e TELEGRAM_BOT_TOKEN=xxx -p 8000:8000 embedchain/telegram-bot
|
||||
```
|
||||
|
||||
<Note>
|
||||
If you wish to use **Docker**, you would need to host your bot on a server.
|
||||
You can use [ngrok](https://ngrok.com/) to expose your localhost to the
|
||||
internet and then set the webhook using the ngrok URL.
|
||||
</Note>
|
||||
|
||||
</Tab>
|
||||
<Tab title="replit">
|
||||
<Card>
|
||||
Fork <ins>**[this](https://replit.com/@taranjeetio/EC-Telegram-Bot-Template?v=1#README.md)**</ins> replit template.
|
||||
</Card>
|
||||
|
||||
- Set your `OPENAI_API_KEY` in Secrets.
|
||||
- Set the unique token as `TELEGRAM_BOT_TOKEN` in Secrets.
|
||||
|
||||
</Tab>
|
||||
|
||||
</Tabs>
|
||||
|
||||
- Click on `Run` in the replit container and a URL will get generated for your bot.
|
||||
- Now set your webhook by running the following link in your browser:
|
||||
|
||||
```url
|
||||
https://api.telegram.org/bot<Your_Telegram_Bot_Token>/setWebhook?url=<Replit_Generated_URL>
|
||||
```
|
||||
|
||||
- When you get a successful response in your browser, your bot is ready to be used.
|
||||
|
||||
### 🚀 Usage Instructions
|
||||
|
||||
@@ -12,10 +12,19 @@ pip install --upgrade embedchain
|
||||
|
||||
2. Launch your WhatsApp bot:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="docker">
|
||||
```bash
|
||||
docker run --name whatsapp-bot -e OPENAI_API_KEY=sk-xxx -p 8000:8000 embedchain/whatsapp-bot
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="python">
|
||||
```bash
|
||||
python -m embedchain.bots.whatsapp --port 5000
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
```bash
|
||||
python -m embedchain.bots.whatsapp --port 5000
|
||||
```
|
||||
|
||||
If your bot needs to be accessible online, use your machine's public IP or DNS. Otherwise, employ a proxy server like [ngrok](https://ngrok.com/) to make your local bot accessible.
|
||||
|
||||
|
||||
@@ -3,6 +3,38 @@ title: ❓ FAQs
|
||||
description: 'Collections of all the frequently asked questions'
|
||||
---
|
||||
|
||||
#### Does Embedchain support OpenAI's Assistant APIs?
|
||||
|
||||
Yes, it does. Please refer to the [OpenAI Assistant docs page](/get-started/openai-assistant).
|
||||
|
||||
#### How to use `gpt-4-turbo` model released on OpenAI DevDay?
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```python main.py
|
||||
import os
|
||||
from embedchain import Pipeline as App
|
||||
|
||||
os.environ['OPENAI_API_KEY'] = 'xxx'
|
||||
|
||||
# load llm configuration from gpt4_turbo.yaml file
|
||||
app = App.from_config(yaml_path="gpt4_turbo.yaml")
|
||||
```
|
||||
|
||||
```yaml gpt4_turbo.yaml
|
||||
llm:
|
||||
provider: openai
|
||||
config:
|
||||
model: 'gpt-4-turbo'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
stream: false
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
#### How to use GPT-4 as the LLM model?
|
||||
|
||||
<CodeGroup>
|
||||
@@ -48,7 +80,7 @@ app = App.from_config(yaml_path="opensource.yaml")
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
title: '🤖 OpenAI Assistant'
|
||||
---
|
||||
|
||||
<img src="https://blogs.swarthmore.edu/its/wp-content/uploads/2022/05/openai.jpg" align="center" width="500" alt="OpenAI Logo"/>
|
||||
|
||||
Embedchain now supports [OpenAI Assistants API](https://platform.openai.com/docs/assistants/overview) which allows you to build AI assistants within your own applications. An Assistant has instructions and can leverage models, tools, and knowledge to respond to user queries.
|
||||
|
||||
At a high level, an integration of the Assistants API has the following flow:
|
||||
|
||||
1. Create an Assistant in the API by defining custom instructions and picking a model
|
||||
2. Create a Thread when a user starts a conversation
|
||||
3. Add Messages to the Thread as the user ask questions
|
||||
4. Run the Assistant on the Thread to trigger responses. This automatically calls the relevant tools.
|
||||
|
||||
Creating an OpenAI Assistant using Embedchain is very simple 3 step process.
|
||||
|
||||
## Step 1: Create OpenAI Assistant
|
||||
|
||||
Make sure that you have `OPENAI_API_KEY` set in the environment variable.
|
||||
|
||||
```python Initialize
|
||||
from embedchain.store.assistants import OpenAIAssistant
|
||||
|
||||
assistant = OpenAIAssistant(
|
||||
name="OpenAI DevDay Assistant",
|
||||
instructions="You are an organizer of OpenAI DevDay",
|
||||
)
|
||||
```
|
||||
|
||||
If you want to use the existing assistant, you can do something like this:
|
||||
|
||||
```python Initialize
|
||||
# Load an assistant and create a new thread
|
||||
assistant = OpenAIAssistant(assistant_id="asst_xxx")
|
||||
|
||||
# Load a specific thread for an assistant
|
||||
assistant = OpenAIAssistant(assistant_id="asst_xxx", thread_id="thread_xxx")
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
<ResponseField name="name" type="string">
|
||||
Name for your AI assistant
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="instructions" type="string">
|
||||
how the Assistant and model should behave or respond
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="assistant_id" type="string">
|
||||
Load existing OpenAI Assistant. If you pass this, you don't have to pass other arguments.
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="thread_id" type="string">
|
||||
Existing OpenAI thread id if exists
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="model" type="str" default="gpt-4-1106-preview">
|
||||
OpenAI model to use
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="tools" type="list">
|
||||
OpenAI tools to use. Default set to `[{"type": "retrieval"}]`
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="data_sources" type="list" default="[]">
|
||||
Add data sources to your assistant. You can add in the following format: `[{"source": "https://example.com", "data_type": "web_page"}]`
|
||||
</ResponseField>
|
||||
|
||||
<ResponseField name="telemetry" type="boolean" default="True">
|
||||
Anonymous telemetry (doesn't collect any user information or user's files). Used to improve the Embedchain package utilization. Default is `True`.
|
||||
</ResponseField>
|
||||
|
||||
## Step-2: Add data to thread
|
||||
|
||||
You can add any custom data source that is supported by Embedchain. Else, you can directly pass the file path on your local system and Embedchain propagates it to OpenAI Assistant.
|
||||
```python Add data
|
||||
assistant.add("/path/to/file.pdf")
|
||||
assistant.add("https://www.youtube.com/watch?v=U9mJuUkhUzk")
|
||||
assistant.add("https://openai.com/blog/new-models-and-developer-products-announced-at-devday")
|
||||
```
|
||||
|
||||
## Step-3: Chat with your Assistant
|
||||
```python Chat
|
||||
assistant.chat("How much OpenAI credits were offered to attendees during OpenAI DevDay?")
|
||||
# Response: 'Every attendee of OpenAI DevDay 2023 was offered $500 in OpenAI credits.'
|
||||
```
|
||||
|
||||
You can try it out yourself using the following Google Colab notebook:
|
||||
|
||||
<a href="https://colab.research.google.com/drive/1BKlXZYSl6AFRgiHZ5XIzXrXC_24kDYHQ?usp=sharing">
|
||||
<img src="https://camo.githubusercontent.com/84f0493939e0c4de4e6dbe113251b4bfb5353e57134ffd9fcab6b8714514d4d1/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667" alt="Open in Colab" />
|
||||
</a>
|
||||
|
||||
@@ -11,6 +11,10 @@ Install embedchain python package:
|
||||
pip install embedchain
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Embedchain now supports OpenAI's latest `gpt-4-turbo` model. Checkout the [docs here](/get-started/faq#how-to-use-gpt-4-turbo-model-released-on-openai-devday) on how to use it.
|
||||
</Tip>
|
||||
|
||||
Creating an app involves 3 steps:
|
||||
|
||||
<Steps>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.2 MiB |
+26
-20
@@ -3,38 +3,43 @@
|
||||
"name": "Embedchain",
|
||||
"logo": {
|
||||
"dark": "/logo/dark.svg",
|
||||
"light": "/logo/light.svg"
|
||||
"light": "/logo/light.svg",
|
||||
"href": "https://embedchain.ai/"
|
||||
},
|
||||
"favicon": "/favicon.png",
|
||||
"colors": {
|
||||
"primary": "#2B48EE",
|
||||
"light": "#2B48EE",
|
||||
"dark": "#2B48EE",
|
||||
"primary": "#3B2FC9",
|
||||
"light": "#6673FF",
|
||||
"dark": "#3B2FC9",
|
||||
"background": {
|
||||
"dark": "#020415"
|
||||
"dark": "#0f1117",
|
||||
"light": "#fff"
|
||||
}
|
||||
},
|
||||
"modeToggle": {
|
||||
"default": "dark"
|
||||
},
|
||||
"openapi": ["/rest-api.json"],
|
||||
"metadata": {
|
||||
"og:image": "/images/og.png",
|
||||
"twitter:site": "@embedchain"
|
||||
},
|
||||
"topAnchor": {
|
||||
"name": "Documentation",
|
||||
"icon": "book-open"
|
||||
},
|
||||
"anchors": [
|
||||
{
|
||||
"name": "Embedchain Platform",
|
||||
"icon": "tv",
|
||||
"url": "https://app.embedchain.ai/"
|
||||
},
|
||||
{
|
||||
"name": "Join our slack",
|
||||
"icon": "slack",
|
||||
"url": "https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw"
|
||||
}
|
||||
],
|
||||
"topbarLinks": [
|
||||
{
|
||||
"name": "Twitter",
|
||||
"url": "https://twitter.com/embedchain"
|
||||
},
|
||||
{
|
||||
"name": "Slack",
|
||||
"url": "https://join.slack.com/t/embedchain/shared_invite/zt-22uwz3c46-Zg7cIh5rOBteT_xe1jwLDw"
|
||||
},
|
||||
{
|
||||
"name": "Discord",
|
||||
"url": "https://discord.gg/6PzXDgEjG5"
|
||||
"name": "Create account",
|
||||
"url": "https://app.embedchain.ai/login/"
|
||||
}
|
||||
],
|
||||
"topbarCtaButton": {
|
||||
@@ -50,6 +55,7 @@
|
||||
"pages": [
|
||||
"get-started/quickstart",
|
||||
"get-started/introduction",
|
||||
"get-started/openai-assistant",
|
||||
"get-started/faq",
|
||||
"get-started/examples"
|
||||
]
|
||||
@@ -106,7 +112,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Examples",
|
||||
"group": "Use Cases",
|
||||
"pages": [
|
||||
"examples/full_stack",
|
||||
"examples/discord_bot",
|
||||
|
||||
+18
-2
@@ -2,7 +2,9 @@ from typing import Optional
|
||||
|
||||
import yaml
|
||||
|
||||
from embedchain.config import AppConfig, BaseEmbedderConfig, BaseLlmConfig
|
||||
from embedchain.client import Client
|
||||
from embedchain.config import (AppConfig, BaseEmbedderConfig, BaseLlmConfig,
|
||||
ChunkerConfig)
|
||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||
from embedchain.embedchain import EmbedChain
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
@@ -11,6 +13,7 @@ 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.utils import validate_yaml_config
|
||||
from embedchain.vectordb.base import BaseVectorDB
|
||||
from embedchain.vectordb.chroma import ChromaDB
|
||||
|
||||
@@ -37,6 +40,7 @@ class App(EmbedChain):
|
||||
embedder: BaseEmbedder = None,
|
||||
embedder_config: Optional[BaseEmbedderConfig] = None,
|
||||
system_prompt: Optional[str] = None,
|
||||
chunker: Optional[ChunkerConfig] = None,
|
||||
):
|
||||
"""
|
||||
Initialize a new `App` instance.
|
||||
@@ -64,6 +68,9 @@ class App(EmbedChain):
|
||||
:type system_prompt: Optional[str], optional
|
||||
:raises TypeError: LLM, database or embedder or their config is not a valid class instance.
|
||||
"""
|
||||
# Setup user directory if it doesn't exist already
|
||||
Client.setup_dir()
|
||||
|
||||
# Type check configs
|
||||
if config and not isinstance(config, AppConfig):
|
||||
raise TypeError(
|
||||
@@ -96,6 +103,9 @@ class App(EmbedChain):
|
||||
if embedder is None:
|
||||
embedder = OpenAIEmbedder(config=embedder_config)
|
||||
|
||||
self.chunker = None
|
||||
if chunker:
|
||||
self.chunker = ChunkerConfig(**chunker)
|
||||
# Type check assignments
|
||||
if not isinstance(llm, BaseLlm):
|
||||
raise TypeError(
|
||||
@@ -127,10 +137,16 @@ class App(EmbedChain):
|
||||
with open(yaml_path, "r") as file:
|
||||
config_data = yaml.safe_load(file)
|
||||
|
||||
try:
|
||||
validate_yaml_config(config_data)
|
||||
except Exception as e:
|
||||
raise Exception(f"❌ Error occurred while validating the YAML config. Error: {str(e)}")
|
||||
|
||||
app_config_data = config_data.get("app", {})
|
||||
llm_config_data = config_data.get("llm", {})
|
||||
db_config_data = config_data.get("vectordb", {})
|
||||
embedding_model_config_data = config_data.get("embedding_model", config_data.get("embedder", {}))
|
||||
chunker_config_data = config_data.get("chunker", {})
|
||||
|
||||
app_config = AppConfig(**app_config_data.get("config", {}))
|
||||
|
||||
@@ -142,4 +158,4 @@ class App(EmbedChain):
|
||||
|
||||
embedder_provider = embedding_model_config_data.get("provider", "openai")
|
||||
embedder = EmbedderFactory.create(embedder_provider, embedding_model_config_data.get("config", {}))
|
||||
return cls(config=app_config, llm=llm, db=db, embedder=embedder)
|
||||
return cls(config=app_config, llm=llm, db=db, embedder=embedder, chunker=chunker_config_data)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Any
|
||||
|
||||
from embedchain import App
|
||||
from embedchain.config import AddConfig, AppConfig, BaseLlmConfig
|
||||
from embedchain import Pipeline as App
|
||||
from embedchain.config import AddConfig, BaseLlmConfig, PipelineConfig
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.helper.json_serializable import (JSONSerializable,
|
||||
register_deserializable)
|
||||
@@ -12,7 +12,7 @@ from embedchain.vectordb.chroma import ChromaDB
|
||||
@register_deserializable
|
||||
class BaseBot(JSONSerializable):
|
||||
def __init__(self):
|
||||
self.app = App(config=AppConfig(), llm=OpenAILlm(), db=ChromaDB(), embedder=OpenAIEmbedder())
|
||||
self.app = App(config=PipelineConfig(), llm=OpenAILlm(), db=ChromaDB(), embedding_model=OpenAIEmbedder())
|
||||
|
||||
def add(self, data: Any, config: AddConfig = None):
|
||||
"""
|
||||
|
||||
@@ -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 PostgresChunker(BaseChunker):
|
||||
"""Chunker for postgres."""
|
||||
|
||||
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)
|
||||
@@ -5,7 +5,7 @@ import uuid
|
||||
|
||||
import requests
|
||||
|
||||
from embedchain.embedchain import CONFIG_DIR, CONFIG_FILE
|
||||
from embedchain.constants import CONFIG_DIR, CONFIG_FILE
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import builtins
|
||||
from importlib import import_module
|
||||
from typing import Callable, Optional
|
||||
|
||||
from embedchain.config.base_config import BaseConfig
|
||||
@@ -18,7 +20,18 @@ class ChunkerConfig(BaseConfig):
|
||||
):
|
||||
self.chunk_size = chunk_size if chunk_size else 2000
|
||||
self.chunk_overlap = chunk_overlap if chunk_overlap else 0
|
||||
self.length_function = length_function if length_function else len
|
||||
if isinstance(length_function, str):
|
||||
self.length_function = self.load_func(length_function)
|
||||
else:
|
||||
self.length_function = length_function if length_function else len
|
||||
|
||||
def load_func(self, dotpath: str):
|
||||
if "." not in dotpath:
|
||||
return getattr(builtins, dotpath)
|
||||
else:
|
||||
module_, func = dotpath.rsplit(".", maxsplit=1)
|
||||
m = import_module(module_)
|
||||
return getattr(m, func)
|
||||
|
||||
|
||||
@register_deserializable
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
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")
|
||||
@@ -1,4 +1,5 @@
|
||||
from importlib import import_module
|
||||
from typing import Any, Dict
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config import AddConfig
|
||||
@@ -15,7 +16,7 @@ class DataFormatter(JSONSerializable):
|
||||
.add or .add_local method call
|
||||
"""
|
||||
|
||||
def __init__(self, data_type: DataType, config: AddConfig):
|
||||
def __init__(self, data_type: DataType, config: AddConfig, kwargs: Dict[str, Any]):
|
||||
"""
|
||||
Initialize a dataformatter, set data type and chunker based on datatype.
|
||||
|
||||
@@ -24,15 +25,15 @@ class DataFormatter(JSONSerializable):
|
||||
:param config: AddConfig instance with nested loader and chunker config attributes.
|
||||
:type config: AddConfig
|
||||
"""
|
||||
self.loader = self._get_loader(data_type=data_type, config=config.loader)
|
||||
self.chunker = self._get_chunker(data_type=data_type, config=config.chunker)
|
||||
self.loader = self._get_loader(data_type=data_type, config=config.loader, kwargs=kwargs)
|
||||
self.chunker = self._get_chunker(data_type=data_type, config=config.chunker, kwargs=kwargs)
|
||||
|
||||
def _lazy_load(self, module_path: str):
|
||||
module_path, class_name = module_path.rsplit(".", 1)
|
||||
module = import_module(module_path)
|
||||
return getattr(module, class_name)
|
||||
|
||||
def _get_loader(self, data_type: DataType, config: LoaderConfig) -> BaseLoader:
|
||||
def _get_loader(self, data_type: DataType, config: LoaderConfig, kwargs: Dict[str, Any]) -> BaseLoader:
|
||||
"""
|
||||
Returns the appropriate data loader for the given data type.
|
||||
|
||||
@@ -63,13 +64,28 @@ class DataFormatter(JSONSerializable):
|
||||
DataType.GMAIL: "embedchain.loaders.gmail.GmailLoader",
|
||||
DataType.NOTION: "embedchain.loaders.notion.NotionLoader",
|
||||
}
|
||||
|
||||
custom_loaders = set(
|
||||
[
|
||||
DataType.POSTGRES,
|
||||
]
|
||||
)
|
||||
|
||||
if data_type in loaders:
|
||||
loader_class: type = self._lazy_load(loaders[data_type])
|
||||
return loader_class()
|
||||
else:
|
||||
raise ValueError(f"Unsupported data type: {data_type}")
|
||||
elif data_type in custom_loaders:
|
||||
loader_class: type = kwargs.get("loader", None)
|
||||
if loader_class is not None:
|
||||
return loader_class
|
||||
|
||||
def _get_chunker(self, data_type: DataType, config: ChunkerConfig) -> BaseChunker:
|
||||
raise ValueError(
|
||||
f"Cant find the loader for {data_type}.\
|
||||
We recommend to pass the loader to use data_type: {data_type},\
|
||||
check `https://docs.embedchain.ai/data-sources/overview`."
|
||||
)
|
||||
|
||||
def _get_chunker(self, data_type: DataType, config: ChunkerConfig, kwargs: Dict[str, Any]) -> BaseChunker:
|
||||
"""Returns the appropriate chunker for the given data type (updated for lazy loading)."""
|
||||
chunker_classes = {
|
||||
DataType.YOUTUBE_VIDEO: "embedchain.chunkers.youtube_video.YoutubeVideoChunker",
|
||||
@@ -89,12 +105,21 @@ class DataFormatter(JSONSerializable):
|
||||
DataType.OPENAPI: "embedchain.chunkers.openapi.OpenAPIChunker",
|
||||
DataType.GMAIL: "embedchain.chunkers.gmail.GmailChunker",
|
||||
DataType.NOTION: "embedchain.chunkers.notion.NotionChunker",
|
||||
DataType.POSTGRES: "embedchain.chunkers.postgres.PostgresChunker",
|
||||
}
|
||||
|
||||
if data_type in chunker_classes:
|
||||
chunker_class = self._lazy_load(chunker_classes[data_type])
|
||||
if "chunker" in kwargs:
|
||||
chunker_class = kwargs.get("chunker")
|
||||
else:
|
||||
chunker_class = self._lazy_load(chunker_classes[data_type])
|
||||
|
||||
chunker = chunker_class(config)
|
||||
chunker.set_data_type(data_type)
|
||||
return chunker
|
||||
else:
|
||||
raise ValueError(f"Unsupported data type: {data_type}")
|
||||
raise ValueError(
|
||||
f"Cant find the chunker for {data_type}.\
|
||||
We recommend to pass the chunker to use data_type: {data_type},\
|
||||
check `https://docs.embedchain.ai/data-sources/overview`."
|
||||
)
|
||||
|
||||
+41
-32
@@ -1,17 +1,16 @@
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional, Tuple, Union
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from langchain.docstore.document import Document
|
||||
|
||||
from embedchain.chunkers.base_chunker import BaseChunker
|
||||
from embedchain.config import AddConfig, BaseLlmConfig
|
||||
from embedchain.config import AddConfig, BaseLlmConfig, ChunkerConfig
|
||||
from embedchain.config.apps.base_app_config import BaseAppConfig
|
||||
from embedchain.constants import SQLITE_PATH
|
||||
from embedchain.data_formatter import DataFormatter
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.helper.json_serializable import JSONSerializable
|
||||
@@ -25,12 +24,6 @@ from embedchain.vectordb.base import BaseVectorDB
|
||||
|
||||
load_dotenv()
|
||||
|
||||
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):
|
||||
def __init__(
|
||||
@@ -81,14 +74,18 @@ class EmbedChain(JSONSerializable):
|
||||
if system_prompt:
|
||||
self.llm.config.system_prompt = system_prompt
|
||||
|
||||
# Fetch the history from the database if exists
|
||||
self.llm.update_history(app_id=self.config.id)
|
||||
|
||||
# Attributes that aren't subclass related.
|
||||
self.user_asks = []
|
||||
|
||||
self.chunker: ChunkerConfig = None
|
||||
# Send anonymous telemetry
|
||||
self._telemetry_props = {"class": self.__class__.__name__}
|
||||
self.telemetry = AnonymousTelemetry(enabled=self.config.collect_metrics)
|
||||
# Establish a connection to the SQLite database
|
||||
self.connection = sqlite3.connect(SQLITE_PATH)
|
||||
self.connection = sqlite3.connect(SQLITE_PATH, check_same_thread=False)
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
# Create the 'data_sources' table if it doesn't exist
|
||||
@@ -136,6 +133,7 @@ class EmbedChain(JSONSerializable):
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
config: Optional[AddConfig] = None,
|
||||
dry_run=False,
|
||||
**kwargs: Dict[str, Any],
|
||||
):
|
||||
"""
|
||||
Adds the data from the given URL to the vector db.
|
||||
@@ -157,7 +155,11 @@ class EmbedChain(JSONSerializable):
|
||||
:return: source_hash, a md5-hash of the source, in hexadecimal representation.
|
||||
:rtype: str
|
||||
"""
|
||||
if config is None:
|
||||
if config is not None:
|
||||
pass
|
||||
elif self.chunker is not None:
|
||||
config = AddConfig(chunker=self.chunker)
|
||||
else:
|
||||
config = AddConfig()
|
||||
|
||||
try:
|
||||
@@ -175,21 +177,6 @@ class EmbedChain(JSONSerializable):
|
||||
if data_type:
|
||||
try:
|
||||
data_type = DataType(data_type)
|
||||
if data_type == DataType.JSON:
|
||||
if isinstance(source, str):
|
||||
if not is_valid_json_string(source):
|
||||
raise ValueError(
|
||||
f"Invalid json input: {source}",
|
||||
"Provide the correct JSON formatted source, \
|
||||
refer `https://docs.embedchain.ai/data-sources/json`",
|
||||
)
|
||||
elif not isinstance(source, str):
|
||||
raise ValueError(
|
||||
"Invaid content input. \
|
||||
If you want to upload (list, dict, etc.), do \
|
||||
`json.dump(data, indent=0)` and add the stringified JSON. \
|
||||
Check - `https://docs.embedchain.ai/data-sources/json`"
|
||||
)
|
||||
except ValueError:
|
||||
raise ValueError(
|
||||
f"Invalid data_type: '{data_type}'.",
|
||||
@@ -213,8 +200,9 @@ class EmbedChain(JSONSerializable):
|
||||
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])
|
||||
|
||||
data_formatter = DataFormatter(data_type, config, kwargs)
|
||||
documents, metadatas, _ids, new_chunks = self.load_and_embed(
|
||||
data_formatter.loader, data_formatter.chunker, source, metadata, source_hash, dry_run
|
||||
)
|
||||
@@ -260,6 +248,7 @@ class EmbedChain(JSONSerializable):
|
||||
data_type: Optional[DataType] = None,
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
config: Optional[AddConfig] = None,
|
||||
**kwargs: Dict[str, Any],
|
||||
):
|
||||
"""
|
||||
Adds the data from the given URL to the vector db.
|
||||
@@ -285,7 +274,13 @@ class EmbedChain(JSONSerializable):
|
||||
logging.warning(
|
||||
"The `add_local` method is deprecated and will be removed in future versions. Please use the `add` method for both local and remote files." # noqa: E501
|
||||
)
|
||||
return self.add(source=source, data_type=data_type, metadata=metadata, config=config)
|
||||
return self.add(
|
||||
source=source,
|
||||
data_type=data_type,
|
||||
metadata=metadata,
|
||||
config=config,
|
||||
kwargs=kwargs,
|
||||
)
|
||||
|
||||
def _get_existing_doc_id(self, chunker: BaseChunker, src: Any):
|
||||
"""
|
||||
@@ -483,13 +478,13 @@ class EmbedChain(JSONSerializable):
|
||||
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:
|
||||
where = query_config.where
|
||||
else:
|
||||
where = {}
|
||||
if query_config is not None and query_config.where is not None:
|
||||
where = query_config.where
|
||||
|
||||
if self.config.id is not None:
|
||||
where.update({"app_id": self.config.id})
|
||||
if self.config.id is not None:
|
||||
where.update({"app_id": self.config.id})
|
||||
|
||||
# We cannot query the database with the input query in case of an image search. This is because we need
|
||||
# to bring down both the image and text to the same dimension to be able to compare them.
|
||||
@@ -603,6 +598,9 @@ class EmbedChain(JSONSerializable):
|
||||
input_query=input_query, contexts=contexts_data_for_llm_query, config=config, dry_run=dry_run
|
||||
)
|
||||
|
||||
# add conversation in memory
|
||||
self.llm.add_history(self.config.id, input_query, answer)
|
||||
|
||||
# Send anonymous telemetry
|
||||
self.telemetry.capture(event_name="chat", properties=self._telemetry_props)
|
||||
|
||||
@@ -646,5 +644,16 @@ class EmbedChain(JSONSerializable):
|
||||
self.db.reset()
|
||||
self.cursor.execute("DELETE FROM data_sources WHERE pipeline_id = ?", (self.config.id,))
|
||||
self.connection.commit()
|
||||
self.delete_history()
|
||||
# Send anonymous telemetry
|
||||
self.telemetry.capture(event_name="reset", properties=self._telemetry_props)
|
||||
|
||||
def get_history(self, num_rounds: int = 10, display_format: bool = True):
|
||||
return self.llm.memory.get_recent_memories(
|
||||
app_id=self.config.id,
|
||||
num_rounds=num_rounds,
|
||||
display_format=display_format,
|
||||
)
|
||||
|
||||
def delete_history(self):
|
||||
self.llm.memory.delete_chat_history(app_id=self.config.id)
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
"""
|
||||
Note that this file is copied from Chroma repository. We will remove this file once the fix in
|
||||
ChromaDB's repository.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from chromadb.api.types import Documents, Embeddings
|
||||
|
||||
|
||||
class OpenAIEmbeddingFunction:
|
||||
def __init__(
|
||||
self,
|
||||
api_key: Optional[str] = None,
|
||||
model_name: str = "text-embedding-ada-002",
|
||||
organization_id: Optional[str] = None,
|
||||
api_base: Optional[str] = None,
|
||||
api_type: Optional[str] = None,
|
||||
api_version: Optional[str] = None,
|
||||
deployment_id: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initialize the OpenAIEmbeddingFunction.
|
||||
Args:
|
||||
api_key (str, optional): Your API key for the OpenAI API. If not
|
||||
provided, it will raise an error to provide an OpenAI API key.
|
||||
organization_id(str, optional): The OpenAI organization ID if applicable
|
||||
model_name (str, optional): The name of the model to use for text
|
||||
embeddings. Defaults to "text-embedding-ada-002".
|
||||
api_base (str, optional): The base path for the API. If not provided,
|
||||
it will use the base path for the OpenAI API. This can be used to
|
||||
point to a different deployment, such as an Azure deployment.
|
||||
api_type (str, optional): The type of the API deployment. This can be
|
||||
used to specify a different deployment, such as 'azure'. If not
|
||||
provided, it will use the default OpenAI deployment.
|
||||
api_version (str, optional): The api version for the API. If not provided,
|
||||
it will use the api version for the OpenAI API. This can be used to
|
||||
point to a different deployment, such as an Azure deployment.
|
||||
deployment_id (str, optional): Deployment ID for Azure OpenAI.
|
||||
|
||||
"""
|
||||
try:
|
||||
import openai
|
||||
except ImportError:
|
||||
raise ValueError("The openai python package is not installed. Please install it with `pip install openai`")
|
||||
|
||||
if api_key is not None:
|
||||
openai.api_key = api_key
|
||||
# If the api key is still not set, raise an error
|
||||
elif openai.api_key is None:
|
||||
raise ValueError(
|
||||
"Please provide an OpenAI API key. You can get one at https://platform.openai.com/account/api-keys"
|
||||
)
|
||||
|
||||
if api_base is not None:
|
||||
openai.api_base = api_base
|
||||
|
||||
if api_version is not None:
|
||||
openai.api_version = api_version
|
||||
|
||||
self._api_type = api_type
|
||||
if api_type is not None:
|
||||
openai.api_type = api_type
|
||||
|
||||
if organization_id is not None:
|
||||
openai.organization = organization_id
|
||||
|
||||
self._v1 = openai.__version__.startswith("1.")
|
||||
if self._v1:
|
||||
if api_type == "azure":
|
||||
self._client = openai.AzureOpenAI(
|
||||
api_key=api_key, api_version=api_version, azure_endpoint=api_base
|
||||
).embeddings
|
||||
else:
|
||||
self._client = openai.OpenAI(api_key=api_key, base_url=api_base).embeddings
|
||||
else:
|
||||
self._client = openai.Embedding
|
||||
self._model_name = model_name
|
||||
self._deployment_id = deployment_id
|
||||
|
||||
def __call__(self, input: Documents) -> Embeddings:
|
||||
# replace newlines, which can negatively affect performance.
|
||||
input = [t.replace("\n", " ") for t in input]
|
||||
|
||||
# Call the OpenAI Embedding API
|
||||
if self._v1:
|
||||
embeddings = self._client.create(input=input, model=self._deployment_id or self._model_name).data
|
||||
|
||||
# Sort resulting embeddings by index
|
||||
sorted_embeddings = sorted(embeddings, key=lambda e: e.index) # type: ignore
|
||||
|
||||
# Return just the embeddings
|
||||
return [result.embedding for result in sorted_embeddings]
|
||||
else:
|
||||
if self._api_type == "azure":
|
||||
embeddings = self._client.create(input=input, engine=self._deployment_id or self._model_name)["data"]
|
||||
else:
|
||||
embeddings = self._client.create(input=input, model=self._model_name)["data"]
|
||||
|
||||
# Sort resulting embeddings by index
|
||||
sorted_embeddings = sorted(embeddings, key=lambda e: e["index"]) # type: ignore
|
||||
|
||||
# Return just the embeddings
|
||||
return [result["embedding"] for result in sorted_embeddings]
|
||||
@@ -7,13 +7,7 @@ from embedchain.config import BaseEmbedderConfig
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.models import VectorDimensions
|
||||
|
||||
try:
|
||||
from chromadb.utils import embedding_functions
|
||||
except RuntimeError:
|
||||
from embedchain.utils import use_pysqlite3
|
||||
|
||||
use_pysqlite3()
|
||||
from chromadb.utils import embedding_functions
|
||||
from .chroma_embeddings import OpenAIEmbeddingFunction
|
||||
|
||||
|
||||
class OpenAIEmbedder(BaseEmbedder):
|
||||
@@ -30,11 +24,10 @@ class OpenAIEmbedder(BaseEmbedder):
|
||||
raise ValueError(
|
||||
"OPENAI_API_KEY or OPENAI_ORGANIZATION environment variables not provided"
|
||||
) # noqa:E501
|
||||
embedding_fn = embedding_functions.OpenAIEmbeddingFunction(
|
||||
embedding_fn = OpenAIEmbeddingFunction(
|
||||
api_key=os.getenv("OPENAI_API_KEY"),
|
||||
organization_id=os.getenv("OPENAI_ORGANIZATION"),
|
||||
model_name=self.config.model,
|
||||
)
|
||||
|
||||
self.set_embedding_fn(embedding_fn=embedding_fn)
|
||||
self.set_vector_dimension(vector_dimension=VectorDimensions.OPENAI.value)
|
||||
|
||||
+15
-17
@@ -1,14 +1,15 @@
|
||||
import logging
|
||||
from typing import Any, Dict, Generator, List, Optional
|
||||
|
||||
from langchain.memory import ConversationBufferMemory
|
||||
from langchain.schema import BaseMessage
|
||||
from langchain.schema import BaseMessage as LCBaseMessage
|
||||
|
||||
from embedchain.config import BaseLlmConfig
|
||||
from embedchain.config.llm.base import (DEFAULT_PROMPT,
|
||||
DEFAULT_PROMPT_WITH_HISTORY_TEMPLATE,
|
||||
DOCS_SITE_PROMPT_TEMPLATE)
|
||||
from embedchain.helper.json_serializable import JSONSerializable
|
||||
from embedchain.memory.base import ECChatMemory
|
||||
from embedchain.memory.message import ChatMessage
|
||||
|
||||
|
||||
class BaseLlm(JSONSerializable):
|
||||
@@ -23,7 +24,7 @@ class BaseLlm(JSONSerializable):
|
||||
else:
|
||||
self.config = config
|
||||
|
||||
self.memory = ConversationBufferMemory()
|
||||
self.memory = ECChatMemory()
|
||||
self.is_docs_site_instance = False
|
||||
self.online = False
|
||||
self.history: Any = None
|
||||
@@ -44,11 +45,18 @@ class BaseLlm(JSONSerializable):
|
||||
"""
|
||||
self.history = history
|
||||
|
||||
def update_history(self):
|
||||
def update_history(self, app_id: str):
|
||||
"""Update class history attribute with history in memory (for chat method)"""
|
||||
chat_history = self.memory.load_memory_variables({})["history"]
|
||||
chat_history = self.memory.get_recent_memories(app_id=app_id, num_rounds=10)
|
||||
if chat_history:
|
||||
self.set_history(chat_history)
|
||||
self.set_history([str(history) for history in chat_history])
|
||||
|
||||
def add_history(self, app_id: str, question: str, answer: str, metadata: Optional[Dict[str, Any]] = None):
|
||||
chat_message = ChatMessage()
|
||||
chat_message.add_user_message(question, metadata=metadata)
|
||||
chat_message.add_ai_message(answer, metadata=metadata)
|
||||
self.memory.add(app_id=app_id, chat_message=chat_message)
|
||||
self.update_history(app_id=app_id)
|
||||
|
||||
def generate_prompt(self, input_query: str, contexts: List[str], **kwargs: Dict[str, Any]) -> str:
|
||||
"""
|
||||
@@ -165,7 +173,6 @@ class BaseLlm(JSONSerializable):
|
||||
for chunk in answer:
|
||||
streamed_answer = streamed_answer + chunk
|
||||
yield chunk
|
||||
self.memory.chat_memory.add_ai_message(streamed_answer)
|
||||
logging.info(f"Answer: {streamed_answer}")
|
||||
|
||||
def query(self, input_query: str, contexts: List[str], config: BaseLlmConfig = None, dry_run=False):
|
||||
@@ -257,8 +264,6 @@ class BaseLlm(JSONSerializable):
|
||||
if self.online:
|
||||
k["web_search_result"] = self.access_search_and_get_results(input_query)
|
||||
|
||||
self.update_history()
|
||||
|
||||
prompt = self.generate_prompt(input_query, contexts, **k)
|
||||
logging.info(f"Prompt: {prompt}")
|
||||
|
||||
@@ -267,16 +272,9 @@ class BaseLlm(JSONSerializable):
|
||||
|
||||
answer = self.get_answer_from_llm(prompt)
|
||||
|
||||
self.memory.chat_memory.add_user_message(input_query)
|
||||
|
||||
if isinstance(answer, str):
|
||||
self.memory.chat_memory.add_ai_message(answer)
|
||||
logging.info(f"Answer: {answer}")
|
||||
|
||||
# NOTE: Adding to history before and after. This could be seen as redundant.
|
||||
# If we change it, we have to change the tests (no big deal).
|
||||
self.update_history()
|
||||
|
||||
return answer
|
||||
else:
|
||||
# this is a streamed response and needs to be handled differently.
|
||||
@@ -287,7 +285,7 @@ class BaseLlm(JSONSerializable):
|
||||
self.config: BaseLlmConfig = BaseLlmConfig.deserialize(prev_config)
|
||||
|
||||
@staticmethod
|
||||
def _get_messages(prompt: str, system_prompt: Optional[str] = None) -> List[BaseMessage]:
|
||||
def _get_messages(prompt: str, system_prompt: Optional[str] = None) -> List[LCBaseMessage]:
|
||||
"""
|
||||
Construct a list of langchain messages
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ class GPT4ALLLlm(BaseLlm):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
super().__init__(config=config)
|
||||
if self.config.model is None:
|
||||
self.config.model = "orca-mini-3b.ggmlv3.q4_0.bin"
|
||||
self.config.model = "orca-mini-3b-gguf2-q4_0.gguf"
|
||||
self.instance = GPT4ALLLlm._get_instance(self.config.model)
|
||||
self.instance.streaming = self.config.stream
|
||||
|
||||
|
||||
@@ -25,10 +25,21 @@ class JSONLoader(BaseLoader):
|
||||
|
||||
return LLHUBJSONLoader()
|
||||
|
||||
@staticmethod
|
||||
def _check_content(content):
|
||||
if not isinstance(content, str):
|
||||
raise ValueError(
|
||||
"Invaid content input. \
|
||||
If you want to upload (list, dict, etc.), do \
|
||||
`json.dump(data, indent=0)` and add the stringified JSON. \
|
||||
Check - `https://docs.embedchain.ai/data-sources/json`"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def load_data(content):
|
||||
"""Load a json file. Each data point is a key value pair."""
|
||||
|
||||
JSONLoader._check_content(content)
|
||||
loader = JSONLoader._get_llama_hub_loader()
|
||||
|
||||
data = []
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import hashlib
|
||||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from embedchain.loaders.base_loader import BaseLoader
|
||||
|
||||
|
||||
class PostgresLoader(BaseLoader):
|
||||
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||
super().__init__()
|
||||
if not config:
|
||||
raise ValueError(f"Must provide the valid config. Received: {config}")
|
||||
|
||||
self.connection = None
|
||||
self.cursor = None
|
||||
self._setup_loader(config=config)
|
||||
|
||||
def _setup_loader(self, config: Dict[str, Any]):
|
||||
try:
|
||||
import psycopg
|
||||
except ImportError as e:
|
||||
raise ImportError(
|
||||
"Unable to import required packages. \
|
||||
Run `pip install --upgrade 'embedchain[postgres]'`"
|
||||
) from e
|
||||
|
||||
config_info = ""
|
||||
if "url" in config:
|
||||
config_info = config.get("url")
|
||||
else:
|
||||
conn_params = []
|
||||
for key, value in config.items():
|
||||
conn_params.append(f"{key}={value}")
|
||||
config_info = " ".join(conn_params)
|
||||
|
||||
logging.info(f"Connecting to postrgres sql: {config_info}")
|
||||
self.connection = psycopg.connect(conninfo=config_info)
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
def _check_query(self, query):
|
||||
if not isinstance(query, str):
|
||||
raise ValueError(
|
||||
f"Invalid postgres query: {query}",
|
||||
"Provide the valid source to add from postgres, \
|
||||
make sure you are following `https://docs.embedchain.ai/data-sources/postgres`",
|
||||
)
|
||||
|
||||
def load_data(self, query):
|
||||
self._check_query(query)
|
||||
try:
|
||||
data = []
|
||||
data_content = []
|
||||
self.cursor.execute(query)
|
||||
results = self.cursor.fetchall()
|
||||
for result in results:
|
||||
doc_content = str(result)
|
||||
data.append({"content": doc_content, "meta_data": {"url": f"postgres_query-({query})"}})
|
||||
data_content.append(doc_content)
|
||||
doc_id = hashlib.sha256((query + ", ".join(data_content)).encode()).hexdigest()
|
||||
return {
|
||||
"doc_id": doc_id,
|
||||
"data": data,
|
||||
}
|
||||
except Exception as e:
|
||||
raise ValueError(f"Failed to load data using query={query} with: {e}")
|
||||
|
||||
def close_connection(self):
|
||||
if self.cursor:
|
||||
self.cursor.close()
|
||||
self.cursor = None
|
||||
if self.connection:
|
||||
self.connection.close()
|
||||
self.connection = None
|
||||
@@ -0,0 +1,116 @@
|
||||
import json
|
||||
import logging
|
||||
import sqlite3
|
||||
import uuid
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from embedchain.constants import SQLITE_PATH
|
||||
from embedchain.memory.message import ChatMessage
|
||||
from embedchain.memory.utils import merge_metadata_dict
|
||||
|
||||
CHAT_MESSAGE_CREATE_TABLE_QUERY = """
|
||||
CREATE TABLE IF NOT EXISTS chat_history (
|
||||
app_id TEXT,
|
||||
id TEXT,
|
||||
question TEXT,
|
||||
answer TEXT,
|
||||
metadata TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id, app_id)
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
class ECChatMemory:
|
||||
def __init__(self) -> None:
|
||||
with sqlite3.connect(SQLITE_PATH) as self.connection:
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
self.cursor.execute(CHAT_MESSAGE_CREATE_TABLE_QUERY)
|
||||
self.connection.commit()
|
||||
|
||||
def add(self, app_id, chat_message: ChatMessage) -> Optional[str]:
|
||||
memory_id = str(uuid.uuid4())
|
||||
metadata_dict = merge_metadata_dict(chat_message.human_message.metadata, chat_message.ai_message.metadata)
|
||||
if metadata_dict:
|
||||
metadata = self._serialize_json(metadata_dict)
|
||||
ADD_CHAT_MESSAGE_QUERY = """
|
||||
INSERT INTO chat_history (app_id, id, question, answer, metadata)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
"""
|
||||
self.cursor.execute(
|
||||
ADD_CHAT_MESSAGE_QUERY,
|
||||
(
|
||||
app_id,
|
||||
memory_id,
|
||||
chat_message.human_message.content,
|
||||
chat_message.ai_message.content,
|
||||
metadata if metadata_dict else "{}",
|
||||
),
|
||||
)
|
||||
self.connection.commit()
|
||||
logging.info(f"Added chat memory to db with id: {memory_id}")
|
||||
return memory_id
|
||||
|
||||
def delete_chat_history(self, app_id: str):
|
||||
DELETE_CHAT_HISTORY_QUERY = """
|
||||
DELETE FROM chat_history WHERE app_id=?
|
||||
"""
|
||||
self.cursor.execute(
|
||||
DELETE_CHAT_HISTORY_QUERY,
|
||||
(app_id,),
|
||||
)
|
||||
self.connection.commit()
|
||||
|
||||
def get_recent_memories(self, app_id, num_rounds=10, display_format=False) -> List[ChatMessage]:
|
||||
"""
|
||||
Get the most recent num_rounds rounds of conversations
|
||||
between human and AI, for a given app_id.
|
||||
"""
|
||||
|
||||
QUERY = """
|
||||
SELECT * FROM chat_history
|
||||
WHERE app_id=?
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?
|
||||
"""
|
||||
self.cursor.execute(
|
||||
QUERY,
|
||||
(app_id, num_rounds),
|
||||
)
|
||||
|
||||
results = self.cursor.fetchall()
|
||||
history = []
|
||||
for result in results:
|
||||
app_id, _, question, answer, metadata, timestamp = result
|
||||
metadata = self._deserialize_json(metadata=metadata)
|
||||
# Return list of dict if display_format is True
|
||||
if display_format:
|
||||
history.append({"human": question, "ai": answer, "metadata": metadata, "timestamp": timestamp})
|
||||
else:
|
||||
memory = ChatMessage()
|
||||
memory.add_user_message(question, metadata=metadata)
|
||||
memory.add_ai_message(answer, metadata=metadata)
|
||||
history.append(memory)
|
||||
return history
|
||||
|
||||
def _serialize_json(self, metadata: Dict[str, Any]):
|
||||
return json.dumps(metadata)
|
||||
|
||||
def _deserialize_json(self, metadata: str):
|
||||
return json.loads(metadata)
|
||||
|
||||
def close_connection(self):
|
||||
self.connection.close()
|
||||
|
||||
def count_history_messages(self, app_id: str):
|
||||
QUERY = """
|
||||
SELECT COUNT(*) FROM chat_history
|
||||
WHERE app_id=?
|
||||
"""
|
||||
self.cursor.execute(
|
||||
QUERY,
|
||||
(app_id,),
|
||||
)
|
||||
count = self.cursor.fetchone()[0]
|
||||
return count
|
||||
@@ -0,0 +1,72 @@
|
||||
import logging
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from embedchain.helper.json_serializable import JSONSerializable
|
||||
|
||||
|
||||
class BaseMessage(JSONSerializable):
|
||||
"""
|
||||
The base abstract message class.
|
||||
|
||||
Messages are the inputs and outputs of Models.
|
||||
"""
|
||||
|
||||
# The string content of the message.
|
||||
content: str
|
||||
|
||||
# The creator of the message. AI, Human, Bot etc.
|
||||
by: str
|
||||
|
||||
# Any additional info.
|
||||
metadata: Dict[str, Any]
|
||||
|
||||
def __init__(self, content: str, creator: str, metadata: Optional[Dict[str, Any]] = None) -> None:
|
||||
super().__init__()
|
||||
self.content = content
|
||||
self.creator = creator
|
||||
self.metadata = metadata
|
||||
|
||||
@property
|
||||
def type(self) -> str:
|
||||
"""Type of the Message, used for serialization."""
|
||||
|
||||
@classmethod
|
||||
def is_lc_serializable(cls) -> bool:
|
||||
"""Return whether this class is serializable."""
|
||||
return True
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.creator}: {self.content}"
|
||||
|
||||
|
||||
class ChatMessage(JSONSerializable):
|
||||
"""
|
||||
The base abstract chat message class.
|
||||
|
||||
Chat messages are the pair of (question, answer) conversation
|
||||
between human and model.
|
||||
"""
|
||||
|
||||
human_message: Optional[BaseMessage] = None
|
||||
ai_message: Optional[BaseMessage] = None
|
||||
|
||||
def add_user_message(self, message: str, metadata: Optional[dict] = None):
|
||||
if self.human_message:
|
||||
logging.info(
|
||||
"Human message already exists in the chat message,\
|
||||
overwritting it with new message."
|
||||
)
|
||||
|
||||
self.human_message = BaseMessage(content=message, creator="human", metadata=metadata)
|
||||
|
||||
def add_ai_message(self, message: str, metadata: Optional[dict] = None):
|
||||
if self.ai_message:
|
||||
logging.info(
|
||||
"AI message already exists in the chat message,\
|
||||
overwritting it with new message."
|
||||
)
|
||||
|
||||
self.ai_message = BaseMessage(content=message, creator="ai", metadata=metadata)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.human_message}\n{self.ai_message}"
|
||||
@@ -0,0 +1,35 @@
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
def merge_metadata_dict(left: Optional[Dict[str, Any]], right: Optional[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Merge the metadatas of two BaseMessage types.
|
||||
|
||||
Args:
|
||||
left (Dict[str, Any]): metadata of human message
|
||||
right (Dict[str, Any]): metadata of ai message
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: combined metadata dict with dedup
|
||||
to be saved in db.
|
||||
"""
|
||||
if not left and not right:
|
||||
return None
|
||||
elif not left:
|
||||
return right
|
||||
elif not right:
|
||||
return left
|
||||
|
||||
merged = left.copy()
|
||||
for k, v in right.items():
|
||||
if k not in merged:
|
||||
merged[k] = v
|
||||
elif type(merged[k]) != type(v):
|
||||
raise ValueError(f'additional_kwargs["{k}"] already exists in this message,' " but with a different type.")
|
||||
elif isinstance(merged[k], str):
|
||||
merged[k] += v
|
||||
elif isinstance(merged[k], dict):
|
||||
merged[k] = merge_metadata_dict(merged[k], v)
|
||||
else:
|
||||
raise ValueError(f"Additional kwargs key {k} already exists in this message.")
|
||||
return merged
|
||||
@@ -29,6 +29,7 @@ class IndirectDataType(Enum):
|
||||
JSON = "json"
|
||||
OPENAPI = "openapi"
|
||||
GMAIL = "gmail"
|
||||
POSTGRES = "postgres"
|
||||
|
||||
|
||||
class SpecialDataType(Enum):
|
||||
@@ -57,3 +58,4 @@ class DataType(Enum):
|
||||
JSON = IndirectDataType.JSON.value
|
||||
OPENAPI = IndirectDataType.OPENAPI.value
|
||||
GMAIL = IndirectDataType.GMAIL.value
|
||||
POSTGRES = IndirectDataType.POSTGRES.value
|
||||
|
||||
+21
-41
@@ -7,11 +7,11 @@ 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.config import ChunkerConfig, PipelineConfig
|
||||
from embedchain.constants import SQLITE_PATH
|
||||
from embedchain.embedchain import EmbedChain
|
||||
from embedchain.embedder.base import BaseEmbedder
|
||||
from embedchain.embedder.openai import OpenAIEmbedder
|
||||
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
||||
@@ -19,11 +19,10 @@ from embedchain.helper.json_serializable import register_deserializable
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.llm.openai import OpenAILlm
|
||||
from embedchain.telemetry.posthog import AnonymousTelemetry
|
||||
from embedchain.utils import validate_yaml_config
|
||||
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):
|
||||
@@ -42,8 +41,9 @@ class Pipeline(EmbedChain):
|
||||
embedding_model: BaseEmbedder = None,
|
||||
llm: BaseLlm = None,
|
||||
yaml_path: str = None,
|
||||
log_level=logging.INFO,
|
||||
log_level=logging.WARN,
|
||||
auto_deploy: bool = False,
|
||||
chunker: ChunkerConfig = None,
|
||||
):
|
||||
"""
|
||||
Initialize a new `App` instance.
|
||||
@@ -58,12 +58,15 @@ class Pipeline(EmbedChain):
|
||||
: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
|
||||
:param log_level: Log level to use, defaults to logging.WARN
|
||||
: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
|
||||
"""
|
||||
# Setup user directory if it doesn't exist already
|
||||
Client.setup_dir()
|
||||
|
||||
if id and yaml_path:
|
||||
raise Exception("Cannot provide both id and config. Please provide only one of them.")
|
||||
|
||||
@@ -75,18 +78,18 @@ class Pipeline(EmbedChain):
|
||||
|
||||
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.chunker = None
|
||||
if chunker:
|
||||
self.chunker = ChunkerConfig(**chunker)
|
||||
|
||||
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:
|
||||
@@ -115,7 +118,7 @@ class Pipeline(EmbedChain):
|
||||
self.telemetry = AnonymousTelemetry(enabled=self.config.collect_metrics)
|
||||
|
||||
# Establish a connection to the SQLite database
|
||||
self.connection = sqlite3.connect(SQLITE_PATH)
|
||||
self.connection = sqlite3.connect(SQLITE_PATH, check_same_thread=False)
|
||||
self.cursor = self.connection.cursor()
|
||||
|
||||
# Create the 'data_sources' table if it doesn't exist
|
||||
@@ -357,10 +360,16 @@ class Pipeline(EmbedChain):
|
||||
with open(yaml_path, "r") as file:
|
||||
config_data = yaml.safe_load(file)
|
||||
|
||||
try:
|
||||
validate_yaml_config(config_data)
|
||||
except Exception as e:
|
||||
raise Exception(f"❌ Error occurred while validating the YAML config. Error: {str(e)}")
|
||||
|
||||
pipeline_config_data = config_data.get("app", {}).get("config", {})
|
||||
db_config_data = config_data.get("vectordb", {})
|
||||
embedding_model_config_data = config_data.get("embedding_model", config_data.get("embedder", {}))
|
||||
llm_config_data = config_data.get("llm", {})
|
||||
chunker_config_data = config_data.get("chunker", {})
|
||||
|
||||
pipeline_config = PipelineConfig(**pipeline_config_data)
|
||||
|
||||
@@ -389,34 +398,5 @@ class Pipeline(EmbedChain):
|
||||
embedding_model=embedding_model,
|
||||
yaml_path=yaml_path,
|
||||
auto_deploy=auto_deploy,
|
||||
chunker=chunker_config_data,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
import time
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
from openai import OpenAI
|
||||
from openai.types.beta.threads import MessageContentText, ThreadMessage
|
||||
|
||||
from embedchain import Pipeline
|
||||
from embedchain.config import AddConfig
|
||||
from embedchain.data_formatter import DataFormatter
|
||||
from embedchain.models.data_type import DataType
|
||||
from embedchain.telemetry.posthog import AnonymousTelemetry
|
||||
from embedchain.utils import detect_datatype
|
||||
|
||||
logging.basicConfig(level=logging.WARN)
|
||||
|
||||
|
||||
class OpenAIAssistant:
|
||||
def __init__(
|
||||
self,
|
||||
name=None,
|
||||
instructions=None,
|
||||
tools=None,
|
||||
thread_id=None,
|
||||
model="gpt-4-1106-preview",
|
||||
data_sources=None,
|
||||
assistant_id=None,
|
||||
log_level=logging.WARN,
|
||||
collect_metrics=True,
|
||||
):
|
||||
self.name = name or "OpenAI Assistant"
|
||||
self.instructions = instructions
|
||||
self.tools = tools or [{"type": "retrieval"}]
|
||||
self.model = model
|
||||
self.data_sources = data_sources or []
|
||||
self.log_level = log_level
|
||||
self._client = OpenAI()
|
||||
self._initialize_assistant(assistant_id)
|
||||
self.thread_id = thread_id or self._create_thread()
|
||||
self._telemetry_props = {"class": self.__class__.__name__}
|
||||
self.telemetry = AnonymousTelemetry(enabled=collect_metrics)
|
||||
self.telemetry.capture(event_name="init", properties=self._telemetry_props)
|
||||
|
||||
def add(self, source, data_type=None):
|
||||
file_path = self._prepare_source_path(source, data_type)
|
||||
self._add_file_to_assistant(file_path)
|
||||
|
||||
event_props = {
|
||||
**self._telemetry_props,
|
||||
"data_type": data_type or detect_datatype(source),
|
||||
}
|
||||
self.telemetry.capture(event_name="add", properties=event_props)
|
||||
logging.info("Data successfully added to the assistant.")
|
||||
|
||||
def chat(self, message):
|
||||
self._send_message(message)
|
||||
self.telemetry.capture(event_name="chat", properties=self._telemetry_props)
|
||||
return self._get_latest_response()
|
||||
|
||||
def delete_thread(self):
|
||||
self._client.beta.threads.delete(self.thread_id)
|
||||
self.thread_id = self._create_thread()
|
||||
|
||||
# Internal methods
|
||||
def _initialize_assistant(self, assistant_id):
|
||||
file_ids = self._generate_file_ids(self.data_sources)
|
||||
self.assistant = (
|
||||
self._client.beta.assistants.retrieve(assistant_id)
|
||||
if assistant_id
|
||||
else self._client.beta.assistants.create(
|
||||
name=self.name, model=self.model, file_ids=file_ids, instructions=self.instructions, tools=self.tools
|
||||
)
|
||||
)
|
||||
|
||||
def _create_thread(self):
|
||||
thread = self._client.beta.threads.create()
|
||||
return thread.id
|
||||
|
||||
def _prepare_source_path(self, source, data_type=None):
|
||||
if Path(source).is_file():
|
||||
return source
|
||||
data_type = data_type or detect_datatype(source)
|
||||
formatter = DataFormatter(data_type=DataType(data_type), config=AddConfig(), kwargs={})
|
||||
data = formatter.loader.load_data(source)["data"]
|
||||
return self._save_temp_data(data=data[0]["content"].encode(), source=source)
|
||||
|
||||
def _add_file_to_assistant(self, file_path):
|
||||
file_obj = self._client.files.create(file=open(file_path, "rb"), purpose="assistants")
|
||||
self._client.beta.assistants.files.create(assistant_id=self.assistant.id, file_id=file_obj.id)
|
||||
|
||||
def _generate_file_ids(self, data_sources):
|
||||
return [
|
||||
self._add_file_to_assistant(self._prepare_source_path(ds["source"], ds.get("data_type")))
|
||||
for ds in data_sources
|
||||
]
|
||||
|
||||
def _send_message(self, message):
|
||||
self._client.beta.threads.messages.create(thread_id=self.thread_id, role="user", content=message)
|
||||
self._wait_for_completion()
|
||||
|
||||
def _wait_for_completion(self):
|
||||
run = self._client.beta.threads.runs.create(
|
||||
thread_id=self.thread_id,
|
||||
assistant_id=self.assistant.id,
|
||||
instructions=self.instructions,
|
||||
)
|
||||
run_id = run.id
|
||||
run_status = run.status
|
||||
|
||||
while run_status in ["queued", "in_progress", "requires_action"]:
|
||||
time.sleep(0.1) # Sleep before making the next API call to avoid hitting rate limits
|
||||
run = self._client.beta.threads.runs.retrieve(thread_id=self.thread_id, run_id=run_id)
|
||||
run_status = run.status
|
||||
if run_status == "failed":
|
||||
raise ValueError(f"Thread run failed with the following error: {run.last_error}")
|
||||
|
||||
def _get_latest_response(self):
|
||||
history = self._get_history()
|
||||
return self._format_message(history[0]) if history else None
|
||||
|
||||
def _get_history(self):
|
||||
messages = self._client.beta.threads.messages.list(thread_id=self.thread_id, order="desc")
|
||||
return list(messages)
|
||||
|
||||
def _format_message(self, thread_message):
|
||||
thread_message = cast(ThreadMessage, thread_message)
|
||||
content = [c.text.value for c in thread_message.content if isinstance(c, MessageContentText)]
|
||||
return " ".join(content)
|
||||
|
||||
def _save_temp_data(self, data, source):
|
||||
special_chars_pattern = r'[\\/:*?"<>|&=% ]+'
|
||||
sanitized_source = re.sub(special_chars_pattern, "_", source)[:256]
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
file_path = os.path.join(temp_dir, sanitized_source)
|
||||
with open(file_path, "wb") as file:
|
||||
file.write(data)
|
||||
return file_path
|
||||
|
||||
|
||||
class AIAssistant:
|
||||
def __init__(
|
||||
self,
|
||||
name=None,
|
||||
instructions=None,
|
||||
yaml_path=None,
|
||||
assistant_id=None,
|
||||
thread_id=None,
|
||||
data_sources=None,
|
||||
log_level=logging.WARN,
|
||||
collect_metrics=True,
|
||||
):
|
||||
logging.basicConfig(level=log_level)
|
||||
|
||||
self.name = name or "AI Assistant"
|
||||
self.data_sources = data_sources or []
|
||||
self.log_level = log_level
|
||||
self.instructions = instructions
|
||||
self.assistant_id = assistant_id or str(uuid.uuid4())
|
||||
self.thread_id = thread_id or str(uuid.uuid4())
|
||||
self.pipeline = Pipeline.from_config(yaml_path=yaml_path) if yaml_path else Pipeline()
|
||||
self.pipeline.local_id = self.pipeline.config.id = self.thread_id
|
||||
|
||||
if self.instructions:
|
||||
self.pipeline.system_prompt = self.instructions
|
||||
|
||||
print(
|
||||
f"🎉 Created AI Assistant with name: {self.name}, assistant_id: {self.assistant_id}, thread_id: {self.thread_id}" # noqa: E501
|
||||
)
|
||||
|
||||
# telemetry related properties
|
||||
self._telemetry_props = {"class": self.__class__.__name__}
|
||||
self.telemetry = AnonymousTelemetry(enabled=collect_metrics)
|
||||
self.telemetry.capture(event_name="init", properties=self._telemetry_props)
|
||||
|
||||
if self.data_sources:
|
||||
for data_source in self.data_sources:
|
||||
metadata = {"assistant_id": self.assistant_id, "thread_id": "global_knowledge"}
|
||||
self.pipeline.add(data_source["source"], data_source.get("data_type"), metadata=metadata)
|
||||
|
||||
def add(self, source, data_type=None):
|
||||
metadata = {"assistant_id": self.assistant_id, "thread_id": self.thread_id}
|
||||
self.pipeline.add(source, data_type=data_type, metadata=metadata)
|
||||
event_props = {
|
||||
**self._telemetry_props,
|
||||
"data_type": data_type or detect_datatype(source),
|
||||
}
|
||||
self.telemetry.capture(event_name="add", properties=event_props)
|
||||
|
||||
def chat(self, query):
|
||||
where = {
|
||||
"$and": [
|
||||
{"assistant_id": {"$eq": self.assistant_id}},
|
||||
{"thread_id": {"$in": [self.thread_id, "global_knowledge"]}},
|
||||
]
|
||||
}
|
||||
return self.pipeline.chat(query, where=where)
|
||||
|
||||
def delete(self):
|
||||
self.pipeline.reset()
|
||||
@@ -5,6 +5,8 @@ import re
|
||||
import string
|
||||
from typing import Any
|
||||
|
||||
from schema import Optional, Or, Schema
|
||||
|
||||
from embedchain.models.data_type import DataType
|
||||
|
||||
|
||||
@@ -283,3 +285,72 @@ def is_valid_json_string(source: str):
|
||||
Check the docs to see the supported formats - `https://docs.embedchain.ai/data-sources/json`"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def validate_yaml_config(config_data):
|
||||
schema = Schema(
|
||||
{
|
||||
Optional("app"): {
|
||||
Optional("config"): {
|
||||
Optional("id"): str,
|
||||
Optional("name"): str,
|
||||
Optional("log_level"): Or("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"),
|
||||
Optional("collect_metrics"): bool,
|
||||
Optional("collection_name"): str,
|
||||
}
|
||||
},
|
||||
Optional("llm"): {
|
||||
Optional("provider"): Or(
|
||||
"openai",
|
||||
"azure_openai",
|
||||
"anthropic",
|
||||
"huggingface",
|
||||
"cohere",
|
||||
"gpt4all",
|
||||
"jina",
|
||||
"llama2",
|
||||
"vertexai",
|
||||
),
|
||||
Optional("config"): {
|
||||
Optional("model"): str,
|
||||
Optional("number_documents"): int,
|
||||
Optional("temperature"): float,
|
||||
Optional("max_tokens"): int,
|
||||
Optional("top_p"): Or(float, int),
|
||||
Optional("stream"): bool,
|
||||
Optional("template"): str,
|
||||
Optional("system_prompt"): str,
|
||||
Optional("deployment_name"): str,
|
||||
Optional("where"): dict,
|
||||
Optional("query_type"): str,
|
||||
},
|
||||
},
|
||||
Optional("vectordb"): {
|
||||
Optional("provider"): Or(
|
||||
"chroma", "elasticsearch", "opensearch", "pinecone", "qdrant", "weaviate", "zilliz"
|
||||
),
|
||||
Optional("config"): object, # TODO: add particular config schema for each provider
|
||||
},
|
||||
Optional("embedder"): {
|
||||
Optional("provider"): Or("openai", "gpt4all", "huggingface", "vertexai", "azure_openai"),
|
||||
Optional("config"): {
|
||||
Optional("model"): Optional(str),
|
||||
Optional("deployment_name"): Optional(str),
|
||||
},
|
||||
},
|
||||
Optional("embedding_model"): {
|
||||
Optional("provider"): Or("openai", "gpt4all", "huggingface", "vertexai", "azure_openai"),
|
||||
Optional("config"): {
|
||||
Optional("model"): str,
|
||||
Optional("deployment_name"): str,
|
||||
},
|
||||
},
|
||||
Optional("chunker"): {
|
||||
Optional("chunk_size"): int,
|
||||
Optional("chunk_overlap"): int,
|
||||
Optional("length_function"): str,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return schema.validate(config_data)
|
||||
|
||||
@@ -77,7 +77,7 @@ class ChromaDB(BaseVectorDB):
|
||||
def _generate_where_clause(self, where: Dict[str, any]) -> str:
|
||||
# If only one filter is supplied, return it as is
|
||||
# (no need to wrap in $and based on chroma docs)
|
||||
if len(where.keys()) == 1:
|
||||
if len(where.keys()) <= 1:
|
||||
return where
|
||||
where_filters = []
|
||||
for k, v in where.items():
|
||||
@@ -224,7 +224,7 @@ class ChromaDB(BaseVectorDB):
|
||||
input_query,
|
||||
],
|
||||
n_results=n_results,
|
||||
where=where,
|
||||
where=self._generate_where_clause(where),
|
||||
)
|
||||
else:
|
||||
result = self.collection.query(
|
||||
@@ -232,7 +232,7 @@ class ChromaDB(BaseVectorDB):
|
||||
input_query,
|
||||
],
|
||||
n_results=n_results,
|
||||
where=where,
|
||||
where=self._generate_where_clause(where),
|
||||
)
|
||||
except InvalidDimensionException as e:
|
||||
raise InvalidDimensionException(
|
||||
@@ -275,7 +275,7 @@ class ChromaDB(BaseVectorDB):
|
||||
return self.collection.count()
|
||||
|
||||
def delete(self, where):
|
||||
return self.collection.delete(where=where)
|
||||
return self.collection.delete(where=self._generate_where_clause(where))
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
|
||||
@@ -222,3 +222,16 @@ class ZillizVectorDB(BaseVectorDB):
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("Collection name must be a string")
|
||||
self.config.collection_name = name
|
||||
|
||||
def delete(self, keys: Union[list, str, int]):
|
||||
"""
|
||||
Delete the embeddings from DB. Zilliz only support deleting with keys.
|
||||
|
||||
|
||||
:param keys: Primary keys of the table entries to delete.
|
||||
:type keys: Union[list, str, int]
|
||||
"""
|
||||
self.client.delete(
|
||||
collection_name=self.config.collection_name,
|
||||
pks=keys,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11 AS backend
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /usr/src/discord_bot
|
||||
COPY requirements.txt .
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
# Discord Bot
|
||||
|
||||
This is a docker template to create your own Discord bot using the embedchain package. To know more about the bot and how to use it, go [here](https://docs.embedchain.ai/examples/discord_bot).
|
||||
This is a docker template to create your own Discord bot using the embedchain package. To know more about the bot and how to use it, go [here](https://docs.embedchain.ai/examples/discord_bot).
|
||||
|
||||
To run this use the following command,
|
||||
|
||||
```bash
|
||||
docker run --name discord-bot -e OPENAI_API_KEY=sk-xxx -e DISCORD_BOT_TOKEN=xxx -p 8080:8080 embedchain/discord-bot:latest
|
||||
```
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3.11 AS backend
|
||||
FROM python:3.11-slim AS backend
|
||||
|
||||
WORKDIR /usr/src/app/backend
|
||||
COPY requirements.txt .
|
||||
|
||||
@@ -2,20 +2,22 @@ version: "3.9"
|
||||
|
||||
services:
|
||||
backend:
|
||||
container_name: embedchain_backend
|
||||
container_name: embedchain-backend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: backend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/backend
|
||||
ports:
|
||||
- "8000:8000"
|
||||
|
||||
frontend:
|
||||
container_name: embedchain_frontend
|
||||
container_name: embedchain-frontend
|
||||
restart: unless-stopped
|
||||
build:
|
||||
context: frontend
|
||||
dockerfile: Dockerfile
|
||||
image: embedchain/frontend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18 AS frontend
|
||||
FROM node:18-slim AS frontend
|
||||
|
||||
WORKDIR /usr/src/app/frontend
|
||||
COPY package.json .
|
||||
|
||||
@@ -5,7 +5,7 @@ app:
|
||||
llm:
|
||||
provider: gpt4all
|
||||
config:
|
||||
model: 'orca-mini-3b.ggmlv3.q4_0.bin'
|
||||
model: 'orca-mini-3b-gguf2-q4_0.gguf'
|
||||
temperature: 0.5
|
||||
max_tokens: 1000
|
||||
top_p: 1
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
import os
|
||||
import logging
|
||||
import os
|
||||
|
||||
import yaml
|
||||
from fastapi import FastAPI, UploadFile, Depends, HTTPException
|
||||
from database import Base, SessionLocal, engine
|
||||
from fastapi import Depends, FastAPI, HTTPException, UploadFile
|
||||
from models import DefaultResponse, DeployAppRequest, QueryApp, SourceApp
|
||||
from services import get_app, get_apps, remove_app, save_app
|
||||
from sqlalchemy.orm import Session
|
||||
from utils import generate_error_message_for_api_keys
|
||||
|
||||
from embedchain import Pipeline as App
|
||||
from embedchain.client import Client
|
||||
from models import (
|
||||
QueryApp,
|
||||
SourceApp,
|
||||
DefaultResponse,
|
||||
DeployAppRequest,
|
||||
)
|
||||
from database import Base, engine, SessionLocal
|
||||
from services import get_app, save_app, get_apps, remove_app
|
||||
from utils import generate_error_message_for_api_keys
|
||||
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import Column, String, Integer
|
||||
|
||||
from database import Base
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy import Column, Integer, String
|
||||
|
||||
|
||||
class QueryApp(BaseModel):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fastapi==0.104.0
|
||||
uvicorn==0.23.2
|
||||
embedchain==0.0.91
|
||||
embedchain[streamlit, community, opensource, elasticsearch, opensearch, poe, discord, slack, whatsapp, weaviate, pinecone, qdrant, images, huggingface_hub, cohere, milvus, dataloaders, vertexai, llama2, gmail, json]==0.0.91
|
||||
embedchain==0.1.3
|
||||
embedchain[streamlit, community, opensource, elasticsearch, opensearch, poe, discord, slack, whatsapp, weaviate, pinecone, qdrant, images, huggingface_hub, cohere, milvus, dataloaders, vertexai, llama2, gmail, json]==0.1.3
|
||||
sqlalchemy==2.0.22
|
||||
python-multipart==0.0.6
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from models import AppModel
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
def get_app(db: Session, app_id: str):
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
TELEGRAM_BOT_TOKEN=
|
||||
OPENAI_API_KEY=
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /usr/src/
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "telegram_bot.py"]
|
||||
@@ -63,4 +63,4 @@ def send_message(chat_id, text):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000, debug=False)
|
||||
app.run(host="0.0.0.0", port=8000, debug=False)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
TELEGRAM_BOT_TOKEN=""
|
||||
OPENAI_API_KEY=""
|
||||
@@ -0,0 +1 @@
|
||||
OPENAI_API_KEY=
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /usr/src/
|
||||
COPY requirements.txt .
|
||||
RUN pip install -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["python", "whatsapp_bot.py"]
|
||||
@@ -1 +0,0 @@
|
||||
OPENAI_API_KEY=""
|
||||
@@ -48,4 +48,4 @@ def query(message):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", port=5000, debug=False)
|
||||
app.run(host="0.0.0.0", port=8000, debug=False)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
"llm:\n",
|
||||
" provider: gpt4all\n",
|
||||
" config:\n",
|
||||
" model: 'orca-mini-3b.ggmlv3.q4_0.bin'\n",
|
||||
" model: 'orca-mini-3b-gguf2-q4_0.gguf'\n",
|
||||
" temperature: 0.5\n",
|
||||
" max_tokens: 1000\n",
|
||||
" top_p: 1\n",
|
||||
|
||||
Generated
+390
-111
@@ -147,6 +147,20 @@ files = [
|
||||
[package.dependencies]
|
||||
frozenlist = ">=1.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "aiostream"
|
||||
version = "0.5.2"
|
||||
description = "Generator-based operators for asynchronous iteration"
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "aiostream-0.5.2-py3-none-any.whl", hash = "sha256:054660370be9d37f6fe3ece3851009240416bd082e469fd90cc8673d3818cf71"},
|
||||
{file = "aiostream-0.5.2.tar.gz", hash = "sha256:b71b519a2d66c38f0872403ab86417955b77352f08d9ad02ad46fc3926b389f4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.6.0"
|
||||
@@ -488,7 +502,7 @@ cffi = ">=1.0.0"
|
||||
name = "cachetools"
|
||||
version = "5.3.1"
|
||||
description = "Extensible memoizing collections and decorators"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"},
|
||||
@@ -730,13 +744,13 @@ numpy = "*"
|
||||
|
||||
[[package]]
|
||||
name = "chromadb"
|
||||
version = "0.4.14"
|
||||
version = "0.4.16"
|
||||
description = "Chroma."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "chromadb-0.4.14-py3-none-any.whl", hash = "sha256:c1b59bdfb4b35a40bad0b8927c5ed757adf191ff9db2b9a384dc46a76e1ff10f"},
|
||||
{file = "chromadb-0.4.14.tar.gz", hash = "sha256:0fcef603bcf9c854305020c3f8d368c09b1545d48bd2bceefd51861090f87dad"},
|
||||
{file = "chromadb-0.4.16-py3-none-any.whl", hash = "sha256:a2e79d80cf25adc5658af568c66949628a8991779d832044a0fabed983b79fc3"},
|
||||
{file = "chromadb-0.4.16.tar.gz", hash = "sha256:d5fb113ea02f87b969887279aec625e1a2a68bf6acedf1609f95d27670a78dc0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -745,14 +759,20 @@ chroma-hnswlib = "0.7.3"
|
||||
fastapi = ">=0.95.2"
|
||||
grpcio = ">=1.58.0"
|
||||
importlib-resources = "*"
|
||||
kubernetes = ">=28.1.0"
|
||||
numpy = {version = ">=1.22.5", markers = "python_version >= \"3.8\""}
|
||||
onnxruntime = ">=1.14.1"
|
||||
opentelemetry-api = ">=1.2.0"
|
||||
opentelemetry-exporter-otlp-proto-grpc = ">=1.2.0"
|
||||
opentelemetry-sdk = ">=1.2.0"
|
||||
overrides = ">=7.3.1"
|
||||
posthog = ">=2.4.0"
|
||||
pulsar-client = ">=3.1.0"
|
||||
pydantic = ">=1.9"
|
||||
pypika = ">=0.48.9"
|
||||
PyYAML = ">=6.0.0"
|
||||
requests = ">=2.28"
|
||||
tenacity = ">=8.2.3"
|
||||
tokenizers = ">=0.13.2"
|
||||
tqdm = ">=4.65.0"
|
||||
typer = ">=0.9.0"
|
||||
@@ -849,6 +869,17 @@ humanfriendly = ">=9.1"
|
||||
[package.extras]
|
||||
cron = ["capturer (>=2.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "contextlib2"
|
||||
version = "21.6.0"
|
||||
description = "Backports and enhancements for the contextlib module"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "contextlib2-21.6.0-py2.py3-none-any.whl", hash = "sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f"},
|
||||
{file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "contourpy"
|
||||
version = "1.1.1"
|
||||
@@ -911,10 +942,7 @@ files = [
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = [
|
||||
{version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""},
|
||||
{version = ">=1.26.0rc1,<2.0", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
bokeh = ["bokeh", "selenium"]
|
||||
@@ -1073,7 +1101,7 @@ dev = ["flake8", "hypothesis", "ipython", "mypy (>=0.710)", "portray", "pytest (
|
||||
name = "deprecated"
|
||||
version = "1.2.14"
|
||||
description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "Deprecated-1.2.14-py2.py3-none-any.whl", hash = "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c"},
|
||||
@@ -1131,6 +1159,17 @@ files = [
|
||||
{file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "distro"
|
||||
version = "1.8.0"
|
||||
description = "Distro - an OS platform information API"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "distro-1.8.0-py3-none-any.whl", hash = "sha256:99522ca3e365cac527b44bde033f64c6945d90eb9f769703caaec52b09bbd3ff"},
|
||||
{file = "distro-1.8.0.tar.gz", hash = "sha256:02e111d1dc6a50abb8eed6bf31c3e48ed8b0830d1ea2a1b78c61765c2513fdd8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.4.2"
|
||||
@@ -1666,7 +1705,7 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"]
|
||||
name = "google-auth"
|
||||
version = "2.23.3"
|
||||
description = "Google Authentication Library"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "google-auth-2.23.3.tar.gz", hash = "sha256:6864247895eea5d13b9c57c9e03abb49cb94ce2dc7c58e91cba3248c7477c9e3"},
|
||||
@@ -1921,7 +1960,7 @@ requests = ["requests (>=2.18.0,<3.0.0dev)"]
|
||||
name = "googleapis-common-protos"
|
||||
version = "1.61.0"
|
||||
description = "Common protobufs used in Google APIs"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "googleapis-common-protos-1.61.0.tar.gz", hash = "sha256:8a64866a97f6304a7179873a465d6eee97b7a24ec6cfd78e0f575e96b821240b"},
|
||||
@@ -1937,14 +1976,14 @@ grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"]
|
||||
|
||||
[[package]]
|
||||
name = "gpt4all"
|
||||
version = "1.0.8"
|
||||
version = "2.0.2"
|
||||
description = "Python bindings for GPT4All"
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "gpt4all-1.0.8-py3-none-macosx_10_9_universal2.whl", hash = "sha256:405180fb9eb924dcb0ded070200923948b25b9b192fa5d059e805f1349ba9b15"},
|
||||
{file = "gpt4all-1.0.8-py3-none-manylinux1_x86_64.whl", hash = "sha256:96b5f8e139784d9ce11aea2cb6d39d7866943d7cb574917af48eca4cccb31a12"},
|
||||
{file = "gpt4all-1.0.8-py3-none-win_amd64.whl", hash = "sha256:96dbe139f4f17bcf8a0e81d241e52b7d812d3b500ffa9b89a34dcb7f63e52100"},
|
||||
{file = "gpt4all-2.0.2-py3-none-macosx_10_15_universal2.whl", hash = "sha256:f18f348d21e2ce8e45dbf8334960670660b53f69a8e47a26bb7e64924e6ed130"},
|
||||
{file = "gpt4all-2.0.2-py3-none-manylinux1_x86_64.whl", hash = "sha256:e4c19df94f45829565563017577b299c012ebed18ebea1d6df0273ef89c92a01"},
|
||||
{file = "gpt4all-2.0.2-py3-none-win_amd64.whl", hash = "sha256:c09440bfb3463b9e278875fc726cf1f75d2a2b19bb73d97dde5e57b0b1f6e059"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2230,7 +2269,7 @@ files = [
|
||||
name = "httpcore"
|
||||
version = "0.18.0"
|
||||
description = "A minimal low-level HTTP client."
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "httpcore-0.18.0-py3-none-any.whl", hash = "sha256:adc5398ee0a476567bf87467063ee63584a8bce86078bf748e48754f60202ced"},
|
||||
@@ -2298,7 +2337,7 @@ test = ["Cython (>=0.29.24,<0.30.0)"]
|
||||
name = "httpx"
|
||||
version = "0.25.0"
|
||||
description = "The next generation HTTP client."
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "httpx-0.25.0-py3-none-any.whl", hash = "sha256:181ea7f8ba3a82578be86ef4171554dd45fec26a02556a744db029a0a27b7100"},
|
||||
@@ -2419,7 +2458,7 @@ files = [
|
||||
name = "importlib-metadata"
|
||||
version = "6.8.0"
|
||||
description = "Read metadata from Python packages"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"},
|
||||
@@ -2675,15 +2714,41 @@ files = [
|
||||
{file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kubernetes"
|
||||
version = "28.1.0"
|
||||
description = "Kubernetes python client"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "kubernetes-28.1.0-py2.py3-none-any.whl", hash = "sha256:10f56f8160dcb73647f15fafda268e7f60cf7dbc9f8e46d52fcd46d3beb0c18d"},
|
||||
{file = "kubernetes-28.1.0.tar.gz", hash = "sha256:1468069a573430fb1cb5ad22876868f57977930f80a6749405da31cd6086a7e9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
certifi = ">=14.05.14"
|
||||
google-auth = ">=1.0.1"
|
||||
oauthlib = ">=3.2.2"
|
||||
python-dateutil = ">=2.5.3"
|
||||
pyyaml = ">=5.4.1"
|
||||
requests = "*"
|
||||
requests-oauthlib = "*"
|
||||
six = ">=1.9.0"
|
||||
urllib3 = ">=1.24.2,<2.0"
|
||||
websocket-client = ">=0.32.0,<0.40.0 || >0.40.0,<0.41.dev0 || >=0.43.dev0"
|
||||
|
||||
[package.extras]
|
||||
adal = ["adal (>=1.0.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.0.303"
|
||||
version = "0.0.332"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
files = [
|
||||
{file = "langchain-0.0.303-py3-none-any.whl", hash = "sha256:1745961f66b60bc3b513820a34c560dd37c4ba4b7499ba82545dc4816d0133bd"},
|
||||
{file = "langchain-0.0.303.tar.gz", hash = "sha256:84d2727eb8b3b27a9d0aa0da9f05408c2564a4a923c7d5b154a16e488430e725"},
|
||||
{file = "langchain-0.0.332-py3-none-any.whl", hash = "sha256:4cbf183b8a385483907192efea2f55d34c0f0c441b0a02f41af1eeec4526677c"},
|
||||
{file = "langchain-0.0.332.tar.gz", hash = "sha256:8356b6c0073680d66d5ee2d9e54c23c90198ee74ab2431a0256934a69a511c1f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2692,8 +2757,7 @@ anyio = "<4.0"
|
||||
async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""}
|
||||
dataclasses-json = ">=0.5.7,<0.7"
|
||||
jsonpatch = ">=1.33,<2.0"
|
||||
langsmith = ">=0.0.38,<0.1.0"
|
||||
numexpr = ">=2.8.4,<3.0.0"
|
||||
langsmith = ">=0.0.52,<0.1.0"
|
||||
numpy = ">=1,<2"
|
||||
pydantic = ">=1,<3"
|
||||
PyYAML = ">=5.3"
|
||||
@@ -2702,16 +2766,17 @@ SQLAlchemy = ">=1.4,<3"
|
||||
tenacity = ">=8.1.0,<9.0.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.6.8,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "libdeeplake (>=0.0.60,<0.0.61)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=1.2.4,<2.0.0)", "momento (>=1.5.0,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.4.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"]
|
||||
all = ["O365 (>=2.0.26,<3.0.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "amadeus (>=8.1.0)", "arxiv (>=1.4,<2.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "awadb (>=0.3.9,<0.4.0)", "azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "beautifulsoup4 (>=4,<5)", "clarifai (>=9.1.0)", "clickhouse-connect (>=0.5.14,<0.6.0)", "cohere (>=4,<5)", "deeplake (>=3.8.3,<4.0.0)", "docarray[hnswlib] (>=0.32.0,<0.33.0)", "duckduckgo-search (>=3.8.3,<4.0.0)", "elasticsearch (>=8,<9)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-auth (>=2.18.1,<3.0.0)", "google-search-results (>=2,<3)", "gptcache (>=0.1.7)", "html2text (>=2020.1.16,<2021.0.0)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lancedb (>=0.1,<0.2)", "langkit (>=0.0.6,<0.1.0)", "lark (>=1.1.5,<2.0.0)", "librosa (>=0.10.0.post2,<0.11.0)", "lxml (>=4.9.2,<5.0.0)", "manifest-ml (>=0.0.1,<0.0.2)", "marqo (>=1.2.4,<2.0.0)", "momento (>=1.10.1,<2.0.0)", "nebula3-python (>=3.4.0,<4.0.0)", "neo4j (>=5.8.1,<6.0.0)", "networkx (>=2.6.3,<4)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "opensearch-py (>=2.0.0,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pexpect (>=4.8.0,<5.0.0)", "pgvector (>=0.1.6,<0.2.0)", "pinecone-client (>=2,<3)", "pinecone-text (>=0.4.2,<0.5.0)", "psycopg2-binary (>=2.9.5,<3.0.0)", "pymongo (>=4.3.3,<5.0.0)", "pyowm (>=3.3.0,<4.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pytesseract (>=0.3.10,<0.4.0)", "python-arango (>=7.5.9,<8.0.0)", "pyvespa (>=0.33.0,<0.34.0)", "qdrant-client (>=1.3.1,<2.0.0)", "rdflib (>=6.3.2,<7.0.0)", "redis (>=4,<5)", "requests-toolbelt (>=1.0.0,<2.0.0)", "sentence-transformers (>=2,<3)", "singlestoredb (>=0.7.1,<0.8.0)", "tensorflow-text (>=2.11.0,<3.0.0)", "tigrisdb (>=1.0.0b6,<2.0.0)", "tiktoken (>=0.3.2,<0.6.0)", "torch (>=1,<3)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"]
|
||||
azure = ["azure-ai-formrecognizer (>=3.2.1,<4.0.0)", "azure-ai-vision (>=0.11.1b1,<0.12.0)", "azure-cognitiveservices-speech (>=1.28.0,<2.0.0)", "azure-core (>=1.26.4,<2.0.0)", "azure-cosmos (>=4.4.0b1,<5.0.0)", "azure-identity (>=1.12.0,<2.0.0)", "azure-search-documents (==11.4.0b8)", "openai (>=0,<1)"]
|
||||
clarifai = ["clarifai (>=9.1.0)"]
|
||||
cli = ["typer (>=0.9.0,<0.10.0)"]
|
||||
cohere = ["cohere (>=4,<5)"]
|
||||
docarray = ["docarray[hnswlib] (>=0.32.0,<0.33.0)"]
|
||||
embeddings = ["sentence-transformers (>=2,<3)"]
|
||||
extended-testing = ["amazon-textract-caller (<2)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "dashvector (>=1.0.1,<2.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "openai (>=0,<1)", "openapi-schema-pydantic (>=1.2,<2.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"]
|
||||
extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15.0,<3.0.0)", "anthropic (>=0.3.11,<0.4.0)", "arxiv (>=1.4,<2.0)", "assemblyai (>=0.17.0,<0.18.0)", "atlassian-python-api (>=3.36.0,<4.0.0)", "beautifulsoup4 (>=4,<5)", "bibtexparser (>=1.4.0,<2.0.0)", "cassio (>=0.1.0,<0.2.0)", "chardet (>=5.1.0,<6.0.0)", "dashvector (>=1.0.1,<2.0.0)", "esprima (>=4.0.1,<5.0.0)", "faiss-cpu (>=1,<2)", "feedparser (>=6.0.10,<7.0.0)", "fireworks-ai (>=0.6.0,<0.7.0)", "geopandas (>=0.13.1,<0.14.0)", "gitpython (>=3.1.32,<4.0.0)", "google-cloud-documentai (>=2.20.1,<3.0.0)", "gql (>=3.4.1,<4.0.0)", "html2text (>=2020.1.16,<2021.0.0)", "jinja2 (>=3,<4)", "jq (>=1.4.1,<2.0.0)", "jsonschema (>1)", "lxml (>=4.9.2,<5.0.0)", "markdownify (>=0.11.6,<0.12.0)", "motor (>=3.3.1,<4.0.0)", "mwparserfromhell (>=0.6.4,<0.7.0)", "mwxml (>=0.3.3,<0.4.0)", "newspaper3k (>=0.2.8,<0.3.0)", "numexpr (>=2.8.6,<3.0.0)", "openai (>=0,<1)", "openapi-pydantic (>=0.3.2,<0.4.0)", "pandas (>=2.0.1,<3.0.0)", "pdfminer-six (>=20221105,<20221106)", "pgvector (>=0.1.6,<0.2.0)", "psychicapi (>=0.8.0,<0.9.0)", "py-trello (>=0.19.0,<0.20.0)", "pymupdf (>=1.22.3,<2.0.0)", "pypdf (>=3.4.0,<4.0.0)", "pypdfium2 (>=4.10.0,<5.0.0)", "pyspark (>=3.4.0,<4.0.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "rapidfuzz (>=3.1.1,<4.0.0)", "rapidocr-onnxruntime (>=1.3.2,<2.0.0)", "requests-toolbelt (>=1.0.0,<2.0.0)", "rspace_client (>=2.5.0,<3.0.0)", "scikit-learn (>=1.2.2,<2.0.0)", "sqlite-vss (>=0.1.2,<0.2.0)", "streamlit (>=1.18.0,<2.0.0)", "sympy (>=1.12,<2.0)", "telethon (>=1.28.5,<2.0.0)", "timescale-vector (>=0.0.1,<0.0.2)", "tqdm (>=4.48.0)", "upstash-redis (>=0.15.0,<0.16.0)", "xata (>=1.0.0a7,<2.0.0)", "xmltodict (>=0.13.0,<0.14.0)"]
|
||||
javascript = ["esprima (>=4.0.1,<5.0.0)"]
|
||||
llms = ["clarifai (>=9.1.0)", "cohere (>=4,<5)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "openlm (>=0.0.5,<0.0.6)", "torch (>=1,<3)", "transformers (>=4,<5)"]
|
||||
openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.4.0)"]
|
||||
openai = ["openai (>=0,<1)", "tiktoken (>=0.3.2,<0.6.0)"]
|
||||
qdrant = ["qdrant-client (>=1.3.1,<2.0.0)"]
|
||||
text-helpers = ["chardet (>=5.1.0,<6.0.0)"]
|
||||
|
||||
@@ -2731,17 +2796,18 @@ six = "*"
|
||||
|
||||
[[package]]
|
||||
name = "langsmith"
|
||||
version = "0.0.43"
|
||||
version = "0.0.62"
|
||||
description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
|
||||
optional = false
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
files = [
|
||||
{file = "langsmith-0.0.43-py3-none-any.whl", hash = "sha256:27854bebdae6a35c88e1c1172e6abba27592287b70511aca2a953a59fade0e87"},
|
||||
{file = "langsmith-0.0.43.tar.gz", hash = "sha256:f7705f13eb8ce3b8eb16c4d2b2760c62cfb9a3b3ab6aa0728afa84d26b2a6e55"},
|
||||
{file = "langsmith-0.0.62-py3-none-any.whl", hash = "sha256:d50fe00eee06001ac5f705d4ff09c6b4a2f20688d57de5fbd6974a510da672fa"},
|
||||
{file = "langsmith-0.0.62.tar.gz", hash = "sha256:196b16bea6856a83c8d95f3f709beebc6c72ea82c113021d3f62ac7cbde51bfe"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pydantic = ">=1,<3"
|
||||
pytest-subtests = ">=0.11.0,<0.12.0"
|
||||
requests = ">=2,<3"
|
||||
|
||||
[[package]]
|
||||
@@ -2790,13 +2856,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "llama-hub"
|
||||
version = "0.0.29"
|
||||
version = "0.0.43"
|
||||
description = "A library of community-driven data loaders for LLMs. Use with LlamaIndex and/or LangChain. "
|
||||
optional = true
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
files = [
|
||||
{file = "llama_hub-0.0.29-py3-none-any.whl", hash = "sha256:728e4a1ba292adf804479baf015c6395a606329cdf3c0f3a0fae2d2ec836de18"},
|
||||
{file = "llama_hub-0.0.29.tar.gz", hash = "sha256:06e3232a96f6895c5b0bfe5a916a19d51c2534bfd6a829515f6d85e9b612d9ec"},
|
||||
{file = "llama_hub-0.0.43-py3-none-any.whl", hash = "sha256:6dbf1261f75e97de7f086d1ca3258db39f530526382d347f9523fcbb472f72c9"},
|
||||
{file = "llama_hub-0.0.43.tar.gz", hash = "sha256:82b4405d8f20f9538621d0324aaaeeba8945c0eca4cd8998d67c3140bb7cbd05"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2808,32 +2874,38 @@ retrying = "*"
|
||||
|
||||
[[package]]
|
||||
name = "llama-index"
|
||||
version = "0.8.29"
|
||||
version = "0.8.65"
|
||||
description = "Interface between LLMs and your data"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.8.1,<3.12"
|
||||
files = [
|
||||
{file = "llama_index-0.8.29-py3-none-any.whl", hash = "sha256:e6e0ffc9cd561668e7a68c0d58c20b614979f0c86393a36a705ab583b0b838f9"},
|
||||
{file = "llama_index-0.8.29.tar.gz", hash = "sha256:ff1489e78dac9bc7590c1de191d06fb73bb65220f82130dd5af6cb14d30e8bac"},
|
||||
{file = "llama_index-0.8.65-py3-none-any.whl", hash = "sha256:0bdb32a33e846b3b7517cb4a39c21768f1cf263b2b6a111e0405b2eabe6bac01"},
|
||||
{file = "llama_index-0.8.65.tar.gz", hash = "sha256:826b824aba2ea4a14369f7840df3975d4e1af068bc9e8770d2d7f392db5eb873"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
beautifulsoup4 = "*"
|
||||
dataclasses-json = "*"
|
||||
aiostream = ">=0.5.2,<0.6.0"
|
||||
dataclasses-json = ">=0.5.7,<0.6.0"
|
||||
deprecated = ">=1.2.9.3"
|
||||
fsspec = ">=2023.5.0"
|
||||
langchain = ">=0.0.262"
|
||||
nest-asyncio = "*"
|
||||
nltk = "*"
|
||||
langchain = ">=0.0.303"
|
||||
nest-asyncio = ">=1.5.8,<2.0.0"
|
||||
nltk = ">=3.8.1,<4.0.0"
|
||||
numpy = "*"
|
||||
openai = ">=0.26.4"
|
||||
openai = ">=1.1.0"
|
||||
pandas = "*"
|
||||
sqlalchemy = ">=2.0.15"
|
||||
SQLAlchemy = {version = ">=1.4.49", extras = ["asyncio"]}
|
||||
tenacity = ">=8.2.0,<9.0.0"
|
||||
tiktoken = "*"
|
||||
tiktoken = ">=0.3.3"
|
||||
typing-extensions = ">=4.5.0"
|
||||
typing-inspect = ">=0.8.0"
|
||||
urllib3 = "<2"
|
||||
|
||||
[package.extras]
|
||||
local-models = ["optimum[onnxruntime] (>=1.13.2,<2.0.0)", "sentencepiece (>=0.1.99,<0.2.0)", "transformers[torch] (>=4.34.0,<5.0.0)"]
|
||||
postgres = ["asyncpg (>=0.28.0,<0.29.0)", "pgvector (>=0.1.0,<0.2.0)", "psycopg-binary (>=3.1.12,<4.0.0)"]
|
||||
query-tools = ["guidance (>=0.0.64,<0.0.65)", "jsonpath-ng (>=1.6.0,<2.0.0)", "lm-format-enforcer (>=0.4.3,<0.5.0)", "rank-bm25 (>=0.2.2,<0.3.0)", "scikit-learn (<1.3.0)", "spacy (>=3.7.1,<4.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "loguru"
|
||||
version = "0.7.2"
|
||||
@@ -3358,47 +3430,6 @@ files = [
|
||||
[package.dependencies]
|
||||
setuptools = "*"
|
||||
|
||||
[[package]]
|
||||
name = "numexpr"
|
||||
version = "2.8.7"
|
||||
description = "Fast numerical expression evaluator for NumPy"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "numexpr-2.8.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d88531ffea3ea9287e8a1665c6a2d0206d3f4660d5244423e2a134a7f0ce5fba"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db1065ba663a854115cf1f493afd7206e2efcef6643129e8061e97a51ad66ebb"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4546416004ff2e7eb9cf52c2d7ab82732b1b505593193ee9f93fa770edc5230"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb2f473fdfd09d17db3038e34818d05b6bc561a36785aa927d6c0e06bccc9911"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5496fc9e3ae214637cbca1ab556b0e602bd3afe9ff4c943a29c482430972cda8"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-win32.whl", hash = "sha256:d43f1f0253a6f2db2f76214e6f7ae9611b422cba3f7d4c86415d7a78bbbd606f"},
|
||||
{file = "numexpr-2.8.7-cp310-cp310-win_amd64.whl", hash = "sha256:cf5f112bce5c5966c47cc33700bc14ce745c8351d437ed57a9574fff581f341a"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:32934d51b5bc8a6636436326da79ed380e2f151989968789cf65b1210572cb46"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f021ac93cb3dd5d8ba2882627b615b1f58cb089dcc85764c6fbe7a549ed21b0c"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dccf572763517db6562fb7b17db46aacbbf62a9ca0a66672872f4f71aee7b186"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11121b14ee3179bade92e823f25f1b94e18716d33845db5081973331188c3338"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81451962d4145a46dba189df65df101d4d1caddb6efe6ebfe05982cd9f62b2cf"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-win32.whl", hash = "sha256:da55ba845b847cc33c4bf81cee4b1bddfb0831118cabff8db62888ab8697ec34"},
|
||||
{file = "numexpr-2.8.7-cp311-cp311-win_amd64.whl", hash = "sha256:fd93b88d5332069916fa00829ea1b972b7e73abcb1081eee5c905a514b8b59e3"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5340d2c86d83f52e1a3e7fd97c37d358ae99af9de316bdeeab2565b9b1e622ca"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3bdf8cbc00c77a46230c765d242f92d35905c239b20c256c48dbac91e49f253"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d46c47e361fa60966a3339cb4f463ae6151ce7d78ed38075f06e8585d2c8929f"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a371cfc1670a18eea2d5c70abaa95a0e8824b70d28da884bad11931266e3a0ca"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:47a249cecd1382d482a5bf1fac0d11392fb2ed0f7d415ebc4cd901959deb1ec9"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-win32.whl", hash = "sha256:b8a5b2c21c26b62875bf819d375d798b96a32644e3c28bd4ce7789ed1fb489da"},
|
||||
{file = "numexpr-2.8.7-cp312-cp312-win_amd64.whl", hash = "sha256:f29f4d08d9b0ed6fa5d32082971294b2f9131b8577c2b7c36432ed670924313f"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ecaa5be24cf8fa0f00108e9dfa1021b7510e9dd9d159b8d8bc7c7ddbb995b31"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a84284e0a407ca52980fd20962e89aff671c84cd6e73458f2e29ea2aa206356"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e838289e3b7bbe100b99e35496e6cc4cc0541c2207078941ee5a1d46e6b925ae"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0983052f308ea75dd232eb7f4729eed839db8fe8d82289940342b32cc55b15d0"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8bf005acd7f1985c71b1b247aaac8950d6ea05a0fe0bbbbf3f96cd398b136daa"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-win32.whl", hash = "sha256:56ec95f8d1db0819e64987dcf1789acd500fa4ea396eeabe4af6efdcb8902d07"},
|
||||
{file = "numexpr-2.8.7-cp39-cp39-win_amd64.whl", hash = "sha256:c7bf60fc1a9c90a9cb21c4c235723e579bff70c8d5362228cb2cf34426104ba2"},
|
||||
{file = "numexpr-2.8.7.tar.gz", hash = "sha256:596eeb3bbfebc912f4b6eaaf842b61ba722cebdb8bc42dfefa657d3a74953849"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.13.3"
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.26.1"
|
||||
@@ -3602,7 +3633,7 @@ wheel = "*"
|
||||
name = "oauthlib"
|
||||
version = "3.2.2"
|
||||
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca"},
|
||||
@@ -3730,25 +3761,25 @@ sympy = "*"
|
||||
|
||||
[[package]]
|
||||
name = "openai"
|
||||
version = "0.28.1"
|
||||
description = "Python client library for the OpenAI API"
|
||||
version = "1.1.2"
|
||||
description = "Client library for the openai API"
|
||||
optional = false
|
||||
python-versions = ">=3.7.1"
|
||||
files = [
|
||||
{file = "openai-0.28.1-py3-none-any.whl", hash = "sha256:d18690f9e3d31eedb66b57b88c2165d760b24ea0a01f150dd3f068155088ce68"},
|
||||
{file = "openai-0.28.1.tar.gz", hash = "sha256:4be1dad329a65b4ce1a660fe6d5431b438f429b5855c883435f0f7fcb6d2dcc8"},
|
||||
{file = "openai-1.1.2-py3-none-any.whl", hash = "sha256:72fa414378913ca74432ac618ca6cdfd78a502fcfad1e06cc499b9dba8ff2c8e"},
|
||||
{file = "openai-1.1.2.tar.gz", hash = "sha256:bcb4d1fd471cf616031053636841acdc820cd42cbc6cd3e4036c85f682752656"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = "*"
|
||||
requests = ">=2.20"
|
||||
tqdm = "*"
|
||||
anyio = ">=3.5.0,<4"
|
||||
distro = ">=1.7.0,<2"
|
||||
httpx = ">=0.23.0,<1"
|
||||
pydantic = ">=1.9.0,<3"
|
||||
tqdm = ">4"
|
||||
typing-extensions = ">=4.5,<5"
|
||||
|
||||
[package.extras]
|
||||
datalib = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
|
||||
dev = ["black (>=21.6b0,<22.0)", "pytest (==6.*)", "pytest-asyncio", "pytest-mock"]
|
||||
embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "scipy", "tenacity (>=8.0.1)"]
|
||||
wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"]
|
||||
datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
|
||||
|
||||
[[package]]
|
||||
name = "opencv-python"
|
||||
@@ -3815,6 +3846,101 @@ develop = ["black", "botocore", "coverage (<7.0.0)", "jinja2", "mock", "myst-par
|
||||
docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"]
|
||||
kerberos = ["requests-kerberos"]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-api"
|
||||
version = "1.21.0"
|
||||
description = "OpenTelemetry Python API"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_api-1.21.0-py3-none-any.whl", hash = "sha256:4bb86b28627b7e41098f0e93280fe4892a1abed1b79a19aec6f928f39b17dffb"},
|
||||
{file = "opentelemetry_api-1.21.0.tar.gz", hash = "sha256:d6185fd5043e000075d921822fd2d26b953eba8ca21b1e2fa360dd46a7686316"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
deprecated = ">=1.2.6"
|
||||
importlib-metadata = ">=6.0,<7.0"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-common"
|
||||
version = "1.21.0"
|
||||
description = "OpenTelemetry Protobuf encoding"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_exporter_otlp_proto_common-1.21.0-py3-none-any.whl", hash = "sha256:97b1022b38270ec65d11fbfa348e0cd49d12006485c2321ea3b1b7037d42b6ec"},
|
||||
{file = "opentelemetry_exporter_otlp_proto_common-1.21.0.tar.gz", hash = "sha256:61db274d8a68d636fb2ec2a0f281922949361cdd8236e25ff5539edf942b3226"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
backoff = {version = ">=1.10.0,<3.0.0", markers = "python_version >= \"3.7\""}
|
||||
opentelemetry-proto = "1.21.0"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-grpc"
|
||||
version = "1.21.0"
|
||||
description = "OpenTelemetry Collector Protobuf over gRPC Exporter"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_exporter_otlp_proto_grpc-1.21.0-py3-none-any.whl", hash = "sha256:ab37c63d6cb58d6506f76d71d07018eb1f561d83e642a8f5aa53dddf306087a4"},
|
||||
{file = "opentelemetry_exporter_otlp_proto_grpc-1.21.0.tar.gz", hash = "sha256:a497c5611245a2d17d9aa1e1cbb7ab567843d53231dcc844a62cea9f0924ffa7"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
backoff = {version = ">=1.10.0,<3.0.0", markers = "python_version >= \"3.7\""}
|
||||
deprecated = ">=1.2.6"
|
||||
googleapis-common-protos = ">=1.52,<2.0"
|
||||
grpcio = ">=1.0.0,<2.0.0"
|
||||
opentelemetry-api = ">=1.15,<2.0"
|
||||
opentelemetry-exporter-otlp-proto-common = "1.21.0"
|
||||
opentelemetry-proto = "1.21.0"
|
||||
opentelemetry-sdk = ">=1.21.0,<1.22.0"
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest-grpc"]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "1.21.0"
|
||||
description = "OpenTelemetry Python Proto"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_proto-1.21.0-py3-none-any.whl", hash = "sha256:32fc4248e83eebd80994e13963e683f25f3b443226336bb12b5b6d53638f50ba"},
|
||||
{file = "opentelemetry_proto-1.21.0.tar.gz", hash = "sha256:7d5172c29ed1b525b5ecf4ebe758c7138a9224441b3cfe683d0a237c33b1941f"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
protobuf = ">=3.19,<5.0"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-sdk"
|
||||
version = "1.21.0"
|
||||
description = "OpenTelemetry Python SDK"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_sdk-1.21.0-py3-none-any.whl", hash = "sha256:9fe633243a8c655fedace3a0b89ccdfc654c0290ea2d8e839bd5db3131186f73"},
|
||||
{file = "opentelemetry_sdk-1.21.0.tar.gz", hash = "sha256:3ec8cd3020328d6bc5c9991ccaf9ae820ccb6395a5648d9a95d3ec88275b8879"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
opentelemetry-api = "1.21.0"
|
||||
opentelemetry-semantic-conventions = "0.42b0"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.42b0"
|
||||
description = "OpenTelemetry Semantic Conventions"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "opentelemetry_semantic_conventions-0.42b0-py3-none-any.whl", hash = "sha256:5cd719cbfec448af658860796c5d0fcea2fdf0945a2bed2363f42cb1ee39f526"},
|
||||
{file = "opentelemetry_semantic_conventions-0.42b0.tar.gz", hash = "sha256:44ae67a0a3252a05072877857e5cc1242c98d4cf12870159f1a94bec800d38ec"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overrides"
|
||||
version = "7.4.0"
|
||||
@@ -3875,7 +4001,6 @@ files = [
|
||||
numpy = [
|
||||
{version = ">=1.22.4", markers = "python_version < \"3.11\""},
|
||||
{version = ">=1.23.2", markers = "python_version == \"3.11\""},
|
||||
{version = ">=1.26.0", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
python-dateutil = ">=2.8.2"
|
||||
pytz = ">=2020.1"
|
||||
@@ -4213,6 +4338,117 @@ files = [
|
||||
[package.extras]
|
||||
test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg"
|
||||
version = "3.1.12"
|
||||
description = "PostgreSQL database adapter for Python"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "psycopg-3.1.12-py3-none-any.whl", hash = "sha256:8ec5230d6a7eb654b4fb3cf2d3eda8871d68f24807b934790504467f1deee9f8"},
|
||||
{file = "psycopg-3.1.12.tar.gz", hash = "sha256:cec7ad2bc6a8510e56c45746c631cf9394148bdc8a9a11fd8cf8554ce129ae78"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.1"
|
||||
tzdata = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
binary = ["psycopg-binary (==3.1.12)"]
|
||||
c = ["psycopg-c (==3.1.12)"]
|
||||
dev = ["black (>=23.1.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=1.4.1)", "types-setuptools (>=57.4)", "wheel (>=0.37)"]
|
||||
docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"]
|
||||
pool = ["psycopg-pool"]
|
||||
test = ["anyio (>=3.6.2,<4.0)", "mypy (>=1.4.1)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-binary"
|
||||
version = "3.1.12"
|
||||
description = "PostgreSQL database adapter for Python -- C optimisation distribution"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29a69f62aae8617361376d9ed1e34966ae9c3a74c4ab3aa430a7ce0c11530862"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7308316fdb6796399041b80db0ab9f356504ed26427e46834ade82ba94b067ce"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130752b9b2f8d071f179e257b9698cedfe4546be81ad5ecd8ed52cf9d725580d"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45bcecc96a6e6fe11e06b75f7ba8005d6f717f16fae7ab1cf5a0aec5191f87c3"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc3f0fcc4fcccffda2450c725bee9fad73bc6c110cfbe3b8a777063845d9c6b9"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f93749f0fe69cfbfec22af690bb4b241f1a4347c57be26fe2e5b70588f7d602f"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:36147f708cc6a9d74c2b8d880f8dd3a6d53364b5c487536adaa022d435c90733"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2bbcc6fbabc2b92d18d955d9fa104fd9d8bd2dcb97a279c4e788c6b714ffd1af"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0dee8a1ecc501d9c3db06d08184712459bbb5806a09121c3a25e8cbe91e234d7"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:49d6acf228edb5bd9000735b89b780b18face776d081b905cf68e149d57dfcc1"},
|
||||
{file = "psycopg_binary-3.1.12-cp310-cp310-win_amd64.whl", hash = "sha256:ee65335781a54f29f4abc28060a6188c41bdd42fdc3cbc1dd84695ed8ef18321"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d401722aa38bda64d1ba8293f6dad99f6f684711e2c016a93f138f2bbcff2a4b"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:46eac158e8e794d9414a8fe7706beeee9b1ecc4accbea914314825ace8137105"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f017400679aa38f6cb22b888b8ec198a5b100ec2132e6b3bcfa797b14b5b438"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d176c4614f5208ab9938d5426d61627c8fbc7f8dab53fef42c8bf2ab8605aa51"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c48c4f3fcfd9e75e3fdb18eea320de591e06059a859280ec26ce8d753299353d"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98fce28d8136bdd883f20d26467bf259b5fb559eb64d8f83695690714cdfdad3"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4a0f44bc29fc1b56ee1c865796cbe354078ee1e985f898e4915db185055bf7d"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6def4f238ca02d6b42336b405d02729c081c978cda9b6ba7549a9c63a91ba823"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:000838cb5ab7851116b462e58893a96b0f1e35864135a6283f3242a730ec45d3"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7949e1aefe339f04dbecac6aa036c9cd137a58f966c4b96ab933823c340ee12"},
|
||||
{file = "psycopg_binary-3.1.12-cp311-cp311-win_amd64.whl", hash = "sha256:b32922872460575083487de41e17e8cf308c3550da02c704efe42960bc6c19de"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:70054ada2f890d004dc3d5ff908e34aecb085fd599d40db2975c09a39c50dfc3"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7544d6d74f5b5f9daafe8a4ed7d266787d62a2bf16f5120c45d42d1f4a856bc8"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43197161099cb4e36a9ca44c10657908b619d7263ffcff30932ad4627430dc3c"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68398cdf3aedd4042b1126b9aba34615f1ab592831483282f19f0159fce5ca75"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77ae6cda3ffee2425aca9ea7af57296d0c701e2ac5897b48b95dfee050234592"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278e8888e90fb6ebd7eae8ccb85199eafd712b734e641e0d40f2a903e946102d"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:047c4ba8d3089465b0a69c4c669128df43403867858d78da6b40b33788bfa89f"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8248b11ac490bb74de80457ab0e9cef31c08164ff7b867031927a17e5c9e19ed"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6979c02acb9783c6134ee516751b8f891a2d4db7f73ebecc9e92750283d6fb99"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:eaf2375b724ad61ee82a5c2a849e57b12b3cb510ec8845084132bbb907cb3335"},
|
||||
{file = "psycopg_binary-3.1.12-cp312-cp312-win_amd64.whl", hash = "sha256:6177cfa6f872a9cc84dbfc7dc163af6ef01639c50acc9a441673f29c2305c37a"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b81427fd5a97c9b4ac12f3b8d985870b0c3866b5fc2e72e51cacd3630ffd6466"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f17a2c393879aa54f840540009d0e70a30d22ffa0038d81e258ac2c99b15d74"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c6a5d125a61101ef5ab7384206e43952fe2a5fca997b96d28a28a752512f900"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942a18df448a33d77aa7dff7e93062ace7926608a965db003622cb5f27910ba2"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3195baff3e3e5d71828400d38af0ffc5a15d7dca2bfaadc9eb615235774b9290"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f26bb34e0e9bb83fba00c4835f91f5c5348cdf689df8c8b503571c0d0027c8f5"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:104bdc85c5c4884b3f900155b635588a28740f561b32a3e27c38bcd249feba41"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:53464cb71e06faac479f44b8870f115004187e1dfb299b9725d1d7f85d9e5479"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:052835aac03ee6a9d5b6fe35c468da79084ebe38709e6d3c24ff5b9422fb2947"},
|
||||
{file = "psycopg_binary-3.1.12-cp37-cp37m-win_amd64.whl", hash = "sha256:a21a7fffec1a225b26d72adb960d771fc5a9aba8e1f7dd710abcaa9a980e9740"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6925a543e88cdfd1a2f679c7a33c08f107de60728a4a3c52f88d4491d40a7f51"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b04957bd5caff94eac38306357b6d448dd20a6f68fd998e115e3731a55118d83"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f55979804853efa5ce84d7ef59ff3772e0823247497f7d4a6870e6527fd791"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d343e1f564fdc8964e1c08b8a6c1f6ebf4b45ee5631b5241c9cbac793f4500c"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48c4ba35f717783327931aa9da6e6aab81b6b90f3e6b902b18e269d73e7d0882"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d77c95d6086e0714225764772bf8110bb29dfbc6c32aa56e725a01998ce20e7c"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6dea80e65c7a97150d555b64744e7279ff4c6b259d27580b756a5b282a7d44e3"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:03a851123d0155e1d6ca5b6cccf624e2fc71c8f7eae76f5100196e0fca047d30"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:99ad07b9ef5853713bb63c55e179af52994e96f445c5d66b87d8b986182922ef"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4441d0f8ecae499a6ac5c79078c9fcd406c0bf70e72cb6cba888aca51aa46943"},
|
||||
{file = "psycopg_binary-3.1.12-cp38-cp38-win_amd64.whl", hash = "sha256:cb45a709b966583773acc3418fffbf6d73b014943b6efceca6a7d3ca960956cf"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5112245daf98e22046316e72690689a8952a9b078908206a6b16cd28d84cde7c"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2eb94bf0bd653c940517cd92dc4f98c85d505f69013b247dda747413bcf0a8b"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d41b03ce52a109858735ac19fe0295e3f77bef0388d6a3e105074ad68f4a9645"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4fddc3c9beaf745de3da10230f0144a4c667b21c3f7a94a3bb1fb004954c9810"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5987616698c895ae079fb5e26811b72948cb3b75c2c690446379298e96c1568"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4ae45d58bd79795a2d23d05be5496b226b09ac2688b9ed9808e13c345e2d542"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb98252ac8ba41a121f88979e4232ffc1d6722c953531cbdae2b328322308581"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ca09e4937c9db24a58951ee9aea7aae7bca11a954b30c59f3b271e9bdebd80d7"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:03e321e149d051daa20892ed1bb3beabf0aae98a8c37da30ec80fa12306f9ba9"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d819cb43cccc10ba501b9d462409fcaaeb19f77b8379b2e7ca0ced4a49446d4a"},
|
||||
{file = "psycopg_binary-3.1.12-cp39-cp39-win_amd64.whl", hash = "sha256:c9eb2ba27760bc1303f0708ba95b9e4f3f3b77a081ef4f7f53375c71da3a1bee"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-pool"
|
||||
version = "3.1.8"
|
||||
description = "Connection Pool for Psycopg"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "psycopg-pool-3.1.8.tar.gz", hash = "sha256:53d9691503b538d419bf147359028633780294976743b1654dbf5f3a85b675db"},
|
||||
{file = "psycopg_pool-3.1.8-py3-none-any.whl", hash = "sha256:dc9b177e749aae4ad155d22f9d02ccb14fe2bf30792227fb02317361b446ee39"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=3.10"
|
||||
|
||||
[[package]]
|
||||
name = "pulsar-client"
|
||||
version = "3.3.0"
|
||||
@@ -4264,7 +4500,7 @@ functions = ["apache-bookkeeper-client (>=4.16.1)", "grpcio (>=1.8.2)", "prometh
|
||||
name = "pyasn1"
|
||||
version = "0.5.0"
|
||||
description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
files = [
|
||||
{file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"},
|
||||
@@ -4275,7 +4511,7 @@ files = [
|
||||
name = "pyasn1-modules"
|
||||
version = "0.3.0"
|
||||
description = "A collection of ASN.1-based protocols modules"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
|
||||
files = [
|
||||
{file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"},
|
||||
@@ -4698,6 +4934,21 @@ pytest = ">=5.0"
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "pytest-asyncio", "tox"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-subtests"
|
||||
version = "0.11.0"
|
||||
description = "unittest subTest() support and subtests fixture"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-subtests-0.11.0.tar.gz", hash = "sha256:51865c88457545f51fb72011942f0a3c6901ee9e24cbfb6d1b9dc1348bafbe37"},
|
||||
{file = "pytest_subtests-0.11.0-py3-none-any.whl", hash = "sha256:453389984952eec85ab0ce0c4f026337153df79587048271c7fd0f49119c07e4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=19.2.0"
|
||||
pytest = ">=7.0"
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.8.2"
|
||||
@@ -4904,10 +5155,7 @@ files = [
|
||||
grpcio = ">=1.41.0"
|
||||
grpcio-tools = ">=1.41.0"
|
||||
httpx = {version = ">=0.14.0", extras = ["http2"]}
|
||||
numpy = [
|
||||
{version = ">=1.21", markers = "python_version >= \"3.8\" and python_version < \"3.12\""},
|
||||
{version = ">=1.26", markers = "python_version >= \"3.12\""},
|
||||
]
|
||||
numpy = {version = ">=1.21", markers = "python_version >= \"3.8\" and python_version < \"3.12\""}
|
||||
portalocker = ">=2.7.0,<3.0.0"
|
||||
pydantic = ">=1.10.8"
|
||||
urllib3 = ">=1.26.14,<2.0.0"
|
||||
@@ -5176,7 +5424,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
name = "requests-oauthlib"
|
||||
version = "1.3.1"
|
||||
description = "OAuthlib authentication support for Requests."
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
{file = "requests-oauthlib-1.3.1.tar.gz", hash = "sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a"},
|
||||
@@ -5228,7 +5476,7 @@ six = ">=1.7.0"
|
||||
name = "rsa"
|
||||
version = "4.9"
|
||||
description = "Pure-Python RSA implementation"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=3.6,<4"
|
||||
files = [
|
||||
{file = "rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7"},
|
||||
@@ -5382,6 +5630,20 @@ tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"]
|
||||
testing = ["h5py (>=3.7.0)", "huggingface_hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools_rust (>=1.5.2)"]
|
||||
torch = ["safetensors[numpy]", "torch (>=1.10)"]
|
||||
|
||||
[[package]]
|
||||
name = "schema"
|
||||
version = "0.7.5"
|
||||
description = "Simple data validation library"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "schema-0.7.5-py2.py3-none-any.whl", hash = "sha256:f3ffdeeada09ec34bf40d7d79996d9f7175db93b7a5065de0faa7f41083c1e6c"},
|
||||
{file = "schema-0.7.5.tar.gz", hash = "sha256:f06717112c61895cabc4707752b88716e8420a8819d71404501e114f91043197"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
contextlib2 = ">=0.5.5"
|
||||
|
||||
[[package]]
|
||||
name = "scikit-learn"
|
||||
version = "1.3.1"
|
||||
@@ -5714,7 +5976,7 @@ files = [
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
greenlet = {version = "!=0.4.17", markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\""}
|
||||
greenlet = {version = "!=0.4.17", optional = true, markers = "platform_machine == \"win32\" or platform_machine == \"WIN32\" or platform_machine == \"AMD64\" or platform_machine == \"amd64\" or platform_machine == \"x86_64\" or platform_machine == \"ppc64le\" or platform_machine == \"aarch64\" or extra == \"asyncio\""}
|
||||
typing-extensions = ">=4.2.0"
|
||||
|
||||
[package.extras]
|
||||
@@ -6764,6 +7026,22 @@ validators = ">=0.21.2,<1.0.0"
|
||||
[package.extras]
|
||||
grpc = ["grpcio (>=1.57.0,<2.0.0)", "grpcio-tools (>=1.57.0,<2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "websocket-client"
|
||||
version = "1.6.4"
|
||||
description = "WebSocket client for Python with low level API options"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "websocket-client-1.6.4.tar.gz", hash = "sha256:b3324019b3c28572086c4a319f91d1dcd44e6e11cd340232978c684a7650d0df"},
|
||||
{file = "websocket_client-1.6.4-py3-none-any.whl", hash = "sha256:084072e0a7f5f347ef2ac3d8698a5e0b4ffbfcab607628cadabc650fc9a83a24"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["Sphinx (>=6.0)", "sphinx-rtd-theme (>=1.1.0)"]
|
||||
optional = ["python-socks", "wsaccel"]
|
||||
test = ["websockets"]
|
||||
|
||||
[[package]]
|
||||
name = "websockets"
|
||||
version = "11.0.3"
|
||||
@@ -6892,7 +7170,7 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
name = "wrapt"
|
||||
version = "1.15.0"
|
||||
description = "Module for decorators, wrappers and monkey patching."
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
files = [
|
||||
{file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
|
||||
@@ -7131,6 +7409,7 @@ opensearch = ["opensearch-py"]
|
||||
opensource = ["gpt4all", "sentence-transformers", "torch"]
|
||||
pinecone = ["pinecone-client"]
|
||||
poe = ["fastapi-poe"]
|
||||
postgres = ["psycopg", "psycopg-binary", "psycopg-pool"]
|
||||
qdrant = ["qdrant-client"]
|
||||
slack = ["flask", "slack-sdk"]
|
||||
streamlit = []
|
||||
@@ -7140,5 +7419,5 @@ whatsapp = ["flask", "twilio"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.9,<3.13"
|
||||
content-hash = "0b83ba3fd2485b3b4aa3c6a7534b214378d349538f7eb63c65768aafecdfad60"
|
||||
python-versions = ">=3.9,<3.12"
|
||||
content-hash = "fa041b870ce060414e7c2d2bc21c2c4909aff117b40a161f2eaafafe44136597"
|
||||
|
||||
+13
-9
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "embedchain"
|
||||
version = "0.0.91"
|
||||
version = "0.1.7"
|
||||
description = "Data platform for LLMs - Load, index, retrieve and sync any unstructured data"
|
||||
authors = [
|
||||
"Taranjeet Singh <taranjeet@embedchain.ai>",
|
||||
@@ -88,12 +88,12 @@ exclude = '''
|
||||
color = true
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9,<3.13"
|
||||
python = ">=3.9,<3.12"
|
||||
python-dotenv = "^1.0.0"
|
||||
langchain = "^0.0.303"
|
||||
langchain = "^0.0.332"
|
||||
requests = "^2.31.0"
|
||||
openai = ">=0.28.0"
|
||||
chromadb = "^0.4.8"
|
||||
openai = ">=1.1.1"
|
||||
chromadb = "^0.4.16"
|
||||
posthog = "^3.0.2"
|
||||
tiktoken = { version = "^0.4.0", optional = true }
|
||||
youtube-transcript-api = { version = "^0.6.1", optional = true }
|
||||
@@ -101,11 +101,12 @@ beautifulsoup4 = { version = "^4.12.2", optional = true }
|
||||
pypdf = { version = "^3.11.0", optional = true }
|
||||
pytube = { version = "^15.0.0", optional = true }
|
||||
duckduckgo-search = { version = "^3.8.5", optional = true }
|
||||
llama-hub = { version = "^0.0.29", optional = true }
|
||||
llama-hub = { version = "^0.0.43", optional = true }
|
||||
llama-index = { version = "^0.8.65", optional = true }
|
||||
sentence-transformers = { version = "^2.2.2", optional = true }
|
||||
torch = { version = "2.0.0", optional = true }
|
||||
# Torch 2.0.1 is not compatible with poetry (https://github.com/pytorch/pytorch/issues/100974)
|
||||
gpt4all = { version = "1.0.8", optional = true }
|
||||
gpt4all = { version = "2.0.2", optional = true }
|
||||
# 1.0.9 is not working for some users (https://github.com/nomic-ai/gpt4all/issues/1394)
|
||||
opensearch-py = { version = "2.3.1", optional = true }
|
||||
elasticsearch = { version = "^8.9.0", optional = true }
|
||||
@@ -128,6 +129,10 @@ huggingface_hub = { version = "^0.17.3", optional = true }
|
||||
pymilvus = { version = "2.3.1", optional = true }
|
||||
google-cloud-aiplatform = { version = "^1.26.1", optional = true }
|
||||
replicate = { version = "^0.15.4", optional = true }
|
||||
schema = "^0.7.5"
|
||||
psycopg = { version = "^3.1.12", optional = true }
|
||||
psycopg-binary = { version = "^3.1.12", optional = true }
|
||||
psycopg-pool = { version = "^3.1.8", optional = true }
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.3.0"
|
||||
@@ -182,9 +187,8 @@ gmail = [
|
||||
"google-api-core",
|
||||
]
|
||||
json = ["llama-hub"]
|
||||
postgres = ["psycopg", "psycopg-binary", "psycopg-pool"]
|
||||
|
||||
[tool.poetry.group.docs.dependencies]
|
||||
|
||||
|
||||
|
||||
[tool.poetry.scripts]
|
||||
|
||||
@@ -86,7 +86,9 @@ class TestAppFromConfig:
|
||||
with open(yaml_path, "r") as file:
|
||||
return yaml.safe_load(file)
|
||||
|
||||
def test_from_chroma_config(self):
|
||||
def test_from_chroma_config(self, mocker):
|
||||
mocker.patch("embedchain.vectordb.chroma.chromadb.Client")
|
||||
|
||||
yaml_path = "configs/chroma.yaml"
|
||||
config_data = self.load_config_data(yaml_path)
|
||||
|
||||
@@ -119,7 +121,9 @@ class TestAppFromConfig:
|
||||
assert app.embedder.config.model == embedder_config["model"]
|
||||
assert app.embedder.config.deployment_name == embedder_config["deployment_name"]
|
||||
|
||||
def test_from_opensource_config(self):
|
||||
def test_from_opensource_config(self, mocker):
|
||||
mocker.patch("embedchain.vectordb.chroma.chromadb.Client")
|
||||
|
||||
yaml_path = "configs/opensource.yaml"
|
||||
config_data = self.load_config_data(yaml_path)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ 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.postgres import PostgresChunker
|
||||
from embedchain.chunkers.qna_pair import QnaPairChunker
|
||||
from embedchain.chunkers.sitemap import SitemapChunker
|
||||
from embedchain.chunkers.table import TableChunker
|
||||
@@ -33,6 +34,7 @@ chunker_common_config = {
|
||||
JSONChunker: {"chunk_size": 1000, "chunk_overlap": 0, "length_function": len},
|
||||
OpenAPIChunker: {"chunk_size": 1000, "chunk_overlap": 0, "length_function": len},
|
||||
GmailChunker: {"chunk_size": 1000, "chunk_overlap": 0, "length_function": len},
|
||||
PostgresChunker: {"chunk_size": 1000, "chunk_overlap": 0, "length_function": len},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from embedchain import App
|
||||
from embedchain.config import AppConfig, ChromaDbConfig
|
||||
from embedchain.embedchain import EmbedChain
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.memory.base import ECChatMemory
|
||||
|
||||
os.environ["OPENAI_API_KEY"] = "test-api-key"
|
||||
|
||||
@@ -25,6 +26,11 @@ def test_whole_app(app_instance, mocker):
|
||||
mocker.patch.object(BaseLlm, "get_answer_from_llm", return_value=knowledge)
|
||||
mocker.patch.object(BaseLlm, "get_llm_model_answer", return_value=knowledge)
|
||||
mocker.patch.object(BaseLlm, "generate_prompt")
|
||||
mocker.patch.object(
|
||||
BaseLlm,
|
||||
"add_history",
|
||||
)
|
||||
mocker.patch.object(ECChatMemory, "delete_chat_history", autospec=True)
|
||||
|
||||
app_instance.add(knowledge, data_type="text")
|
||||
app_instance.query("What text did I give you?")
|
||||
@@ -35,10 +41,16 @@ def test_whole_app(app_instance, mocker):
|
||||
|
||||
|
||||
def test_add_after_reset(app_instance, mocker):
|
||||
mocker.patch("embedchain.vectordb.chroma.chromadb.Client")
|
||||
|
||||
config = AppConfig(log_level="DEBUG", collect_metrics=False)
|
||||
chroma_config = {"allow_reset": True}
|
||||
|
||||
app_instance = App(config=config, db_config=ChromaDbConfig(**chroma_config))
|
||||
|
||||
# mock delete chat history
|
||||
mocker.patch.object(ECChatMemory, "delete_chat_history", autospec=True)
|
||||
|
||||
app_instance.reset()
|
||||
|
||||
app_instance.db.client.heartbeat()
|
||||
@@ -61,5 +73,5 @@ def test_add_after_reset(app_instance, mocker):
|
||||
def test_add_with_incorrect_content(app_instance, mocker):
|
||||
content = [{"foo": "bar"}]
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
with pytest.raises(TypeError):
|
||||
app_instance.add(content, data_type="json")
|
||||
|
||||
+26
-18
@@ -5,6 +5,8 @@ from unittest.mock import MagicMock, patch
|
||||
from embedchain import App
|
||||
from embedchain.config import AppConfig, BaseLlmConfig
|
||||
from embedchain.llm.base import BaseLlm
|
||||
from embedchain.memory.base import ECChatMemory
|
||||
from embedchain.memory.message import ChatMessage
|
||||
|
||||
|
||||
class TestApp(unittest.TestCase):
|
||||
@@ -31,14 +33,14 @@ class TestApp(unittest.TestCase):
|
||||
"""
|
||||
config = AppConfig(collect_metrics=False)
|
||||
app = App(config=config)
|
||||
first_answer = app.chat("Test query 1")
|
||||
self.assertEqual(first_answer, "Test answer")
|
||||
self.assertEqual(len(app.llm.memory.chat_memory.messages), 2)
|
||||
self.assertEqual(len(app.llm.history.splitlines()), 2)
|
||||
second_answer = app.chat("Test query 2")
|
||||
self.assertEqual(second_answer, "Test answer")
|
||||
self.assertEqual(len(app.llm.memory.chat_memory.messages), 4)
|
||||
self.assertEqual(len(app.llm.history.splitlines()), 4)
|
||||
with patch.object(BaseLlm, "add_history") as mock_history:
|
||||
first_answer = app.chat("Test query 1")
|
||||
self.assertEqual(first_answer, "Test answer")
|
||||
mock_history.assert_called_with(app.config.id, "Test query 1", "Test answer")
|
||||
|
||||
second_answer = app.chat("Test query 2")
|
||||
self.assertEqual(second_answer, "Test answer")
|
||||
mock_history.assert_called_with(app.config.id, "Test query 2", "Test answer")
|
||||
|
||||
@patch.object(App, "retrieve_from_database", return_value=["Test context"])
|
||||
@patch.object(BaseLlm, "get_answer_from_llm", return_value="Test answer")
|
||||
@@ -49,16 +51,22 @@ class TestApp(unittest.TestCase):
|
||||
|
||||
Also tests that a dry run does not change the history
|
||||
"""
|
||||
config = AppConfig(collect_metrics=False)
|
||||
app = App(config=config)
|
||||
first_answer = app.chat("Test query 1")
|
||||
self.assertEqual(first_answer, "Test answer")
|
||||
self.assertEqual(len(app.llm.history.splitlines()), 2)
|
||||
history = app.llm.history
|
||||
dry_run = app.chat("Test query 2", dry_run=True)
|
||||
self.assertIn("History:", dry_run)
|
||||
self.assertEqual(history, app.llm.history)
|
||||
self.assertEqual(len(app.llm.history.splitlines()), 2)
|
||||
with patch.object(ECChatMemory, "get_recent_memories") as mock_memory:
|
||||
mock_message = ChatMessage()
|
||||
mock_message.add_user_message("Test query 1")
|
||||
mock_message.add_ai_message("Test answer")
|
||||
mock_memory.return_value = [mock_message]
|
||||
|
||||
config = AppConfig(collect_metrics=False)
|
||||
app = App(config=config)
|
||||
first_answer = app.chat("Test query 1")
|
||||
self.assertEqual(first_answer, "Test answer")
|
||||
self.assertEqual(len(app.llm.history), 1)
|
||||
history = app.llm.history
|
||||
dry_run = app.chat("Test query 2", dry_run=True)
|
||||
self.assertIn("History:", dry_run)
|
||||
self.assertEqual(history, app.llm.history)
|
||||
self.assertEqual(len(app.llm.history), 1)
|
||||
|
||||
@patch("chromadb.api.models.Collection.Collection.add", MagicMock)
|
||||
def test_chat_with_where_in_params(self):
|
||||
|
||||
@@ -13,7 +13,7 @@ def config():
|
||||
top_p=0.8,
|
||||
stream=False,
|
||||
system_prompt="System prompt",
|
||||
model="orca-mini-3b.ggmlv3.q4_0.bin",
|
||||
model="orca-mini-3b-gguf2-q4_0.gguf",
|
||||
)
|
||||
yield config
|
||||
|
||||
@@ -40,7 +40,7 @@ def test_gpt4all_init_with_config(config, gpt4all_with_config):
|
||||
|
||||
|
||||
def test_gpt4all_init_without_config(gpt4all_without_config):
|
||||
assert gpt4all_without_config.config.model == "orca-mini-3b.ggmlv3.q4_0.bin"
|
||||
assert gpt4all_without_config.config.model == "orca-mini-3b-gguf2-q4_0.gguf"
|
||||
assert isinstance(gpt4all_without_config.instance, LangchainGPT4All)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import psycopg
|
||||
import pytest
|
||||
|
||||
from embedchain.loaders.postgres import PostgresLoader
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def postgres_loader(mocker):
|
||||
with mocker.patch.object(psycopg, "connect"):
|
||||
config = {"url": "postgres://user:password@localhost:5432/database"}
|
||||
loader = PostgresLoader(config=config)
|
||||
yield loader
|
||||
|
||||
|
||||
def test_postgres_loader_initialization(postgres_loader):
|
||||
assert postgres_loader.connection is not None
|
||||
assert postgres_loader.cursor is not None
|
||||
|
||||
|
||||
def test_postgres_loader_invalid_config():
|
||||
with pytest.raises(ValueError, match="Must provide the valid config. Received: None"):
|
||||
PostgresLoader(config=None)
|
||||
|
||||
|
||||
def test_load_data(postgres_loader, monkeypatch):
|
||||
mock_cursor = MagicMock()
|
||||
monkeypatch.setattr(postgres_loader, "cursor", mock_cursor)
|
||||
|
||||
query = "SELECT * FROM table"
|
||||
mock_cursor.fetchall.return_value = [(1, "data1"), (2, "data2")]
|
||||
|
||||
result = postgres_loader.load_data(query)
|
||||
|
||||
assert "doc_id" in result
|
||||
assert "data" in result
|
||||
assert len(result["data"]) == 2
|
||||
assert result["data"][0]["meta_data"]["url"] == f"postgres_query-({query})"
|
||||
assert result["data"][1]["meta_data"]["url"] == f"postgres_query-({query})"
|
||||
assert mock_cursor.execute.called_with(query)
|
||||
|
||||
|
||||
def test_load_data_exception(postgres_loader, monkeypatch):
|
||||
mock_cursor = MagicMock()
|
||||
monkeypatch.setattr(postgres_loader, "cursor", mock_cursor)
|
||||
|
||||
_ = "SELECT * FROM table"
|
||||
mock_cursor.execute.side_effect = Exception("Mocked exception")
|
||||
|
||||
with pytest.raises(
|
||||
ValueError, match=r"Failed to load data using query=SELECT \* FROM table with: Mocked exception"
|
||||
):
|
||||
postgres_loader.load_data("SELECT * FROM table")
|
||||
|
||||
|
||||
def test_close_connection(postgres_loader):
|
||||
postgres_loader.close_connection()
|
||||
assert postgres_loader.cursor is None
|
||||
assert postgres_loader.connection is None
|
||||
@@ -0,0 +1,67 @@
|
||||
import pytest
|
||||
|
||||
from embedchain.memory.base import ECChatMemory
|
||||
from embedchain.memory.message import ChatMessage
|
||||
|
||||
|
||||
# Fixture for creating an instance of ECChatMemory
|
||||
@pytest.fixture
|
||||
def chat_memory_instance():
|
||||
return ECChatMemory()
|
||||
|
||||
|
||||
def test_add_chat_memory(chat_memory_instance):
|
||||
app_id = "test_app"
|
||||
human_message = "Hello, how are you?"
|
||||
ai_message = "I'm fine, thank you!"
|
||||
|
||||
chat_message = ChatMessage()
|
||||
chat_message.add_user_message(human_message)
|
||||
chat_message.add_ai_message(ai_message)
|
||||
|
||||
chat_memory_instance.add(app_id, chat_message)
|
||||
|
||||
assert chat_memory_instance.count_history_messages(app_id) == 1
|
||||
chat_memory_instance.delete_chat_history(app_id)
|
||||
|
||||
|
||||
def test_get_recent_memories(chat_memory_instance):
|
||||
app_id = "test_app"
|
||||
|
||||
for i in range(1, 7):
|
||||
human_message = f"Question {i}"
|
||||
ai_message = f"Answer {i}"
|
||||
|
||||
chat_message = ChatMessage()
|
||||
chat_message.add_user_message(human_message)
|
||||
chat_message.add_ai_message(ai_message)
|
||||
|
||||
chat_memory_instance.add(app_id, chat_message)
|
||||
|
||||
recent_memories = chat_memory_instance.get_recent_memories(app_id, num_rounds=5)
|
||||
|
||||
assert len(recent_memories) == 5
|
||||
|
||||
|
||||
def test_delete_chat_history(chat_memory_instance):
|
||||
app_id = "test_app"
|
||||
|
||||
for i in range(1, 6):
|
||||
human_message = f"Question {i}"
|
||||
ai_message = f"Answer {i}"
|
||||
|
||||
chat_message = ChatMessage()
|
||||
chat_message.add_user_message(human_message)
|
||||
chat_message.add_ai_message(ai_message)
|
||||
|
||||
chat_memory_instance.add(app_id, chat_message)
|
||||
|
||||
chat_memory_instance.delete_chat_history(app_id)
|
||||
|
||||
assert chat_memory_instance.count_history_messages(app_id) == 0
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def close_connection(chat_memory_instance):
|
||||
yield
|
||||
chat_memory_instance.close_connection()
|
||||
@@ -0,0 +1,37 @@
|
||||
from embedchain.memory.message import BaseMessage, ChatMessage
|
||||
|
||||
|
||||
def test_ec_base_message():
|
||||
content = "Hello, how are you?"
|
||||
creator = "human"
|
||||
metadata = {"key": "value"}
|
||||
|
||||
message = BaseMessage(content=content, creator=creator, metadata=metadata)
|
||||
|
||||
assert message.content == content
|
||||
assert message.creator == creator
|
||||
assert message.metadata == metadata
|
||||
assert message.type is None
|
||||
assert message.is_lc_serializable() is True
|
||||
assert str(message) == f"{creator}: {content}"
|
||||
|
||||
|
||||
def test_ec_base_chat_message():
|
||||
human_message_content = "Hello, how are you?"
|
||||
ai_message_content = "I'm fine, thank you!"
|
||||
human_metadata = {"user": "John"}
|
||||
ai_metadata = {"response_time": 0.5}
|
||||
|
||||
chat_message = ChatMessage()
|
||||
chat_message.add_user_message(human_message_content, metadata=human_metadata)
|
||||
chat_message.add_ai_message(ai_message_content, metadata=ai_metadata)
|
||||
|
||||
assert chat_message.human_message.content == human_message_content
|
||||
assert chat_message.human_message.creator == "human"
|
||||
assert chat_message.human_message.metadata == human_metadata
|
||||
|
||||
assert chat_message.ai_message.content == ai_message_content
|
||||
assert chat_message.ai_message.creator == "ai"
|
||||
assert chat_message.ai_message.metadata == ai_metadata
|
||||
|
||||
assert str(chat_message) == f"human: {human_message_content}\nai: {ai_message_content}"
|
||||
@@ -0,0 +1,36 @@
|
||||
import yaml
|
||||
|
||||
from embedchain.utils import validate_yaml_config
|
||||
|
||||
CONFIG_YAMLS = [
|
||||
"configs/anthropic.yaml",
|
||||
"configs/azure_openai.yaml",
|
||||
"configs/chroma.yaml",
|
||||
"configs/chunker.yaml",
|
||||
"configs/cohere.yaml",
|
||||
"configs/full-stack.yaml",
|
||||
"configs/gpt4all.yaml",
|
||||
"configs/huggingface.yaml",
|
||||
"configs/jina.yaml",
|
||||
"configs/llama2.yaml",
|
||||
"configs/opensearch.yaml",
|
||||
"configs/opensource.yaml",
|
||||
"configs/pinecone.yaml",
|
||||
"configs/vertexai.yaml",
|
||||
"configs/weaviate.yaml",
|
||||
]
|
||||
|
||||
|
||||
class TestAllConfigYamls:
|
||||
def test_all_config_yamls(self):
|
||||
"""Test that all config yamls are valid."""
|
||||
for config_yaml in CONFIG_YAMLS:
|
||||
with open(config_yaml, "r") as f:
|
||||
config = yaml.safe_load(f)
|
||||
assert config is not None
|
||||
|
||||
try:
|
||||
validate_yaml_config(config)
|
||||
except Exception as e:
|
||||
print(f"Error in {config_yaml}: {e}")
|
||||
raise e
|
||||
@@ -33,12 +33,14 @@ def cleanup_db():
|
||||
print("Error: %s - %s." % (e.filename, e.strerror))
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="ChromaDB client needs to be mocked")
|
||||
def test_chroma_db_init_with_host_and_port(chroma_db):
|
||||
settings = chroma_db.client.get_settings()
|
||||
assert settings.chroma_server_host == "test-host"
|
||||
assert settings.chroma_server_http_port == "1234"
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="ChromaDB client needs to be mocked")
|
||||
def test_chroma_db_init_with_basic_auth():
|
||||
chroma_config = {
|
||||
"host": "test-host",
|
||||
@@ -159,6 +161,8 @@ def test_chroma_db_collection_add_with_skip_embedding(app_with_settings):
|
||||
"embeddings": None,
|
||||
"ids": ["id"],
|
||||
"metadatas": [{"url": "url_1", "doc_id": "doc_id_1"}],
|
||||
"data": None,
|
||||
"uris": None,
|
||||
}
|
||||
|
||||
assert data == expected_value
|
||||
|
||||
Reference in New Issue
Block a user