Spaces:
Running
Running
shaileshjadhavSS
commited on
Commit
·
20b2575
1
Parent(s):
246a4b8
Added cloudinary api for file storage
Browse files- .gitignore +8 -1
- README.md +74 -13
- app.py +26 -14
- requirements.txt +2 -0
- services/cloudinary_api.py +5 -0
- settings/base.py +7 -0
- user_auth/user_manager.py +29 -2
.gitignore
CHANGED
|
@@ -1,3 +1,10 @@
|
|
| 1 |
**/__pycache__/
|
| 2 |
*.env
|
| 3 |
-
app.log
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
**/__pycache__/
|
| 2 |
*.env
|
| 3 |
+
app.log
|
| 4 |
+
*.jpg
|
| 5 |
+
*.jpeg
|
| 6 |
+
*.png
|
| 7 |
+
*.mp4
|
| 8 |
+
*.mp3
|
| 9 |
+
*.json
|
| 10 |
+
debug.log
|
README.md
CHANGED
|
@@ -1,13 +1,74 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# iConcierge Chatbot
|
| 2 |
+
The iConcierge chatbot is designed to assist users in tracking their meals, identifying recent meals, providing nutritional information, and suggesting the next meal of the day. The chatbot takes into account the user's profile, meal history, and other relevant factors to offer personalized meal suggestions.
|
| 3 |
+
|
| 4 |
+
## Clone the repository
|
| 5 |
+
Clone the repository:
|
| 6 |
+
```
|
| 7 |
+
$ git clone https://nonstop-development@bitbucket.org/nonstopio-dev/iconcierge.git
|
| 8 |
+
|
| 9 |
+
$ cd iconcierge
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
## Installation
|
| 13 |
+
|
| 14 |
+
### Environment Configuration
|
| 15 |
+
First, create an env.sh file with the following content to set up your
|
| 16 |
+
environment variables:
|
| 17 |
+
|
| 18 |
+
```
|
| 19 |
+
export GOOGLE_API_KEY="API_KEY"
|
| 20 |
+
export DB_NAME="DATABASE_NAME"
|
| 21 |
+
export DB_USER="USERNAME"
|
| 22 |
+
export DB_PASSWORD="PASSWORD"
|
| 23 |
+
export DB_HOST="localhost"
|
| 24 |
+
export DB_PORT="5432"
|
| 25 |
+
export CLOUDINARY_CLOUD_NAME="CLOUD_NAM"
|
| 26 |
+
export CLOUDINARY_API_KEY="CLOUDINARY_API_KEY"
|
| 27 |
+
export CLOUDINARY_API_SECRET="CLOUDINARY_API_SECRET"
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
To apply these environment variables, run the following command in your console:
|
| 31 |
+
```
|
| 32 |
+
source env.sh
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
### Package Installation
|
| 36 |
+
|
| 37 |
+
Next, install the required packages by running:
|
| 38 |
+
```
|
| 39 |
+
pip install -r requirements.txt
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
### Execution
|
| 43 |
+
To run the iConcierge chatbot application, use the following command:
|
| 44 |
+
```
|
| 45 |
+
streamlit run app.py
|
| 46 |
+
```
|
| 47 |
+
The application will be available at http://localhost:8501.
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
## Docker Setup
|
| 51 |
+
|
| 52 |
+
## Prerequisites
|
| 53 |
+
To run this project using Docker, you need to have Docker installed on your machine. You can download and install Docker from the official Docker installation guide.
|
| 54 |
+
|
| 55 |
+
## Installation
|
| 56 |
+
|
| 57 |
+
## Build the Docker Image
|
| 58 |
+
Build the Docker image using the following command:
|
| 59 |
+
```
|
| 60 |
+
docker build -t <image_name> .
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## Run the Docker Container
|
| 64 |
+
Run the Docker container with the following command:
|
| 65 |
+
```
|
| 66 |
+
docker run -p 8501:8501 <image_name>
|
| 67 |
+
```
|
| 68 |
+
The application will be available at http://localhost:8501.
|
| 69 |
+
|
| 70 |
+
## PostgreSQL (User Details)
|
| 71 |
+
We used Retool PostgreSQL to store user details, ensuring efficient and secure management of user data. Make sure your PostgreSQL database is properly configured and the credentials are correctly set in the env.sh file.
|
| 72 |
+
|
| 73 |
+
For more detailed documentation on how to configure and manage your PostgreSQL database, refer to the [official PostgreSQL documentation](https://www.postgresql.org/docs/).
|
| 74 |
+
|
app.py
CHANGED
|
@@ -30,7 +30,7 @@ if 'model' not in st.session_state:
|
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
-
def save_chat_history(user_name, chat_history):
|
| 34 |
"""
|
| 35 |
Save chat history to a file in a user-specific directory with a timestamp.
|
| 36 |
"""
|
|
@@ -45,10 +45,18 @@ def save_chat_history(user_name, chat_history):
|
|
| 45 |
serializable_history = []
|
| 46 |
for entry in chat_history:
|
| 47 |
if entry['role'] == 'user':
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
serializable_history.append(user_entry)
|
| 53 |
elif entry['role'] == 'model':
|
| 54 |
model_entry = {
|
|
@@ -60,8 +68,11 @@ def save_chat_history(user_name, chat_history):
|
|
| 60 |
with open(file_path, "w") as f:
|
| 61 |
json.dump(serializable_history, f, indent=4)
|
| 62 |
|
| 63 |
-
|
| 64 |
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
def authenticate_user(email, password):
|
| 67 |
"""
|
|
@@ -72,7 +83,7 @@ def authenticate_user(email, password):
|
|
| 72 |
authenticated = auth_manager.authenticate_user(email, password)
|
| 73 |
return authenticated
|
| 74 |
|
| 75 |
-
def conversation_chat(file_path, text_prompt):
|
| 76 |
"""
|
| 77 |
Handle the conversation with the chat session using the provided file path and text prompt.
|
| 78 |
"""
|
|
@@ -89,7 +100,7 @@ def conversation_chat(file_path, text_prompt):
|
|
| 89 |
|
| 90 |
logger.info(f"Successfully saved uploaded file: {file_path.name}")
|
| 91 |
|
| 92 |
-
file = genai.upload_file(path=temp_file_path, display_name=
|
| 93 |
user_entry = {
|
| 94 |
"role": "user",
|
| 95 |
"parts": [file, user_input]
|
|
@@ -117,7 +128,7 @@ def conversation_chat(file_path, text_prompt):
|
|
| 117 |
logger.error(f"Error processing file: {e}")
|
| 118 |
st.session_state.history.append("Error")
|
| 119 |
|
| 120 |
-
def display_chat():
|
| 121 |
"""
|
| 122 |
Display chat input and responses.
|
| 123 |
"""
|
|
@@ -131,7 +142,7 @@ def display_chat():
|
|
| 131 |
if st.button('Logout'):
|
| 132 |
|
| 133 |
# Save chat history before logging out
|
| 134 |
-
save_chat_history(st.session_state.email, st.session_state.history)
|
| 135 |
|
| 136 |
st.session_state.authenticated = False
|
| 137 |
st.session_state.email = ""
|
|
@@ -149,7 +160,7 @@ def display_chat():
|
|
| 149 |
submit_button = st.form_submit_button(label='Send ⬆️')
|
| 150 |
|
| 151 |
if submit_button:
|
| 152 |
-
conversation_chat(file_path, text_prompt)
|
| 153 |
|
| 154 |
if clear_chat_button:
|
| 155 |
st.session_state.history = []
|
|
@@ -162,9 +173,10 @@ def display_chat():
|
|
| 162 |
if entry['role'] == 'user':
|
| 163 |
if len(entry['parts']) > 1:
|
| 164 |
uploaded_file = entry['parts'][0]
|
|
|
|
| 165 |
if uploaded_file.mime_type.startswith("image/"):
|
| 166 |
file_name= uploaded_file.display_name
|
| 167 |
-
with open(
|
| 168 |
encoded_img = base64.b64encode(file.read()).decode('utf-8')
|
| 169 |
img_html = f'<img src="data:image/png;base64,{encoded_img}" width="200" style="margin-top: 5px;"/>'
|
| 170 |
st.markdown(f"""
|
|
@@ -177,7 +189,7 @@ def display_chat():
|
|
| 177 |
</div>
|
| 178 |
""", unsafe_allow_html=True)
|
| 179 |
else:
|
| 180 |
-
message(
|
| 181 |
|
| 182 |
if entry['parts'][1] != "":
|
| 183 |
message(entry['parts'][1], is_user=True, key=f"{i}_user", avatar_style="adventurer")
|
|
@@ -199,7 +211,7 @@ def main():
|
|
| 199 |
st.session_state.profile = user_manager.get_user(st.session_state.email).profile
|
| 200 |
st.session_state.model = create_model(GOOGLE_API_KEY, st.session_state.profile)
|
| 201 |
|
| 202 |
-
display_chat()
|
| 203 |
else:
|
| 204 |
st.title("Wellness Bot 🦾🤖 \n\nLogin/SignUp")
|
| 205 |
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
+
def save_chat_history(user_name, chat_history, user_manager):
|
| 34 |
"""
|
| 35 |
Save chat history to a file in a user-specific directory with a timestamp.
|
| 36 |
"""
|
|
|
|
| 45 |
serializable_history = []
|
| 46 |
for entry in chat_history:
|
| 47 |
if entry['role'] == 'user':
|
| 48 |
+
if len(entry['parts']) > 1:
|
| 49 |
+
uploaded_file = entry['parts'][0]
|
| 50 |
+
uploaded_file_url = user_manager.upload_to_cloudinary(uploaded_file.display_name)
|
| 51 |
+
user_entry = {
|
| 52 |
+
'role': 'user',
|
| 53 |
+
'parts': f"file_api: {uploaded_file.uri}, file_temp: {uploaded_file_url}, {entry['parts'][1]}"
|
| 54 |
+
}
|
| 55 |
+
else:
|
| 56 |
+
user_entry = {
|
| 57 |
+
'role': 'user',
|
| 58 |
+
'parts': entry['parts'][0]
|
| 59 |
+
}
|
| 60 |
serializable_history.append(user_entry)
|
| 61 |
elif entry['role'] == 'model':
|
| 62 |
model_entry = {
|
|
|
|
| 68 |
with open(file_path, "w") as f:
|
| 69 |
json.dump(serializable_history, f, indent=4)
|
| 70 |
|
| 71 |
+
history_json = json.dumps(serializable_history)
|
| 72 |
|
| 73 |
+
user_manager.save_history(user_name, history_json)
|
| 74 |
+
|
| 75 |
+
logger.info(f"Chat history saved to {file_path}")
|
| 76 |
|
| 77 |
def authenticate_user(email, password):
|
| 78 |
"""
|
|
|
|
| 83 |
authenticated = auth_manager.authenticate_user(email, password)
|
| 84 |
return authenticated
|
| 85 |
|
| 86 |
+
def conversation_chat(file_path, text_prompt, user_manager):
|
| 87 |
"""
|
| 88 |
Handle the conversation with the chat session using the provided file path and text prompt.
|
| 89 |
"""
|
|
|
|
| 100 |
|
| 101 |
logger.info(f"Successfully saved uploaded file: {file_path.name}")
|
| 102 |
|
| 103 |
+
file = genai.upload_file(path=temp_file_path, display_name=temp_file_path)
|
| 104 |
user_entry = {
|
| 105 |
"role": "user",
|
| 106 |
"parts": [file, user_input]
|
|
|
|
| 128 |
logger.error(f"Error processing file: {e}")
|
| 129 |
st.session_state.history.append("Error")
|
| 130 |
|
| 131 |
+
def display_chat(user_manager):
|
| 132 |
"""
|
| 133 |
Display chat input and responses.
|
| 134 |
"""
|
|
|
|
| 142 |
if st.button('Logout'):
|
| 143 |
|
| 144 |
# Save chat history before logging out
|
| 145 |
+
save_chat_history(st.session_state.email, st.session_state.history, user_manager)
|
| 146 |
|
| 147 |
st.session_state.authenticated = False
|
| 148 |
st.session_state.email = ""
|
|
|
|
| 160 |
submit_button = st.form_submit_button(label='Send ⬆️')
|
| 161 |
|
| 162 |
if submit_button:
|
| 163 |
+
conversation_chat(file_path, text_prompt, user_manager)
|
| 164 |
|
| 165 |
if clear_chat_button:
|
| 166 |
st.session_state.history = []
|
|
|
|
| 173 |
if entry['role'] == 'user':
|
| 174 |
if len(entry['parts']) > 1:
|
| 175 |
uploaded_file = entry['parts'][0]
|
| 176 |
+
base_file_name = os.path.basename(uploaded_file.display_name)
|
| 177 |
if uploaded_file.mime_type.startswith("image/"):
|
| 178 |
file_name= uploaded_file.display_name
|
| 179 |
+
with open(file_name, "rb") as file:
|
| 180 |
encoded_img = base64.b64encode(file.read()).decode('utf-8')
|
| 181 |
img_html = f'<img src="data:image/png;base64,{encoded_img}" width="200" style="margin-top: 5px;"/>'
|
| 182 |
st.markdown(f"""
|
|
|
|
| 189 |
</div>
|
| 190 |
""", unsafe_allow_html=True)
|
| 191 |
else:
|
| 192 |
+
message(base_file_name, is_user=True, key=f"{i}_user", avatar_style="adventurer")
|
| 193 |
|
| 194 |
if entry['parts'][1] != "":
|
| 195 |
message(entry['parts'][1], is_user=True, key=f"{i}_user", avatar_style="adventurer")
|
|
|
|
| 211 |
st.session_state.profile = user_manager.get_user(st.session_state.email).profile
|
| 212 |
st.session_state.model = create_model(GOOGLE_API_KEY, st.session_state.profile)
|
| 213 |
|
| 214 |
+
display_chat(user_manager)
|
| 215 |
else:
|
| 216 |
st.title("Wellness Bot 🦾🤖 \n\nLogin/SignUp")
|
| 217 |
|
requirements.txt
CHANGED
|
@@ -8,6 +8,7 @@ cachetools==5.3.3
|
|
| 8 |
certifi==2024.6.2
|
| 9 |
charset-normalizer==3.3.2
|
| 10 |
click==8.1.7
|
|
|
|
| 11 |
Flask==3.0.3
|
| 12 |
Flask-Session==0.8.0
|
| 13 |
gitdb==4.0.11
|
|
@@ -38,6 +39,7 @@ pillow==10.3.0
|
|
| 38 |
proto-plus==1.24.0
|
| 39 |
protobuf==4.25.3
|
| 40 |
psycopg2-binary==2.9.9
|
|
|
|
| 41 |
pyarrow==16.1.0
|
| 42 |
pyasn1==0.6.0
|
| 43 |
pyasn1_modules==0.4.0
|
|
|
|
| 8 |
certifi==2024.6.2
|
| 9 |
charset-normalizer==3.3.2
|
| 10 |
click==8.1.7
|
| 11 |
+
cloudinary==1.40.0
|
| 12 |
Flask==3.0.3
|
| 13 |
Flask-Session==0.8.0
|
| 14 |
gitdb==4.0.11
|
|
|
|
| 39 |
proto-plus==1.24.0
|
| 40 |
protobuf==4.25.3
|
| 41 |
psycopg2-binary==2.9.9
|
| 42 |
+
psycopg2-binary==2.9.9
|
| 43 |
pyarrow==16.1.0
|
| 44 |
pyasn1==0.6.0
|
| 45 |
pyasn1_modules==0.4.0
|
services/cloudinary_api.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import cloudinary
|
| 2 |
+
|
| 3 |
+
def upload_image(file_path):
|
| 4 |
+
response = cloudinary.uploader.upload(file_path)
|
| 5 |
+
return response['url']
|
settings/base.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
| 1 |
import os
|
| 2 |
import logging
|
|
|
|
| 3 |
|
| 4 |
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
| 5 |
|
|
@@ -9,6 +10,12 @@ DB_PASSWORD = os.environ.get("DB_PASSWORD")
|
|
| 9 |
DB_HOST = os.environ.get("DB_HOST")
|
| 10 |
DB_PORT = os.environ.get("DB_PORT")
|
| 11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
def setup_logger():
|
| 13 |
logger = logging.getLogger('app_logger')
|
| 14 |
logger.setLevel(logging.DEBUG)
|
|
|
|
| 1 |
import os
|
| 2 |
import logging
|
| 3 |
+
import cloudinary
|
| 4 |
|
| 5 |
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
|
| 6 |
|
|
|
|
| 10 |
DB_HOST = os.environ.get("DB_HOST")
|
| 11 |
DB_PORT = os.environ.get("DB_PORT")
|
| 12 |
|
| 13 |
+
# Configuration
|
| 14 |
+
cloudinary.config(
|
| 15 |
+
cloud_name = os.environ.get("CLOUDINARY_CLOUD_NAME"),
|
| 16 |
+
api_key = os.environ.get("CLOUDINARY_API_KEY"),
|
| 17 |
+
api_secret = os.environ.get("CLOUDINARY_API_SECRET")
|
| 18 |
+
)
|
| 19 |
def setup_logger():
|
| 20 |
logger = logging.getLogger('app_logger')
|
| 21 |
logger.setLevel(logging.DEBUG)
|
user_auth/user_manager.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
import psycopg2
|
|
|
|
|
|
|
| 2 |
from user_auth.user import User
|
| 3 |
-
from settings.base import setup_logger, DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USER
|
| 4 |
|
| 5 |
|
| 6 |
logger = setup_logger()
|
|
@@ -51,8 +53,33 @@ class UserManager:
|
|
| 51 |
"daily_calorie_intake": result[14]
|
| 52 |
}
|
| 53 |
logger.info(f'User retrieved from database: {result[1]}')
|
| 54 |
-
return User(email=result[1], password=result[
|
| 55 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
def close(self):
|
| 58 |
self.cursor.close()
|
|
|
|
| 1 |
import psycopg2
|
| 2 |
+
from psycopg2 import sql
|
| 3 |
+
import cloudinary.uploader
|
| 4 |
from user_auth.user import User
|
| 5 |
+
from settings.base import setup_logger, DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USER, cloudinary
|
| 6 |
|
| 7 |
|
| 8 |
logger = setup_logger()
|
|
|
|
| 53 |
"daily_calorie_intake": result[14]
|
| 54 |
}
|
| 55 |
logger.info(f'User retrieved from database: {result[1]}')
|
| 56 |
+
return User(email=result[1], password=result[2], profile=profile)
|
| 57 |
return None
|
| 58 |
+
|
| 59 |
+
def save_history(self, email, history_json):
|
| 60 |
+
try:
|
| 61 |
+
with self.conn.cursor() as cur:
|
| 62 |
+
query = sql.SQL("""
|
| 63 |
+
INSERT INTO chat_history (username, data)
|
| 64 |
+
VALUES (%s, %s)
|
| 65 |
+
""")
|
| 66 |
+
cur.execute(query, (email, history_json))
|
| 67 |
+
self.conn.commit()
|
| 68 |
+
logger.info(f"Chat history saved to database for user: {email}")
|
| 69 |
+
except Exception as e:
|
| 70 |
+
self.conn.rollback()
|
| 71 |
+
logger.error(f"Error saving chat history to database: {e}")
|
| 72 |
+
|
| 73 |
+
def upload_to_cloudinary(self, file_path):
|
| 74 |
+
try:
|
| 75 |
+
# Upload file to Cloudinary
|
| 76 |
+
upload_result = cloudinary.uploader.upload(file_path)
|
| 77 |
+
uploaded_file_url = upload_result['url']
|
| 78 |
+
logger.info(f"Uploaded file to Cloudinary: {uploaded_file_url}")
|
| 79 |
+
return uploaded_file_url
|
| 80 |
+
except Exception as e:
|
| 81 |
+
logger.exception(f"Error uploading file to Cloudinary: {repr(e)}")
|
| 82 |
+
return None
|
| 83 |
|
| 84 |
def close(self):
|
| 85 |
self.cursor.close()
|