Spaces:
Sleeping
Sleeping
Vela
commited on
Commit
Β·
8853856
1
Parent(s):
74b0947
enhanced frontedn
Browse files- src/backend/api_routes/__pycache__/chat_api.cpython-313.pyc +0 -0
- src/backend/api_routes/__pycache__/chat_history_supabase_api.cpython-313.pyc +0 -0
- src/backend/api_routes/__pycache__/knowledge_base_api.cpython-313.pyc +0 -0
- src/backend/api_routes/chat_api.py +5 -5
- src/backend/api_routes/chat_history_supabase_api.py +27 -7
- src/backend/api_routes/knowledge_base_api.py +3 -3
- src/backend/data/dataset.py +1 -1
- src/backend/data/pinecone_db.py +0 -230
- src/backend/services/__pycache__/embedding_service.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/pinecone_service.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/supabase_service.cpython-313.pyc +0 -0
- src/backend/services/embedding_service.py +1 -1
- src/backend/services/pinecone_service.py +2 -2
- src/backend/services/supabase_service.py +45 -2
- src/frontend/app/__pycache__/common_functions.cpython-313.pyc +0 -0
- src/frontend/app/__pycache__/pinecone_data_handler.cpython-313.pyc +0 -0
- src/frontend/app/common_functions.py +287 -133
- src/frontend/app/pinecone_data_handler.py +145 -70
- src/frontend/home.py +64 -71
- src/frontend/pages/Admin_Portal.py +76 -27
- src/frontend/pages/{chatbot.py β Chat_With_Us.py} +8 -4
- src/frontend/pages/Knowledge_Base_Explorer.py +55 -12
src/backend/api_routes/__pycache__/chat_api.cpython-313.pyc
CHANGED
Binary files a/src/backend/api_routes/__pycache__/chat_api.cpython-313.pyc and b/src/backend/api_routes/__pycache__/chat_api.cpython-313.pyc differ
|
|
src/backend/api_routes/__pycache__/chat_history_supabase_api.cpython-313.pyc
CHANGED
Binary files a/src/backend/api_routes/__pycache__/chat_history_supabase_api.cpython-313.pyc and b/src/backend/api_routes/__pycache__/chat_history_supabase_api.cpython-313.pyc differ
|
|
src/backend/api_routes/__pycache__/knowledge_base_api.cpython-313.pyc
CHANGED
Binary files a/src/backend/api_routes/__pycache__/knowledge_base_api.cpython-313.pyc and b/src/backend/api_routes/__pycache__/knowledge_base_api.cpython-313.pyc differ
|
|
src/backend/api_routes/chat_api.py
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
from fastapi import APIRouter, HTTPException, status, Depends
|
2 |
-
from services.embedding_service import get_text_embedding
|
3 |
-
from services.pinecone_service import retrieve_context_from_pinecone
|
4 |
-
from services.llm_model_service import get_health_advice
|
5 |
-
from services.schemas import ConversationInput
|
6 |
-
from utils import logger
|
7 |
|
8 |
logger = logger.get_logger()
|
9 |
|
|
|
1 |
from fastapi import APIRouter, HTTPException, status, Depends
|
2 |
+
from backend.services.embedding_service import get_text_embedding
|
3 |
+
from backend.services.pinecone_service import retrieve_context_from_pinecone
|
4 |
+
from backend.services.llm_model_service import get_health_advice
|
5 |
+
from backend.services.schemas import ConversationInput
|
6 |
+
from backend.utils import logger
|
7 |
|
8 |
logger = logger.get_logger()
|
9 |
|
src/backend/api_routes/chat_history_supabase_api.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
from typing import Dict, Any, Union
|
2 |
from fastapi import APIRouter, HTTPException, status, Query
|
3 |
-
from services.schemas import ChatHistoryRequest
|
4 |
-
from services import supabase_service
|
5 |
-
from utils import logger
|
6 |
|
7 |
logger = logger.get_logger()
|
8 |
|
@@ -12,7 +12,7 @@ router = APIRouter(
|
|
12 |
)
|
13 |
|
14 |
@router.post('/store', response_model=Dict[str, Any], status_code=status.HTTP_201_CREATED)
|
15 |
-
def add_chat_history(chat_history: ChatHistoryRequest) -> Dict[str, Any]:
|
16 |
"""
|
17 |
Save chat conversation history in the database.
|
18 |
|
@@ -50,7 +50,7 @@ def add_chat_history(chat_history: ChatHistoryRequest) -> Dict[str, Any]:
|
|
50 |
)
|
51 |
|
52 |
@router.get('/retrieve', response_model=Union[Dict[str, Any], None])
|
53 |
-
def get_chat_history(
|
54 |
conversation_id: str = Query(..., description="Conversation ID for chat history retrieval")
|
55 |
) -> Union[Dict[str, Any], None]:
|
56 |
"""
|
@@ -96,4 +96,24 @@ def get_chat_history(
|
|
96 |
raise HTTPException(
|
97 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
98 |
detail="Unexpected error occurred while retrieving chat history. Please try again later."
|
99 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Dict,List, Any, Union
|
2 |
from fastapi import APIRouter, HTTPException, status, Query
|
3 |
+
from backend.services.schemas import ChatHistoryRequest
|
4 |
+
from backend.services import supabase_service
|
5 |
+
from backend.utils import logger
|
6 |
|
7 |
logger = logger.get_logger()
|
8 |
|
|
|
12 |
)
|
13 |
|
14 |
@router.post('/store', response_model=Dict[str, Any], status_code=status.HTTP_201_CREATED)
|
15 |
+
async def add_chat_history(chat_history: ChatHistoryRequest) -> Dict[str, Any]:
|
16 |
"""
|
17 |
Save chat conversation history in the database.
|
18 |
|
|
|
50 |
)
|
51 |
|
52 |
@router.get('/retrieve', response_model=Union[Dict[str, Any], None])
|
53 |
+
async def get_chat_history(
|
54 |
conversation_id: str = Query(..., description="Conversation ID for chat history retrieval")
|
55 |
) -> Union[Dict[str, Any], None]:
|
56 |
"""
|
|
|
96 |
raise HTTPException(
|
97 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
98 |
detail="Unexpected error occurred while retrieving chat history. Please try again later."
|
99 |
+
)
|
100 |
+
|
101 |
+
@router.get("/bucket-items", response_model=List[str])
|
102 |
+
async def retrieve_bucket_items():
|
103 |
+
"""
|
104 |
+
API endpoint to retrieve item names from a specified Supabase storage bucket.
|
105 |
+
|
106 |
+
Returns:
|
107 |
+
List[str]: A list of item names with '.json' removed, excluding the last item in the bucket.
|
108 |
+
|
109 |
+
Raises:
|
110 |
+
HTTPException: If an error occurs while fetching bucket items.
|
111 |
+
"""
|
112 |
+
try:
|
113 |
+
conversation_ids = supabase_service.get_bucket_items()
|
114 |
+
if conversation_ids:
|
115 |
+
return conversation_ids
|
116 |
+
else:
|
117 |
+
raise HTTPException(status_code=404, detail="No items found in the bucket.")
|
118 |
+
except Exception as e:
|
119 |
+
raise HTTPException(status_code=500, detail=f"Error fetching bucket items: {e}")
|
src/backend/api_routes/knowledge_base_api.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
from fastapi import APIRouter, HTTPException
|
2 |
-
from services import pinecone_service, embedding_service
|
3 |
-
from services.schemas import UpsertRequest, DeleteRequest, MetadataRequest
|
4 |
import pandas as pd
|
5 |
-
from utils import logger
|
6 |
from fastapi.responses import JSONResponse
|
7 |
|
8 |
logger = logger.get_logger()
|
|
|
1 |
from fastapi import APIRouter, HTTPException
|
2 |
+
from backend.services import pinecone_service, embedding_service
|
3 |
+
from backend.services.schemas import UpsertRequest, DeleteRequest, MetadataRequest
|
4 |
import pandas as pd
|
5 |
+
from backend.utils import logger
|
6 |
from fastapi.responses import JSONResponse
|
7 |
|
8 |
logger = logger.get_logger()
|
src/backend/data/dataset.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1 |
import os
|
2 |
import pandas as pd
|
3 |
import string
|
4 |
-
from utils import logger
|
5 |
|
6 |
logger = logger.get_logger()
|
7 |
|
|
|
1 |
import os
|
2 |
import pandas as pd
|
3 |
import string
|
4 |
+
from backend.utils import logger
|
5 |
|
6 |
logger = logger.get_logger()
|
7 |
|
src/backend/data/pinecone_db.py
DELETED
@@ -1,230 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
# import sys
|
3 |
-
# src_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..", "backend"))
|
4 |
-
# sys.path.append(src_directory)
|
5 |
-
from pinecone import Pinecone, ServerlessSpec
|
6 |
-
import time
|
7 |
-
from tqdm import tqdm
|
8 |
-
from dotenv import load_dotenv
|
9 |
-
from utils import logger
|
10 |
-
import pandas as pd
|
11 |
-
from models import embedding_model
|
12 |
-
|
13 |
-
load_dotenv()
|
14 |
-
PINECONE_API_KEY = os.environ.get("PINECONE_API_KEY")
|
15 |
-
logger = logger.get_logger()
|
16 |
-
NAMESPACE = "health-care-dataset"
|
17 |
-
INDEX_NAME = "health-care-index"
|
18 |
-
PINECONE = Pinecone(api_key=PINECONE_API_KEY)
|
19 |
-
|
20 |
-
def initialize_pinecone_index(pinecone, index_name, dimension=384, metric="cosine", cloud="aws", region="us-east-1"):
|
21 |
-
"""
|
22 |
-
Retrieves an existing Pinecone index or creates a new one if it does not exist.
|
23 |
-
|
24 |
-
This method checks for the presence of the specified index. If the index does not exist,
|
25 |
-
it initiates the creation process, waits until the index is ready, and then returns the index.
|
26 |
-
|
27 |
-
Args:
|
28 |
-
pinecone (Pinecone): Pinecone client instance.
|
29 |
-
index_name (str): Name of the index to retrieve or create.
|
30 |
-
dimension (int, optional): Vector dimension for the index. Default is 384.
|
31 |
-
metric (str, optional): Distance metric for the index. Default is "cosine".
|
32 |
-
cloud (str, optional): Cloud provider for hosting the index. Default is "aws".
|
33 |
-
region (str, optional): Region where the index will be hosted. Default is "us-east-1".
|
34 |
-
|
35 |
-
Returns:
|
36 |
-
pinecone.Index: The Pinecone index instance.
|
37 |
-
|
38 |
-
Raises:
|
39 |
-
Exception: If an error occurs during index creation or retrieval.
|
40 |
-
|
41 |
-
Example:
|
42 |
-
>>> index = get_or_create_index(pinecone, "sample_index")
|
43 |
-
Logs: "Index 'sample_index' is ready and accessible."
|
44 |
-
"""
|
45 |
-
try:
|
46 |
-
logger.info(f"Checking if the index '{index_name}' exists...")
|
47 |
-
|
48 |
-
# Check if index already exists
|
49 |
-
if not pinecone.has_index(index_name):
|
50 |
-
logger.info(f"Index '{index_name}' does not exist. Creating a new index...")
|
51 |
-
|
52 |
-
# Create a new index
|
53 |
-
pinecone.create_index(
|
54 |
-
name=index_name,
|
55 |
-
dimension=dimension,
|
56 |
-
metric=metric,
|
57 |
-
spec=ServerlessSpec(cloud=cloud, region=region)
|
58 |
-
)
|
59 |
-
logger.info(f"Index '{index_name}' creation initiated. Waiting for it to be ready...")
|
60 |
-
|
61 |
-
# Wait until index is ready
|
62 |
-
while True:
|
63 |
-
index_status = pinecone.describe_index(index_name)
|
64 |
-
if index_status.status.get("ready", False):
|
65 |
-
index = pinecone.Index(index_name)
|
66 |
-
logger.info(f"Index '{index_name}' is ready and accessible.")
|
67 |
-
return index
|
68 |
-
else:
|
69 |
-
logger.debug(f"Index '{index_name}' is not ready yet. Checking again in 1 second.")
|
70 |
-
time.sleep(1)
|
71 |
-
else:
|
72 |
-
# Return the existing index
|
73 |
-
index = pinecone.Index(index_name)
|
74 |
-
logger.info(f"Index '{index_name}' already exists. Returning the existing index.")
|
75 |
-
return index
|
76 |
-
|
77 |
-
except Exception as e:
|
78 |
-
logger.error(f"Error occurred while getting or creating the Pinecone index: {str(e)}", exc_info=True)
|
79 |
-
return None
|
80 |
-
|
81 |
-
def delete_records_by_ids(ids_to_delete):
|
82 |
-
"""
|
83 |
-
Deletes specified IDs from the database index.
|
84 |
-
|
85 |
-
This method interacts with the index to delete entries based on the provided list of IDs.
|
86 |
-
It logs a success message if the deletion is successful or returns an error message if it fails.
|
87 |
-
|
88 |
-
Args:
|
89 |
-
ids_to_delete (list):
|
90 |
-
A list of unique identifiers (IDs) to be deleted from the database.
|
91 |
-
|
92 |
-
Returns:
|
93 |
-
str: A success message is logged upon successful deletion.
|
94 |
-
If an error occurs, a string describing the failure is returned.
|
95 |
-
|
96 |
-
Raises:
|
97 |
-
Exception: Logs an error if the deletion process encounters an issue.
|
98 |
-
|
99 |
-
Example:
|
100 |
-
>>> remove_ids_from_database(['id_123', 'id_456'])
|
101 |
-
Logs: "IDs deleted successfully."
|
102 |
-
|
103 |
-
Notes:
|
104 |
-
- The method assumes `get_index()` initializes the index object.
|
105 |
-
- Deletion occurs within the specified `NAMESPACE`.
|
106 |
-
"""
|
107 |
-
try:
|
108 |
-
index = initialize_pinecone_index(PINECONE,INDEX_NAME)
|
109 |
-
index.delete(ids=ids_to_delete, namespace=NAMESPACE)
|
110 |
-
logger.info("IDs deleted successfully.")
|
111 |
-
except Exception as e:
|
112 |
-
return f"Failed to delete the IDs: {e}"
|
113 |
-
|
114 |
-
def retrieve_relevant_metadata(prompt, n_result=3, score_threshold=0.47):
|
115 |
-
"""
|
116 |
-
Retrieves relevant context data based on a given prompt and extracts metadata.
|
117 |
-
|
118 |
-
This method queries the Pinecone index with the provided prompt's embedding,
|
119 |
-
fetches the top `n_result` entries, and filters out entries with a score below
|
120 |
-
the specified threshold. Extracted metadata is formatted and returned.
|
121 |
-
|
122 |
-
Args:
|
123 |
-
prompt (str or list):
|
124 |
-
The input prompt used to generate the text embedding.
|
125 |
-
If a list is provided, the method extracts the last element.
|
126 |
-
n_result (int, optional):
|
127 |
-
The number of relevant results to return. Defaults to 3.
|
128 |
-
score_threshold (float, optional):
|
129 |
-
The minimum score required for an entry to be included in the results. Defaults to 0.5.
|
130 |
-
|
131 |
-
Returns:
|
132 |
-
list: A list of dictionaries containing:
|
133 |
-
- `"question"` (str): Extracted question or `"N/A"` if unavailable.
|
134 |
-
- `"answer"` (str): Extracted answer or `"N/A"` if unavailable.
|
135 |
-
- `"instruction"` (str): Extracted instruction or `"N/A"` if unavailable.
|
136 |
-
- `"score"` (str): The score value as a string for consistency.
|
137 |
-
|
138 |
-
If no relevant entries are found, the list will contain a single
|
139 |
-
dictionary with the key `"response"` and a message indicating no data was found.
|
140 |
-
|
141 |
-
Example:
|
142 |
-
>>> prompt = ["Tell me about mental health"]
|
143 |
-
>>> fetch_and_extract_metadata(prompt, n_result=2)
|
144 |
-
[{'question': 'What is mental health?', 'answer': 'Mental health refers to...',
|
145 |
-
'instruction': 'Focus on general well-being.', 'score': '0.6'}]
|
146 |
-
|
147 |
-
Notes:
|
148 |
-
- Assumes `get_or_create_index()` initializes the index object.
|
149 |
-
- Uses `embedding_model.get_text_embedding()` to generate text embeddings.
|
150 |
-
- Entries without a `metadata` key or with missing fields default to `"N/A"`.
|
151 |
-
- Entries with a score below `score_threshold` are excluded from results.
|
152 |
-
"""
|
153 |
-
try:
|
154 |
-
index = initialize_pinecone_index(PINECONE, INDEX_NAME)
|
155 |
-
prompt = prompt[-1] if isinstance(prompt, list) else prompt
|
156 |
-
|
157 |
-
# Generate embedding for the provided prompt
|
158 |
-
embedding = embedding_model.get_text_embedding(prompt)
|
159 |
-
response = index.query(
|
160 |
-
top_k=n_result,
|
161 |
-
vector=embedding,
|
162 |
-
namespace=NAMESPACE,
|
163 |
-
include_metadata=True
|
164 |
-
)
|
165 |
-
|
166 |
-
# Extract and filter metadata
|
167 |
-
metadata = [
|
168 |
-
{
|
169 |
-
"question": entry.get('metadata', {}).get('question', 'N/A'),
|
170 |
-
"answer": entry.get('metadata', {}).get('answer', 'N/A'),
|
171 |
-
"instruction": entry.get('metadata', {}).get('instruction', 'N/A'),
|
172 |
-
"score": f"{entry.get('score', 0)}",
|
173 |
-
"id": f"{entry.get('id', 'N/A')}"
|
174 |
-
}
|
175 |
-
for entry in response.get('matches', [])
|
176 |
-
if entry.get('score', 0) >= score_threshold
|
177 |
-
]
|
178 |
-
|
179 |
-
# Return metadata or fallback message
|
180 |
-
return metadata if metadata else [{"response": "No relevant data found."}]
|
181 |
-
|
182 |
-
except Exception as e:
|
183 |
-
logger.error(f"Failed to fetch context for '{prompt[:20]}'. Error: {e}")
|
184 |
-
return [{"response": "Failed to fetch data due to an error."}]
|
185 |
-
|
186 |
-
def upsert_vector_data(df: pd.DataFrame):
|
187 |
-
|
188 |
-
"""
|
189 |
-
Generates embeddings for the given DataFrame and uploads data to Pinecone in batches.
|
190 |
-
|
191 |
-
Parameters:
|
192 |
-
- df (pd.DataFrame): DataFrame containing 'input', 'question', and 'answer' columns.
|
193 |
-
|
194 |
-
Returns:
|
195 |
-
- None
|
196 |
-
"""
|
197 |
-
|
198 |
-
try:
|
199 |
-
index = initialize_pinecone_index(PINECONE,INDEX_NAME)
|
200 |
-
df["embedding"] = [
|
201 |
-
embedding_model.get_text_embedding([q])[0]
|
202 |
-
for q in tqdm(df["input"], desc="Generating Embeddings")
|
203 |
-
]
|
204 |
-
except Exception as e:
|
205 |
-
logger.error(f"Error generating embeddings: {e}")
|
206 |
-
return
|
207 |
-
|
208 |
-
# # Upload data to Pinecone in batches
|
209 |
-
BATCH_SIZE = 500
|
210 |
-
|
211 |
-
for i in tqdm(range(0, len(df), BATCH_SIZE), desc="Uploading Data to Pinecone"):
|
212 |
-
batch = df.iloc[i : i + BATCH_SIZE]
|
213 |
-
|
214 |
-
vectors = []
|
215 |
-
for idx, (embedding, (_, row_data)) in enumerate(zip(batch["embedding"], batch.iterrows())):
|
216 |
-
question = row_data.get("input")
|
217 |
-
vector_id = f"{question[:50]}:{i + idx}" # Ensures IDs remain unique across
|
218 |
-
metadata = {
|
219 |
-
"question": row_data.get("input"),
|
220 |
-
"answer": row_data.get("output"),
|
221 |
-
"instruction": row_data.get("instruction"),
|
222 |
-
}
|
223 |
-
vectors.append((vector_id, embedding, metadata))
|
224 |
-
|
225 |
-
try:
|
226 |
-
index.upsert(vectors=vectors,namespace=NAMESPACE)
|
227 |
-
except Exception as e:
|
228 |
-
logger.error(f"Error uploading batch starting at index {i}: {e}")
|
229 |
-
|
230 |
-
logger.info("All question-answer pairs stored successfully!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/backend/services/__pycache__/embedding_service.cpython-313.pyc
CHANGED
Binary files a/src/backend/services/__pycache__/embedding_service.cpython-313.pyc and b/src/backend/services/__pycache__/embedding_service.cpython-313.pyc differ
|
|
src/backend/services/__pycache__/pinecone_service.cpython-313.pyc
CHANGED
Binary files a/src/backend/services/__pycache__/pinecone_service.cpython-313.pyc and b/src/backend/services/__pycache__/pinecone_service.cpython-313.pyc differ
|
|
src/backend/services/__pycache__/supabase_service.cpython-313.pyc
CHANGED
Binary files a/src/backend/services/__pycache__/supabase_service.cpython-313.pyc and b/src/backend/services/__pycache__/supabase_service.cpython-313.pyc differ
|
|
src/backend/services/embedding_service.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
from sentence_transformers import SentenceTransformer
|
2 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
3 |
-
from utils import logger
|
4 |
|
5 |
logger = logger.get_logger()
|
6 |
|
|
|
1 |
from sentence_transformers import SentenceTransformer
|
2 |
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
3 |
+
from backend.utils import logger
|
4 |
|
5 |
logger = logger.get_logger()
|
6 |
|
src/backend/services/pinecone_service.py
CHANGED
@@ -6,9 +6,9 @@ from pinecone import Pinecone, ServerlessSpec
|
|
6 |
import time
|
7 |
from tqdm import tqdm
|
8 |
from dotenv import load_dotenv
|
9 |
-
from utils import logger
|
10 |
import pandas as pd
|
11 |
-
from services.embedding_service import get_text_embedding
|
12 |
from sentence_transformers import CrossEncoder
|
13 |
|
14 |
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
|
|
6 |
import time
|
7 |
from tqdm import tqdm
|
8 |
from dotenv import load_dotenv
|
9 |
+
from backend.utils import logger
|
10 |
import pandas as pd
|
11 |
+
from backend.services.embedding_service import get_text_embedding
|
12 |
from sentence_transformers import CrossEncoder
|
13 |
|
14 |
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
src/backend/services/supabase_service.py
CHANGED
@@ -1,8 +1,11 @@
|
|
1 |
import json
|
2 |
import os
|
|
|
|
|
|
|
3 |
from datetime import datetime
|
4 |
from supabase import create_client, StorageException
|
5 |
-
from utils import logger
|
6 |
from dotenv import load_dotenv
|
7 |
|
8 |
# Logger Initialization
|
@@ -14,6 +17,7 @@ SUPABASE_URL = os.getenv('SUPABASE_URL')
|
|
14 |
SUPABASE_KEY = os.getenv('SUPABASE_KEY')
|
15 |
SUPABASE_BUCKET = os.getenv('SUPABASE_BUCKET')
|
16 |
LLM_MODEL_NAME = os.getenv('LLM_MODEL_NAME')
|
|
|
17 |
|
18 |
# Supabase Client Initialization
|
19 |
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
@@ -137,4 +141,43 @@ def retrieve_chat_history(conversation_id: str) -> dict:
|
|
137 |
return {"success": False, "error": "Failed to retrieve chat history. Storage error occurred."}
|
138 |
except Exception as e:
|
139 |
logger.error(f"Unexpected error retrieving chat history for ID {conversation_id}: {e}")
|
140 |
-
return {"success": False, "error": "Unexpected error occurred while retrieving chat history."}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import json
|
2 |
import os
|
3 |
+
import sys
|
4 |
+
src_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), "../..", "backend"))
|
5 |
+
sys.path.append(src_directory)
|
6 |
from datetime import datetime
|
7 |
from supabase import create_client, StorageException
|
8 |
+
from backend.utils import logger
|
9 |
from dotenv import load_dotenv
|
10 |
|
11 |
# Logger Initialization
|
|
|
17 |
SUPABASE_KEY = os.getenv('SUPABASE_KEY')
|
18 |
SUPABASE_BUCKET = os.getenv('SUPABASE_BUCKET')
|
19 |
LLM_MODEL_NAME = os.getenv('LLM_MODEL_NAME')
|
20 |
+
BUCKET_FOLDER = "chat-history"
|
21 |
|
22 |
# Supabase Client Initialization
|
23 |
supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
|
|
141 |
return {"success": False, "error": "Failed to retrieve chat history. Storage error occurred."}
|
142 |
except Exception as e:
|
143 |
logger.error(f"Unexpected error retrieving chat history for ID {conversation_id}: {e}")
|
144 |
+
return {"success": False, "error": "Unexpected error occurred while retrieving chat history."}
|
145 |
+
|
146 |
+
def get_bucket_items():
|
147 |
+
"""
|
148 |
+
Retrieves item names from a specified Supabase storage bucket and returns them as a list,
|
149 |
+
excluding the '.json' extension and omitting the last item in the response.
|
150 |
+
|
151 |
+
This function uses the globally defined `SUPABASE_BUCKET` and `BUCKET_FOLDER` variables
|
152 |
+
to identify the bucket and folder path.
|
153 |
+
|
154 |
+
Returns:
|
155 |
+
list: A list of item names with '.json' removed, excluding the last item in the bucket.
|
156 |
+
|
157 |
+
Logs:
|
158 |
+
- An error if there are no items found in the bucket.
|
159 |
+
- An error if an exception occurs during the fetching process.
|
160 |
+
|
161 |
+
Example:
|
162 |
+
Suppose the bucket contains:
|
163 |
+
- "2025-03-18.json"
|
164 |
+
- "2025-03-19.json"
|
165 |
+
- "2025-03-20.json"
|
166 |
+
|
167 |
+
The function will return:
|
168 |
+
['2025-03-18', '2025-03-19']
|
169 |
+
|
170 |
+
Raises:
|
171 |
+
Exception: Logs an error if fetching bucket items fails.
|
172 |
+
"""
|
173 |
+
try:
|
174 |
+
response = supabase.storage.from_(SUPABASE_BUCKET).list(BUCKET_FOLDER)
|
175 |
+
conversation_ids = []
|
176 |
+
if response:
|
177 |
+
for item in response[:-1]:
|
178 |
+
conversation_ids.append(item['name'].replace('.json', ''))
|
179 |
+
return conversation_ids
|
180 |
+
else:
|
181 |
+
logger.error("No items found in the bucket.")
|
182 |
+
except Exception as e:
|
183 |
+
logger.error(f"Error fetching bucket items: {e}")
|
src/frontend/app/__pycache__/common_functions.cpython-313.pyc
CHANGED
Binary files a/src/frontend/app/__pycache__/common_functions.cpython-313.pyc and b/src/frontend/app/__pycache__/common_functions.cpython-313.pyc differ
|
|
src/frontend/app/__pycache__/pinecone_data_handler.cpython-313.pyc
CHANGED
Binary files a/src/frontend/app/__pycache__/pinecone_data_handler.cpython-313.pyc and b/src/frontend/app/__pycache__/pinecone_data_handler.cpython-313.pyc differ
|
|
src/frontend/app/common_functions.py
CHANGED
@@ -2,7 +2,7 @@ import os
|
|
2 |
import base64
|
3 |
import requests
|
4 |
from dotenv import load_dotenv
|
5 |
-
from utils import logger
|
6 |
import json
|
7 |
import time
|
8 |
import streamlit as st
|
@@ -19,9 +19,26 @@ ABOUT_US = "An AI-powered assistant for personalized healthcare guidance."
|
|
19 |
API_URL = os.getenv("API_URL", "http://localhost:8000")
|
20 |
|
21 |
def config_homepage(page_title=PAGE_TITLE):
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
st.set_page_config(
|
24 |
-
page_title=
|
25 |
page_icon=PAGE_ICON,
|
26 |
layout=PAGE_LAYOUT,
|
27 |
initial_sidebar_state="collapsed",
|
@@ -31,14 +48,41 @@ def config_homepage(page_title=PAGE_TITLE):
|
|
31 |
"About": ABOUT_US
|
32 |
}
|
33 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
-
|
|
|
|
|
|
|
|
|
36 |
st.markdown(f"""
|
37 |
-
<h1 style="
|
38 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
</h1>
|
40 |
-
|
41 |
-
)
|
42 |
|
43 |
def img_to_base64(image_path):
|
44 |
"""Convert image to base64."""
|
@@ -49,16 +93,196 @@ def img_to_base64(image_path):
|
|
49 |
logger.error(f"Error converting image to base64: {str(e)}")
|
50 |
return None
|
51 |
|
52 |
-
def typewriter_effect(text, speed=0.
|
53 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
placeholder = st.empty()
|
55 |
displayed_text = ""
|
56 |
-
|
57 |
for char in text:
|
58 |
displayed_text += char
|
59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
time.sleep(speed)
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
def get_api_response(endpoint:str, prompt: list):
|
63 |
try:
|
64 |
logger.info(f"Sending user prompt to API endpoint: {API_URL}{endpoint}")
|
@@ -113,6 +337,47 @@ def store_chat_history_in_db(conversation_id, messages):
|
|
113 |
except Exception as e:
|
114 |
logger.info(f"Failed to add the chat in db {e}")
|
115 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
def get_chat_history_from_db(conversation_id: str, retries=3, delay=5):
|
117 |
API_URL = "http://127.0.0.1:8000/chat-history/retrieve"
|
118 |
for attempt in range(retries):
|
@@ -143,7 +408,7 @@ def display_chat_history(conversation_id):
|
|
143 |
first_message_content = chat_history["data"]["messages"][0].get('content', '').strip()
|
144 |
button_text = first_message_content[:20] if first_message_content else "No Content"
|
145 |
|
146 |
-
if st.sidebar.button(f"Show History for {button_text}", key=f"show_history_{conversation_id}"):
|
147 |
st.subheader(f"Chat History for Conversation ID: {conversation_id}")
|
148 |
|
149 |
for message in chat_history["data"]["messages"]:
|
@@ -170,122 +435,11 @@ def display_chat_history(conversation_id):
|
|
170 |
logger.error(f"Error retrieving chat history for {conversation_id}: {e}")
|
171 |
st.error("An unexpected error occurred while retrieving chat history.")
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
url("data:image/png;base64,{encoded_img}") center/cover fixed no-repeat;
|
182 |
-
min-height: 100vh;
|
183 |
-
}}
|
184 |
-
</style>
|
185 |
-
""",
|
186 |
-
unsafe_allow_html=True
|
187 |
-
)
|
188 |
-
|
189 |
-
def custom_navbar():
|
190 |
-
st.markdown(
|
191 |
-
"""
|
192 |
-
<style>
|
193 |
-
.navbar {
|
194 |
-
display: flex;
|
195 |
-
justify-content: space-between;
|
196 |
-
align-items: center;
|
197 |
-
background-color: #F0F2F6;
|
198 |
-
padding: 12px 32px;
|
199 |
-
margin-top: -30px;
|
200 |
-
width: 100%;
|
201 |
-
max-width: 1200px;
|
202 |
-
border-radius: 32px;
|
203 |
-
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
|
204 |
-
border: 1px solid #D1D5DB;
|
205 |
-
margin-left: auto;
|
206 |
-
margin-right: auto;
|
207 |
-
box-sizing: border-box;
|
208 |
-
flex-wrap: wrap;
|
209 |
-
}
|
210 |
-
|
211 |
-
.logo {
|
212 |
-
font-family: 'Arial', sans-serif;
|
213 |
-
font-size: 30px;
|
214 |
-
font-weight: bold;
|
215 |
-
color: #1E293B;
|
216 |
-
white-space: nowrap;
|
217 |
-
text-overflow: ellipsis;
|
218 |
-
flex-wrap: wrap;
|
219 |
-
}
|
220 |
-
|
221 |
-
.nav-links {
|
222 |
-
display: flex;
|
223 |
-
gap: 32px;
|
224 |
-
align-items: center;
|
225 |
-
flex-wrap: wrap;
|
226 |
-
}
|
227 |
-
|
228 |
-
.nav-link {
|
229 |
-
color: #1E293B !important;
|
230 |
-
background-color: transparent;
|
231 |
-
text-decoration: none;
|
232 |
-
font-weight: 600;
|
233 |
-
font-size: 18px;
|
234 |
-
padding: 6px 16px;
|
235 |
-
border-radius: 8px;
|
236 |
-
transition: background-color 0.3s ease, color 0.3s ease;
|
237 |
-
white-space: nowrap;
|
238 |
-
}
|
239 |
-
|
240 |
-
.nav-link:hover {
|
241 |
-
background-color: #2E5D5B;
|
242 |
-
color: #FFFFFF;
|
243 |
-
}
|
244 |
-
|
245 |
-
@media (max-width: 768px) {
|
246 |
-
.navbar {
|
247 |
-
flex-direction: column;
|
248 |
-
text-align: center;
|
249 |
-
padding: 12px 16px; /* Adjusted padding for smaller screens */
|
250 |
-
}
|
251 |
-
|
252 |
-
.nav-links {
|
253 |
-
flex-direction: column;
|
254 |
-
gap: 12px;
|
255 |
-
margin-top: 8px;
|
256 |
-
}
|
257 |
-
}
|
258 |
-
|
259 |
-
</style>
|
260 |
-
|
261 |
-
<div class="navbar">
|
262 |
-
<div class="logo">Yuvabe Care Companion AI</div>
|
263 |
-
<div class="nav-links">
|
264 |
-
<a href="/" class="nav-link">Home</a>
|
265 |
-
<a href="/Admin_Portal" class="nav-link">Admin Portal</a>
|
266 |
-
<a href="/Knowledge_Base_Explorer" class="nav-link">Knowledge Base Explorer</a>
|
267 |
-
<a href="/chatbot" class="nav-link">Chat With Us</a>
|
268 |
-
</div>
|
269 |
-
</div>
|
270 |
-
""",
|
271 |
-
unsafe_allow_html=True
|
272 |
-
)
|
273 |
-
|
274 |
-
def type_text(container, text, delay=0.03):
|
275 |
-
"""Simulates a typing effect for text with only text highlighted."""
|
276 |
-
displayed_text = ""
|
277 |
-
for char in text:
|
278 |
-
displayed_text += char
|
279 |
-
container.markdown(f"""
|
280 |
-
<h2 style="
|
281 |
-
color: #3D6D6B;
|
282 |
-
text-align: left;
|
283 |
-
background: linear-gradient(90deg, #3D6D6B, #6EA8A5);
|
284 |
-
-webkit-background-clip: text;
|
285 |
-
color: white;
|
286 |
-
font-weight: bold;
|
287 |
-
font-size: 28px;">
|
288 |
-
{displayed_text}
|
289 |
-
</h2>
|
290 |
-
""", unsafe_allow_html=True)
|
291 |
-
time.sleep(delay)
|
|
|
2 |
import base64
|
3 |
import requests
|
4 |
from dotenv import load_dotenv
|
5 |
+
from frontend.utils import logger
|
6 |
import json
|
7 |
import time
|
8 |
import streamlit as st
|
|
|
19 |
API_URL = os.getenv("API_URL", "http://localhost:8000")
|
20 |
|
21 |
def config_homepage(page_title=PAGE_TITLE):
|
22 |
+
"""
|
23 |
+
Configures the Streamlit homepage with essential settings.
|
24 |
+
|
25 |
+
This function sets up the page title, icon, layout, and sidebar state.
|
26 |
+
It also defines custom menu items for better navigation.
|
27 |
+
|
28 |
+
Args:
|
29 |
+
page_title (str): The title displayed on the browser tab (default is PAGE_TITLE).
|
30 |
+
|
31 |
+
Key Features:
|
32 |
+
- Ensures `st.set_page_config()` is called only once to avoid errors.
|
33 |
+
- Uses constants for improved maintainability and consistency.
|
34 |
+
- Provides links for help, bug reporting, and an 'About' section.
|
35 |
+
|
36 |
+
Example:
|
37 |
+
>>> config_homepage("My Custom App")
|
38 |
+
"""
|
39 |
+
if "page_config_set" not in st.session_state:
|
40 |
st.set_page_config(
|
41 |
+
page_title=page_title,
|
42 |
page_icon=PAGE_ICON,
|
43 |
layout=PAGE_LAYOUT,
|
44 |
initial_sidebar_state="collapsed",
|
|
|
48 |
"About": ABOUT_US
|
49 |
}
|
50 |
)
|
51 |
+
st.session_state.page_config_set = True
|
52 |
+
|
53 |
+
def set_page_title(page_title=PAGE_TITLE, icon="βοΈ", color="#2E7D32", font_size="36px"):
|
54 |
+
"""
|
55 |
+
Sets a custom-styled page title for the Streamlit application.
|
56 |
+
|
57 |
+
Parameters:
|
58 |
+
-----------
|
59 |
+
page_title : str
|
60 |
+
The text to display as the page title. Defaults to the value of PAGE_TITLE.
|
61 |
+
icon : str, optional
|
62 |
+
An optional emoji or symbol to enhance the visual appeal of the title. Defaults to "βοΈ".
|
63 |
+
color : str, optional
|
64 |
+
Hex color code for the title text. Defaults to a fresh green shade (#2E7D32).
|
65 |
+
font_size : str, optional
|
66 |
+
Font size for the title text. Defaults to "36px".
|
67 |
|
68 |
+
Example Usage:
|
69 |
+
---------------
|
70 |
+
set_page_title("Welcome to Yuvabe", icon="πΏ", color="#1E88E5", font_size="42px")
|
71 |
+
"""
|
72 |
+
|
73 |
st.markdown(f"""
|
74 |
+
<h1 style="
|
75 |
+
color: {color};
|
76 |
+
font-size: {font_size};
|
77 |
+
font-weight: bold;
|
78 |
+
margin-bottom: 15px;
|
79 |
+
text-align: center;
|
80 |
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); /* Adds depth for a cleaner look */
|
81 |
+
padding: 10px 0; /* Improved spacing */
|
82 |
+
">
|
83 |
+
<i>{page_title} {icon}</i>
|
84 |
</h1>
|
85 |
+
""", unsafe_allow_html=True)
|
|
|
86 |
|
87 |
def img_to_base64(image_path):
|
88 |
"""Convert image to base64."""
|
|
|
93 |
logger.error(f"Error converting image to base64: {str(e)}")
|
94 |
return None
|
95 |
|
96 |
+
def typewriter_effect(text, speed=0.03, gradient=False):
|
97 |
+
"""
|
98 |
+
Displays text with a typewriter effect.
|
99 |
+
Supports optional gradient styling for enhanced visual appeal.
|
100 |
+
|
101 |
+
Args:
|
102 |
+
text (str): The text to display with the typing effect.
|
103 |
+
speed (float): Typing speed in seconds (default 0.03).
|
104 |
+
gradient (bool): If True, applies a gradient effect to the text.
|
105 |
+
"""
|
106 |
placeholder = st.empty()
|
107 |
displayed_text = ""
|
108 |
+
|
109 |
for char in text:
|
110 |
displayed_text += char
|
111 |
+
|
112 |
+
if gradient:
|
113 |
+
placeholder.markdown(f"""
|
114 |
+
<h2 style="
|
115 |
+
color: #3D6D6B;
|
116 |
+
text-align: left;
|
117 |
+
background: linear-gradient(90deg, #3D6D6B, #6EA8A5);
|
118 |
+
-webkit-background-clip: text;
|
119 |
+
color: white;
|
120 |
+
font-weight: bold;
|
121 |
+
font-size: 28px;">
|
122 |
+
{displayed_text}
|
123 |
+
</h2>
|
124 |
+
""", unsafe_allow_html=True)
|
125 |
+
else:
|
126 |
+
placeholder.markdown(displayed_text)
|
127 |
+
|
128 |
time.sleep(speed)
|
129 |
+
|
130 |
+
def custom_navbar():
|
131 |
+
"""
|
132 |
+
Renders a custom navigation bar with a modern design for the Streamlit application.
|
133 |
+
|
134 |
+
The navigation bar includes:
|
135 |
+
- **Logo:** Displays "Yuvabe Care Companion AI" as the app's brand.
|
136 |
+
- **Navigation Links:** Provides links to key sections like Home, Admin Portal, Knowledge Base Explorer, and Chatbot.
|
137 |
+
|
138 |
+
Key Features:
|
139 |
+
- Responsive Design: The layout adjusts for different screen sizes using media queries.
|
140 |
+
- Enhanced UI: Includes a soft background, subtle shadow, and smooth hover effects for improved aesthetics.
|
141 |
+
- Accessibility: Ensures text visibility and clickable elements for better user interaction.
|
142 |
+
|
143 |
+
Example Usage:
|
144 |
+
>>> custom_navbar()
|
145 |
+
|
146 |
+
"""
|
147 |
+
st.markdown(
|
148 |
+
"""
|
149 |
+
<style>
|
150 |
+
.navbar {
|
151 |
+
display: flex;
|
152 |
+
justify-content: space-between;
|
153 |
+
align-items: center;
|
154 |
+
background-color: #FFFFFF;
|
155 |
+
padding: 16px 32px;
|
156 |
+
width: 100%;
|
157 |
+
border-radius: 50px;
|
158 |
+
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
159 |
+
border-bottom: 3px solid #2E5D5B;
|
160 |
+
box-sizing: border-box;
|
161 |
+
white-space: nowrap;
|
162 |
+
overflow-x: auto;
|
163 |
+
}
|
164 |
+
|
165 |
+
.logo {
|
166 |
+
font-family: 'Arial', sans-serif;
|
167 |
+
font-size: 28px;
|
168 |
+
font-weight: bold;
|
169 |
+
color: #1E293B;
|
170 |
+
}
|
171 |
+
|
172 |
+
.nav-links {
|
173 |
+
display: flex;
|
174 |
+
gap: 32px;
|
175 |
+
align-items: center;
|
176 |
+
}
|
177 |
+
|
178 |
+
.nav-link {
|
179 |
+
color: #1E293B !important;
|
180 |
+
text-decoration: none;
|
181 |
+
font-weight: 600;
|
182 |
+
font-size: 22px;
|
183 |
+
padding: 8px 16px;
|
184 |
+
border-radius: 6px;
|
185 |
+
transition: background-color 0.3s ease, color 0.3s ease;
|
186 |
+
}
|
187 |
+
|
188 |
+
.nav-link:hover {
|
189 |
+
background-color: #2E5D5B;
|
190 |
+
color: #FFFFFF !important;
|
191 |
+
border-radius: 50px;
|
192 |
+
}
|
193 |
+
|
194 |
+
@media (max-width: 1024px) {
|
195 |
+
.navbar {
|
196 |
+
flex-direction: column;
|
197 |
+
text-align: center;
|
198 |
+
padding: 12px 24px;
|
199 |
+
}
|
200 |
+
|
201 |
+
.nav-links {
|
202 |
+
flex-direction: column;
|
203 |
+
gap: 12px;
|
204 |
+
width: 100%;
|
205 |
+
}
|
206 |
+
|
207 |
+
.nav-link {
|
208 |
+
width: 100%;
|
209 |
+
text-align: center;
|
210 |
+
}
|
211 |
+
}
|
212 |
+
</style>
|
213 |
+
|
214 |
+
<div class="navbar">
|
215 |
+
<div class="logo">Yuvabe Care Companion AI</div>
|
216 |
+
<div class="nav-links">
|
217 |
+
<a href="/" class="nav-link">Home</a>
|
218 |
+
<a href="/Admin_Portal" class="nav-link">Admin Portal</a>
|
219 |
+
<a href="/Knowledge_Base_Explorer" class="nav-link">Knowledge Base Explorer</a>
|
220 |
+
<a href="/chatbot" class="nav-link">Chat With Us</a>
|
221 |
+
</div>
|
222 |
+
</div>
|
223 |
+
""",
|
224 |
+
unsafe_allow_html=True
|
225 |
+
)
|
226 |
+
|
227 |
+
def set_bg_image(file_path, opacity=0.5):
|
228 |
+
"""
|
229 |
+
Sets a background image for the Streamlit application with optional opacity control.
|
230 |
+
|
231 |
+
This function applies a background image to the entire Streamlit app (`.stApp` container)
|
232 |
+
using CSS with a linear gradient overlay. The overlay enhances text readability by adding
|
233 |
+
a semi-transparent dark layer over the image.
|
234 |
+
|
235 |
+
Args:
|
236 |
+
file_path (str): The file path of the background image (supports PNG, JPG, etc.).
|
237 |
+
opacity (float, optional): The opacity level of the dark overlay.
|
238 |
+
Values range from 0 (fully transparent) to 1 (fully opaque).
|
239 |
+
Default is 0.5, providing balanced readability and background visibility.
|
240 |
+
|
241 |
+
Example Usage:
|
242 |
+
```python
|
243 |
+
set_bg_image("src/frontend/images/health_care_banner.png", opacity=0.6)
|
244 |
+
```
|
245 |
+
|
246 |
+
Notes:
|
247 |
+
- Ensure the provided `file_path` is accessible and the image is properly encoded in base64 format.
|
248 |
+
- For optimal results, use high-resolution images with suitable contrast to enhance readability.
|
249 |
+
|
250 |
+
"""
|
251 |
+
encoded_img = img_to_base64(file_path)
|
252 |
+
st.markdown(
|
253 |
+
f"""
|
254 |
+
<style>
|
255 |
+
.stApp {{
|
256 |
+
background: linear-gradient(rgba(0, 0, 0, {opacity}), rgba(0, 0, 0, {opacity})),
|
257 |
+
url("data:image/png;base64,{encoded_img}") center/cover fixed no-repeat;
|
258 |
+
min-height: 100vh;
|
259 |
+
}}
|
260 |
+
</style>
|
261 |
+
""",
|
262 |
+
unsafe_allow_html=True
|
263 |
+
)
|
264 |
+
|
265 |
+
|
266 |
+
|
267 |
+
|
268 |
+
|
269 |
+
|
270 |
+
|
271 |
+
|
272 |
+
|
273 |
+
|
274 |
+
|
275 |
+
|
276 |
+
|
277 |
+
|
278 |
+
|
279 |
+
|
280 |
+
|
281 |
+
|
282 |
+
|
283 |
+
|
284 |
+
|
285 |
+
|
286 |
def get_api_response(endpoint:str, prompt: list):
|
287 |
try:
|
288 |
logger.info(f"Sending user prompt to API endpoint: {API_URL}{endpoint}")
|
|
|
337 |
except Exception as e:
|
338 |
logger.info(f"Failed to add the chat in db {e}")
|
339 |
|
340 |
+
def display_message_box(role, content):
|
341 |
+
"""
|
342 |
+
Displays a styled message box for user or assistant content.
|
343 |
+
|
344 |
+
Args:
|
345 |
+
role (str): The role of the speaker (e.g., 'User' or 'Assistant').
|
346 |
+
content (str): The text content to display.
|
347 |
+
"""
|
348 |
+
# Define styles based on role
|
349 |
+
background_color = "#E3F2FD" if role.lower() == 'user' else "#E8F5E9"
|
350 |
+
border_color = "#1E88E5" if role.lower() == 'user' else "#43A047"
|
351 |
+
text_align = "left" if role.lower() == 'user' else "right"
|
352 |
+
flex_direction = "row" if role.lower() == 'user' else "row-reverse"
|
353 |
+
avatar = "path_to_user_avatar.png" if role.lower() == 'user' else "path_to_assistant_avatar.png"
|
354 |
+
|
355 |
+
st.markdown(f"""
|
356 |
+
<div style="
|
357 |
+
display: flex;
|
358 |
+
flex-direction: {flex_direction};
|
359 |
+
align-items: center;
|
360 |
+
margin-bottom: 10px;
|
361 |
+
gap: 10px;">
|
362 |
+
|
363 |
+
<img src="{avatar}" alt="{role} avatar" style="width: 40px; height: 40px; border-radius: 50%;">
|
364 |
+
|
365 |
+
<div style="
|
366 |
+
background-color: {background_color};
|
367 |
+
padding: 15px;
|
368 |
+
border-left: 5px solid {border_color};
|
369 |
+
border-radius: 8px;
|
370 |
+
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
|
371 |
+
width: 100%;">
|
372 |
+
|
373 |
+
<strong style="color: #333; font-size: 16px;">{role}:</strong>
|
374 |
+
<div style="margin-top: 5px; color: #555; font-size: 14px;">
|
375 |
+
{content}
|
376 |
+
</div>
|
377 |
+
</div>
|
378 |
+
</div>
|
379 |
+
""", unsafe_allow_html=True)
|
380 |
+
|
381 |
def get_chat_history_from_db(conversation_id: str, retries=3, delay=5):
|
382 |
API_URL = "http://127.0.0.1:8000/chat-history/retrieve"
|
383 |
for attempt in range(retries):
|
|
|
408 |
first_message_content = chat_history["data"]["messages"][0].get('content', '').strip()
|
409 |
button_text = first_message_content[:20] if first_message_content else "No Content"
|
410 |
|
411 |
+
if st.sidebar.button(f"Show History for {button_text} : {conversation_id}", key=f"show_history_{conversation_id}"):
|
412 |
st.subheader(f"Chat History for Conversation ID: {conversation_id}")
|
413 |
|
414 |
for message in chat_history["data"]["messages"]:
|
|
|
435 |
logger.error(f"Error retrieving chat history for {conversation_id}: {e}")
|
436 |
st.error("An unexpected error occurred while retrieving chat history.")
|
437 |
|
438 |
+
def get_bucket_items():
|
439 |
+
API_URL = "http://127.0.0.1:8000/chat-history/bucket-items"
|
440 |
+
try:
|
441 |
+
response = requests.get(API_URL)
|
442 |
+
response.raise_for_status()
|
443 |
+
return response.json()
|
444 |
+
except Exception as e:
|
445 |
+
logger.error(f"Failed to get the bucket items {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/frontend/app/pinecone_data_handler.py
CHANGED
@@ -1,67 +1,125 @@
|
|
1 |
import requests
|
2 |
-
from app import common_functions
|
3 |
import streamlit as st
|
4 |
|
5 |
-
|
6 |
API_BASE_URL = "http://localhost:8000/knowledge-base"
|
7 |
|
8 |
-
def upsert_data(
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
with st.form("upsert_form"):
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
15 |
|
16 |
if upsert_submit:
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
20 |
|
21 |
-
|
22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
with st.form("delete_form"):
|
24 |
-
|
25 |
-
|
|
|
|
|
26 |
|
27 |
if delete_submit:
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
#
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
#
|
39 |
-
|
40 |
-
|
41 |
-
#
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
with st.form("fetch_metadata_form"):
|
|
|
65 |
prompt_text = st.text_area(
|
66 |
"Describe Your Concern",
|
67 |
"e.g., I've been feeling anxious lately.",
|
@@ -81,30 +139,47 @@ def render_metadata_fetch_form(st):
|
|
81 |
help="Set the minimum relevance score for the results. Higher values ensure more accurate matches."
|
82 |
)
|
83 |
|
84 |
-
metadata_submit = st.form_submit_button("Fetch Metadata")
|
85 |
|
86 |
if metadata_submit:
|
|
|
|
|
|
|
|
|
|
|
87 |
payload = {
|
88 |
"prompt": prompt_text.strip(),
|
89 |
"n_result": n_result,
|
90 |
"score_threshold": score_threshold
|
91 |
}
|
92 |
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import requests
|
2 |
+
from frontend.app import common_functions
|
3 |
import streamlit as st
|
4 |
|
|
|
5 |
API_BASE_URL = "http://localhost:8000/knowledge-base"
|
6 |
|
7 |
+
def upsert_data():
|
8 |
+
"""
|
9 |
+
Displays a form to upsert data into the Pinecone database.
|
10 |
+
|
11 |
+
Features:
|
12 |
+
- Users can provide 'Input', 'Output', and 'Instruction'.
|
13 |
+
- Displays appropriate success or error messages.
|
14 |
+
- Improved error handling with detailed feedback.
|
15 |
+
"""
|
16 |
+
|
17 |
+
st.subheader("Enter the data to upsert")
|
18 |
with st.form("upsert_form"):
|
19 |
+
# Input Fields
|
20 |
+
input_text = st.text_area("Input", placeholder="Enter input text here...", height=150)
|
21 |
+
output_text = st.text_area("Output", placeholder="Enter output text here...", height=150)
|
22 |
+
instruction_text = st.text_input("Instruction", placeholder="Provide guidance for the data...")
|
23 |
+
|
24 |
+
upsert_submit = st.form_submit_button("π Upsert Data")
|
25 |
|
26 |
if upsert_submit:
|
27 |
+
# β
Validation Check
|
28 |
+
if not input_text.strip() or not output_text.strip() or not instruction_text.strip():
|
29 |
+
st.error("β All fields are required. Please fill out each section before submitting.")
|
30 |
+
return
|
31 |
|
32 |
+
# β
Payload Creation
|
33 |
+
payload = {
|
34 |
+
"data": [
|
35 |
+
{
|
36 |
+
"input": input_text.strip(),
|
37 |
+
"output": output_text.strip(),
|
38 |
+
"instruction": instruction_text.strip()
|
39 |
+
}
|
40 |
+
]
|
41 |
+
}
|
42 |
+
|
43 |
+
# API Call
|
44 |
+
with st.spinner("β³ Processing your data..."):
|
45 |
+
try:
|
46 |
+
response = requests.post(f"{API_BASE_URL}/upsert-data", json=payload)
|
47 |
+
response_data = response.json()
|
48 |
+
|
49 |
+
if response.status_code == 200:
|
50 |
+
st.success(f"β
Data successfully upserted: {response_data.get('message', 'Success')}")
|
51 |
+
st.toast("π Upsert successful!")
|
52 |
+
elif response.status_code == 400:
|
53 |
+
st.warning(f"β οΈ Bad Request: {response_data.get('detail', 'Check your input data.')}")
|
54 |
+
elif response.status_code == 500:
|
55 |
+
st.error("β Internal Server Error. Please try again later.")
|
56 |
+
else:
|
57 |
+
st.error(f"β Unexpected error: {response_data.get('detail', 'Unknown issue occurred.')}")
|
58 |
+
except requests.exceptions.RequestException as e:
|
59 |
+
st.error(f"β Network error: {e}")
|
60 |
+
|
61 |
+
def delete_records():
|
62 |
+
"""
|
63 |
+
Displays a form to delete records from the Pinecone database.
|
64 |
+
|
65 |
+
Features:
|
66 |
+
- Users can input comma-separated IDs for deletion.
|
67 |
+
- Includes validation checks for empty or malformed IDs.
|
68 |
+
- Enhanced error handling for better user feedback.
|
69 |
+
"""
|
70 |
+
st.subheader("Enter id to delete")
|
71 |
with st.form("delete_form"):
|
72 |
+
ids_input = st.text_area("IDs to Delete", placeholder="Enter IDs separated by commas (e.g., id_123, id_456)")
|
73 |
+
ids_to_delete = [id.strip() for id in ids_input.split(",") if id.strip()]
|
74 |
+
|
75 |
+
delete_submit = st.form_submit_button("ποΈ Delete Records")
|
76 |
|
77 |
if delete_submit:
|
78 |
+
# β
Validation Check
|
79 |
+
if not ids_to_delete:
|
80 |
+
st.error("β Please provide at least one valid ID.")
|
81 |
+
return
|
82 |
+
|
83 |
+
# π Confirmation Prompt for Safety
|
84 |
+
if not st.confirm("Are you sure you want to delete the selected records? This action is irreversible."):
|
85 |
+
st.info("β Deletion canceled.")
|
86 |
+
return
|
87 |
+
|
88 |
+
# β
Payload Creation
|
89 |
+
payload = {"ids_to_delete": ids_to_delete}
|
90 |
+
|
91 |
+
# β
API Call with Improved Error Handling
|
92 |
+
with st.spinner("β³ Deleting records..."):
|
93 |
+
try:
|
94 |
+
response = requests.post(f"{API_BASE_URL}/delete-records", json=payload)
|
95 |
+
response_data = response.json()
|
96 |
+
|
97 |
+
if response.status_code == 200:
|
98 |
+
st.success(f"β
{response_data.get('message', 'Records successfully deleted.')}")
|
99 |
+
st.toast("π― Deletion successful!")
|
100 |
+
elif response.status_code == 400:
|
101 |
+
st.warning(f"β οΈ Bad Request: {response_data.get('detail', 'Check the provided IDs.')}")
|
102 |
+
elif response.status_code == 404:
|
103 |
+
st.warning("β οΈ No matching records found. Please verify the provided IDs.")
|
104 |
+
elif response.status_code == 500:
|
105 |
+
st.error("β Internal Server Error. Please try again later.")
|
106 |
+
else:
|
107 |
+
st.error(f"β Unexpected error: {response_data.get('detail', 'Unknown issue occurred.')}")
|
108 |
+
except requests.exceptions.RequestException as e:
|
109 |
+
st.error(f"β Network error: {e}")
|
110 |
+
|
111 |
+
def render_metadata_fetch_form():
|
112 |
+
"""
|
113 |
+
Renders a form to fetch metadata based on user concerns.
|
114 |
+
|
115 |
+
Features:
|
116 |
+
- Input validation to ensure meaningful data is provided.
|
117 |
+
- Displays metadata in a visually appealing format.
|
118 |
+
- Improved error handling with detailed messages.
|
119 |
+
"""
|
120 |
+
st.header("π Fetch Metadata")
|
121 |
with st.form("fetch_metadata_form"):
|
122 |
+
# π Input Fields
|
123 |
prompt_text = st.text_area(
|
124 |
"Describe Your Concern",
|
125 |
"e.g., I've been feeling anxious lately.",
|
|
|
139 |
help="Set the minimum relevance score for the results. Higher values ensure more accurate matches."
|
140 |
)
|
141 |
|
142 |
+
metadata_submit = st.form_submit_button("π Fetch Metadata")
|
143 |
|
144 |
if metadata_submit:
|
145 |
+
# β
Input Validation
|
146 |
+
if not prompt_text.strip():
|
147 |
+
st.warning("β Please provide a valid concern description.")
|
148 |
+
return
|
149 |
+
|
150 |
payload = {
|
151 |
"prompt": prompt_text.strip(),
|
152 |
"n_result": n_result,
|
153 |
"score_threshold": score_threshold
|
154 |
}
|
155 |
|
156 |
+
# π Enhanced API Request with Better Error Handling
|
157 |
+
with st.spinner("β³ Fetching metadata..."):
|
158 |
+
try:
|
159 |
+
response = requests.post(f"{API_BASE_URL}/fetch-metadata", json=payload)
|
160 |
+
response.raise_for_status()
|
161 |
+
metadata = response.json().get('metadata', [])
|
162 |
+
|
163 |
+
# β
Display Results
|
164 |
+
if metadata:
|
165 |
+
st.success(f"β
Found {len(metadata)} relevant result(s).")
|
166 |
+
st.subheader("Search Results")
|
167 |
+
|
168 |
+
for index, entry in enumerate(metadata, start=1):
|
169 |
+
common_functions.typewriter_effect(f"**π§ Question:** {entry.get('question', 'N/A')}",speed=0)
|
170 |
+
common_functions.typewriter_effect(f"**π¬ Answer:** {entry.get('answer', 'N/A')}",speed=0)
|
171 |
+
st.markdown(f"**π Score:** `{entry.get('score', 'N/A')}`")
|
172 |
+
st.markdown(f"**π ID:** `{entry.get('id', 'N/A')}`")
|
173 |
+
|
174 |
+
else:
|
175 |
+
st.info("π€ No relevant data found. Try refining your concern or adjusting the score threshold.")
|
176 |
+
|
177 |
+
# Exception Handling for Specific Errors
|
178 |
+
except requests.exceptions.HTTPError as http_err:
|
179 |
+
st.error(f"β HTTP Error: {http_err}")
|
180 |
+
except requests.exceptions.ConnectionError:
|
181 |
+
st.error("β Network error. Please check your internet connection.")
|
182 |
+
except requests.exceptions.Timeout:
|
183 |
+
st.error("β Request timed out. Please try again later.")
|
184 |
+
except requests.exceptions.RequestException as e:
|
185 |
+
st.error(f"β Unexpected error: {e}")
|
src/frontend/home.py
CHANGED
@@ -1,84 +1,77 @@
|
|
1 |
import streamlit as st
|
2 |
-
from app import common_functions
|
3 |
|
4 |
-
|
|
|
|
|
5 |
common_functions.config_homepage()
|
6 |
common_functions.set_bg_image("src/frontend/images/health_care_baner.png")
|
7 |
common_functions.custom_navbar()
|
8 |
st.divider()
|
9 |
|
10 |
def render_homepage():
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
- Admin Portal β Effortlessly manage records, track data, and configure settings with ease.
|
20 |
-
|
21 |
-
- Knowledge Base Explorer β Discover precise and relevant insights using advanced vector search technology.
|
22 |
-
|
23 |
-
- Chat with Us β Engage with our intelligent assistant for personalized guidance, helping you articulate your health concerns with clarity and confidence.
|
24 |
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
font-weight: bold;
|
32 |
-
font-size:
|
33 |
-
|
34 |
-
|
35 |
-
padding: 10px 20px;
|
36 |
-
border-radius: 8px;
|
37 |
">
|
38 |
-
|
39 |
-
</
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
# def render_homepage():
|
45 |
-
# """Renders the Yuvabe Care Companion AI homepage."""
|
46 |
-
|
47 |
-
# # Welcome Section with Visual
|
48 |
-
# st.image("src/frontend/images/health_care_baner.png",
|
49 |
-
# use_container_width=True,
|
50 |
-
# caption="Your AI-Powered Health Companion")
|
51 |
-
|
52 |
-
# # Navigation Tabs
|
53 |
-
# Home, Admin_Portal, Knowledge_Base_Explorer = st.tabs(
|
54 |
-
# ["π Home", "π Admin Portal", "π Knowledge Base Explorer"]
|
55 |
-
# )
|
56 |
-
|
57 |
-
# with Home:
|
58 |
-
# st.markdown("""
|
59 |
-
# ### π Welcome to the Yuvabe Care Companion AI!
|
60 |
-
# This platform offers comprehensive tools to support your healthcare journey. Use the tabs above to navigate:
|
61 |
-
# """)
|
62 |
-
|
63 |
-
# # Feature Overview Section
|
64 |
-
# st.markdown("""
|
65 |
-
# ### πΉ Key Features
|
66 |
-
# - **Admin Portal** β Manage records, data, and configurations efficiently.
|
67 |
-
# - **Knowledge Base Explorer** β Leverage advanced vector search to find relevant knowledge entries with precision.
|
68 |
-
# - **Patient Assistance** β Personalized guidance to help patients describe their concerns.
|
69 |
-
|
70 |
-
# > π‘ *Explore each section for detailed functionality.*
|
71 |
-
# """)
|
72 |
-
|
73 |
-
# with Admin_Portal:
|
74 |
-
# admin_page.render_admin_portal()
|
75 |
-
# # if st.button("Go to Admin Portal"):
|
76 |
-
# # st.switch_page("pages/admin_portal.py")
|
77 |
-
|
78 |
-
# with Knowledge_Base_Explorer:
|
79 |
-
# knowledge_base_explorer_page.render_knowledge_base_explorer()
|
80 |
-
# if st.button("Go to Knowledge Base Explorer"):
|
81 |
-
# st.switch_page("pages/knowledge_base_explorer.py")
|
82 |
|
83 |
-
|
84 |
-
|
|
|
1 |
import streamlit as st
|
2 |
+
from frontend.app import common_functions
|
3 |
|
4 |
+
WELCOME_TEXT = "Welcome to the Yuvabe Care Companion AI!"
|
5 |
+
|
6 |
+
# Page Configuration
|
7 |
common_functions.config_homepage()
|
8 |
common_functions.set_bg_image("src/frontend/images/health_care_baner.png")
|
9 |
common_functions.custom_navbar()
|
10 |
st.divider()
|
11 |
|
12 |
def render_homepage():
|
13 |
+
"""
|
14 |
+
Renders the Yuvabe Care Companion AI homepage with improved visuals and enhanced user experience.
|
15 |
+
|
16 |
+
Features:
|
17 |
+
- Displays a warm welcome message with animated text.
|
18 |
+
- Highlights key features using clean and modern UI design.
|
19 |
+
- Encourages user engagement with a prominent 'Get Started' call-to-action.
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
|
21 |
+
Visual Enhancements:
|
22 |
+
- Consistent color theme with improved contrast for readability.
|
23 |
+
- Box shadows and rounded corners for a modern touch.
|
24 |
+
- Organized content using bullet points, ensuring clarity and focus.
|
25 |
+
|
26 |
+
"""
|
27 |
+
|
28 |
+
# Welcome Text with Animation
|
29 |
+
common_functions.typewriter_effect(WELCOME_TEXT, speed=0.02, gradient=True)
|
30 |
|
31 |
+
# Key Features Section
|
32 |
+
st.markdown(
|
33 |
+
"""
|
34 |
+
<div style="
|
35 |
+
background-color: #1B3C59;
|
36 |
+
color: #FFFFFF;
|
37 |
+
padding: 25px;
|
38 |
+
border-radius: 15px;
|
39 |
+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
|
40 |
+
margin-top: 20px;
|
41 |
+
">
|
42 |
+
<h2 style="text-align: left; font-weight: bold;">Key Features</h2>
|
43 |
+
<ul style="padding-left: 20px;">
|
44 |
+
<li><b>π οΈ Admin Portal</b> β Effortlessly manage records, track data, and configure settings with ease.</li>
|
45 |
+
<li><b>π Knowledge Base Explorer</b> β Discover precise and relevant insights using advanced vector search technology.</li>
|
46 |
+
<li><b>π¬ Chat with Us</b> β Engage with our intelligent assistant for personalized guidance.</li>
|
47 |
+
</ul>
|
48 |
+
<p style="margin-top: 15px; font-style: italic; font-weight: bold;">
|
49 |
+
π‘ Explore each section to unlock powerful features tailored to enhance your experience.
|
50 |
+
</p>
|
51 |
+
</div>
|
52 |
+
""",
|
53 |
+
unsafe_allow_html=True
|
54 |
+
)
|
55 |
+
|
56 |
+
# Call-to-Action Section
|
57 |
+
st.markdown(
|
58 |
+
"""
|
59 |
+
<div style="
|
60 |
+
text-align: center;
|
61 |
+
margin-top: 30px;
|
62 |
+
padding: 18px 35px;
|
63 |
+
background-color: #4CAF50;
|
64 |
+
color: #FFFFFF;
|
65 |
font-weight: bold;
|
66 |
+
font-size: 20px;
|
67 |
+
border-radius: 12px;
|
68 |
+
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
|
|
|
|
|
69 |
">
|
70 |
+
πΏ Ready to Get Started? Begin Your Journey Now! π
|
71 |
+
</div>
|
72 |
+
""",
|
73 |
+
unsafe_allow_html=True
|
74 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
+
if __name__ == "__main__":
|
77 |
+
render_homepage()
|
src/frontend/pages/Admin_Portal.py
CHANGED
@@ -1,49 +1,98 @@
|
|
1 |
import streamlit as st
|
2 |
-
from app import pinecone_data_handler
|
3 |
-
from app import common_functions
|
4 |
|
5 |
# # Page Configuration
|
6 |
common_functions.config_homepage()
|
|
|
7 |
|
8 |
def render_admin_portal():
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
st.divider()
|
18 |
|
19 |
-
|
20 |
DataManager = st.tabs(["π Pinecone Data Manager"])[0]
|
21 |
|
22 |
with DataManager:
|
23 |
-
Upsert, Delete = st.tabs(["Upsert Data", "Delete Records"])
|
24 |
|
25 |
# Upsert Section
|
26 |
with Upsert:
|
27 |
-
st.markdown(
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
)
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
36 |
|
37 |
# Delete Section
|
38 |
with Delete:
|
39 |
-
st.markdown(
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
)
|
45 |
-
|
46 |
-
|
|
|
47 |
|
48 |
# Call the function to render the Admin Portal
|
49 |
if __name__ == "__main__":
|
|
|
1 |
import streamlit as st
|
2 |
+
from frontend.app import pinecone_data_handler,common_functions
|
|
|
3 |
|
4 |
# # Page Configuration
|
5 |
common_functions.config_homepage()
|
6 |
+
# common_functions.set_bg_image("src/frontend/images/health_care_baner.png")
|
7 |
|
8 |
def render_admin_portal():
|
9 |
+
|
10 |
+
"""
|
11 |
+
Renders the enhanced Admin Portal page with improved UI, navigation, and user guidance.
|
12 |
+
|
13 |
+
Features:
|
14 |
+
- Upsert data functionality with informative tips.
|
15 |
+
- Delete records feature with enhanced warnings and confirmation prompts.
|
16 |
+
"""
|
17 |
+
|
18 |
+
# Header Section
|
19 |
+
st.markdown(
|
20 |
+
"""
|
21 |
+
<div style="
|
22 |
+
background-color: #1B3C59;
|
23 |
+
color: #FFFFFF;
|
24 |
+
padding: 10px;
|
25 |
+
border-radius: 12px;
|
26 |
+
text-align: center;
|
27 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
28 |
+
border-radius: 80px;
|
29 |
+
">
|
30 |
+
<h1>π οΈ Admin Portal</h1>
|
31 |
+
<p style="font-size: 16px;">
|
32 |
+
Manage your Pinecone database securely and efficiently.
|
33 |
+
</p>
|
34 |
+
</div>
|
35 |
+
""",
|
36 |
+
unsafe_allow_html=True
|
37 |
+
)
|
38 |
+
|
39 |
st.divider()
|
40 |
|
41 |
+
# Data Manager Tabs
|
42 |
DataManager = st.tabs(["π Pinecone Data Manager"])[0]
|
43 |
|
44 |
with DataManager:
|
45 |
+
Upsert, Delete = st.tabs(["π’ Upsert Data", "π΄ Delete Records"])
|
46 |
|
47 |
# Upsert Section
|
48 |
with Upsert:
|
49 |
+
st.markdown(
|
50 |
+
"""
|
51 |
+
<div style="
|
52 |
+
background-color: #E3F2FD;
|
53 |
+
padding: 20px;
|
54 |
+
border-radius: 10px;
|
55 |
+
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
|
56 |
+
">
|
57 |
+
<h3>π₯ Upsert Data</h3>
|
58 |
+
<p style="color: #1976D2;">
|
59 |
+
Use this section to <b>insert</b> or <b>update</b> records in Pinecone.
|
60 |
+
</p>
|
61 |
+
<p>
|
62 |
+
β
Ensure your data is correctly formatted before uploading.<br>
|
63 |
+
</p>
|
64 |
+
</div>
|
65 |
+
""",
|
66 |
+
unsafe_allow_html=True
|
67 |
)
|
68 |
+
|
69 |
+
st.divider()
|
70 |
+
|
71 |
+
# Call Upsert Function
|
72 |
+
pinecone_data_handler.upsert_data()
|
73 |
|
74 |
# Delete Section
|
75 |
with Delete:
|
76 |
+
st.markdown(
|
77 |
+
"""
|
78 |
+
<div style="
|
79 |
+
background-color: #FFEBEE;
|
80 |
+
padding: 20px;
|
81 |
+
border-radius: 10px;
|
82 |
+
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
|
83 |
+
">
|
84 |
+
<h3>β οΈ Delete Records</h3>
|
85 |
+
<p style="color: #D32F2F;">
|
86 |
+
β <b>Warning:</b> Deleting data is irreversible.<br>
|
87 |
+
Please confirm your action before proceeding.
|
88 |
+
</p>
|
89 |
+
</div>
|
90 |
+
""",
|
91 |
+
unsafe_allow_html=True
|
92 |
)
|
93 |
+
|
94 |
+
st.divider()
|
95 |
+
pinecone_data_handler.delete_records()
|
96 |
|
97 |
# Call the function to render the Admin Portal
|
98 |
if __name__ == "__main__":
|
src/frontend/pages/{chatbot.py β Chat_With_Us.py}
RENAMED
@@ -1,13 +1,13 @@
|
|
1 |
import streamlit as st
|
2 |
import requests
|
3 |
-
from app import common_functions
|
4 |
from datetime import datetime
|
5 |
|
6 |
API_URL = "http://localhost:8000/chat/get-health-advice/"
|
7 |
NUMBER_OF_MESSAGES_TO_DISPLAY = 20
|
8 |
common_functions.config_homepage()
|
9 |
common_functions.set_page_title()
|
10 |
-
common_functions.set_bg_image("src/frontend/images/health_care_baner_2.jpg")
|
11 |
# Initialize conversation history
|
12 |
def initialize_conversation():
|
13 |
assistant_message = ("Hello! I am your Yuvabe Care Companion AI, here to assist you with general medicine queries. "
|
@@ -36,14 +36,18 @@ def render_chatbot():
|
|
36 |
if 'conversation_id' not in st.session_state:
|
37 |
st.session_state.conversation_id = datetime.now().strftime("%Y-%m-%d")
|
38 |
|
39 |
-
common_functions.
|
|
|
|
|
|
|
40 |
|
41 |
# Display chat history
|
42 |
for message in st.session_state.conversation_history [-NUMBER_OF_MESSAGES_TO_DISPLAY:]:
|
43 |
role = message["role"]
|
44 |
avatar_image = "src/frontend/images/chat_doctor_logo.png" if role == "assistant" else "src/frontend/images/healthy.png" if role == "user" else None
|
45 |
with st.chat_message(role, avatar=avatar_image):
|
46 |
-
|
|
|
47 |
|
48 |
# User Input
|
49 |
user_input = st.chat_input("Ask your health-related question:")
|
|
|
1 |
import streamlit as st
|
2 |
import requests
|
3 |
+
from frontend.app import common_functions
|
4 |
from datetime import datetime
|
5 |
|
6 |
API_URL = "http://localhost:8000/chat/get-health-advice/"
|
7 |
NUMBER_OF_MESSAGES_TO_DISPLAY = 20
|
8 |
common_functions.config_homepage()
|
9 |
common_functions.set_page_title()
|
10 |
+
# common_functions.set_bg_image("src/frontend/images/health_care_baner_2.jpg")
|
11 |
# Initialize conversation history
|
12 |
def initialize_conversation():
|
13 |
assistant_message = ("Hello! I am your Yuvabe Care Companion AI, here to assist you with general medicine queries. "
|
|
|
36 |
if 'conversation_id' not in st.session_state:
|
37 |
st.session_state.conversation_id = datetime.now().strftime("%Y-%m-%d")
|
38 |
|
39 |
+
conversation_ids = common_functions.get_bucket_items()
|
40 |
+
if conversation_ids:
|
41 |
+
for conversation_id in conversation_ids[-3:]:
|
42 |
+
common_functions.display_chat_history(conversation_id)
|
43 |
|
44 |
# Display chat history
|
45 |
for message in st.session_state.conversation_history [-NUMBER_OF_MESSAGES_TO_DISPLAY:]:
|
46 |
role = message["role"]
|
47 |
avatar_image = "src/frontend/images/chat_doctor_logo.png" if role == "assistant" else "src/frontend/images/healthy.png" if role == "user" else None
|
48 |
with st.chat_message(role, avatar=avatar_image):
|
49 |
+
common_functions.display_message_box(role,message['content'])
|
50 |
+
# st.write(message["content"])
|
51 |
|
52 |
# User Input
|
53 |
user_input = st.chat_input("Ask your health-related question:")
|
src/frontend/pages/Knowledge_Base_Explorer.py
CHANGED
@@ -1,22 +1,65 @@
|
|
1 |
import streamlit as st
|
2 |
-
from app import pinecone_data_handler, common_functions
|
3 |
|
|
|
4 |
common_functions.config_homepage()
|
5 |
|
6 |
def render_knowledge_base_explorer():
|
7 |
-
"""Renders the Knowledge Base Explorer page
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
# Call the function to render the Knowledge Base Explorer
|
21 |
if __name__ == "__main__":
|
22 |
render_knowledge_base_explorer()
|
|
|
1 |
import streamlit as st
|
2 |
+
from frontend.app import pinecone_data_handler, common_functions
|
3 |
|
4 |
+
# Page Configuration
|
5 |
common_functions.config_homepage()
|
6 |
|
7 |
def render_knowledge_base_explorer():
|
8 |
+
"""Renders the Knowledge Base Explorer page for fetching accurate metadata from Pinecone Vector DB."""
|
9 |
+
|
10 |
+
st.markdown(
|
11 |
+
"""
|
12 |
+
<div style="
|
13 |
+
background-color: #1B3C59;
|
14 |
+
color: #FFFFFF;
|
15 |
+
padding: 20px;
|
16 |
+
border-radius: 12px;
|
17 |
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
18 |
+
text-align: center;
|
19 |
+
">
|
20 |
+
<h1>π Knowledge Base Explorer</h1>
|
21 |
+
<p>Powered by <b>Pinecone Vector DB</b> for precise metadata retrieval.</p>
|
22 |
+
</div>
|
23 |
+
""",
|
24 |
+
unsafe_allow_html=True
|
25 |
+
)
|
26 |
+
|
27 |
+
st.divider()
|
28 |
+
|
29 |
+
# Guidance Section
|
30 |
+
st.markdown(
|
31 |
+
"""
|
32 |
+
### How to Use the Knowledge Base Explorer
|
33 |
+
1. **Enter your query** related to health concerns.
|
34 |
+
2. Click **Fetch Metadata** to retrieve the most relevant insights.
|
35 |
+
3. Results are fetched from **Pinecone Vector DB**, ensuring fast and accurate responses.
|
36 |
|
37 |
+
β
**Pro Tip:** Use precise keywords for better results (e.g., "mental health tips" instead of "help").
|
38 |
+
"""
|
39 |
+
)
|
40 |
|
41 |
+
st.divider()
|
42 |
+
|
43 |
+
# Knowledge Base Section
|
44 |
+
with st.expander("π **Explore the Knowledge Base (Pinecone Vector DB)**", expanded=True):
|
45 |
+
st.info(
|
46 |
+
"π‘ **Looking for specific metadata?**"
|
47 |
+
"\nOur system intelligently maps your query to the most relevant results."
|
48 |
+
)
|
49 |
+
|
50 |
+
try:
|
51 |
+
result = pinecone_data_handler.render_metadata_fetch_form()
|
52 |
+
|
53 |
+
# if result:
|
54 |
+
# st.success("β
**Metadata fetched successfully!**")
|
55 |
+
# st.write(result)
|
56 |
+
# else:
|
57 |
+
# st.warning("β οΈ No relevant metadata found. Try refining your query for better results.")
|
58 |
+
|
59 |
+
except Exception as e:
|
60 |
+
st.error(f"β An error occurred while fetching metadata: {str(e)}")
|
61 |
+
|
62 |
+
|
63 |
# Call the function to render the Knowledge Base Explorer
|
64 |
if __name__ == "__main__":
|
65 |
render_knowledge_base_explorer()
|