-
Notifications
You must be signed in to change notification settings - Fork 136
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Chat History microservice for chat data persistence (#286)
* Initial Implementation * Added Updates to the mongoConnection Signed-off-by: Yogesh Pandey <yogesh.pandey@intel.com>
- Loading branch information
1 parent
f5a5489
commit 30d95b7
Showing
10 changed files
with
569 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# Chat History Microservice | ||
|
||
The Chat History Microservice allows you to store, retrieve and manage chat conversations with a MongoDB database. This microservice can be used for data persistence in OPEA chat applications, enabling you to save and access chat histories. | ||
|
||
It can be integrated into any application by making HTTP requests to the provided API endpoints as shown in the flow diagram below. | ||
|
||
![Flow Chart](./assets/img/chathistory_flow.png) | ||
|
||
## Setup Environment Variables | ||
|
||
```bash | ||
export http_proxy=${your_http_proxy} | ||
export https_proxy=${your_http_proxy} | ||
export MONGO_HOST=${MONGO_HOST} | ||
export MONGO_PORT=27017 | ||
export DB_NAME=${DB_NAME} | ||
export COLLECTION_NAME=${COLLECTION_NAME} | ||
``` | ||
|
||
# 🚀Start Microservice with Docker | ||
|
||
## Build Docker Image | ||
|
||
```bash | ||
cd ../../../../ | ||
docker build -t opea/chathistory-mongo-server:latest --build-arg https_proxy=$https_proxy --build-arg http_proxy=$http_proxy -f comps/chathistory/mongo/docker/Dockerfile . | ||
``` | ||
|
||
## Run Docker with CLI | ||
|
||
- Run mongoDB image | ||
|
||
```bash | ||
docker run -d -p 27017:27017 --name=mongo mongo:latest | ||
``` | ||
|
||
- Run the chathistory Service | ||
|
||
```bash | ||
docker run -d --name="chathistory-mongo-server" -p 6013:6013 -p 6012:6012 -p 6014:6014 -e http_proxy=$http_proxy -e https_proxy=$https_proxy -e no_proxy=$no_proxy -e MONGO_HOST=${MONGO_HOST} -e MONGO_PORT=${MONGO_PORT} -e DB_NAME=${DB_NAME} -e COLLECTION_NAME=${COLLECTION_NAME} opea/chathistory-mongo-server:latest | ||
``` | ||
|
||
# Invoke Microservice | ||
|
||
Once chathistory service is up and running, users can update the database by using the below API endpoint. The API returns a unique UUID for the saved conversation. | ||
|
||
```bash | ||
curl -X 'POST' \ | ||
http://${host_ip}:6012/v1/chathistory/create \ | ||
-H 'accept: application/json' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{ | ||
"data": { | ||
"messages": "test Messages", "user": "test" | ||
} | ||
}' | ||
``` | ||
|
||
- Get all the Conversations for a user | ||
|
||
```bash | ||
curl -X 'POST' \ | ||
http://${host_ip}:6013/v1/chathistory/get \ | ||
-H 'accept: application/json' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{ | ||
"user": "test"}' | ||
``` | ||
|
||
- Get specific conversation by specifying the id. | ||
|
||
```bash | ||
curl -X 'POST' \ | ||
http://${host_ip}:6013/v1/chathistory/get \ | ||
-H 'accept: application/json' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{ | ||
"user": "test", "id":"668620173180b591e1e0cd74"}' | ||
``` | ||
|
||
- Update the conversation by specifying the id. | ||
|
||
```bash | ||
curl -X 'POST' \ | ||
http://${host_ip}:6012/v1/chathistory/create \ | ||
-H 'accept: application/json' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{ | ||
"data": { | ||
"messages": "test Messages Update", "user": "test" | ||
}, | ||
"id":"668620173180b591e1e0cd74" | ||
}' | ||
``` | ||
|
||
- Delete a stored conversation by specifying the id. | ||
|
||
```bash | ||
curl -X 'POST' \ | ||
http://${host_ip}:6014/v1/chathistory/delete \ | ||
-H 'accept: application/json' \ | ||
-H 'Content-Type: application/json' \ | ||
-d '{ | ||
"user": "test", "id":"668620173180b591e1e0cd74"}' | ||
``` |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
from typing import Optional | ||
|
||
from fastapi import HTTPException | ||
from mongo_store import DocumentStore | ||
from pydantic import BaseModel | ||
|
||
from comps.cores.mega.micro_service import opea_microservices, register_microservice | ||
from comps.cores.proto.api_protocol import ChatCompletionRequest | ||
|
||
|
||
class ChatMessage(BaseModel): | ||
data: ChatCompletionRequest | ||
first_query: Optional[str] = None | ||
id: Optional[str] = None | ||
|
||
|
||
class ChatId(BaseModel): | ||
user: str | ||
id: Optional[str] = None | ||
|
||
|
||
def get_first_string(value): | ||
if isinstance(value, str): | ||
return value | ||
elif isinstance(value, list): | ||
# Assuming we want the first string from the first dictionary | ||
if value and isinstance(value[0], dict): | ||
first_dict = value[0] | ||
if first_dict: | ||
# Get the first value from the dictionary | ||
first_key = next(iter(first_dict)) | ||
return first_dict[first_key] | ||
|
||
|
||
@register_microservice( | ||
name="opea_service@chathistory_mongo_create", | ||
endpoint="/v1/chathistory/create", | ||
host="0.0.0.0", | ||
input_datatype=ChatMessage, | ||
port=6012, | ||
) | ||
async def create_documents(document: ChatMessage): | ||
"""Creates or updates a document in the document store. | ||
Args: | ||
document (ChatMessage): The ChatMessage object containing the data to be stored. | ||
Returns: | ||
The result of the operation if successful, None otherwise. | ||
""" | ||
|
||
try: | ||
if document.data.user is None: | ||
raise HTTPException(status_code=500, detail="Please provide the user information") | ||
store = DocumentStore(document.data.user) | ||
store.initialize_storage() | ||
if document.first_query is None: | ||
document.first_query = get_first_string(document.data.messages) | ||
if document.id: | ||
res = await store.update_document(document.id, document.data, document.first_query) | ||
else: | ||
res = await store.save_document(document) | ||
return res | ||
except Exception as e: | ||
# Handle the exception here | ||
print(f"An error occurred: {str(e)}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
@register_microservice( | ||
name="opea_service@chathistory_mongo_get", | ||
endpoint="/v1/chathistory/get", | ||
host="0.0.0.0", | ||
input_datatype=ChatId, | ||
port=6013, | ||
) | ||
async def get_documents(document: ChatId): | ||
"""Retrieves documents from the document store based on the provided ChatId. | ||
Args: | ||
document (ChatId): The ChatId object containing the user and optional document id. | ||
Returns: | ||
The retrieved documents if successful, None otherwise. | ||
""" | ||
try: | ||
store = DocumentStore(document.user) | ||
store.initialize_storage() | ||
if document.id is None: | ||
res = await store.get_all_documents_of_user() | ||
else: | ||
res = await store.get_user_documents_by_id(document.id) | ||
return res | ||
except Exception as e: | ||
# Handle the exception here | ||
print(f"An error occurred: {str(e)}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
@register_microservice( | ||
name="opea_service@chathistory_mongo_delete", | ||
endpoint="/v1/chathistory/delete", | ||
host="0.0.0.0", | ||
input_datatype=ChatId, | ||
port=6014, | ||
) | ||
async def delete_documents(document: ChatId): | ||
"""Deletes a document from the document store based on the provided ChatId. | ||
Args: | ||
document (ChatId): The ChatId object containing the user and document id. | ||
Returns: | ||
The result of the deletion if successful, None otherwise. | ||
""" | ||
try: | ||
store = DocumentStore(document.user) | ||
store.initialize_storage() | ||
if document.id is None: | ||
raise Exception("Document id is required.") | ||
else: | ||
res = await store.delete_document(document.id) | ||
return res | ||
except Exception as e: | ||
# Handle the exception here | ||
print(f"An error occurred: {str(e)}") | ||
raise HTTPException(status_code=500, detail=str(e)) | ||
|
||
|
||
if __name__ == "__main__": | ||
opea_microservices["opea_service@chathistory_mongo_get"].start() | ||
opea_microservices["opea_service@chathistory_mongo_create"].start() | ||
opea_microservices["opea_service@chathistory_mongo_delete"].start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
import os | ||
|
||
# MONGO configuration | ||
MONGO_HOST = os.getenv("MONGO_HOST", "localhost") | ||
MONGO_PORT = os.getenv("MONGO_PORT", 27017) | ||
DB_NAME = os.getenv("DB_NAME", "OPEA") | ||
COLLECTION_NAME = os.getenv("COLLECTION_NAME", "ChatHistory") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
FROM python:3.11-slim | ||
|
||
ENV LANG C.UTF-8 | ||
|
||
RUN apt-get update -y && apt-get install -y --no-install-recommends --fix-missing \ | ||
build-essential \ | ||
libgl1-mesa-glx \ | ||
libjemalloc-dev \ | ||
vim | ||
|
||
RUN useradd -m -s /bin/bash user && \ | ||
mkdir -p /home/user && \ | ||
chown -R user /home/user/ | ||
|
||
USER user | ||
|
||
COPY comps /home/user/comps | ||
COPY requirements.txt /home/user/ | ||
|
||
RUN pip install --no-cache-dir --upgrade pip && \ | ||
pip install --no-cache-dir -r /home/user/comps/chathistory/mongo/requirements.txt && \ | ||
pip install --no-cache-dir -r /home/user/requirements.txt | ||
|
||
ENV PYTHONPATH=$PYTHONPATH:/home/user | ||
|
||
WORKDIR /home/user/comps/chathistory/mongo | ||
|
||
ENTRYPOINT ["python", "chathistory_mongo.py"] |
36 changes: 36 additions & 0 deletions
36
comps/chathistory/mongo/docker/docker-compose-chathistory-mongo.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
version: "3" | ||
services: | ||
mongo: | ||
image: mongo:7.0.11 | ||
container_name: mongodb | ||
ports: | ||
- 27017:27017 | ||
environment: | ||
http_proxy: ${http_proxy} | ||
https_proxy: ${https_proxy} | ||
no_proxy: ${no_proxy} | ||
command: mongod --quiet --logpath /dev/null | ||
|
||
chathistory-mongo: | ||
image: opea/chathistory-mongo-server:latest | ||
container_name: chathistory-mongo-server | ||
ports: | ||
- "6012:6012" | ||
- "6013:6013" | ||
- "6014:6014" | ||
ipc: host | ||
environment: | ||
http_proxy: ${http_proxy} | ||
no_proxy: ${no_proxy} | ||
https_proxy: ${https_proxy} | ||
MONGO_HOST: ${MONGO_HOST} | ||
MONGO_PORT: ${MONGO_PORT} | ||
COLLECTION_NAME: ${COLLECTION_NAME} | ||
restart: unless-stopped | ||
|
||
networks: | ||
default: | ||
driver: bridge |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright (C) 2024 Intel Corporation | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
from typing import Any | ||
|
||
import motor.motor_asyncio as motor | ||
from config import DB_NAME, MONGO_HOST, MONGO_PORT | ||
|
||
|
||
class MongoClient: | ||
conn_url = f"mongodb://{MONGO_HOST}:{MONGO_PORT}/" | ||
|
||
@staticmethod | ||
def get_db_client() -> Any: | ||
try: | ||
client = motor.AsyncIOMotorClient(MongoClient.conn_url) | ||
db = client[DB_NAME] | ||
return db | ||
|
||
except Exception as e: | ||
print(e) | ||
raise Exception(e) |
Oops, something went wrong.