Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 12eb16d60b | |||
| ec9f454ad1 | |||
| 9f1f17a611 | |||
| 94369657ef | |||
| 490d7db601 | |||
| ea18b80f90 | |||
| 70077f4e46 | |||
| 85106c7c7e | |||
| 1b19d0d19c | |||
| 13f01e399c | |||
| 261e2d088c | |||
| b0ae3e95c7 | |||
| fc633dadeb | |||
| aafb334916 | |||
| 04d851e802 | |||
| de31c63dac | |||
| c068f58543 | |||
| 70df373807 | |||
| 4388f6bfc2 | |||
| d0956a0dc1 | |||
| ccf515cadd | |||
| a6e4235bb0 | |||
| 9ba408086e | |||
| bbb3bca1c7 | |||
| 564036a166 | |||
| abf99ce5ea |
@@ -1,5 +1,8 @@
|
||||
blank_issues_enabled: true
|
||||
contact_links:
|
||||
- name: 1-on-1 Session
|
||||
url: https://cal.com/taranjeetio/ec
|
||||
about: Speak directly with Taranjeet, the founder, to discuss issues, share feedback, or explore improvements for Embedchain
|
||||
- name: Discord
|
||||
url: https://discord.gg/6PzXDgEjG5
|
||||
about: General community discussions
|
||||
about: General community discussions
|
||||
|
||||
+32
-16
@@ -1,24 +1,40 @@
|
||||
name: cd
|
||||
name: Publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
types: [published] # This will trigger the workflow when you create a new release
|
||||
|
||||
jobs:
|
||||
publish_to_pypi:
|
||||
name: publish to pypi on new release
|
||||
build-n-publish:
|
||||
name: Build and publish Python 🐍 distributions 📦 to PyPI and TestPyPI
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
# IMPORTANT: this permission is mandatory for trusted publishing
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: JRubics/poetry-publish@v1.16
|
||||
name: Build and publish to PyPI
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
pypi_token: ${{ secrets.PYPI_TOKEN }}
|
||||
ignore_dev_requirements: "yes"
|
||||
repository_url: https://upload.pypi.org/legacy/
|
||||
repository_name: embedchain
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install dependencies
|
||||
run: poetry install
|
||||
|
||||
- name: Build a binary wheel and a source tarball
|
||||
run: poetry build
|
||||
|
||||
- name: Publish distribution 📦 to Test PyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository_url: https://test.pypi.org/legacy/
|
||||
|
||||
- name: Publish distribution 📦 to PyPI
|
||||
if: startsWith(github.ref, 'refs/tags')
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
|
||||
@@ -1,42 +1,23 @@
|
||||
# embedchain
|
||||
|
||||
[](https://pypi.org/project/embedchain/)
|
||||
[](https://discord.gg/6PzXDgEjG5)
|
||||
[](https://discord.gg/CUU9FPhRNt)
|
||||
[](https://twitter.com/embedchain)
|
||||
[](https://embedchain.substack.com/)
|
||||
[](https://colab.research.google.com/drive/138lMWhENGeEu7Q1-6lNbNTHGLZXBBz_B?usp=sharing)
|
||||
|
||||
Embedchain is a framework to easily create LLM powered bots over any dataset. If you want a javascript version, check out [embedchain-js](https://github.com/embedchain/embedchainjs)
|
||||
|
||||
## 🤝 Schedule a 1-on-1 Session
|
||||
|
||||
Book a [1-on-1 Session](https://cal.com/taranjeetio/ec) with Taranjeet, the founder, to discuss any issues, provide feedback, or explore how we can improve Embedchain for you.
|
||||
|
||||
## 🔧 Quick install
|
||||
|
||||
```bash
|
||||
pip install embedchain
|
||||
```
|
||||
|
||||
## 🔥 Latest
|
||||
|
||||
- **[2023/07/19]** Released support for 🦙 `llama2` model. Start creating your `llama2` based bots like this:
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from embedchain import Llama2App
|
||||
|
||||
os.environ['REPLICATE_API_TOKEN'] = "REPLICATE API TOKEN"
|
||||
|
||||
zuck_bot = Llama2App()
|
||||
|
||||
# Embed your data
|
||||
zuck_bot.add("https://www.youtube.com/watch?v=Ff4fRgnuFgQ")
|
||||
zuck_bot.add("https://en.wikipedia.org/wiki/Mark_Zuckerberg")
|
||||
|
||||
# Nice, your bot is ready now. Start asking questions to your bot.
|
||||
zuck_bot.query("Who is Mark Zuckerberg?")
|
||||
# Answer: Mark Zuckerberg is an American internet entrepreneur and business magnate. He is the co-founder and CEO of Facebook.
|
||||
```
|
||||
|
||||
|
||||
## 🔍 Demo
|
||||
|
||||
Try out embedchain in your browser:
|
||||
@@ -51,6 +32,16 @@ The documentation for embedchain can be found at [docs.embedchain.ai](https://do
|
||||
|
||||
Embedchain empowers you to create chatbot models similar to ChatGPT, using your own evolving dataset.
|
||||
|
||||
### Data Types Supported
|
||||
|
||||
* Youtube video
|
||||
* PDF file
|
||||
* Web page
|
||||
* Sitemap
|
||||
* Doc file
|
||||
* Code documentation website loader
|
||||
* Notion
|
||||
|
||||
### Queries
|
||||
|
||||
For example, you can use Embedchain to create an Elon Musk bot using the following code:
|
||||
@@ -78,7 +69,7 @@ elon_bot.query("How many companies does Elon Musk run?")
|
||||
Contributions are welcome! Please check out the issues on the repository, and feel free to open a pull request.
|
||||
For more information, please see the [contributing guidelines](CONTRIBUTING.md).
|
||||
|
||||
For more refrence, please go through [Development Guide](https://docs.embedchain.ai/contribution/dev) and [Documentation Guide](https://docs.embedchain.ai/contribution/docs).
|
||||
For more reference, please go through [Development Guide](https://docs.embedchain.ai/contribution/dev) and [Documentation Guide](https://docs.embedchain.ai/contribution/docs).
|
||||
|
||||
|
||||
## Citation
|
||||
|
||||
@@ -38,6 +38,9 @@ Embedchain community has been super active in creating demos on top of Embedchai
|
||||
- [Understanding what the LLM framework embedchain does](https://zenn.dev/hijikix/articles/4bc8d60156a436) by Daisuke Hashimoto
|
||||
- [In bed with GPT and Node.js](https://dev.to/worldlinetech/in-bed-with-gpt-and-nodejs-4kh2) by Raphaël Semeteys, ([LinkedIn Post](https://www.linkedin.com/posts/raphaelsemeteys_in-bed-with-gpt-and-nodejs-activity-7088113552326029313-nn87/))
|
||||
- [Using Embedchain — A powerful LangChain Python wrapper to build Chat Bots even faster!⚡](https://medium.com/@avra42/using-embedchain-a-powerful-langchain-python-wrapper-to-build-chat-bots-even-faster-35c12994a360) by Avra, ([Tweet](https://twitter.com/Avra_b/status/1686767751560310784/))
|
||||
- [What is the Embedchain library?](https://jahaniwww.com/%da%a9%d8%aa%d8%a7%d8%a8%d8%ae%d8%a7%d9%86%d9%87-embedchain/) by Ali Jahani, ([LinkedIn Post](https://www.linkedin.com/posts/ajahani_aepaetaeqaexaggahyaeu-aetaexaesabraeaaeqaepaeu-activity-7097605202135904256-ppU-/))
|
||||
- [LangChain is Nice, But Have You Tried EmbedChain ?](https://medium.com/thoughts-on-machine-learning/langchain-is-nice-but-have-you-tried-embedchain-215a34421cde) by FS Ndzomga, ([Tweet](https://twitter.com/ndzfs/status/1695583640372035951/))
|
||||
- [Simplest Method to Build a Custom Chatbot with GPT-3.5 (via Embedchain)](https://www.ainewsletter.today/p/simplest-method-to-build-a-custom) by Arjun, ([Tweet](https://twitter.com/aiguy_arjun/status/1696393808467091758/))
|
||||
|
||||
### LinkedIn
|
||||
|
||||
@@ -50,6 +53,7 @@ Embedchain community has been super active in creating demos on top of Embedchai
|
||||
- [About embedchain](https://www.linkedin.com/feed/update/urn:li:activity:7080984218914189312/) by Morris Lee
|
||||
- [How to use Embedchain](https://www.linkedin.com/posts/nehaabansal_github-embedchainembedchain-framework-activity-7085830340136595456-kbW5/) by Neha Bansal
|
||||
- [Youtube/Webpage summary for Energy Study](https://www.linkedin.com/posts/bar%C4%B1%C5%9F-sanl%C4%B1-34b82715_enerji-python-activity-7082735341563977730-Js0U/) by Barış Sanlı, ([Tweet](https://twitter.com/barissanli/status/1676968784979193857/))
|
||||
- [Demo: How to use Embedchain? (Contains Collab Notebook link)](https://www.linkedin.com/posts/liorsinclair_embedchain-is-getting-a-lot-of-traction-because-activity-7103044695995424768-RckT/) by Lior Sinclair
|
||||
|
||||
### Twitter
|
||||
|
||||
@@ -79,9 +83,31 @@ Embedchain community has been super active in creating demos on top of Embedchai
|
||||
- [AI ChatBot in 5 lines Python Code](https://www.youtube.com/watch?v=zjWvLJLksv8) by Data Engineering
|
||||
- [Interview with Karl Marx](https://www.youtube.com/watch?v=5Y4Tscwj1xk) by Alexander Ray Williams
|
||||
- [Vlog where we try to build a bot based on our content on the internet](https://www.youtube.com/watch?v=I2w8CWM3bx4) by DV, ([Tweet](https://twitter.com/dvcoolster/status/1688387017544261632))
|
||||
- [CHAT with ANY ONLINE RESOURCES using EMBEDCHAIN|STREAMLIT with MEMORY |All OPENSOURCE](https://www.youtube.com/watch?v=TqQIHWoWTDQ&pp=ygUKZW1iZWRjaGFpbg%3D%3D) by DataInsightEdge
|
||||
- [Build POWERFUL LLM Bots EASILY with Your Own Data - Embedchain - Langchain 2.0? (Tutorial)](https://www.youtube.com/watch?v=jE24Y_GasE8) by WorldofAI, ([Tweet](https://twitter.com/intheworldofai/status/1696229166922780737))
|
||||
- [Embedchain: An AI knowledge base assistant for customizing enterprise private data, which can be connected to discord, whatsapp, slack, tele and other terminals (with gradio to build a request interface) in Chinese](https://www.youtube.com/watch?v=5RZzCJRk-d0) by AIGC LINK
|
||||
- [Embedchain Introduction](https://www.youtube.com/watch?v=Jet9zAqyggI) by Fahd Mirza
|
||||
|
||||
## Mentions
|
||||
|
||||
### Github repos
|
||||
|
||||
- [Awesome-LLM](https://github.com/Hannibal046/Awesome-LLM)
|
||||
- [awesome-chatgpt-api](https://github.com/reorx/awesome-chatgpt-api)
|
||||
- [awesome-langchain](https://github.com/kyrolabs/awesome-langchain)
|
||||
- [Awesome-Prompt-Engineering](https://github.com/promptslab/Awesome-Prompt-Engineering)
|
||||
- [awesome-chatgpt](https://github.com/eon01/awesome-chatgpt)
|
||||
- [Awesome-LLMOps](https://github.com/tensorchord/Awesome-LLMOps)
|
||||
- [awesome-generative-ai](https://github.com/filipecalegario/awesome-generative-ai)
|
||||
- [awesome-gpt](https://github.com/formulahendry/awesome-gpt)
|
||||
- [awesome-ChatGPT-repositories](https://github.com/taishi-i/awesome-ChatGPT-repositories)
|
||||
- [awesome-gpt-prompt-engineering](https://github.com/snwfdhmp/awesome-gpt-prompt-engineering)
|
||||
- [awesome-chatgpt](https://github.com/awesome-chatgpt/awesome-chatgpt)
|
||||
- [awesome-llm-and-aigc](https://github.com/sjinzh/awesome-llm-and-aigc)
|
||||
- [awesome-compbio-chatgpt](https://github.com/csbl-br/awesome-compbio-chatgpt)
|
||||
- [Awesome-LLM4Tool](https://github.com/OpenGVLab/Awesome-LLM4Tool)
|
||||
|
||||
## Meetups
|
||||
|
||||
- [Dash and ChatGPT: Future of AI-enabled apps 30/08/23](https://go.plotly.com/dash-chatgpt)
|
||||
- [Pie & AI: Bangalore - Build end-to-end LLM app using Embedchain 01/09/23](https://www.eventbrite.com/e/pie-ai-bangalore-build-end-to-end-llm-app-using-embedchain-tickets-698045722547)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: '🔮 Poe Bot'
|
||||
---
|
||||
|
||||
### 🚀 Getting started
|
||||
|
||||
1. Install embedchain python package:
|
||||
|
||||
```bash
|
||||
pip install embedchain[poe]
|
||||
```
|
||||
|
||||
2. Create a free account on [Poe](https://www.poe.com?utm_source=embedchain).
|
||||
3. Click "Create Bot" button on top left
|
||||
4. Give it a handle and an optional description.
|
||||
5. Select `Use API`.
|
||||
6. Under `API URL` enter your server or ngrok address. 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.
|
||||
7. Copy your api key and paste it in `.env` as `POE_API_KEY`.
|
||||
8. Start the bot.
|
||||
|
||||
```bash
|
||||
python -m embedchain.bots.poe
|
||||
```
|
||||
|
||||
If you want to run the bot on another port, you can pass `--port option` like
|
||||
|
||||
```bash
|
||||
python -m embedchain.bots.poe --port 5000
|
||||
```
|
||||
|
||||
9. Click `Run check` to make sure your machine can be reached.
|
||||
10. Make sure your bot is private if that's what you want.
|
||||
11. Click `Create bot` at the bottom to finally create the bot
|
||||
12. Now you bot is created.
|
||||
|
||||
### 💬 How to use
|
||||
|
||||
- To include data sources, use this command:
|
||||
```text
|
||||
/add <url_or_text>
|
||||
```
|
||||
|
||||
- You can refer the [Supported Data formats](https://docs.embedchain.ai/advanced/data_types) section to refer the supported data types in embedchain.
|
||||
|
||||
- To ask the bot questions, just type your query:
|
||||
```text
|
||||
<your-question-here>
|
||||
```
|
||||
+3
-2
@@ -36,7 +36,7 @@
|
||||
},
|
||||
{
|
||||
"group": "Examples",
|
||||
"pages": ["examples/full_stack", "examples/api_server", "examples/discord_bot", "examples/slack_bot", "examples/telegram_bot", "examples/whatsapp_bot"]
|
||||
"pages": ["examples/full_stack", "examples/api_server", "examples/discord_bot", "examples/slack_bot", "examples/telegram_bot", "examples/whatsapp_bot", "examples/poe_bot"]
|
||||
},
|
||||
{
|
||||
"group": "Contribution Guidelines",
|
||||
@@ -47,7 +47,8 @@
|
||||
"footerSocials": {
|
||||
"twitter": "https://twitter.com/embedchain",
|
||||
"github": "https://github.com/embedchain/embedchain",
|
||||
"linkedin": "https://www.linkedin.com/company/embedchain"
|
||||
"linkedin": "https://www.linkedin.com/company/embedchain",
|
||||
"website": "https://embedchain.ai"
|
||||
},
|
||||
"backgroundImage": "/background.png",
|
||||
"isWhiteLabeled": true
|
||||
|
||||
+14
-4
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
import openai
|
||||
|
||||
from embedchain.config import AppConfig, ChatConfig
|
||||
@@ -14,19 +16,27 @@ class App(EmbedChain):
|
||||
dry_run(query): test your prompt without consuming tokens.
|
||||
"""
|
||||
|
||||
def __init__(self, config: AppConfig = None):
|
||||
def __init__(self, config: AppConfig = None, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
:param config: AppConfig instance to load as configuration. Optional.
|
||||
:param system_prompt: System prompt string. Optional.
|
||||
"""
|
||||
if config is None:
|
||||
config = AppConfig()
|
||||
|
||||
super().__init__(config)
|
||||
super().__init__(config, system_prompt)
|
||||
|
||||
def get_llm_model_answer(self, prompt, config: ChatConfig):
|
||||
messages = []
|
||||
if config.system_prompt:
|
||||
messages.append({"role": "system", "content": config.system_prompt})
|
||||
system_prompt = (
|
||||
self.system_prompt
|
||||
if self.system_prompt is not None
|
||||
else config.system_prompt
|
||||
if config.system_prompt is not None
|
||||
else None
|
||||
)
|
||||
if system_prompt:
|
||||
messages.append({"role": "system", "content": system_prompt})
|
||||
messages.append({"role": "user", "content": prompt})
|
||||
response = openai.ChatCompletion.create(
|
||||
model=config.model or "gpt-3.5-turbo-0613",
|
||||
|
||||
@@ -18,10 +18,11 @@ class CustomApp(EmbedChain):
|
||||
dry_run(query): test your prompt without consuming tokens.
|
||||
"""
|
||||
|
||||
def __init__(self, config: CustomAppConfig = None):
|
||||
def __init__(self, config: CustomAppConfig = None, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
:param config: Optional. `CustomAppConfig` instance to load as configuration.
|
||||
:raises ValueError: Config must be provided for custom app
|
||||
:param system_prompt: Optional. System prompt string.
|
||||
"""
|
||||
if config is None:
|
||||
raise ValueError("Config must be provided for custom app")
|
||||
@@ -34,7 +35,7 @@ class CustomApp(EmbedChain):
|
||||
# Because these models run locally, they should have an instance running when the custom app is created
|
||||
self.open_source_app = OpenSourceApp(config=config.open_source_app_config)
|
||||
|
||||
super().__init__(config)
|
||||
super().__init__(config, system_prompt)
|
||||
|
||||
def set_llm_model(self, provider: Providers):
|
||||
self.provider = provider
|
||||
@@ -51,6 +52,9 @@ class CustomApp(EmbedChain):
|
||||
"Streaming responses have not been implemented for this model yet. Please disable."
|
||||
)
|
||||
|
||||
if config.system_prompt is None and self.system_prompt is not None:
|
||||
config.system_prompt = self.system_prompt
|
||||
|
||||
try:
|
||||
if self.provider == Providers.OPENAI:
|
||||
return CustomApp._get_openai_answer(prompt, config)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from langchain.llms import Replicate
|
||||
|
||||
@@ -15,9 +16,10 @@ class Llama2App(EmbedChain):
|
||||
query(query): finds answer to the given query using vector database and LLM.
|
||||
"""
|
||||
|
||||
def __init__(self, config: AppConfig = None):
|
||||
def __init__(self, config: AppConfig = None, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
:param config: AppConfig instance to load as configuration. Optional.
|
||||
:param system_prompt: System prompt string. Optional.
|
||||
"""
|
||||
if "REPLICATE_API_TOKEN" not in os.environ:
|
||||
raise ValueError("Please set the REPLICATE_API_TOKEN environment variable.")
|
||||
@@ -25,11 +27,11 @@ class Llama2App(EmbedChain):
|
||||
if config is None:
|
||||
config = AppConfig()
|
||||
|
||||
super().__init__(config)
|
||||
super().__init__(config, system_prompt)
|
||||
|
||||
def get_llm_model_answer(self, prompt, config: ChatConfig = None):
|
||||
# TODO: Move the model and other inputs into config
|
||||
if config.system_prompt:
|
||||
if self.system_prompt or config.system_prompt:
|
||||
raise ValueError("Llama2App does not support `system_prompt`")
|
||||
llm = Replicate(
|
||||
model="a16z-infra/llama13b-v2-chat:df7690f1994d94e96ad9d568eac121aecf50684a0b0963b25a41cc40061269e5",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from typing import Iterable, Union
|
||||
from typing import Iterable, Union, Optional
|
||||
|
||||
from embedchain.config import ChatConfig, OpenSourceAppConfig
|
||||
from embedchain.embedchain import EmbedChain
|
||||
@@ -18,10 +18,11 @@ class OpenSourceApp(EmbedChain):
|
||||
query(query): finds answer to the given query using vector database and LLM.
|
||||
"""
|
||||
|
||||
def __init__(self, config: OpenSourceAppConfig = None):
|
||||
def __init__(self, config: OpenSourceAppConfig = None, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
:param config: OpenSourceAppConfig instance to load as configuration. Optional.
|
||||
`ef` defaults to open source.
|
||||
:param system_prompt: System prompt string. Optional.
|
||||
"""
|
||||
logging.info("Loading open source embedding model. This may take some time...") # noqa:E501
|
||||
if not config:
|
||||
@@ -33,7 +34,7 @@ class OpenSourceApp(EmbedChain):
|
||||
self.instance = OpenSourceApp._get_instance(config.model)
|
||||
|
||||
logging.info("Successfully loaded open source embedding model.")
|
||||
super().__init__(config)
|
||||
super().__init__(config, system_prompt)
|
||||
|
||||
def get_llm_model_answer(self, prompt, config: ChatConfig):
|
||||
return self._get_gpt4all_answer(prompt=prompt, config=config)
|
||||
@@ -55,7 +56,7 @@ class OpenSourceApp(EmbedChain):
|
||||
"OpenSourceApp does not support switching models at runtime. Please create a new app instance."
|
||||
)
|
||||
|
||||
if config.system_prompt:
|
||||
if self.system_prompt or config.system_prompt:
|
||||
raise ValueError("OpenSourceApp does not support `system_prompt`")
|
||||
|
||||
response = self.instance.generate(
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import argparse
|
||||
import logging
|
||||
import os
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi_poe import PoeBot, run
|
||||
|
||||
from embedchain.config import QueryConfig
|
||||
|
||||
from .base import BaseBot
|
||||
|
||||
|
||||
class EcPoeBot(BaseBot, PoeBot):
|
||||
def __init__(self):
|
||||
self.history_length = 5
|
||||
super().__init__()
|
||||
|
||||
async def get_response(self, query):
|
||||
last_message = query.query[-1].content
|
||||
try:
|
||||
history = (
|
||||
[f"{m.role}: {m.content}" for m in query.query[-(self.history_length + 1) : -1]]
|
||||
if len(query.query) > 0
|
||||
else None
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error(f"Error when processing the chat history. Message is being sent without history. Error: {e}")
|
||||
logging.warning(history)
|
||||
answer = self.handle_message(last_message, history)
|
||||
yield self.text_event(answer)
|
||||
|
||||
def handle_message(self, message, history: Optional[List[str]] = None):
|
||||
if message.startswith("/add "):
|
||||
response = self.add_data(message)
|
||||
else:
|
||||
response = self.ask_bot(message, history)
|
||||
return response
|
||||
|
||||
def add_data(self, message):
|
||||
data = message.split(" ")[-1]
|
||||
try:
|
||||
self.add(data)
|
||||
response = f"Added data from: {data}"
|
||||
except Exception:
|
||||
logging.exception(f"Failed to add data {data}.")
|
||||
response = "Some error occurred while adding data."
|
||||
return response
|
||||
|
||||
def ask_bot(self, message, history: List[str]):
|
||||
try:
|
||||
config = QueryConfig(history=history)
|
||||
response = self.query(message, config)
|
||||
except Exception:
|
||||
logging.exception(f"Failed to query {message}.")
|
||||
response = "An error occurred. Please try again!"
|
||||
return response
|
||||
|
||||
|
||||
def start_command():
|
||||
parser = argparse.ArgumentParser(description="EmbedChain PoeBot command line interface")
|
||||
# parser.add_argument("--host", default="0.0.0.0", help="Host IP to bind")
|
||||
parser.add_argument("--port", default=8080, type=int, help="Port to bind")
|
||||
parser.add_argument("--api-key", type=str, help="Poe API key")
|
||||
# parser.add_argument(
|
||||
# "--history-length",
|
||||
# default=5,
|
||||
# type=int,
|
||||
# help="Set the max size of the chat history. Multiplies cost, but improves conversation awareness.",
|
||||
# )
|
||||
args = parser.parse_args()
|
||||
|
||||
# FIXME: Arguments are automatically loaded by Poebot's ArgumentParser which causes it to fail.
|
||||
# the port argument here is also just for show, it actually works because poe has the same argument.
|
||||
|
||||
run(EcPoeBot(), api_key=args.api_key or os.environ.get("POE_API_KEY"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_command()
|
||||
@@ -1,9 +1,11 @@
|
||||
import hashlib
|
||||
import importlib.metadata
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional
|
||||
|
||||
import requests
|
||||
@@ -25,31 +27,56 @@ load_dotenv()
|
||||
|
||||
ABS_PATH = os.getcwd()
|
||||
DB_DIR = os.path.join(ABS_PATH, "db")
|
||||
|
||||
memory = ConversationBufferMemory()
|
||||
HOME_DIR = str(Path.home())
|
||||
CONFIG_DIR = os.path.join(HOME_DIR, ".embedchain")
|
||||
CONFIG_FILE = os.path.join(CONFIG_DIR, "config.json")
|
||||
|
||||
|
||||
class EmbedChain:
|
||||
def __init__(self, config: BaseAppConfig):
|
||||
def __init__(self, config: BaseAppConfig, system_prompt: Optional[str] = None):
|
||||
"""
|
||||
Initializes the EmbedChain instance, sets up a vector DB client and
|
||||
creates a collection.
|
||||
|
||||
:param config: BaseAppConfig instance to load as configuration.
|
||||
:param system_prompt: Optional. System prompt string.
|
||||
"""
|
||||
|
||||
self.config = config
|
||||
self.system_prompt = system_prompt
|
||||
self.collection = self.config.db._get_or_create_collection(self.config.collection_name)
|
||||
self.db = self.config.db
|
||||
self.user_asks = []
|
||||
self.is_docs_site_instance = False
|
||||
self.online = False
|
||||
self.memory = ConversationBufferMemory()
|
||||
|
||||
# Send anonymous telemetry
|
||||
self.s_id = self.config.id if self.config.id else str(uuid.uuid4())
|
||||
self.u_id = self._load_or_generate_user_id()
|
||||
thread_telemetry = threading.Thread(target=self._send_telemetry_event, args=("init",))
|
||||
thread_telemetry.start()
|
||||
|
||||
def _load_or_generate_user_id(self):
|
||||
"""
|
||||
Loads the user id from the config file if it exists, otherwise generates a new
|
||||
one and saves it to the config file.
|
||||
"""
|
||||
if not os.path.exists(CONFIG_DIR):
|
||||
os.makedirs(CONFIG_DIR)
|
||||
|
||||
if os.path.exists(CONFIG_FILE):
|
||||
with open(CONFIG_FILE, "r") as f:
|
||||
data = json.load(f)
|
||||
if "user_id" in data:
|
||||
return data["user_id"]
|
||||
|
||||
u_id = str(uuid.uuid4())
|
||||
with open(CONFIG_FILE, "w") as f:
|
||||
json.dump({"user_id": u_id}, f)
|
||||
|
||||
return u_id
|
||||
|
||||
def add(
|
||||
self,
|
||||
source,
|
||||
@@ -362,8 +389,7 @@ class EmbedChain:
|
||||
k["web_search_result"] = self.access_search_and_get_results(input_query)
|
||||
contexts = self.retrieve_from_database(input_query, config)
|
||||
|
||||
global memory
|
||||
chat_history = memory.load_memory_variables({})["history"]
|
||||
chat_history = self.memory.load_memory_variables({})["history"]
|
||||
|
||||
if chat_history:
|
||||
config.set_history(chat_history)
|
||||
@@ -376,14 +402,14 @@ class EmbedChain:
|
||||
|
||||
answer = self.get_answer_from_llm(prompt, config)
|
||||
|
||||
memory.chat_memory.add_user_message(input_query)
|
||||
self.memory.chat_memory.add_user_message(input_query)
|
||||
|
||||
# Send anonymous telemetry
|
||||
thread_telemetry = threading.Thread(target=self._send_telemetry_event, args=("chat",))
|
||||
thread_telemetry.start()
|
||||
|
||||
if isinstance(answer, str):
|
||||
memory.chat_memory.add_ai_message(answer)
|
||||
self.memory.chat_memory.add_ai_message(answer)
|
||||
logging.info(f"Answer: {answer}")
|
||||
return answer
|
||||
else:
|
||||
@@ -395,7 +421,7 @@ class EmbedChain:
|
||||
for chunk in answer:
|
||||
streamed_answer = streamed_answer + chunk
|
||||
yield chunk
|
||||
memory.chat_memory.add_ai_message(streamed_answer)
|
||||
self.memory.chat_memory.add_ai_message(streamed_answer)
|
||||
logging.info(f"Answer: {streamed_answer}")
|
||||
|
||||
def set_collection(self, collection_name):
|
||||
@@ -445,9 +471,11 @@ class EmbedChain:
|
||||
"version": importlib.metadata.version(__package__ or __name__),
|
||||
"method": method,
|
||||
"language": "py",
|
||||
"u_id": self.u_id,
|
||||
}
|
||||
if extra_metadata:
|
||||
metadata.update(extra_metadata)
|
||||
|
||||
response = requests.post(url, json={"metadata": metadata})
|
||||
response.raise_for_status()
|
||||
if response.status_code != 200:
|
||||
logging.warning(f"Telemetry event failed with status code {response.status_code}")
|
||||
|
||||
@@ -93,15 +93,6 @@ def use_pysqlite3():
|
||||
"Error:",
|
||||
e,
|
||||
)
|
||||
__import__("pysqlite3")
|
||||
sys.modules["sqlite3"] = sys.modules.pop("pysqlite3")
|
||||
# Let the user know what happened.
|
||||
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S,%f")[:-3]
|
||||
print(
|
||||
f"{current_time} [embedchain] [INFO]",
|
||||
"Swapped std-lib sqlite3 with pysqlite3 for ChromaDb compatibility.",
|
||||
f"Your original version was {sqlite3.sqlite_version}.",
|
||||
)
|
||||
|
||||
|
||||
def format_source(source: str, limit: int = 20) -> str:
|
||||
|
||||
@@ -28,8 +28,7 @@ class ChromaDB(BaseVectorDB):
|
||||
|
||||
if host and port:
|
||||
logging.info(f"Connecting to ChromaDB server: {host}:{port}")
|
||||
self.settings = Settings(chroma_server_host=host, chroma_server_http_port=port)
|
||||
self.client = chromadb.HttpClient(self.settings)
|
||||
self.client = chromadb.HttpClient(host=host, port=8000)
|
||||
else:
|
||||
if db_dir is None:
|
||||
db_dir = "db"
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "embedchain"
|
||||
version = "0.0.42"
|
||||
version = "0.0.51"
|
||||
description = "embedchain is a framework to easily create LLM powered bots over any dataset"
|
||||
authors = ["Taranjeet Singh"]
|
||||
license = "Apache License"
|
||||
@@ -85,6 +85,7 @@ python-dotenv = "^1.0.0"
|
||||
langchain = "^0.0.237"
|
||||
requests = "^2.31.0"
|
||||
openai = "^0.27.5"
|
||||
tiktoken = "^0.4.0"
|
||||
chromadb ="^0.4.2"
|
||||
youtube-transcript-api = "^0.6.1"
|
||||
beautifulsoup4 = "^4.12.2"
|
||||
@@ -98,6 +99,7 @@ gpt4all = { version = "^1.0.8", optional = true }
|
||||
elasticsearch = { version = "^8.9.0", optional = true }
|
||||
flask = "^2.3.3"
|
||||
twilio = "^8.5.0"
|
||||
fastapi-poe = { version = "0.0.16", optional = true }
|
||||
|
||||
|
||||
|
||||
@@ -116,10 +118,10 @@ streamlit = ["streamlit"]
|
||||
community = ["llama-index"]
|
||||
opensource = ["sentence-transformers", "torch", "gpt4all"]
|
||||
elasticsearch = ["elasticsearch"]
|
||||
poe = ["fastapi-poe"]
|
||||
|
||||
[tool.poetry.group.docs.dependencies]
|
||||
|
||||
|
||||
|
||||
[tool.poetry.scripts]
|
||||
|
||||
|
||||
@@ -7,15 +7,13 @@ from embedchain.config import AppConfig
|
||||
|
||||
|
||||
class TestApp(unittest.TestCase):
|
||||
os.environ["OPENAI_API_KEY"] = "test_key"
|
||||
|
||||
def setUp(self):
|
||||
os.environ["OPENAI_API_KEY"] = "test_key"
|
||||
self.app = App(config=AppConfig(collect_metrics=False))
|
||||
|
||||
@patch("embedchain.embedchain.memory", autospec=True)
|
||||
@patch.object(App, "retrieve_from_database", return_value=["Test context"])
|
||||
@patch.object(App, "get_answer_from_llm", return_value="Test answer")
|
||||
def test_chat_with_memory(self, mock_answer, mock_retrieve, mock_memory):
|
||||
def test_chat_with_memory(self, mock_get_answer, mock_retrieve):
|
||||
"""
|
||||
This test checks the functionality of the 'chat' method in the App class with respect to the chat history
|
||||
memory.
|
||||
@@ -23,27 +21,17 @@ class TestApp(unittest.TestCase):
|
||||
The second call is expected to use the chat history from the first call.
|
||||
|
||||
Key assumptions tested:
|
||||
- After the first call, 'memory.chat_memory.add_user_message' and 'memory.chat_memory.add_ai_message' are
|
||||
called with correct arguments, adding the correct chat history.
|
||||
- After the first call, 'memory.chat_memory.add_user_message' and 'memory.chat_memory.add_ai_message' are
|
||||
- During the second call, the 'chat' method uses the chat history from the first call.
|
||||
|
||||
The test isolates the 'chat' method behavior by mocking out 'retrieve_from_database', 'get_answer_from_llm' and
|
||||
'memory' methods.
|
||||
"""
|
||||
mock_memory.load_memory_variables.return_value = {"history": []}
|
||||
app = App()
|
||||
|
||||
# First call to chat
|
||||
first_answer = app.chat("Test query 1")
|
||||
self.assertEqual(first_answer, "Test answer")
|
||||
mock_memory.chat_memory.add_user_message.assert_called_once_with("Test query 1")
|
||||
mock_memory.chat_memory.add_ai_message.assert_called_once_with("Test answer")
|
||||
|
||||
mock_memory.chat_memory.add_user_message.reset_mock()
|
||||
mock_memory.chat_memory.add_ai_message.reset_mock()
|
||||
|
||||
# Second call to chat
|
||||
self.assertEqual(len(app.memory.chat_memory.messages), 2)
|
||||
second_answer = app.chat("Test query 2")
|
||||
self.assertEqual(second_answer, "Test answer")
|
||||
mock_memory.chat_memory.add_user_message.assert_called_once_with("Test query 2")
|
||||
mock_memory.chat_memory.add_ai_message.assert_called_once_with("Test answer")
|
||||
self.assertEqual(len(app.memory.chat_memory.messages), 4)
|
||||
|
||||
@@ -43,7 +43,7 @@ class TestApp(unittest.TestCase):
|
||||
mock_answer.assert_called_once()
|
||||
|
||||
@patch("openai.ChatCompletion.create")
|
||||
def test_query_config_passing(self, mock_create):
|
||||
def test_query_config_app_passing(self, mock_create):
|
||||
mock_create.return_value = {"choices": [{"message": {"content": "response"}}]} # Mock response
|
||||
|
||||
config = AppConfig()
|
||||
@@ -52,9 +52,24 @@ class TestApp(unittest.TestCase):
|
||||
|
||||
app.get_llm_model_answer("Test query", chat_config)
|
||||
|
||||
# Test systemp_prompt: Check that the 'create' method was called with the correct 'messages' argument
|
||||
# Test system_prompt: Check that the 'create' method was called with the correct 'messages' argument
|
||||
messages_arg = mock_create.call_args.kwargs["messages"]
|
||||
self.assertEqual(messages_arg[0]["role"], "system")
|
||||
self.assertEqual(messages_arg[0]["content"], "Test system prompt")
|
||||
|
||||
# TODO: Add tests for other config variables
|
||||
|
||||
@patch("openai.ChatCompletion.create")
|
||||
def test_app_passing(self, mock_create):
|
||||
mock_create.return_value = {"choices": [{"message": {"content": "response"}}]} # Mock response
|
||||
|
||||
config = AppConfig()
|
||||
chat_config = QueryConfig()
|
||||
app = App(config=config, system_prompt="Test system prompt")
|
||||
|
||||
app.get_llm_model_answer("Test query", chat_config)
|
||||
|
||||
# Test system_prompt: Check that the 'create' method was called with the correct 'messages' argument
|
||||
messages_arg = mock_create.call_args.kwargs["messages"]
|
||||
self.assertEqual(messages_arg[0]["role"], "system")
|
||||
self.assertEqual(messages_arg[0]["content"], "Test system prompt")
|
||||
|
||||
Reference in New Issue
Block a user