Spaces:
Sleeping
Sleeping
Vela commited on
Commit ·
bd5a98c
1
Parent(s): 0e43e5f
enhance chat api
Browse files- src/backend/__pycache__/main.cpython-313.pyc +0 -0
- src/backend/api_routes/__pycache__/chat_api.cpython-313.pyc +0 -0
- src/backend/api_routes/__pycache__/chat_history_db_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 +54 -30
- src/backend/api_routes/knowledge_base_api.py +0 -1
- src/backend/chatbot.py +0 -23
- src/backend/data/__pycache__/pinecone_db.cpython-313.pyc +0 -0
- src/backend/main.py +17 -4
- src/backend/models/__pycache__/embedding_model.cpython-313.pyc +0 -0
- src/backend/models/__pycache__/llm_model.cpython-313.pyc +0 -0
- src/backend/models/__pycache__/schemas.cpython-313.pyc +0 -0
- src/backend/models/embedding_model.py +0 -15
- src/backend/models/schemas.py +0 -26
- src/backend/services/__pycache__/embedding_service.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/llm_model_service.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/pinecone_service.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/schemas.cpython-313.pyc +0 -0
- src/backend/services/__pycache__/supabase_service.cpython-313.pyc +0 -0
- src/backend/services/llm_model_service.py +99 -41
- src/backend/services/pinecone_service.py +4 -6
- src/backend/services/schemas.py +32 -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/pages/chatbot.py +6 -6
src/backend/__pycache__/main.cpython-313.pyc
CHANGED
|
Binary files a/src/backend/__pycache__/main.cpython-313.pyc and b/src/backend/__pycache__/main.cpython-313.pyc differ
|
|
|
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_db_api.cpython-313.pyc
CHANGED
|
Binary files a/src/backend/api_routes/__pycache__/chat_history_db_api.cpython-313.pyc and b/src/backend/api_routes/__pycache__/chat_history_db_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,36 +1,14 @@
|
|
| 1 |
-
from fastapi import APIRouter, HTTPException
|
| 2 |
-
from
|
| 3 |
-
from
|
| 4 |
from services.schemas import ConversationInput
|
|
|
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
logger= logger.get_logger()
|
| 9 |
|
| 10 |
router = APIRouter(prefix="/chat", tags=["Chat"])
|
| 11 |
|
| 12 |
-
|
| 13 |
-
# @router.post("/query")
|
| 14 |
-
# async def chat_query(request: ChatRequest):
|
| 15 |
-
# try:
|
| 16 |
-
# logger.info("Trying to fetch response")
|
| 17 |
-
# query = request.query
|
| 18 |
-
# context = pinecone_service.retrieve_context_from_pinecone(query)
|
| 19 |
-
# response= llm_model_service.generate_response_with_context(query,context)
|
| 20 |
-
# logger.info("Fetched response")
|
| 21 |
-
# return response
|
| 22 |
-
# except Exception as e:
|
| 23 |
-
# raise HTTPException(status_code=500, detail=str(e))
|
| 24 |
-
|
| 25 |
-
# @router.get("/history/{date}", response_model=list)
|
| 26 |
-
# async def get_history(date: str):
|
| 27 |
-
# try:
|
| 28 |
-
# history = get_chat_history(date)
|
| 29 |
-
# return history
|
| 30 |
-
# except Exception as e:
|
| 31 |
-
# raise HTTPException(status_code=500, detail=str(e))
|
| 32 |
-
|
| 33 |
-
@router.post("/get-health-advice/")
|
| 34 |
async def get_health_advice(input_data: ConversationInput):
|
| 35 |
"""
|
| 36 |
Handles requests from the frontend and fetches advice using the `get_health_advice()` function.
|
|
@@ -38,12 +16,58 @@ async def get_health_advice(input_data: ConversationInput):
|
|
| 38 |
Args:
|
| 39 |
- input_data (ConversationInput): User's conversation history.
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
Returns:
|
| 42 |
- dict: Contains 'reply' with the assistant's response.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
try:
|
| 45 |
-
|
| 46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
|
| 48 |
except Exception as e:
|
|
|
|
| 49 |
raise HTTPException(status_code=500, detail="Error generating response. Please try again later.")
|
|
|
|
| 1 |
+
from fastapi import APIRouter, HTTPException, Depends
|
| 2 |
+
from fastapi.responses import JSONResponse
|
| 3 |
+
from services import llm_model_service, pinecone_service, embedding_service
|
| 4 |
from services.schemas import ConversationInput
|
| 5 |
+
from utils import logger
|
| 6 |
|
| 7 |
+
logger = logger.get_logger()
|
|
|
|
|
|
|
| 8 |
|
| 9 |
router = APIRouter(prefix="/chat", tags=["Chat"])
|
| 10 |
|
| 11 |
+
@router.post("/get-health-advice", response_model=dict)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
async def get_health_advice(input_data: ConversationInput):
|
| 13 |
"""
|
| 14 |
Handles requests from the frontend and fetches advice using the `get_health_advice()` function.
|
|
|
|
| 16 |
Args:
|
| 17 |
- input_data (ConversationInput): User's conversation history.
|
| 18 |
|
| 19 |
+
Example Input:
|
| 20 |
+
{
|
| 21 |
+
"conversation_history": [
|
| 22 |
+
{"role": "user", "content": "I've been feeling tired lately. What should I do?"},
|
| 23 |
+
{"role": "assistant", "content": "Are you experiencing any other symptoms?"},
|
| 24 |
+
{"role": "user", "content": "No, I just feel drained even after sleeping well."}
|
| 25 |
+
]
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
Returns:
|
| 29 |
- dict: Contains 'reply' with the assistant's response.
|
| 30 |
+
|
| 31 |
+
Raises:
|
| 32 |
+
- HTTPException (400): If conversation history or user query is missing.
|
| 33 |
+
- HTTPException (500): If an internal error occurs during response generation.
|
| 34 |
"""
|
| 35 |
+
if not input_data.conversation_history:
|
| 36 |
+
logger.warning("Empty conversation history received.")
|
| 37 |
+
raise HTTPException(status_code=400, detail="Conversation history cannot be empty.")
|
| 38 |
+
|
| 39 |
try:
|
| 40 |
+
last_entry = input_data.conversation_history[-1]
|
| 41 |
+
if not isinstance(last_entry, dict) or last_entry.get("role") != "user":
|
| 42 |
+
logger.warning("Invalid conversation entry format or missing user query.")
|
| 43 |
+
raise HTTPException(status_code=400, detail="Invalid conversation entry or missing user query.")
|
| 44 |
+
|
| 45 |
+
user_query = last_entry.get("content")
|
| 46 |
+
if not user_query:
|
| 47 |
+
logger.warning("User query content is missing in the conversation history.")
|
| 48 |
+
raise HTTPException(status_code=400, detail="User query content cannot be empty.")
|
| 49 |
+
|
| 50 |
+
logger.info(f"Received user query: {user_query}")
|
| 51 |
+
query_embeddings = embedding_service.get_text_embedding(user_query)
|
| 52 |
+
|
| 53 |
+
db_response = pinecone_service.retrieve_context_from_pinecone(query_embeddings)
|
| 54 |
+
logger.info("Fetched DB response successfully.")
|
| 55 |
+
|
| 56 |
+
assistant_reply = llm_model_service.get_health_advice(
|
| 57 |
+
user_query, db_response, input_data.conversation_history
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
if not assistant_reply:
|
| 61 |
+
logger.warning("Assistant generated an empty response.")
|
| 62 |
+
raise HTTPException(status_code=500, detail="Assistant generated an empty response.")
|
| 63 |
+
|
| 64 |
+
logger.info("Health advice generated successfully.")
|
| 65 |
+
return JSONResponse(content={"reply": assistant_reply}, status_code=200)
|
| 66 |
+
|
| 67 |
+
except HTTPException as http_exc:
|
| 68 |
+
logger.error(f"HTTPException occurred: {http_exc.detail}")
|
| 69 |
+
raise http_exc
|
| 70 |
|
| 71 |
except Exception as e:
|
| 72 |
+
logger.error(f"Unexpected error: {e}", exc_info=True)
|
| 73 |
raise HTTPException(status_code=500, detail="Error generating response. Please try again later.")
|
src/backend/api_routes/knowledge_base_api.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
from fastapi import APIRouter,HTTPException
|
| 2 |
from data import pinecone_db
|
| 3 |
from models.schemas import UpsertRequest,DeleteRequest,MetadataRequest
|
| 4 |
-
from data import pinecone_db
|
| 5 |
import pandas as pd
|
| 6 |
|
| 7 |
router = APIRouter(prefix="/knowledge-base", tags=['Knowledge Base Operations'])
|
|
|
|
| 1 |
from fastapi import APIRouter,HTTPException
|
| 2 |
from data import pinecone_db
|
| 3 |
from models.schemas import UpsertRequest,DeleteRequest,MetadataRequest
|
|
|
|
| 4 |
import pandas as pd
|
| 5 |
|
| 6 |
router = APIRouter(prefix="/knowledge-base", tags=['Knowledge Base Operations'])
|
src/backend/chatbot.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
| 1 |
-
from services.pinecone_service import retrieve_relevant_metadata
|
| 2 |
-
from services.supabase_service import store_chat_history
|
| 3 |
-
from sentence_transformers import CrossEncoder
|
| 4 |
-
|
| 5 |
-
reranker = CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2')
|
| 6 |
-
|
| 7 |
-
def rerank_results(query, results):
|
| 8 |
-
pairs = [(query, result["metadata"]["text"]) for result in results]
|
| 9 |
-
scores = reranker.predict(pairs)
|
| 10 |
-
return [x for _, x in sorted(zip(scores, results), key=lambda pair: pair[0], reverse=True)]
|
| 11 |
-
|
| 12 |
-
def chatbot_response(query):
|
| 13 |
-
results = retrieve_relevant_metadata(query)
|
| 14 |
-
if results:
|
| 15 |
-
reranked_results = rerank_results(query, results)
|
| 16 |
-
best_answer = reranked_results[0]["metadata"]["question"]
|
| 17 |
-
else:
|
| 18 |
-
best_answer = "I'm sorry, I couldn't find an answer for your query."
|
| 19 |
-
|
| 20 |
-
# store_chat_history(query, best_answer)
|
| 21 |
-
return best_answer
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/backend/data/__pycache__/pinecone_db.cpython-313.pyc
CHANGED
|
Binary files a/src/backend/data/__pycache__/pinecone_db.cpython-313.pyc and b/src/backend/data/__pycache__/pinecone_db.cpython-313.pyc differ
|
|
|
src/backend/main.py
CHANGED
|
@@ -1,17 +1,30 @@
|
|
| 1 |
from fastapi import FastAPI
|
|
|
|
| 2 |
from api_routes.chat_api import router as chat_router
|
| 3 |
-
from api_routes.knowledge_base_api import router as knowledge_base_router
|
| 4 |
-
from api_routes.chat_history_db_api import router as chat_history_router
|
| 5 |
|
| 6 |
app = FastAPI(
|
| 7 |
title="Yuvabe Care Companion AI",
|
| 8 |
description="A chatbot for health-related queries"
|
| 9 |
)
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
# Register Routes
|
| 12 |
app.include_router(chat_router)
|
| 13 |
-
app.include_router(knowledge_base_router)
|
| 14 |
-
app.include_router(chat_history_router)
|
| 15 |
|
| 16 |
# Health Check Endpoint
|
| 17 |
@app.get("/health", tags=["Health Check"])
|
|
|
|
| 1 |
from fastapi import FastAPI
|
| 2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 3 |
from api_routes.chat_api import router as chat_router
|
| 4 |
+
# from api_routes.knowledge_base_api import router as knowledge_base_router
|
| 5 |
+
# from api_routes.chat_history_db_api import router as chat_history_router
|
| 6 |
|
| 7 |
app = FastAPI(
|
| 8 |
title="Yuvabe Care Companion AI",
|
| 9 |
description="A chatbot for health-related queries"
|
| 10 |
)
|
| 11 |
|
| 12 |
+
app.add_middleware(
|
| 13 |
+
CORSMiddleware,
|
| 14 |
+
allow_origins=["*"],
|
| 15 |
+
allow_methods=["*"],
|
| 16 |
+
allow_headers=["*"],
|
| 17 |
+
expose_headers=["Cache-Control"],
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
@app.get("/", tags=["Root"])
|
| 21 |
+
def read_root():
|
| 22 |
+
return {"message": "Hello World"}
|
| 23 |
+
|
| 24 |
# Register Routes
|
| 25 |
app.include_router(chat_router)
|
| 26 |
+
# app.include_router(knowledge_base_router)
|
| 27 |
+
# app.include_router(chat_history_router)
|
| 28 |
|
| 29 |
# Health Check Endpoint
|
| 30 |
@app.get("/health", tags=["Health Check"])
|
src/backend/models/__pycache__/embedding_model.cpython-313.pyc
DELETED
|
Binary file (1.13 kB)
|
|
|
src/backend/models/__pycache__/llm_model.cpython-313.pyc
DELETED
|
Binary file (6.42 kB)
|
|
|
src/backend/models/__pycache__/schemas.cpython-313.pyc
DELETED
|
Binary file (2.01 kB)
|
|
|
src/backend/models/embedding_model.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
| 1 |
-
from sentence_transformers import SentenceTransformer
|
| 2 |
-
from utils import logger
|
| 3 |
-
|
| 4 |
-
logger = logger.get_logger()
|
| 5 |
-
|
| 6 |
-
model = SentenceTransformer("all-MiniLM-L6-v2")
|
| 7 |
-
|
| 8 |
-
def get_text_embedding(search_query: str):
|
| 9 |
-
try:
|
| 10 |
-
text_embedding = model.encode(search_query, convert_to_tensor=True).cpu().numpy().tolist()
|
| 11 |
-
logger.info("Text embedding successfully retrieved.")
|
| 12 |
-
return text_embedding
|
| 13 |
-
except Exception as e:
|
| 14 |
-
logger.error(f"Error while getting embedding for text: {e}")
|
| 15 |
-
raise
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/backend/models/schemas.py
DELETED
|
@@ -1,26 +0,0 @@
|
|
| 1 |
-
from pydantic import BaseModel
|
| 2 |
-
from typing import List,Dict, Optional
|
| 3 |
-
|
| 4 |
-
class Chat_Response(BaseModel):
|
| 5 |
-
prompt: Optional[List] = None
|
| 6 |
-
response: Optional[Dict] = None
|
| 7 |
-
|
| 8 |
-
class UpsertRequest(BaseModel):
|
| 9 |
-
data: list # Expecting a list of JSON objects (rows of data)
|
| 10 |
-
|
| 11 |
-
class DeleteRequest(BaseModel):
|
| 12 |
-
ids_to_delete: list
|
| 13 |
-
|
| 14 |
-
class MetadataRequest(BaseModel):
|
| 15 |
-
prompt: str
|
| 16 |
-
n_result: int = 3
|
| 17 |
-
score_threshold: float = 0.45
|
| 18 |
-
|
| 19 |
-
class ChatRequest(BaseModel):
|
| 20 |
-
query: str
|
| 21 |
-
|
| 22 |
-
class ChatResponse(BaseModel):
|
| 23 |
-
response: str
|
| 24 |
-
|
| 25 |
-
class ChatHistoryResponse(BaseModel):
|
| 26 |
-
date: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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__/llm_model_service.cpython-313.pyc
CHANGED
|
Binary files a/src/backend/services/__pycache__/llm_model_service.cpython-313.pyc and b/src/backend/services/__pycache__/llm_model_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__/schemas.cpython-313.pyc
CHANGED
|
Binary files a/src/backend/services/__pycache__/schemas.cpython-313.pyc and b/src/backend/services/__pycache__/schemas.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/llm_model_service.py
CHANGED
|
@@ -1,66 +1,124 @@
|
|
| 1 |
import os
|
|
|
|
| 2 |
from groq import Groq
|
| 3 |
from dotenv import load_dotenv
|
| 4 |
-
from services import pinecone_service
|
| 5 |
from utils import logger
|
| 6 |
|
|
|
|
| 7 |
logger = logger.get_logger()
|
| 8 |
|
|
|
|
| 9 |
load_dotenv()
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
{"role": "system", "content": "
|
| 21 |
-
{"role": "system", "content": "
|
| 22 |
-
{"role": "system", "content":"
|
| 23 |
-
{"role": "system", "content": "If the user asks
|
| 24 |
{"role": "system", "content": "You were created by Velu R, an AI model developer."}
|
| 25 |
]
|
| 26 |
|
| 27 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
"""
|
| 29 |
-
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
Returns:
|
| 33 |
-
- str:
|
| 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 |
response = client.chat.completions.create(
|
| 59 |
model=LLM_MODEL_NAME,
|
| 60 |
-
messages=messages
|
|
|
|
|
|
|
| 61 |
)
|
| 62 |
|
| 63 |
assistant_reply = response.choices[0].message.content.strip()
|
|
|
|
| 64 |
return assistant_reply
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
except Exception as e:
|
|
|
|
| 66 |
return "I'm sorry, but I'm unable to provide a response right now. Please try again later."
|
|
|
|
| 1 |
import os
|
| 2 |
+
from typing import List, Dict, Optional
|
| 3 |
from groq import Groq
|
| 4 |
from dotenv import load_dotenv
|
|
|
|
| 5 |
from utils import logger
|
| 6 |
|
| 7 |
+
# Logger instance
|
| 8 |
logger = logger.get_logger()
|
| 9 |
|
| 10 |
+
# Load environment variables
|
| 11 |
load_dotenv()
|
| 12 |
|
| 13 |
+
# Configuration constants
|
| 14 |
+
LLM_MODEL_NAME = os.getenv("LLM_MODEL_NAME")
|
| 15 |
+
GROQ_API_KEY = os.getenv("GROQ_API")
|
| 16 |
+
|
| 17 |
+
# Initialize Groq client
|
| 18 |
+
client = Groq(api_key=GROQ_API_KEY)
|
| 19 |
+
|
| 20 |
+
# System prompt structure s
|
| 21 |
+
SYSTEM_PROMPT: List[Dict[str, str]] = [
|
| 22 |
+
{"role": "system", "content": "You are Yuvabe Care Companion AI, an advanced healthcare assistant..."},
|
| 23 |
+
{"role": "system", "content": "Your knowledge is up-to-date with the latest medical guidelines as of July 2024..."},
|
| 24 |
+
{"role": "system", "content": "Always provide accurate, empathetic, and responsible responses..."},
|
| 25 |
+
{"role": "system", "content": "If the user asks non-healthcare questions, politely decline..."},
|
| 26 |
{"role": "system", "content": "You were created by Velu R, an AI model developer."}
|
| 27 |
]
|
| 28 |
|
| 29 |
+
# Constants for token limits and configurations
|
| 30 |
+
MAX_TOKENS = 1024
|
| 31 |
+
MAX_HISTORY_TOKENS = 1000
|
| 32 |
+
DEFAULT_TEMPERATURE = 0.7
|
| 33 |
+
|
| 34 |
+
def truncate_conversation_history(history: List[Dict[str, str]], max_tokens: int = MAX_HISTORY_TOKENS) -> List[Dict[str, str]]:
|
| 35 |
"""
|
| 36 |
+
Truncates conversation history to maintain token limits.
|
| 37 |
+
Retains the most recent interactions if token count exceeds the threshold.
|
| 38 |
+
|
| 39 |
+
Args:
|
| 40 |
+
- history (List[Dict[str, str]]): List of conversation messages
|
| 41 |
+
- max_tokens (int): Maximum allowable tokens for conversation history
|
| 42 |
|
| 43 |
Returns:
|
| 44 |
+
- List[Dict[str, str]]: Truncated conversation history
|
| 45 |
"""
|
| 46 |
+
total_tokens = sum(len(msg["content"]) for msg in history)
|
| 47 |
+
if total_tokens > max_tokens:
|
| 48 |
+
logger.warning(f"Conversation history exceeds {max_tokens} tokens. Truncating...")
|
| 49 |
+
while total_tokens > max_tokens and history:
|
| 50 |
+
history.pop(0)
|
| 51 |
+
total_tokens = sum(len(msg["content"]) for msg in history)
|
| 52 |
+
return history
|
| 53 |
+
|
| 54 |
+
def build_prompt(
|
| 55 |
+
user_query: str,
|
| 56 |
+
db_response: Optional[str],
|
| 57 |
+
conversation_history: List[Dict[str, str]]
|
| 58 |
+
) -> List[Dict[str, str]]:
|
| 59 |
+
"""
|
| 60 |
+
Constructs the message prompt for the LLM with system prompts, context, and user queries.
|
| 61 |
+
|
| 62 |
+
Args:
|
| 63 |
+
- user_query (str): The query entered by the user
|
| 64 |
+
- db_response (Optional[str]): Context retrieved from the vector database
|
| 65 |
+
- conversation_history (List[Dict[str, str]]): Previous conversation history
|
| 66 |
+
|
| 67 |
+
Returns:
|
| 68 |
+
- List[Dict[str, str]]: Constructed prompt messages
|
| 69 |
+
"""
|
| 70 |
+
conversation_history = truncate_conversation_history(conversation_history)
|
| 71 |
|
| 72 |
+
if db_response and "No relevant information found" not in db_response:
|
| 73 |
+
return SYSTEM_PROMPT + [
|
| 74 |
+
{"role": "system", "content": f"Relevant Context: {db_response}"},
|
| 75 |
+
{"role": "user", "content": user_query}
|
| 76 |
+
] + conversation_history
|
| 77 |
+
else:
|
| 78 |
+
return SYSTEM_PROMPT + [
|
| 79 |
+
{"role": "system", "content": "Please respond using your internal medical knowledge."},
|
| 80 |
+
{"role": "user", "content": user_query}
|
| 81 |
+
] + conversation_history
|
| 82 |
+
|
| 83 |
+
def get_health_advice(
|
| 84 |
+
user_query: str,
|
| 85 |
+
db_response: Optional[str],
|
| 86 |
+
conversation_history: List[Dict[str, str]]
|
| 87 |
+
) -> str:
|
| 88 |
+
"""
|
| 89 |
+
Generates a healthcare-related response using context from the vector database
|
| 90 |
+
or the LLM's internal knowledge.
|
| 91 |
+
|
| 92 |
+
Args:
|
| 93 |
+
- user_query (str): The user's question or statement
|
| 94 |
+
- db_response (Optional[str]): Retrieved context for the query
|
| 95 |
+
- conversation_history (List[Dict[str, str]]): History of the conversation
|
| 96 |
+
|
| 97 |
+
Returns:
|
| 98 |
+
- str: The assistant's response
|
| 99 |
+
"""
|
| 100 |
+
try:
|
| 101 |
+
messages = build_prompt(user_query, db_response, conversation_history)
|
| 102 |
+
|
| 103 |
response = client.chat.completions.create(
|
| 104 |
model=LLM_MODEL_NAME,
|
| 105 |
+
messages=messages,
|
| 106 |
+
max_tokens=MAX_TOKENS,
|
| 107 |
+
temperature=DEFAULT_TEMPERATURE
|
| 108 |
)
|
| 109 |
|
| 110 |
assistant_reply = response.choices[0].message.content.strip()
|
| 111 |
+
logger.info(f"Generated response: {assistant_reply}")
|
| 112 |
return assistant_reply
|
| 113 |
+
|
| 114 |
+
except (ConnectionError, TimeoutError) as e:
|
| 115 |
+
logger.error(f"Network error: {e}")
|
| 116 |
+
return "I'm currently unable to connect to the system. Please try again later."
|
| 117 |
+
|
| 118 |
+
except KeyError as e:
|
| 119 |
+
logger.error(f"Unexpected response structure: {e}")
|
| 120 |
+
return "I'm sorry, but I couldn't process your request at the moment."
|
| 121 |
+
|
| 122 |
except Exception as e:
|
| 123 |
+
logger.error(f"Unexpected error occurred: {e}")
|
| 124 |
return "I'm sorry, but I'm unable to provide a response right now. Please try again later."
|
src/backend/services/pinecone_service.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 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
|
|
@@ -225,11 +225,9 @@ def upsert_vector_data(df: pd.DataFrame):
|
|
| 225 |
|
| 226 |
logger.info("All question-answer pairs stored successfully!")
|
| 227 |
|
| 228 |
-
def retrieve_context_from_pinecone(
|
| 229 |
|
| 230 |
index = initialize_pinecone_index(PINECONE,INDEX_NAME)
|
| 231 |
-
# Generate embedding for the provided prompt
|
| 232 |
-
embedding = get_text_embedding(prompt)
|
| 233 |
# Query Pinecone for relevant context
|
| 234 |
response = index.query(
|
| 235 |
top_k=n_result,
|
|
|
|
| 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
|
|
|
|
| 225 |
|
| 226 |
logger.info("All question-answer pairs stored successfully!")
|
| 227 |
|
| 228 |
+
def retrieve_context_from_pinecone(embedding, n_result=3, score_threshold=0.5):
|
| 229 |
|
| 230 |
index = initialize_pinecone_index(PINECONE,INDEX_NAME)
|
|
|
|
|
|
|
| 231 |
# Query Pinecone for relevant context
|
| 232 |
response = index.query(
|
| 233 |
top_k=n_result,
|
src/backend/services/schemas.py
CHANGED
|
@@ -1,9 +1,39 @@
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
-
from typing import List
|
| 3 |
|
| 4 |
class ConversationInput(BaseModel):
|
| 5 |
conversation_history: list[dict]
|
| 6 |
|
| 7 |
class ChatHistoryRequest(BaseModel):
|
| 8 |
conversation_id: str
|
| 9 |
-
messages: List[dict]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from pydantic import BaseModel
|
| 2 |
+
from typing import List,Dict, Optional
|
| 3 |
|
| 4 |
class ConversationInput(BaseModel):
|
| 5 |
conversation_history: list[dict]
|
| 6 |
|
| 7 |
class ChatHistoryRequest(BaseModel):
|
| 8 |
conversation_id: str
|
| 9 |
+
messages: List[dict]
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class Chat_Response(BaseModel):
|
| 18 |
+
prompt: Optional[List] = None
|
| 19 |
+
response: Optional[Dict] = None
|
| 20 |
+
|
| 21 |
+
class UpsertRequest(BaseModel):
|
| 22 |
+
data: list # Expecting a list of JSON objects (rows of data)
|
| 23 |
+
|
| 24 |
+
class DeleteRequest(BaseModel):
|
| 25 |
+
ids_to_delete: list
|
| 26 |
+
|
| 27 |
+
class MetadataRequest(BaseModel):
|
| 28 |
+
prompt: str
|
| 29 |
+
n_result: int = 3
|
| 30 |
+
score_threshold: float = 0.45
|
| 31 |
+
|
| 32 |
+
class ChatRequest(BaseModel):
|
| 33 |
+
query: str
|
| 34 |
+
|
| 35 |
+
class ChatResponse(BaseModel):
|
| 36 |
+
response: str
|
| 37 |
+
|
| 38 |
+
class ChatHistoryResponse(BaseModel):
|
| 39 |
+
date: str
|
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/pages/chatbot.py
CHANGED
|
@@ -29,12 +29,12 @@ def fetch_health_advice(conversation_history):
|
|
| 29 |
if "conversation_history" not in st.session_state:
|
| 30 |
st.session_state.conversation_history = initialize_conversation()
|
| 31 |
|
| 32 |
-
#
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
|
| 39 |
# User Input
|
| 40 |
user_input = st.chat_input("Ask your health-related question:")
|
|
|
|
| 29 |
if "conversation_history" not in st.session_state:
|
| 30 |
st.session_state.conversation_history = initialize_conversation()
|
| 31 |
|
| 32 |
+
# Display chat history
|
| 33 |
+
for message in st.session_state.conversation_history [-NUMBER_OF_MESSAGES_TO_DISPLAY:]:
|
| 34 |
+
role = message["role"]
|
| 35 |
+
avatar_image = "src/frontend/images/page_icon.jpg" if role == "assistant" else "src/frontend/images/page_icon.jpg" if role == "user" else None
|
| 36 |
+
with st.chat_message(role, avatar=avatar_image):
|
| 37 |
+
st.write(message["content"])
|
| 38 |
|
| 39 |
# User Input
|
| 40 |
user_input = st.chat_input("Ask your health-related question:")
|