Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1df46b2bb3 | ||
|
|
58f72e1ffe | ||
|
|
33409140b4 | ||
|
|
f6b80e01a1 | ||
|
|
798d3fcc5a | ||
|
|
85f3ac428b | ||
|
|
9fcf2130b5 | ||
|
|
51df00729e | ||
|
|
023a61446f | ||
|
|
e0b73e6a5a | ||
|
|
28460f725c | ||
|
|
c93e49d2b8 | ||
|
|
07fb6bee54 | ||
|
|
3fa7db8420 | ||
|
|
c14bd7b73b | ||
|
|
5201beaab0 | ||
|
|
122313d8a5 | ||
|
|
82fd595306 | ||
|
|
95c0d47236 | ||
|
|
919cc74e94 | ||
|
|
d839991acb | ||
|
|
539286aafd | ||
|
|
23522b7b55 | ||
|
|
bf3fac56e4 | ||
|
|
a5bf8e9075 | ||
|
|
1d31b8f7e4 |
@@ -23,4 +23,3 @@ embedder:
|
|||||||
provider: openai
|
provider: openai
|
||||||
config:
|
config:
|
||||||
model: 'text-embedding-ada-002'
|
model: 'text-embedding-ada-002'
|
||||||
deployment_name: 'test-deployment'
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
llm:
|
||||||
|
provider: openai
|
||||||
|
config:
|
||||||
|
model: 'gpt-4'
|
||||||
|
temperature: 0.5
|
||||||
|
max_tokens: 1000
|
||||||
|
top_p: 1
|
||||||
|
stream: false
|
||||||
@@ -55,8 +55,8 @@ import os
|
|||||||
from embedchain import Pipeline as App
|
from embedchain import Pipeline as App
|
||||||
|
|
||||||
os.environ["OPENAI_API_TYPE"] = "azure"
|
os.environ["OPENAI_API_TYPE"] = "azure"
|
||||||
os.environ["OPENAI_API_BASE"] = "https://xxx.openai.azure.com/"
|
os.environ["AZURE_OPENAI_ENDPOINT"] = "https://xxx.openai.azure.com/"
|
||||||
os.environ["OPENAI_API_KEY"] = "xxx"
|
os.environ["AZURE_OPENAI_API_KEY"] = "xxx"
|
||||||
os.environ["OPENAI_API_VERSION"] = "xxx"
|
os.environ["OPENAI_API_VERSION"] = "xxx"
|
||||||
|
|
||||||
app = App.from_config(yaml_path="config.yaml")
|
app = App.from_config(yaml_path="config.yaml")
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
title: '🗨️ Discourse'
|
||||||
|
---
|
||||||
|
|
||||||
|
You can now easily load data from your community built with [Discourse](https://discourse.org/).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
1. Setup the Discourse Loader with your community url.
|
||||||
|
```Python
|
||||||
|
from embedchain.loaders.discourse import DiscourseLoader
|
||||||
|
|
||||||
|
dicourse_loader = DiscourseLoader(config={"domain": "https://community.openai.com"})
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Once you setup the loader, you can create an app and load data using the above discourse loader
|
||||||
|
```Python
|
||||||
|
import os
|
||||||
|
from embedchain.pipeline import Pipeline as App
|
||||||
|
|
||||||
|
os.environ["OPENAI_API_KEY"] = "sk-xxx"
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
app.add("openai after:2023-10-1", data_type="discourse", loader=dicourse_loader)
|
||||||
|
|
||||||
|
question = "Where can I find the OpenAI API status page?"
|
||||||
|
app.query(question)
|
||||||
|
# Answer: You can find the OpenAI API status page at https:/status.openai.com/.
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: The `add` function of the app will accept any executable search query to load data. Refer [Discourse API Docs](https://docs.discourse.org/#tag/Search) to learn more about search queries.
|
||||||
|
|
||||||
|
3. We automatically create a chunker to chunk your discourse data, however if you wish to provide your own chunker class. Here is how you can do that:
|
||||||
|
```Python
|
||||||
|
|
||||||
|
from embedchain.chunkers.discourse import DiscourseChunker
|
||||||
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
|
|
||||||
|
discourse_chunker_config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||||
|
discourse_chunker = DiscourseChunker(config=discourse_chunker_config)
|
||||||
|
|
||||||
|
app.add("openai", data_type='discourse', loader=dicourse_loader, chunker=discourse_chunker)
|
||||||
|
```
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
---
|
||||||
|
title: '🐬 MySQL'
|
||||||
|
---
|
||||||
|
|
||||||
|
1. Setup the MySQL loader by configuring the SQL db.
|
||||||
|
```Python
|
||||||
|
from embedchain.loaders.mysql import MySQLLoader
|
||||||
|
|
||||||
|
config = {
|
||||||
|
"host": "host",
|
||||||
|
"port": "port",
|
||||||
|
"database": "database",
|
||||||
|
"user": "username",
|
||||||
|
"password": "password",
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_loader = MySQLLoader(config=config)
|
||||||
|
```
|
||||||
|
|
||||||
|
For more details on how to setup with valid config, check MySQL [documentation](https://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html).
|
||||||
|
|
||||||
|
2. Once you setup the loader, you can create an app and load data using the above MySQL loader
|
||||||
|
```Python
|
||||||
|
import os
|
||||||
|
from embedchain.pipeline import Pipeline as App
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
app.add("SELECT * FROM table_name;", data_type='mysql', loader=mysql_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.
|
||||||
|
|
||||||
|
3. We automatically create a chunker to chunk your SQL data, however if you wish to provide your own chunker class. Here is how you can do that:
|
||||||
|
``Python
|
||||||
|
|
||||||
|
from embedchain.chunkers.mysql import MySQLChunker
|
||||||
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
|
|
||||||
|
mysql_chunker_config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||||
|
mysql_chunker = MySQLChunker(config=mysql_chunker_config)
|
||||||
|
|
||||||
|
app.add("SELECT * FROM table_name;", data_type='mysql', loader=mysql_loader, chunker=mysql_chunker)
|
||||||
|
```
|
||||||
@@ -18,9 +18,12 @@ Embedchain comes with built-in support for various data sources. We handle the c
|
|||||||
<Card title="🌐📄 web page" href="/data-sources/web-page"></Card>
|
<Card title="🌐📄 web page" href="/data-sources/web-page"></Card>
|
||||||
<Card title="🧾 xml" href="/data-sources/xml"></Card>
|
<Card title="🧾 xml" href="/data-sources/xml"></Card>
|
||||||
<Card title="🙌 OpenAPI" href="/data-sources/openapi"></Card>
|
<Card title="🙌 OpenAPI" href="/data-sources/openapi"></Card>
|
||||||
<Card title="🎥📺 youtube video" href="/data-sources/youtube-video"></Card>
|
<Card title="📺 youtube video" href="/data-sources/youtube-video"></Card>
|
||||||
<Card title="📬 Gmail" href="/data-sources/gmail"></Card>
|
<Card title="📬 Gmail" href="/data-sources/gmail"></Card>
|
||||||
<Card title="🐘 Postgres" href="/data-sources/postgres"></Card>
|
<Card title="🐘 Postgres" href="/data-sources/postgres"></Card>
|
||||||
|
<Card title="🐬 MySQL" href="/data-sources/mysql"></Card>
|
||||||
|
<Card title="🤖 Slack" href="/data-sources/slack"></Card>
|
||||||
|
<Card title="🗨️ Discourse" href="/data-sources/discourse"></Card>
|
||||||
</CardGroup>
|
</CardGroup>
|
||||||
|
|
||||||
<br/ >
|
<br/ >
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
title: '🤖 Slack'
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-requisite
|
||||||
|
- Download required packages by running `pip install --upgrade "embedchain[slack]"`.
|
||||||
|
- Configure your slack bot token as environment variable `SLACK_USER_TOKEN`.
|
||||||
|
- Find your user token on your [Slack Account](https://api.slack.com/authentication/token-types)
|
||||||
|
- Make sure your slack user token includes [search](https://api.slack.com/scopes/search:read) scope.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
1. Setup the Slack loader by configuring the Slack Webclient.
|
||||||
|
```Python
|
||||||
|
from embedchain.loaders.slack import SlackLoader
|
||||||
|
|
||||||
|
os.environ["SLACK_USER_TOKEN"] = "xoxp-*"
|
||||||
|
|
||||||
|
loader = SlackLoader()
|
||||||
|
|
||||||
|
"""
|
||||||
|
config = {
|
||||||
|
'base_url': slack_app_url,
|
||||||
|
'headers': web_headers,
|
||||||
|
'team_id': slack_team_id,
|
||||||
|
}
|
||||||
|
|
||||||
|
loader = SlackLoader(config)
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: you can also pass the `config` with `base_url`, `headers`, `team_id` to setup your SlackLoader.
|
||||||
|
|
||||||
|
2. Once you setup the loader, you can create an app and load data using the above slack loader
|
||||||
|
```Python
|
||||||
|
import os
|
||||||
|
from embedchain.pipeline import Pipeline as App
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
app.add("in:random", data_type="slack", loader=loader)
|
||||||
|
question = "Which bots are available in the slack workspace's random channel?"
|
||||||
|
# Answer: The available bot in the slack workspace's random channel is the Embedchain bot.
|
||||||
|
```
|
||||||
|
|
||||||
|
3. We automatically create a chunker to chunk your slack data, however if you wish to provide your own chunker class. Here is how you can do that:
|
||||||
|
```Python
|
||||||
|
from embedchain.chunkers.slack import SlackChunker
|
||||||
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
|
|
||||||
|
slack_chunker_config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||||
|
slack_chunker = SlackChunker(config=slack_chunker_config)
|
||||||
|
|
||||||
|
app.add(slack_chunker, data_type="slack", loader=loader, chunker=slack_chunker)
|
||||||
|
```
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: "📝 Substack"
|
||||||
|
---
|
||||||
|
|
||||||
|
To add any Substack data sources to your app, just add the sitemap.xml of that url as the source and set the data_type to `substack`.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from embedchain import Pipeline as App
|
||||||
|
|
||||||
|
app = App()
|
||||||
|
|
||||||
|
# source: for any substack just add the sitemap.xml url
|
||||||
|
app.add('https://www.lennysnewsletter.com/sitemap.xml', data_type='substack')
|
||||||
|
app.query("Who is Brian Chesky?")
|
||||||
|
# Answer: Brian Chesky is the co-founder and CEO of Airbnb.
|
||||||
|
```
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: '🎥📺 Youtube video'
|
title: '📺 Youtube video'
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,21 @@ channels:read
|
|||||||
chat:write
|
chat:write
|
||||||
```
|
```
|
||||||
5. Now select the option `Install to Workspace` and after it's done, copy the `Bot User OAuth Token` and set it in your secrets as `SLACK_BOT_TOKEN`.
|
5. Now select the option `Install to Workspace` and after it's done, copy the `Bot User OAuth Token` and set it in your secrets as `SLACK_BOT_TOKEN`.
|
||||||
6. Run your bot now with `python3 -m embedchain.bots.slack`
|
6. Run your bot now,
|
||||||
7. Expose your bot to the internet. Default port is `5000`, which can be changed by adding `port --8080` to the startup command. You can use your machine's public IP or DNS. Otherwise, employ a proxy server like [ngrok](https://ngrok.com/) to make your local bot accessible.
|
<Tabs>
|
||||||
|
<Tab title="docker">
|
||||||
|
```bash
|
||||||
|
docker run --name slack-bot -e OPENAI_API_KEY=sk-xxx -e SLACK_BOT_TOKEN=xxx -p 8000:8000 embedchain/slack-bot
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
<Tab title="python">
|
||||||
|
```bash
|
||||||
|
pip install --upgrade "embedchain[slack]"
|
||||||
|
python3 -m embedchain.bots.slack --port 8000
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
7. Expose your bot to the internet. You can use your machine's public IP or DNS. Otherwise, employ a proxy server like [ngrok](https://ngrok.com/) to make your local bot accessible.
|
||||||
8. On the Slack API website go to `Event Subscriptions` on the left Sidebar and turn on `Enable Events`.
|
8. On the Slack API website go to `Event Subscriptions` on the left Sidebar and turn on `Enable Events`.
|
||||||
9. In `Request URL`, enter your server or ngrok address.
|
9. In `Request URL`, enter your server or ngrok address.
|
||||||
10. After it gets verified, click on `Subscribe to bot events`, add `message.channels` Bot User Event and click on `Save Changes`.
|
10. After it gets verified, click on `Subscribe to bot events`, add `message.channels` Bot User Event and click on `Save Changes`.
|
||||||
|
|||||||
@@ -83,3 +83,9 @@ app.deploy()
|
|||||||
# 🛠️ Adding data to your pipeline...
|
# 🛠️ Adding data to your pipeline...
|
||||||
# ✅ Data of type: web_page, value: https://www.forbes.com/profile/elon-musk added successfully.
|
# ✅ Data of type: web_page, value: https://www.forbes.com/profile/elon-musk added successfully.
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can try it out yourself using the following Google Colab notebook:
|
||||||
|
|
||||||
|
<a href="https://colab.research.google.com/drive/17ON1LPonnXAtLaZEebnOktstB_1cJJmh?usp=sharing">
|
||||||
|
<img src="https://camo.githubusercontent.com/84f0493939e0c4de4e6dbe113251b4bfb5353e57134ffd9fcab6b8714514d4d1/68747470733a2f2f636f6c61622e72657365617263682e676f6f676c652e636f6d2f6173736574732f636f6c61622d62616467652e737667" alt="Open in Colab" />
|
||||||
|
</a>
|
||||||
|
|||||||
+3
-1
@@ -87,7 +87,9 @@
|
|||||||
"data-sources/text",
|
"data-sources/text",
|
||||||
"data-sources/web-page",
|
"data-sources/web-page",
|
||||||
"data-sources/openapi",
|
"data-sources/openapi",
|
||||||
"data-sources/youtube-video"
|
"data-sources/youtube-video",
|
||||||
|
"data-sources/discourse",
|
||||||
|
"data-sources/substack"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"data-sources/data-type-handling"
|
"data-sources/data-type-handling"
|
||||||
|
|||||||
@@ -6,3 +6,6 @@ from embedchain.apps.app import App # noqa: F401
|
|||||||
from embedchain.client import Client # noqa: F401
|
from embedchain.client import Client # noqa: F401
|
||||||
from embedchain.pipeline import Pipeline # noqa: F401
|
from embedchain.pipeline import Pipeline # noqa: F401
|
||||||
from embedchain.vectordb.chroma import ChromaDB # noqa: F401
|
from embedchain.vectordb.chroma import ChromaDB # noqa: F401
|
||||||
|
|
||||||
|
# Setup the user directory if doesn't exist already
|
||||||
|
Client.setup_dir()
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ from typing import Optional
|
|||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from embedchain.client import Client
|
from embedchain.config import AppConfig, BaseEmbedderConfig, BaseLlmConfig, ChunkerConfig
|
||||||
from embedchain.config import (AppConfig, BaseEmbedderConfig, BaseLlmConfig,
|
|
||||||
ChunkerConfig)
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.embedchain import EmbedChain
|
from embedchain.embedchain import EmbedChain
|
||||||
from embedchain.embedder.base import BaseEmbedder
|
from embedchain.embedder.base import BaseEmbedder
|
||||||
from embedchain.embedder.openai import OpenAIEmbedder
|
from embedchain.embedder.openai import OpenAIEmbedder
|
||||||
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
from embedchain.llm.openai import OpenAILlm
|
from embedchain.llm.openai import OpenAILlm
|
||||||
from embedchain.utils import validate_yaml_config
|
from embedchain.utils import validate_yaml_config
|
||||||
@@ -68,9 +66,6 @@ class App(EmbedChain):
|
|||||||
:type system_prompt: Optional[str], optional
|
:type system_prompt: Optional[str], optional
|
||||||
:raises TypeError: LLM, database or embedder or their config is not a valid class instance.
|
: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
|
# Type check configs
|
||||||
if config and not isinstance(config, AppConfig):
|
if config and not isinstance(config, AppConfig):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ from typing import Any
|
|||||||
from embedchain import Pipeline as App
|
from embedchain import Pipeline as App
|
||||||
from embedchain.config import AddConfig, BaseLlmConfig, PipelineConfig
|
from embedchain.config import AddConfig, BaseLlmConfig, PipelineConfig
|
||||||
from embedchain.embedder.openai import OpenAIEmbedder
|
from embedchain.embedder.openai import OpenAIEmbedder
|
||||||
from embedchain.helper.json_serializable import (JSONSerializable,
|
from embedchain.helpers.json_serializable import (JSONSerializable,
|
||||||
register_deserializable)
|
register_deserializable)
|
||||||
from embedchain.llm.openai import OpenAILlm
|
from embedchain.llm.openai import OpenAILlm
|
||||||
from embedchain.vectordb.chroma import ChromaDB
|
from embedchain.vectordb.chroma import ChromaDB
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import argparse
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .base import BaseBot
|
from .base import BaseBot
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .base import BaseBot
|
from .base import BaseBot
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import signal
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
from embedchain import App
|
from embedchain import App
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .base import BaseBot
|
from .base import BaseBot
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import logging
|
|||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .base import BaseBot
|
from .base import BaseBot
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
from embedchain.models.data_type import DataType
|
from embedchain.models.data_type import DataType
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class CommonChunker(BaseChunker):
|
||||||
|
"""Common chunker for all loaders."""
|
||||||
|
|
||||||
|
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||||
|
if config is None:
|
||||||
|
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||||
|
text_splitter = RecursiveCharacterTextSplitter(
|
||||||
|
chunk_size=config.chunk_size,
|
||||||
|
chunk_overlap=config.chunk_overlap,
|
||||||
|
length_function=config.length_function,
|
||||||
|
)
|
||||||
|
super().__init__(text_splitter)
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||||
|
|
||||||
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class DiscourseChunker(BaseChunker):
|
||||||
|
"""Chunker for discourse."""
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -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.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class MySQLChunker(BaseChunker):
|
||||||
|
"""Chunker for json."""
|
||||||
|
|
||||||
|
def __init__(self, config: Optional[ChunkerConfig] = None):
|
||||||
|
if config is None:
|
||||||
|
config = ChunkerConfig(chunk_size=1000, chunk_overlap=0, length_function=len)
|
||||||
|
text_splitter = RecursiveCharacterTextSplitter(
|
||||||
|
chunk_size=config.chunk_size,
|
||||||
|
chunk_overlap=config.chunk_overlap,
|
||||||
|
length_function=config.length_function,
|
||||||
|
)
|
||||||
|
super().__init__(text_splitter)
|
||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -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.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class SlackChunker(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)
|
||||||
@@ -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.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class SubstackChunker(BaseChunker):
|
||||||
|
"""Chunker for Substack."""
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.text_splitter import RecursiveCharacterTextSplitter
|
|||||||
|
|
||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config.add_config import ChunkerConfig
|
from embedchain.config.add_config import ChunkerConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from importlib import import_module
|
|||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
from embedchain.config.base_config import BaseConfig
|
from embedchain.config.base_config import BaseConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .base_app_config import BaseAppConfig
|
from .base_app_config import BaseAppConfig
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import logging
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config.base_config import BaseConfig
|
from embedchain.config.base_config import BaseConfig
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
from embedchain.vectordb.base import BaseVectorDB
|
from embedchain.vectordb.base import BaseVectorDB
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Any, Dict
|
from typing import Any, Dict
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
|
|
||||||
|
|
||||||
class BaseConfig(JSONSerializable):
|
class BaseConfig(JSONSerializable):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import re
|
import re
|
||||||
from string import Template
|
from string import Template
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from embedchain.config.base_config import BaseConfig
|
from embedchain.config.base_config import BaseConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
DEFAULT_PROMPT = """
|
DEFAULT_PROMPT = """
|
||||||
Use the following pieces of context to answer the query at the end.
|
Use the following pieces of context to answer the query at the end.
|
||||||
@@ -68,6 +68,7 @@ class BaseLlmConfig(BaseConfig):
|
|||||||
system_prompt: Optional[str] = None,
|
system_prompt: Optional[str] = None,
|
||||||
where: Dict[str, Any] = None,
|
where: Dict[str, Any] = None,
|
||||||
query_type: Optional[str] = None,
|
query_type: Optional[str] = None,
|
||||||
|
callbacks: Optional[List] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Initializes a configuration class instance for the LLM.
|
Initializes a configuration class instance for the LLM.
|
||||||
@@ -98,6 +99,8 @@ class BaseLlmConfig(BaseConfig):
|
|||||||
:type system_prompt: Optional[str], optional
|
:type system_prompt: Optional[str], optional
|
||||||
:param where: A dictionary of key-value pairs to filter the database results., defaults to None
|
:param where: A dictionary of key-value pairs to filter the database results., defaults to None
|
||||||
:type where: Dict[str, Any], optional
|
:type where: Dict[str, Any], optional
|
||||||
|
:param callbacks: Langchain callback functions to use, defaults to None
|
||||||
|
:type callbacks: Optional[List], optional
|
||||||
:raises ValueError: If the template is not valid as template should
|
:raises ValueError: If the template is not valid as template should
|
||||||
contain $context and $query (and optionally $history)
|
contain $context and $query (and optionally $history)
|
||||||
:raises ValueError: Stream is not boolean
|
:raises ValueError: Stream is not boolean
|
||||||
@@ -113,6 +116,7 @@ class BaseLlmConfig(BaseConfig):
|
|||||||
self.deployment_name = deployment_name
|
self.deployment_name = deployment_name
|
||||||
self.system_prompt = system_prompt
|
self.system_prompt = system_prompt
|
||||||
self.query_type = query_type
|
self.query_type = query_type
|
||||||
|
self.callbacks = callbacks
|
||||||
|
|
||||||
if type(template) is str:
|
if type(template) is str:
|
||||||
template = Template(template)
|
template = Template(template)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
from .apps.base_app_config import BaseAppConfig
|
from .apps.base_app_config import BaseAppConfig
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from typing import Dict, List, Optional, Union
|
from typing import Dict, List, Optional, Union
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, Optional, Tuple
|
from typing import Dict, Optional, Tuple
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from typing import Any, Dict
|
|||||||
from embedchain.chunkers.base_chunker import BaseChunker
|
from embedchain.chunkers.base_chunker import BaseChunker
|
||||||
from embedchain.config import AddConfig
|
from embedchain.config import AddConfig
|
||||||
from embedchain.config.add_config import ChunkerConfig, LoaderConfig
|
from embedchain.config.add_config import ChunkerConfig, LoaderConfig
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.models.data_type import DataType
|
from embedchain.models.data_type import DataType
|
||||||
|
|
||||||
@@ -63,11 +63,17 @@ class DataFormatter(JSONSerializable):
|
|||||||
DataType.OPENAPI: "embedchain.loaders.openapi.OpenAPILoader",
|
DataType.OPENAPI: "embedchain.loaders.openapi.OpenAPILoader",
|
||||||
DataType.GMAIL: "embedchain.loaders.gmail.GmailLoader",
|
DataType.GMAIL: "embedchain.loaders.gmail.GmailLoader",
|
||||||
DataType.NOTION: "embedchain.loaders.notion.NotionLoader",
|
DataType.NOTION: "embedchain.loaders.notion.NotionLoader",
|
||||||
|
DataType.SUBSTACK: "embedchain.loaders.substack.SubstackLoader",
|
||||||
|
DataType.GITHUB: "embedchain.loaders.github.GithubLoader",
|
||||||
|
DataType.YOUTUBE_CHANNEL: "embedchain.loaders.youtube_channel.YoutubeChannelLoader",
|
||||||
}
|
}
|
||||||
|
|
||||||
custom_loaders = set(
|
custom_loaders = set(
|
||||||
[
|
[
|
||||||
DataType.POSTGRES,
|
DataType.POSTGRES,
|
||||||
|
DataType.MYSQL,
|
||||||
|
DataType.SLACK,
|
||||||
|
DataType.DISCOURSE,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -106,6 +112,12 @@ class DataFormatter(JSONSerializable):
|
|||||||
DataType.GMAIL: "embedchain.chunkers.gmail.GmailChunker",
|
DataType.GMAIL: "embedchain.chunkers.gmail.GmailChunker",
|
||||||
DataType.NOTION: "embedchain.chunkers.notion.NotionChunker",
|
DataType.NOTION: "embedchain.chunkers.notion.NotionChunker",
|
||||||
DataType.POSTGRES: "embedchain.chunkers.postgres.PostgresChunker",
|
DataType.POSTGRES: "embedchain.chunkers.postgres.PostgresChunker",
|
||||||
|
DataType.MYSQL: "embedchain.chunkers.mysql.MySQLChunker",
|
||||||
|
DataType.SLACK: "embedchain.chunkers.slack.SlackChunker",
|
||||||
|
DataType.DISCOURSE: "embedchain.chunkers.discourse.DiscourseChunker",
|
||||||
|
DataType.SUBSTACK: "embedchain.chunkers.substack.SubstackChunker",
|
||||||
|
DataType.GITHUB: "embedchain.chunkers.common_chunker.CommonChunker",
|
||||||
|
DataType.YOUTUBE_CHANNEL: "embedchain.chunkers.common_chunker.CommonChunker",
|
||||||
}
|
}
|
||||||
|
|
||||||
if data_type in chunker_classes:
|
if data_type in chunker_classes:
|
||||||
|
|||||||
@@ -13,11 +13,10 @@ from embedchain.config.apps.base_app_config import BaseAppConfig
|
|||||||
from embedchain.constants import SQLITE_PATH
|
from embedchain.constants import SQLITE_PATH
|
||||||
from embedchain.data_formatter import DataFormatter
|
from embedchain.data_formatter import DataFormatter
|
||||||
from embedchain.embedder.base import BaseEmbedder
|
from embedchain.embedder.base import BaseEmbedder
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.models.data_type import (DataType, DirectDataType,
|
from embedchain.models.data_type import DataType, DirectDataType, IndirectDataType, SpecialDataType
|
||||||
IndirectDataType, SpecialDataType)
|
|
||||||
from embedchain.telemetry.posthog import AnonymousTelemetry
|
from embedchain.telemetry.posthog import AnonymousTelemetry
|
||||||
from embedchain.utils import detect_datatype, is_valid_json_string
|
from embedchain.utils import detect_datatype, is_valid_json_string
|
||||||
from embedchain.vectordb.base import BaseVectorDB
|
from embedchain.vectordb.base import BaseVectorDB
|
||||||
@@ -203,7 +202,7 @@ class EmbedChain(JSONSerializable):
|
|||||||
self.user_asks.append([source, data_type.value, metadata])
|
self.user_asks.append([source, data_type.value, metadata])
|
||||||
|
|
||||||
data_formatter = DataFormatter(data_type, config, kwargs)
|
data_formatter = DataFormatter(data_type, config, kwargs)
|
||||||
documents, metadatas, _ids, new_chunks = self.load_and_embed(
|
documents, metadatas, _ids, new_chunks = self._load_and_embed(
|
||||||
data_formatter.loader, data_formatter.chunker, source, metadata, source_hash, dry_run
|
data_formatter.loader, data_formatter.chunker, source, metadata, source_hash, dry_run
|
||||||
)
|
)
|
||||||
if data_type in {DataType.DOCS_SITE}:
|
if data_type in {DataType.DOCS_SITE}:
|
||||||
@@ -340,7 +339,7 @@ class EmbedChain(JSONSerializable):
|
|||||||
"When it should be DirectDataType, IndirectDataType or SpecialDataType."
|
"When it should be DirectDataType, IndirectDataType or SpecialDataType."
|
||||||
)
|
)
|
||||||
|
|
||||||
def load_and_embed(
|
def _load_and_embed(
|
||||||
self,
|
self,
|
||||||
loader: BaseLoader,
|
loader: BaseLoader,
|
||||||
chunker: BaseChunker,
|
chunker: BaseChunker,
|
||||||
@@ -457,7 +456,7 @@ class EmbedChain(JSONSerializable):
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
def retrieve_from_database(
|
def _retrieve_from_database(
|
||||||
self, input_query: str, config: Optional[BaseLlmConfig] = None, where=None, citations: bool = False
|
self, input_query: str, config: Optional[BaseLlmConfig] = None, where=None, citations: bool = False
|
||||||
) -> Union[List[Tuple[str, str, str]], List[str]]:
|
) -> Union[List[Tuple[str, str, str]], List[str]]:
|
||||||
"""
|
"""
|
||||||
@@ -537,7 +536,9 @@ class EmbedChain(JSONSerializable):
|
|||||||
:rtype: str, if citations is False, otherwise Tuple[str,List[Tuple[str,str,str]]]
|
:rtype: str, if citations is False, otherwise Tuple[str,List[Tuple[str,str,str]]]
|
||||||
"""
|
"""
|
||||||
citations = kwargs.get("citations", False)
|
citations = kwargs.get("citations", False)
|
||||||
contexts = self.retrieve_from_database(input_query=input_query, config=config, where=where, citations=citations)
|
contexts = self._retrieve_from_database(
|
||||||
|
input_query=input_query, config=config, where=where, citations=citations
|
||||||
|
)
|
||||||
if citations and len(contexts) > 0 and isinstance(contexts[0], tuple):
|
if citations and len(contexts) > 0 and isinstance(contexts[0], tuple):
|
||||||
contexts_data_for_llm_query = list(map(lambda x: x[0], contexts))
|
contexts_data_for_llm_query = list(map(lambda x: x[0], contexts))
|
||||||
else:
|
else:
|
||||||
@@ -588,7 +589,9 @@ class EmbedChain(JSONSerializable):
|
|||||||
:rtype: str, if citations is False, otherwise Tuple[str,List[Tuple[str,str,str]]]
|
:rtype: str, if citations is False, otherwise Tuple[str,List[Tuple[str,str,str]]]
|
||||||
"""
|
"""
|
||||||
citations = kwargs.get("citations", False)
|
citations = kwargs.get("citations", False)
|
||||||
contexts = self.retrieve_from_database(input_query=input_query, config=config, where=where, citations=citations)
|
contexts = self._retrieve_from_database(
|
||||||
|
input_query=input_query, config=config, where=where, citations=citations
|
||||||
|
)
|
||||||
if citations and len(contexts) > 0 and isinstance(contexts[0], tuple):
|
if citations and len(contexts) > 0 and isinstance(contexts[0], tuple):
|
||||||
contexts_data_for_llm_query = list(map(lambda x: x[0], contexts))
|
contexts_data_for_llm_query = list(map(lambda x: x[0], contexts))
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -3,12 +3,20 @@ from typing import Any, Callable, Optional
|
|||||||
from embedchain.config.embedder.base import BaseEmbedderConfig
|
from embedchain.config.embedder.base import BaseEmbedderConfig
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from chromadb.api.types import Documents, Embeddings
|
from chromadb.api.types import Embeddable, EmbeddingFunction, Embeddings
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
from embedchain.utils import use_pysqlite3
|
from embedchain.utils import use_pysqlite3
|
||||||
|
|
||||||
use_pysqlite3()
|
use_pysqlite3()
|
||||||
from chromadb.api.types import Documents, Embeddings
|
from chromadb.api.types import Embeddable, EmbeddingFunction, Embeddings
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddingFunc(EmbeddingFunction):
|
||||||
|
def __init__(self, embedding_fn: Callable[[list[str]], list[str]]):
|
||||||
|
self.embedding_fn = embedding_fn
|
||||||
|
|
||||||
|
def __call__(self, input: Embeddable) -> Embeddings:
|
||||||
|
return self.embedding_fn(input)
|
||||||
|
|
||||||
|
|
||||||
class BaseEmbedder:
|
class BaseEmbedder:
|
||||||
@@ -66,7 +74,4 @@ class BaseEmbedder:
|
|||||||
:rtype: Callable
|
:rtype: Callable
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def embed_function(texts: Documents) -> Embeddings:
|
return EmbeddingFunc(embeddings.embed_documents)
|
||||||
return embeddings.embed_documents(texts)
|
|
||||||
|
|
||||||
return embed_function
|
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
"""
|
|
||||||
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]
|
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
import os
|
import os
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from langchain.embeddings import OpenAIEmbeddings
|
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction
|
||||||
|
from langchain.embeddings import AzureOpenAIEmbeddings
|
||||||
|
|
||||||
from embedchain.config import BaseEmbedderConfig
|
from embedchain.config import BaseEmbedderConfig
|
||||||
from embedchain.embedder.base import BaseEmbedder
|
from embedchain.embedder.base import BaseEmbedder
|
||||||
from embedchain.models import VectorDimensions
|
from embedchain.models import VectorDimensions
|
||||||
|
|
||||||
from .chroma_embeddings import OpenAIEmbeddingFunction
|
|
||||||
|
|
||||||
|
|
||||||
class OpenAIEmbedder(BaseEmbedder):
|
class OpenAIEmbedder(BaseEmbedder):
|
||||||
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
||||||
super().__init__(config=config)
|
super().__init__(config=config)
|
||||||
|
|
||||||
if self.config.model is None:
|
if self.config.model is None:
|
||||||
self.config.model = "text-embedding-ada-002"
|
self.config.model = "text-embedding-ada-002"
|
||||||
|
|
||||||
if self.config.deployment_name:
|
if self.config.deployment_name:
|
||||||
embeddings = OpenAIEmbeddings(deployment=self.config.deployment_name)
|
embeddings = AzureOpenAIEmbeddings(deployment=self.config.deployment_name)
|
||||||
embedding_fn = BaseEmbedder._langchain_default_concept(embeddings)
|
embedding_fn = BaseEmbedder._langchain_default_concept(embeddings)
|
||||||
else:
|
else:
|
||||||
if os.getenv("OPENAI_API_KEY") is None and os.getenv("OPENAI_ORGANIZATION") is None:
|
if os.getenv("OPENAI_API_KEY") is None and os.getenv("OPENAI_ORGANIZATION") is None:
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import queue
|
||||||
|
from typing import Any, Dict, List, Union
|
||||||
|
|
||||||
|
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||||
|
from langchain.schema import LLMResult
|
||||||
|
|
||||||
|
STOP_ITEM = "[END]"
|
||||||
|
"""
|
||||||
|
This is a special item that is used to signal the end of the stream.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class StreamingStdOutCallbackHandlerYield(StreamingStdOutCallbackHandler):
|
||||||
|
"""
|
||||||
|
This is a callback handler that yields the tokens as they are generated.
|
||||||
|
For a usage example, see the :func:`generate` function below.
|
||||||
|
"""
|
||||||
|
|
||||||
|
q: queue.Queue
|
||||||
|
"""
|
||||||
|
The queue to write the tokens to as they are generated.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, q: queue.Queue) -> None:
|
||||||
|
"""
|
||||||
|
Initialize the callback handler.
|
||||||
|
q: The queue to write the tokens to as they are generated.
|
||||||
|
"""
|
||||||
|
super().__init__()
|
||||||
|
self.q = q
|
||||||
|
|
||||||
|
def on_llm_start(self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any) -> None:
|
||||||
|
"""Run when LLM starts running."""
|
||||||
|
with self.q.mutex:
|
||||||
|
self.q.queue.clear()
|
||||||
|
|
||||||
|
def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
|
||||||
|
"""Run on new LLM token. Only available when streaming is enabled."""
|
||||||
|
self.q.put(token)
|
||||||
|
|
||||||
|
def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
|
||||||
|
"""Run when LLM ends running."""
|
||||||
|
self.q.put(STOP_ITEM)
|
||||||
|
|
||||||
|
def on_llm_error(self, error: Union[Exception, KeyboardInterrupt], **kwargs: Any) -> None:
|
||||||
|
"""Run when LLM errors."""
|
||||||
|
self.q.put("%s: %s" % (type(error).__name__, str(error)))
|
||||||
|
self.q.put(STOP_ITEM)
|
||||||
|
|
||||||
|
|
||||||
|
def generate(rq: queue.Queue):
|
||||||
|
"""
|
||||||
|
This is a generator that yields the items in the queue until it reaches the stop item.
|
||||||
|
|
||||||
|
Usage example:
|
||||||
|
```
|
||||||
|
def askQuestion(callback_fn: StreamingStdOutCallbackHandlerYield):
|
||||||
|
llm = OpenAI(streaming=True, callbacks=[callback_fn])
|
||||||
|
return llm(prompt="Write a poem about a tree.")
|
||||||
|
|
||||||
|
@app.route("/", methods=["GET"])
|
||||||
|
def generate_output():
|
||||||
|
q = Queue()
|
||||||
|
callback_fn = StreamingStdOutCallbackHandlerYield(q)
|
||||||
|
threading.Thread(target=askQuestion, args=(callback_fn,)).start()
|
||||||
|
return Response(generate(q), mimetype="text/event-stream")
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
while True:
|
||||||
|
result: str = rq.get()
|
||||||
|
if result == STOP_ITEM or result is None:
|
||||||
|
break
|
||||||
|
yield result
|
||||||
@@ -33,7 +33,7 @@ def register_deserializable(cls: Type[T]) -> Type[T]:
|
|||||||
Returns:
|
Returns:
|
||||||
Type: The same class, after registration.
|
Type: The same class, after registration.
|
||||||
"""
|
"""
|
||||||
JSONSerializable.register_class_as_deserializable(cls)
|
JSONSerializable._register_class_as_deserializable(cls)
|
||||||
return cls
|
return cls
|
||||||
|
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class JSONSerializable:
|
|||||||
return cls.deserialize(json_str)
|
return cls.deserialize(json_str)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def register_class_as_deserializable(cls, target_class: Type[T]) -> None:
|
def _register_class_as_deserializable(cls, target_class: Type[T]) -> None:
|
||||||
"""
|
"""
|
||||||
Register a class as deserializable. This is a classmethod and globally shared.
|
Register a class as deserializable. This is a classmethod and globally shared.
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ import os
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import logging
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from embedchain.config import BaseLlmConfig
|
|||||||
from embedchain.config.llm.base import (DEFAULT_PROMPT,
|
from embedchain.config.llm.base import (DEFAULT_PROMPT,
|
||||||
DEFAULT_PROMPT_WITH_HISTORY_TEMPLATE,
|
DEFAULT_PROMPT_WITH_HISTORY_TEMPLATE,
|
||||||
DOCS_SITE_PROMPT_TEMPLATE)
|
DOCS_SITE_PROMPT_TEMPLATE)
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
from embedchain.memory.base import ECChatMemory
|
from embedchain.memory.base import ECChatMemory
|
||||||
from embedchain.memory.message import ChatMessage
|
from embedchain.memory.message import ChatMessage
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Optional
|
|||||||
from langchain.llms import Cohere
|
from langchain.llms import Cohere
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.callbacks.stdout import StdOutCallbackHandler
|
|||||||
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Optional
|
|||||||
from langchain.llms import HuggingFaceHub
|
from langchain.llms import HuggingFaceHub
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from langchain.chat_models import JinaChat
|
|||||||
from langchain.schema import HumanMessage, SystemMessage
|
from langchain.schema import HumanMessage, SystemMessage
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from typing import Optional
|
|||||||
from langchain.llms import Replicate
|
from langchain.llms import Replicate
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from langchain.chat_models import ChatOpenAI
|
|||||||
from langchain.schema import HumanMessage, SystemMessage
|
from langchain.schema import HumanMessage, SystemMessage
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
@@ -34,7 +34,8 @@ class OpenAILlm(BaseLlm):
|
|||||||
from langchain.callbacks.streaming_stdout import \
|
from langchain.callbacks.streaming_stdout import \
|
||||||
StreamingStdOutCallbackHandler
|
StreamingStdOutCallbackHandler
|
||||||
|
|
||||||
chat = ChatOpenAI(**kwargs, streaming=config.stream, callbacks=[StreamingStdOutCallbackHandler()])
|
callbacks = config.callbacks if config.callbacks else [StreamingStdOutCallbackHandler()]
|
||||||
|
chat = ChatOpenAI(**kwargs, streaming=config.stream, callbacks=callbacks)
|
||||||
else:
|
else:
|
||||||
chat = ChatOpenAI(**kwargs)
|
chat = ChatOpenAI(**kwargs)
|
||||||
return chat(messages).content
|
return chat(messages).content
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import logging
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from embedchain.config import BaseLlmConfig
|
from embedchain.config import BaseLlmConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
|
|
||||||
|
|
||||||
class BaseLoader(JSONSerializable):
|
class BaseLoader(JSONSerializable):
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|
||||||
|
class DiscourseLoader(BaseLoader):
|
||||||
|
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||||
|
super().__init__()
|
||||||
|
if not config:
|
||||||
|
raise ValueError(
|
||||||
|
"DiscourseLoader requires a config. Check the documentation for the correct format - `https://docs.embedchain.ai/data-sources/discourse`" # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
self.domain = config.get("domain")
|
||||||
|
if not self.domain:
|
||||||
|
raise ValueError(
|
||||||
|
"DiscourseLoader requires a domain. Check the documentation for the correct format - `https://docs.embedchain.ai/data-sources/discourse`" # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
def _check_query(self, query):
|
||||||
|
if not query or not isinstance(query, str):
|
||||||
|
raise ValueError(
|
||||||
|
"DiscourseLoader requires a query. Check the documentation for the correct format - `https://docs.embedchain.ai/data-sources/discourse`" # noqa: E501
|
||||||
|
)
|
||||||
|
|
||||||
|
def _load_post(self, post_id):
|
||||||
|
post_url = f"{self.domain}posts/{post_id}.json"
|
||||||
|
response = requests.get(post_url)
|
||||||
|
try:
|
||||||
|
response.raise_for_status()
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to load post {post_id}: {e}")
|
||||||
|
return
|
||||||
|
response_data = response.json()
|
||||||
|
post_contents = clean_string(response_data.get("raw"))
|
||||||
|
meta_data = {
|
||||||
|
"url": post_url,
|
||||||
|
"created_at": response_data.get("created_at", ""),
|
||||||
|
"username": response_data.get("username", ""),
|
||||||
|
"topic_slug": response_data.get("topic_slug", ""),
|
||||||
|
"score": response_data.get("score", ""),
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"content": post_contents,
|
||||||
|
"meta_data": meta_data,
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
|
||||||
|
def load_data(self, query):
|
||||||
|
self._check_query(query)
|
||||||
|
data = []
|
||||||
|
data_contents = []
|
||||||
|
logging.info(f"Searching data on discourse url: {self.domain}, for query: {query}")
|
||||||
|
search_url = f"{self.domain}search.json?q={query}"
|
||||||
|
response = requests.get(search_url)
|
||||||
|
try:
|
||||||
|
response.raise_for_status()
|
||||||
|
except Exception as e:
|
||||||
|
raise ValueError(f"Failed to search query {query}: {e}")
|
||||||
|
response_data = response.json()
|
||||||
|
post_ids = response_data.get("grouped_search_result").get("post_ids")
|
||||||
|
for id in post_ids:
|
||||||
|
post_data = self._load_post(id)
|
||||||
|
if post_data:
|
||||||
|
data.append(post_data)
|
||||||
|
data_contents.append(post_data.get("content"))
|
||||||
|
# Sleep for 0.4 sec, to avoid rate limiting. Check `https://meta.discourse.org/t/api-rate-limits/208405/6`
|
||||||
|
time.sleep(0.4)
|
||||||
|
doc_id = hashlib.sha256((query + ", ".join(data_contents)).encode()).hexdigest()
|
||||||
|
response_data = {"doc_id": doc_id, "data": data}
|
||||||
|
return response_data
|
||||||
@@ -12,7 +12,7 @@ except ImportError:
|
|||||||
) from None
|
) from None
|
||||||
|
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ except ImportError:
|
|||||||
raise ImportError(
|
raise ImportError(
|
||||||
'Docx file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'Docx file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import concurrent.futures
|
||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.loaders.json import JSONLoader
|
||||||
|
from embedchain.loaders.mdx import MdxLoader
|
||||||
|
from embedchain.utils import detect_datatype
|
||||||
|
|
||||||
|
|
||||||
|
def _load_file_data(path):
|
||||||
|
data = []
|
||||||
|
data_content = []
|
||||||
|
try:
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
content = f.read().decode("utf-8")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error reading file {path}: {e}")
|
||||||
|
raise ValueError(f"Failed to read file {path}")
|
||||||
|
|
||||||
|
meta_data = {}
|
||||||
|
meta_data["url"] = path
|
||||||
|
data.append(
|
||||||
|
{
|
||||||
|
"content": content,
|
||||||
|
"meta_data": meta_data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
data_content.append(content)
|
||||||
|
doc_id = hashlib.sha256((" ".join(data_content) + path).encode()).hexdigest()
|
||||||
|
return {
|
||||||
|
"doc_id": doc_id,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class GithubLoader(BaseLoader):
|
||||||
|
def load_data(self, repo_url):
|
||||||
|
"""Load data from a git repo."""
|
||||||
|
try:
|
||||||
|
from git import Repo
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError(
|
||||||
|
"GithubLoader requires extra dependencies. Install with `pip install --upgrade 'embedchain[git]'`"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
mdx_loader = MdxLoader()
|
||||||
|
json_loader = JSONLoader()
|
||||||
|
data = []
|
||||||
|
data_urls = []
|
||||||
|
|
||||||
|
def _fetch_or_clone_repo(repo_url: str, local_path: str):
|
||||||
|
if os.path.exists(local_path):
|
||||||
|
logging.info("Repository already exists. Fetching updates...")
|
||||||
|
repo = Repo(local_path)
|
||||||
|
origin = repo.remotes.origin
|
||||||
|
origin.fetch()
|
||||||
|
logging.info("Fetch completed.")
|
||||||
|
else:
|
||||||
|
logging.info("Cloning repository...")
|
||||||
|
Repo.clone_from(repo_url, local_path)
|
||||||
|
logging.info("Clone completed.")
|
||||||
|
|
||||||
|
def _load_file(file_path: str):
|
||||||
|
try:
|
||||||
|
data_type = detect_datatype(file_path).value
|
||||||
|
except Exception:
|
||||||
|
data_type = "unstructured"
|
||||||
|
|
||||||
|
if data_type == "mdx":
|
||||||
|
data = mdx_loader.load_data(file_path)
|
||||||
|
elif data_type == "json":
|
||||||
|
data = json_loader.load_data(file_path)
|
||||||
|
else:
|
||||||
|
data = _load_file_data(file_path)
|
||||||
|
|
||||||
|
return data.get("data", [])
|
||||||
|
|
||||||
|
def _is_file_empty(file_path):
|
||||||
|
return os.path.getsize(file_path) == 0
|
||||||
|
|
||||||
|
def _is_whitelisted(file_path):
|
||||||
|
whitelisted_extensions = ["md", "txt", "html", "json", "py", "js", "jsx", "ts", "tsx", "mdx", "rst"]
|
||||||
|
_, file_extension = os.path.splitext(file_path)
|
||||||
|
return file_extension[1:] in whitelisted_extensions
|
||||||
|
|
||||||
|
def _add_repo_files(repo_path: str):
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
|
||||||
|
future_to_file = {
|
||||||
|
executor.submit(_load_file, os.path.join(root, filename)): os.path.join(root, filename)
|
||||||
|
for root, _, files in os.walk(repo_path)
|
||||||
|
for filename in files
|
||||||
|
if _is_whitelisted(os.path.join(root, filename))
|
||||||
|
and not _is_file_empty(os.path.join(root, filename)) # noqa:E501
|
||||||
|
}
|
||||||
|
for future in tqdm(concurrent.futures.as_completed(future_to_file), total=len(future_to_file)):
|
||||||
|
file = future_to_file[future]
|
||||||
|
try:
|
||||||
|
results = future.result()
|
||||||
|
if results:
|
||||||
|
data.extend(results)
|
||||||
|
data_urls.extend([result.get("meta_data").get("url") for result in results])
|
||||||
|
except Exception as e:
|
||||||
|
logging.warn(f"Failed to process {file}: {e}")
|
||||||
|
|
||||||
|
source_hash = hashlib.sha256(repo_url.encode()).hexdigest()
|
||||||
|
repo_path = f"/tmp/{source_hash}"
|
||||||
|
_fetch_or_clone_repo(repo_url=repo_url, local_path=repo_path)
|
||||||
|
_add_repo_files(repo_path)
|
||||||
|
doc_id = hashlib.sha256((repo_url + ", ".join(data_urls)).encode()).hexdigest()
|
||||||
|
return {
|
||||||
|
"doc_id": doc_id,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|
||||||
|
class MySQLLoader(BaseLoader):
|
||||||
|
def __init__(self, config: Optional[Dict[str, Any]]):
|
||||||
|
super().__init__()
|
||||||
|
if not config:
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid sql config: {config}.",
|
||||||
|
"Provide the correct config, refer `https://docs.embedchain.ai/data-sources/mysql`.",
|
||||||
|
)
|
||||||
|
|
||||||
|
self.config = config
|
||||||
|
self.connection = None
|
||||||
|
self.cursor = None
|
||||||
|
self._setup_loader(config=config)
|
||||||
|
|
||||||
|
def _setup_loader(self, config: Dict[str, Any]):
|
||||||
|
try:
|
||||||
|
import mysql.connector as sqlconnector
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(
|
||||||
|
"Unable to import required packages for MySQL loader. Run `pip install --upgrade 'embedchain[mysql]'`." # noqa: E501
|
||||||
|
) from e
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.connection = sqlconnector.connection.MySQLConnection(**config)
|
||||||
|
self.cursor = self.connection.cursor()
|
||||||
|
except (sqlconnector.Error, IOError) as err:
|
||||||
|
logging.info(f"Connection failed: {err}")
|
||||||
|
raise ValueError(
|
||||||
|
f"Unable to connect with the given config: {config}.",
|
||||||
|
"Please provide the correct configuration to load data from you MySQL DB. \
|
||||||
|
Refer `https://docs.embedchain.ai/data-sources/mysql`.",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _check_query(self, query):
|
||||||
|
if not isinstance(query, str):
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid mysql query: {query}",
|
||||||
|
"Provide the valid query to add from mysql, \
|
||||||
|
make sure you are following `https://docs.embedchain.ai/data-sources/mysql`",
|
||||||
|
)
|
||||||
|
|
||||||
|
def load_data(self, query):
|
||||||
|
self._check_query(query=query)
|
||||||
|
data = []
|
||||||
|
data_content = []
|
||||||
|
self.cursor.execute(query)
|
||||||
|
rows = self.cursor.fetchall()
|
||||||
|
for row in rows:
|
||||||
|
doc_content = clean_string(str(row))
|
||||||
|
data.append({"content": doc_content, "meta_data": {"url": query}})
|
||||||
|
data_content.append(doc_content)
|
||||||
|
doc_id = hashlib.sha256((query + ", ".join(data_content)).encode()).hexdigest()
|
||||||
|
return {
|
||||||
|
"doc_id": doc_id,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ except ImportError:
|
|||||||
) from None
|
) from None
|
||||||
|
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ except ImportError:
|
|||||||
raise ImportError(
|
raise ImportError(
|
||||||
'PDF File requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'PDF File requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,7 @@ class PostgresLoader(BaseLoader):
|
|||||||
def _check_query(self, query):
|
def _check_query(self, query):
|
||||||
if not isinstance(query, str):
|
if not isinstance(query, str):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Invalid postgres query: {query}",
|
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`", # noqa:E501
|
||||||
"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):
|
def load_data(self, query):
|
||||||
@@ -54,7 +52,7 @@ class PostgresLoader(BaseLoader):
|
|||||||
results = self.cursor.fetchall()
|
results = self.cursor.fetchall()
|
||||||
for result in results:
|
for result in results:
|
||||||
doc_content = str(result)
|
doc_content = str(result)
|
||||||
data.append({"content": doc_content, "meta_data": {"url": f"postgres_query-({query})"}})
|
data.append({"content": doc_content, "meta_data": {"url": query}})
|
||||||
data_content.append(doc_content)
|
data_content.append(doc_content)
|
||||||
doc_id = hashlib.sha256((query + ", ".join(data_content)).encode()).hexdigest()
|
doc_id = hashlib.sha256((query + ", ".join(data_content)).encode()).hexdigest()
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import concurrent.futures
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
@@ -11,7 +13,7 @@ except ImportError:
|
|||||||
'Sitemap requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'Sitemap requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.loaders.web_page import WebPageLoader
|
from embedchain.loaders.web_page import WebPageLoader
|
||||||
from embedchain.utils import is_readable
|
from embedchain.utils import is_readable
|
||||||
@@ -19,33 +21,45 @@ from embedchain.utils import is_readable
|
|||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
class SitemapLoader(BaseLoader):
|
class SitemapLoader(BaseLoader):
|
||||||
|
"""
|
||||||
|
This method takes a sitemap URL as input and retrieves
|
||||||
|
all the URLs to use the WebPageLoader to load content
|
||||||
|
of each page.
|
||||||
|
"""
|
||||||
|
|
||||||
def load_data(self, sitemap_url):
|
def load_data(self, sitemap_url):
|
||||||
"""
|
|
||||||
This method takes a sitemap URL as input and retrieves
|
|
||||||
all the URLs to use the WebPageLoader to load content
|
|
||||||
of each page.
|
|
||||||
"""
|
|
||||||
output = []
|
output = []
|
||||||
web_page_loader = WebPageLoader()
|
web_page_loader = WebPageLoader()
|
||||||
response = requests.get(sitemap_url)
|
response = requests.get(sitemap_url)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
|
|
||||||
soup = BeautifulSoup(response.text, "xml")
|
soup = BeautifulSoup(response.text, "xml")
|
||||||
|
|
||||||
links = [link.text for link in soup.find_all("loc") if link.parent.name == "url"]
|
links = [link.text for link in soup.find_all("loc") if link.parent.name == "url"]
|
||||||
if len(links) == 0:
|
if len(links) == 0:
|
||||||
# Get all <loc> tags as a fallback. This might include images.
|
|
||||||
links = [link.text for link in soup.find_all("loc")]
|
links = [link.text for link in soup.find_all("loc")]
|
||||||
|
|
||||||
doc_id = hashlib.sha256((" ".join(links) + sitemap_url).encode()).hexdigest()
|
doc_id = hashlib.sha256((" ".join(links) + sitemap_url).encode()).hexdigest()
|
||||||
|
|
||||||
for link in links:
|
def load_link(link):
|
||||||
try:
|
try:
|
||||||
each_load_data = web_page_loader.load_data(link)
|
each_load_data = web_page_loader.load_data(link)
|
||||||
if is_readable(each_load_data.get("data")[0].get("content")):
|
if is_readable(each_load_data.get("data")[0].get("content")):
|
||||||
output.append(each_load_data.get("data"))
|
return each_load_data.get("data")
|
||||||
else:
|
else:
|
||||||
logging.warning(f"Page is not readable (too many invalid characters): {link}")
|
logging.warning(f"Page is not readable (too many invalid characters): {link}")
|
||||||
except ParserRejectedMarkup as e:
|
except ParserRejectedMarkup as e:
|
||||||
logging.error(f"Failed to parse {link}: {e}")
|
logging.error(f"Failed to parse {link}: {e}")
|
||||||
return {"doc_id": doc_id, "data": [data[0] for data in output]}
|
return None
|
||||||
|
|
||||||
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||||
|
future_to_link = {executor.submit(load_link, link): link for link in links}
|
||||||
|
for future in tqdm(concurrent.futures.as_completed(future_to_link), total=len(links), desc="Loading pages"):
|
||||||
|
link = future_to_link[future]
|
||||||
|
try:
|
||||||
|
data = future.result()
|
||||||
|
if data:
|
||||||
|
output.extend(data)
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error loading page {link}: {e}")
|
||||||
|
|
||||||
|
return {"doc_id": doc_id, "data": output}
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import ssl
|
||||||
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
|
import certifi
|
||||||
|
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
SLACK_API_BASE_URL = "https://www.slack.com/api/"
|
||||||
|
|
||||||
|
|
||||||
|
class SlackLoader(BaseLoader):
|
||||||
|
def __init__(self, config: Optional[Dict[str, Any]] = None):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
if config is not None:
|
||||||
|
self.config = config
|
||||||
|
else:
|
||||||
|
self.config = {"base_url": SLACK_API_BASE_URL}
|
||||||
|
|
||||||
|
self.client = None
|
||||||
|
self._setup_loader(self.config)
|
||||||
|
|
||||||
|
def _setup_loader(self, config: Dict[str, Any]):
|
||||||
|
try:
|
||||||
|
from slack_sdk import WebClient
|
||||||
|
except ImportError as e:
|
||||||
|
raise ImportError(
|
||||||
|
"Slack loader requires extra dependencies. \
|
||||||
|
Install with `pip install --upgrade embedchain[slack]`"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
if os.getenv("SLACK_USER_TOKEN") is None:
|
||||||
|
raise ValueError(
|
||||||
|
"SLACK_USER_TOKEN environment variables not provided. Check `https://docs.embedchain.ai/data-sources/slack` to learn more." # noqa:E501
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.info(f"Creating Slack Loader with config: {config}")
|
||||||
|
# get slack client config params
|
||||||
|
slack_bot_token = os.getenv("SLACK_USER_TOKEN")
|
||||||
|
ssl_cert = ssl.create_default_context(cafile=certifi.where())
|
||||||
|
base_url = config.get("base_url", SLACK_API_BASE_URL)
|
||||||
|
headers = config.get("headers")
|
||||||
|
# for Org-Wide App
|
||||||
|
team_id = config.get("team_id")
|
||||||
|
|
||||||
|
self.client = WebClient(
|
||||||
|
token=slack_bot_token,
|
||||||
|
base_url=base_url,
|
||||||
|
ssl=ssl_cert,
|
||||||
|
headers=headers,
|
||||||
|
team_id=team_id,
|
||||||
|
)
|
||||||
|
logging.info("Slack Loader setup successful!")
|
||||||
|
|
||||||
|
def _check_query(self, query):
|
||||||
|
if not isinstance(query, str):
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid query passed to Slack loader, found: {query}. Check `https://docs.embedchain.ai/data-sources/slack` to learn more." # noqa:E501
|
||||||
|
)
|
||||||
|
|
||||||
|
def load_data(self, query):
|
||||||
|
self._check_query(query)
|
||||||
|
try:
|
||||||
|
data = []
|
||||||
|
data_content = []
|
||||||
|
|
||||||
|
logging.info(f"Searching slack conversations for query: {query}")
|
||||||
|
results = self.client.search_messages(
|
||||||
|
query=query,
|
||||||
|
sort="timestamp",
|
||||||
|
sort_dir="desc",
|
||||||
|
count=1000,
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = results.get("messages")
|
||||||
|
num_message = results.get("total")
|
||||||
|
logging.info(f"Found {num_message} messages for query: {query}")
|
||||||
|
|
||||||
|
matches = messages.get("matches", [])
|
||||||
|
for message in matches:
|
||||||
|
url = message.get("permalink")
|
||||||
|
text = message.get("text")
|
||||||
|
content = clean_string(text)
|
||||||
|
|
||||||
|
message_meta_data_keys = ["channel", "iid", "team", "ts", "type", "user", "username"]
|
||||||
|
meta_data = message.fromkeys(message_meta_data_keys, "")
|
||||||
|
meta_data.update({"url": url})
|
||||||
|
data.append(
|
||||||
|
{
|
||||||
|
"content": content,
|
||||||
|
"meta_data": meta_data,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
data_content.append(content)
|
||||||
|
doc_id = hashlib.md5((query + ", ".join(data_content)).encode()).hexdigest()
|
||||||
|
return {
|
||||||
|
"doc_id": doc_id,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
logging.warning(f"Error in loading slack data: {e}")
|
||||||
|
raise ValueError(
|
||||||
|
f"Error in loading slack data: {e}. Check `https://docs.embedchain.ai/data-sources/slack` to learn more." # noqa:E501
|
||||||
|
) from e
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.utils import is_readable
|
||||||
|
|
||||||
|
|
||||||
|
@register_deserializable
|
||||||
|
class SubstackLoader(BaseLoader):
|
||||||
|
"""
|
||||||
|
This method takes a sitemap URL as input and retrieves
|
||||||
|
all the URLs to use the WebPageLoader to load content
|
||||||
|
of each page.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def load_data(self, url: str):
|
||||||
|
try:
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
from bs4.builder import ParserRejectedMarkup
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Substack requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
|
) from None
|
||||||
|
|
||||||
|
output = []
|
||||||
|
response = requests.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.text, "xml")
|
||||||
|
links = [link.text for link in soup.find_all("loc") if link.parent.name == "url" and "/p/" in link.text]
|
||||||
|
if len(links) == 0:
|
||||||
|
links = [link.text for link in soup.find_all("loc") if "/p/" in link.text]
|
||||||
|
|
||||||
|
doc_id = hashlib.sha256((" ".join(links) + url).encode()).hexdigest()
|
||||||
|
|
||||||
|
def serialize_response(soup: BeautifulSoup):
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
h1_els = soup.find_all("h1")
|
||||||
|
if h1_els is not None and len(h1_els) > 0:
|
||||||
|
data["title"] = h1_els[1].text
|
||||||
|
|
||||||
|
description_el = soup.find("meta", {"name": "description"})
|
||||||
|
if description_el is not None:
|
||||||
|
data["description"] = description_el["content"]
|
||||||
|
|
||||||
|
content_el = soup.find("div", {"class": "available-content"})
|
||||||
|
if content_el is not None:
|
||||||
|
data["content"] = content_el.text
|
||||||
|
|
||||||
|
like_btn = soup.find("div", {"class": "like-button-container"})
|
||||||
|
if like_btn is not None:
|
||||||
|
no_of_likes_div = like_btn.find("div", {"class": "label"})
|
||||||
|
if no_of_likes_div is not None:
|
||||||
|
data["no_of_likes"] = no_of_likes_div.text
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def load_link(link: str):
|
||||||
|
try:
|
||||||
|
each_load_data = requests.get(link)
|
||||||
|
each_load_data.raise_for_status()
|
||||||
|
|
||||||
|
soup = BeautifulSoup(response.text, "html.parser")
|
||||||
|
data = serialize_response(soup)
|
||||||
|
data = str(data)
|
||||||
|
if is_readable(data):
|
||||||
|
return data
|
||||||
|
else:
|
||||||
|
logging.warning(f"Page is not readable (too many invalid characters): {link}")
|
||||||
|
except ParserRejectedMarkup as e:
|
||||||
|
logging.error(f"Failed to parse {link}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
for link in links:
|
||||||
|
data = load_link(link)
|
||||||
|
if data:
|
||||||
|
output.append({"content": data, "meta_data": {"url": link}})
|
||||||
|
# TODO: allow users to configure this
|
||||||
|
time.sleep(1.0) # added to avoid rate limiting
|
||||||
|
|
||||||
|
return {"doc_id": doc_id, "data": output}
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
import hashlib
|
import hashlib
|
||||||
|
|
||||||
try:
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from langchain.document_loaders import UnstructuredFileLoader
|
|
||||||
except ImportError:
|
|
||||||
raise ImportError(
|
|
||||||
'PDF File requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
|
||||||
) from None
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
@@ -15,6 +9,13 @@ from embedchain.utils import clean_string
|
|||||||
class UnstructuredLoader(BaseLoader):
|
class UnstructuredLoader(BaseLoader):
|
||||||
def load_data(self, url):
|
def load_data(self, url):
|
||||||
"""Load data from a Unstructured file."""
|
"""Load data from a Unstructured file."""
|
||||||
|
try:
|
||||||
|
from langchain.document_loaders import UnstructuredFileLoader
|
||||||
|
except ImportError:
|
||||||
|
raise ImportError(
|
||||||
|
'Unstructured file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`' # noqa: E501
|
||||||
|
) from None
|
||||||
|
|
||||||
loader = UnstructuredFileLoader(url)
|
loader = UnstructuredFileLoader(url)
|
||||||
data = []
|
data = []
|
||||||
all_content = []
|
all_content = []
|
||||||
|
|||||||
@@ -10,22 +10,24 @@ except ImportError:
|
|||||||
'Webpage requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'Webpage requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
class WebPageLoader(BaseLoader):
|
class WebPageLoader(BaseLoader):
|
||||||
|
# Shared session for all instances
|
||||||
|
_session = requests.Session()
|
||||||
|
|
||||||
def load_data(self, url):
|
def load_data(self, url):
|
||||||
"""Load data from a web page."""
|
"""Load data from a web page using a shared requests session."""
|
||||||
response = requests.get(url)
|
response = self._session.get(url, timeout=30)
|
||||||
|
response.raise_for_status()
|
||||||
data = response.content
|
data = response.content
|
||||||
content = self._get_clean_content(data, url)
|
content = self._get_clean_content(data, url)
|
||||||
|
|
||||||
meta_data = {
|
meta_data = {"url": url}
|
||||||
"url": url,
|
|
||||||
}
|
|
||||||
|
|
||||||
doc_id = hashlib.sha256((content + url).encode()).hexdigest()
|
doc_id = hashlib.sha256((content + url).encode()).hexdigest()
|
||||||
return {
|
return {
|
||||||
@@ -86,3 +88,7 @@ class WebPageLoader(BaseLoader):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def close_session(cls):
|
||||||
|
cls._session.close()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ except ImportError:
|
|||||||
raise ImportError(
|
raise ImportError(
|
||||||
'XML file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'XML file requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import concurrent.futures
|
||||||
|
import hashlib
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
|
from embedchain.loaders.youtube_video import YoutubeVideoLoader
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubeChannelLoader(BaseLoader):
|
||||||
|
"""Loader for youtube channel."""
|
||||||
|
|
||||||
|
def load_data(self, channel_name):
|
||||||
|
try:
|
||||||
|
import yt_dlp
|
||||||
|
except ImportError as e:
|
||||||
|
raise ValueError(
|
||||||
|
"YoutubeLoader requires extra dependencies. Install with `pip install --upgrade 'embedchain[youtube_channel]'`" # noqa: E501
|
||||||
|
) from e
|
||||||
|
|
||||||
|
data = []
|
||||||
|
data_urls = []
|
||||||
|
youtube_url = f"https://www.youtube.com/{channel_name}/videos"
|
||||||
|
youtube_video_loader = YoutubeVideoLoader()
|
||||||
|
|
||||||
|
def _get_yt_video_links():
|
||||||
|
try:
|
||||||
|
ydl_opts = {
|
||||||
|
"quiet": True,
|
||||||
|
"extract_flat": True,
|
||||||
|
}
|
||||||
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||||
|
info_dict = ydl.extract_info(youtube_url, download=False)
|
||||||
|
if "entries" in info_dict:
|
||||||
|
videos = [entry["url"] for entry in info_dict["entries"]]
|
||||||
|
return videos
|
||||||
|
except Exception:
|
||||||
|
logging.error(f"Failed to fetch youtube videos for channel: {channel_name}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def _load_yt_video(video_link):
|
||||||
|
try:
|
||||||
|
each_load_data = youtube_video_loader.load_data(video_link)
|
||||||
|
if each_load_data:
|
||||||
|
return each_load_data.get("data")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to load youtube video {video_link}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _add_youtube_channel():
|
||||||
|
video_links = _get_yt_video_links()
|
||||||
|
logging.info("Loading videos from youtube channel...")
|
||||||
|
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||||
|
# Submitting all tasks and storing the future object with the video link
|
||||||
|
future_to_video = {
|
||||||
|
executor.submit(_load_yt_video, video_link): video_link for video_link in video_links
|
||||||
|
}
|
||||||
|
|
||||||
|
for future in tqdm(
|
||||||
|
concurrent.futures.as_completed(future_to_video), total=len(video_links), desc="Processing videos"
|
||||||
|
):
|
||||||
|
video = future_to_video[future]
|
||||||
|
try:
|
||||||
|
results = future.result()
|
||||||
|
if results:
|
||||||
|
data.extend(results)
|
||||||
|
data_urls.extend([result.get("meta_data").get("url") for result in results])
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Failed to process youtube video {video}: {e}")
|
||||||
|
|
||||||
|
_add_youtube_channel()
|
||||||
|
doc_id = hashlib.sha256((youtube_url + ", ".join(data_urls)).encode()).hexdigest()
|
||||||
|
return {
|
||||||
|
"doc_id": doc_id,
|
||||||
|
"data": data,
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ except ImportError:
|
|||||||
raise ImportError(
|
raise ImportError(
|
||||||
'YouTube video requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
'YouTube video requires extra dependencies. Install with `pip install --upgrade "embedchain[dataloaders]"`'
|
||||||
) from None
|
) from None
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.loaders.base_loader import BaseLoader
|
from embedchain.loaders.base_loader import BaseLoader
|
||||||
from embedchain.utils import clean_string
|
from embedchain.utils import clean_string
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ class YoutubeVideoLoader(BaseLoader):
|
|||||||
doc = loader.load()
|
doc = loader.load()
|
||||||
output = []
|
output = []
|
||||||
if not len(doc):
|
if not len(doc):
|
||||||
raise ValueError("No data found")
|
raise ValueError(f"No data found for url: {url}")
|
||||||
content = doc[0].page_content
|
content = doc[0].page_content
|
||||||
content = clean_string(content)
|
content = clean_string(content)
|
||||||
meta_data = doc[0].metadata
|
meta_data = doc[0].metadata
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
|
|
||||||
|
|
||||||
class BaseMessage(JSONSerializable):
|
class BaseMessage(JSONSerializable):
|
||||||
|
|||||||
@@ -30,6 +30,12 @@ class IndirectDataType(Enum):
|
|||||||
OPENAPI = "openapi"
|
OPENAPI = "openapi"
|
||||||
GMAIL = "gmail"
|
GMAIL = "gmail"
|
||||||
POSTGRES = "postgres"
|
POSTGRES = "postgres"
|
||||||
|
MYSQL = "mysql"
|
||||||
|
SLACK = "slack"
|
||||||
|
DISCOURSE = "discourse"
|
||||||
|
SUBSTACK = "substack"
|
||||||
|
GITHUB = "github"
|
||||||
|
YOUTUBE_CHANNEL = "youtube_channel"
|
||||||
|
|
||||||
|
|
||||||
class SpecialDataType(Enum):
|
class SpecialDataType(Enum):
|
||||||
@@ -59,3 +65,9 @@ class DataType(Enum):
|
|||||||
OPENAPI = IndirectDataType.OPENAPI.value
|
OPENAPI = IndirectDataType.OPENAPI.value
|
||||||
GMAIL = IndirectDataType.GMAIL.value
|
GMAIL = IndirectDataType.GMAIL.value
|
||||||
POSTGRES = IndirectDataType.POSTGRES.value
|
POSTGRES = IndirectDataType.POSTGRES.value
|
||||||
|
MYSQL = IndirectDataType.MYSQL.value
|
||||||
|
SLACK = IndirectDataType.SLACK.value
|
||||||
|
DISCOURSE = IndirectDataType.DISCOURSE.value
|
||||||
|
SUBSTACK = IndirectDataType.SUBSTACK.value
|
||||||
|
GITHUB = IndirectDataType.GITHUB.value
|
||||||
|
YOUTUBE_CHANNEL = IndirectDataType.YOUTUBE_CHANNEL.value
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from embedchain.embedchain import EmbedChain
|
|||||||
from embedchain.embedder.base import BaseEmbedder
|
from embedchain.embedder.base import BaseEmbedder
|
||||||
from embedchain.embedder.openai import OpenAIEmbedder
|
from embedchain.embedder.openai import OpenAIEmbedder
|
||||||
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
from embedchain.factory import EmbedderFactory, LlmFactory, VectorDBFactory
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.llm.base import BaseLlm
|
from embedchain.llm.base import BaseLlm
|
||||||
from embedchain.llm.openai import OpenAILlm
|
from embedchain.llm.openai import OpenAILlm
|
||||||
from embedchain.telemetry.posthog import AnonymousTelemetry
|
from embedchain.telemetry.posthog import AnonymousTelemetry
|
||||||
@@ -24,6 +24,10 @@ from embedchain.vectordb.base import BaseVectorDB
|
|||||||
from embedchain.vectordb.chroma import ChromaDB
|
from embedchain.vectordb.chroma import ChromaDB
|
||||||
|
|
||||||
|
|
||||||
|
# Setup the user directory if doesn't exist already
|
||||||
|
Client.setup_dir()
|
||||||
|
|
||||||
|
|
||||||
@register_deserializable
|
@register_deserializable
|
||||||
class Pipeline(EmbedChain):
|
class Pipeline(EmbedChain):
|
||||||
"""
|
"""
|
||||||
@@ -64,9 +68,6 @@ class Pipeline(EmbedChain):
|
|||||||
:type auto_deploy: bool, optional
|
:type auto_deploy: bool, optional
|
||||||
:raises Exception: If an error occurs while creating the pipeline
|
: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:
|
if id and yaml_path:
|
||||||
raise Exception("Cannot provide both id and config. Please provide only one of them.")
|
raise Exception("Cannot provide both id and config. Please provide only one of them.")
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from typing import cast
|
|||||||
from openai import OpenAI
|
from openai import OpenAI
|
||||||
from openai.types.beta.threads import MessageContentText, ThreadMessage
|
from openai.types.beta.threads import MessageContentText, ThreadMessage
|
||||||
|
|
||||||
from embedchain import Pipeline
|
from embedchain import Client, Pipeline
|
||||||
from embedchain.config import AddConfig
|
from embedchain.config import AddConfig
|
||||||
from embedchain.data_formatter import DataFormatter
|
from embedchain.data_formatter import DataFormatter
|
||||||
from embedchain.models.data_type import DataType
|
from embedchain.models.data_type import DataType
|
||||||
@@ -19,6 +19,9 @@ from embedchain.utils import detect_datatype
|
|||||||
|
|
||||||
logging.basicConfig(level=logging.WARN)
|
logging.basicConfig(level=logging.WARN)
|
||||||
|
|
||||||
|
# Setup the user directory if doesn't exist already
|
||||||
|
Client.setup_dir()
|
||||||
|
|
||||||
|
|
||||||
class OpenAIAssistant:
|
class OpenAIAssistant:
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class AnonymousTelemetry:
|
|||||||
self.project_api_key = "phc_PHQDA5KwztijnSojsxJ2c1DuJd52QCzJzT2xnSGvjN2"
|
self.project_api_key = "phc_PHQDA5KwztijnSojsxJ2c1DuJd52QCzJzT2xnSGvjN2"
|
||||||
self.host = host
|
self.host = host
|
||||||
self.posthog = Posthog(project_api_key=self.project_api_key, host=self.host)
|
self.posthog = Posthog(project_api_key=self.project_api_key, host=self.host)
|
||||||
self.user_id = self.get_user_id()
|
self.user_id = self._get_user_id()
|
||||||
self.enabled = enabled
|
self.enabled = enabled
|
||||||
|
|
||||||
# Check if telemetry tracking is disabled via environment variable
|
# Check if telemetry tracking is disabled via environment variable
|
||||||
@@ -38,7 +38,7 @@ class AnonymousTelemetry:
|
|||||||
posthog_logger = logging.getLogger("posthog")
|
posthog_logger = logging.getLogger("posthog")
|
||||||
posthog_logger.disabled = True
|
posthog_logger.disabled = True
|
||||||
|
|
||||||
def get_user_id(self):
|
def _get_user_id(self):
|
||||||
if not os.path.exists(CONFIG_DIR):
|
if not os.path.exists(CONFIG_DIR):
|
||||||
os.makedirs(CONFIG_DIR)
|
os.makedirs(CONFIG_DIR)
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,62 @@ from schema import Optional, Or, Schema
|
|||||||
from embedchain.models.data_type import DataType
|
from embedchain.models.data_type import DataType
|
||||||
|
|
||||||
|
|
||||||
|
def parse_content(content, type):
|
||||||
|
implemented = ["html.parser", "lxml", "lxml-xml", "xml", "html5lib"]
|
||||||
|
if type not in implemented:
|
||||||
|
raise ValueError(f"Parser type {type} not implemented. Please choose one of {implemented}")
|
||||||
|
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
soup = BeautifulSoup(content, type)
|
||||||
|
original_size = len(str(soup.get_text()))
|
||||||
|
|
||||||
|
tags_to_exclude = [
|
||||||
|
"nav",
|
||||||
|
"aside",
|
||||||
|
"form",
|
||||||
|
"header",
|
||||||
|
"noscript",
|
||||||
|
"svg",
|
||||||
|
"canvas",
|
||||||
|
"footer",
|
||||||
|
"script",
|
||||||
|
"style",
|
||||||
|
]
|
||||||
|
for tag in soup(tags_to_exclude):
|
||||||
|
tag.decompose()
|
||||||
|
|
||||||
|
ids_to_exclude = ["sidebar", "main-navigation", "menu-main-menu"]
|
||||||
|
for id in ids_to_exclude:
|
||||||
|
tags = soup.find_all(id=id)
|
||||||
|
for tag in tags:
|
||||||
|
tag.decompose()
|
||||||
|
|
||||||
|
classes_to_exclude = [
|
||||||
|
"elementor-location-header",
|
||||||
|
"navbar-header",
|
||||||
|
"nav",
|
||||||
|
"header-sidebar-wrapper",
|
||||||
|
"blog-sidebar-wrapper",
|
||||||
|
"related-posts",
|
||||||
|
]
|
||||||
|
for class_name in classes_to_exclude:
|
||||||
|
tags = soup.find_all(class_=class_name)
|
||||||
|
for tag in tags:
|
||||||
|
tag.decompose()
|
||||||
|
|
||||||
|
content = soup.get_text()
|
||||||
|
content = clean_string(content)
|
||||||
|
|
||||||
|
cleaned_size = len(content)
|
||||||
|
if original_size != 0:
|
||||||
|
logging.info(
|
||||||
|
f"Cleaned page size: {cleaned_size} characters, down from {original_size} (shrunk: {original_size-cleaned_size} chars, {round((1-(cleaned_size/original_size)) * 100, 2)}%)" # noqa:E501
|
||||||
|
)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
|
|
||||||
def clean_string(text):
|
def clean_string(text):
|
||||||
"""
|
"""
|
||||||
This function takes in a string and performs a series of text cleaning operations.
|
This function takes in a string and performs a series of text cleaning operations.
|
||||||
@@ -161,6 +217,10 @@ def detect_datatype(source: Any) -> DataType:
|
|||||||
logging.debug(f"Source of `{formatted_source}` detected as `csv`.")
|
logging.debug(f"Source of `{formatted_source}` detected as `csv`.")
|
||||||
return DataType.CSV
|
return DataType.CSV
|
||||||
|
|
||||||
|
if url.path.endswith(".mdx") or url.path.endswith(".md"):
|
||||||
|
logging.debug(f"Source of `{formatted_source}` detected as `mdx`.")
|
||||||
|
return DataType.MDX
|
||||||
|
|
||||||
if url.path.endswith(".docx"):
|
if url.path.endswith(".docx"):
|
||||||
logging.debug(f"Source of `{formatted_source}` detected as `docx`.")
|
logging.debug(f"Source of `{formatted_source}` detected as `docx`.")
|
||||||
return DataType.DOCX
|
return DataType.DOCX
|
||||||
@@ -200,6 +260,10 @@ def detect_datatype(source: Any) -> DataType:
|
|||||||
logging.debug(f"Source of `{formatted_source}` detected as `docs_site`.")
|
logging.debug(f"Source of `{formatted_source}` detected as `docs_site`.")
|
||||||
return DataType.DOCS_SITE
|
return DataType.DOCS_SITE
|
||||||
|
|
||||||
|
if "github.com" in url.netloc:
|
||||||
|
logging.debug(f"Source of `{formatted_source}` detected as `github`.")
|
||||||
|
return DataType.GITHUB
|
||||||
|
|
||||||
# If none of the above conditions are met, it's a general web page
|
# If none of the above conditions are met, it's a general web page
|
||||||
logging.debug(f"Source of `{formatted_source}` detected as `web_page`.")
|
logging.debug(f"Source of `{formatted_source}` detected as `web_page`.")
|
||||||
return DataType.WEB_PAGE
|
return DataType.WEB_PAGE
|
||||||
@@ -233,6 +297,10 @@ def detect_datatype(source: Any) -> DataType:
|
|||||||
logging.debug(f"Source of `{formatted_source}` detected as `xml`.")
|
logging.debug(f"Source of `{formatted_source}` detected as `xml`.")
|
||||||
return DataType.XML
|
return DataType.XML
|
||||||
|
|
||||||
|
if source.endswith(".mdx") or source.endswith(".md"):
|
||||||
|
logging.debug(f"Source of `{formatted_source}` detected as `mdx`.")
|
||||||
|
return DataType.MDX
|
||||||
|
|
||||||
if source.endswith(".yaml"):
|
if source.endswith(".yaml"):
|
||||||
with open(source, "r") as file:
|
with open(source, "r") as file:
|
||||||
yaml_content = yaml.safe_load(file)
|
yaml_content = yaml.safe_load(file)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
from embedchain.config.vectordb.base import BaseVectorDbConfig
|
||||||
from embedchain.embedder.base import BaseEmbedder
|
from embedchain.embedder.base import BaseEmbedder
|
||||||
from embedchain.helper.json_serializable import JSONSerializable
|
from embedchain.helpers.json_serializable import JSONSerializable
|
||||||
|
|
||||||
|
|
||||||
class BaseVectorDB(JSONSerializable):
|
class BaseVectorDB(JSONSerializable):
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ from typing import Any, Dict, List, Optional, Tuple, Union
|
|||||||
|
|
||||||
from chromadb import Collection, QueryResult
|
from chromadb import Collection, QueryResult
|
||||||
from langchain.docstore.document import Document
|
from langchain.docstore.document import Document
|
||||||
|
from tqdm import tqdm
|
||||||
|
|
||||||
from embedchain.config import ChromaDbConfig
|
from embedchain.config import ChromaDbConfig
|
||||||
from embedchain.helper.json_serializable import register_deserializable
|
from embedchain.helpers.json_serializable import register_deserializable
|
||||||
from embedchain.vectordb.base import BaseVectorDB
|
from embedchain.vectordb.base import BaseVectorDB
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -157,8 +158,7 @@ class ChromaDB(BaseVectorDB):
|
|||||||
" Ids size: {}".format(len(documents), len(metadatas), len(ids))
|
" Ids size: {}".format(len(documents), len(metadatas), len(ids))
|
||||||
)
|
)
|
||||||
|
|
||||||
for i in range(0, len(documents), self.BATCH_SIZE):
|
for i in tqdm(range(0, len(documents), self.BATCH_SIZE), desc="Inserting batches in chromadb"):
|
||||||
print("Inserting batches from {} to {} in chromadb".format(i, min(len(documents), i + self.BATCH_SIZE)))
|
|
||||||
if skip_embedding:
|
if skip_embedding:
|
||||||
self.collection.add(
|
self.collection.add(
|
||||||
embeddings=embeddings[i : i + self.BATCH_SIZE],
|
embeddings=embeddings[i : i + self.BATCH_SIZE],
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user