Spaces:
Sleeping
Sleeping
Commit
·
8828f20
1
Parent(s):
5aeecfe
Add application file
Browse files- .huggingface.yml +4 -0
- Dockerfile +19 -0
- app.py +305 -0
- clear_mongo.py +48 -0
- connect_mongo.py +24 -0
- migrate.py +48 -0
- requirements.txt +20 -0
.huggingface.yml
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
sdk: docker
|
2 |
+
app_file: main.py
|
3 |
+
port: 7860
|
4 |
+
hardware: cpu-basic
|
Dockerfile
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
|
3 |
+
# Create and use a non-root user
|
4 |
+
RUN useradd -m -u 1000 user
|
5 |
+
USER user
|
6 |
+
ENV PATH="/home/user/.local/bin:$PATH"
|
7 |
+
|
8 |
+
# Set working directory
|
9 |
+
WORKDIR /app
|
10 |
+
|
11 |
+
# Copy and install dependencies
|
12 |
+
COPY --chown=user ./requirements.txt requirements.txt
|
13 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
14 |
+
|
15 |
+
# Load environment variables
|
16 |
+
ENV ENV_PATH="/app/.env"
|
17 |
+
|
18 |
+
# Run server with uvicorn
|
19 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
app.py
ADDED
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ==========================
|
2 |
+
# Medical Chatbot Backend (Gemini Flash API + RAG) - Local Prebuilt Model with FAISS Index & Data Stored in MongoDB
|
3 |
+
# ==========================
|
4 |
+
"""
|
5 |
+
This script loads:
|
6 |
+
1) A FAISS index stored in MongoDB (in the "faiss_index" collection)
|
7 |
+
2) A local SentenceTransformer model (downloaded via snapshot_download)
|
8 |
+
3) QA data (the full dataset of 256916 QA entries) stored in MongoDB (in the "qa_data" collection)
|
9 |
+
|
10 |
+
If the QA data or FAISS index are not found in MongoDB, the script loads the full dataset from Hugging Face,
|
11 |
+
computes embeddings for all QA pairs (concatenating the "Patient" and "Doctor" fields), and stores both the raw QA data
|
12 |
+
and the FAISS index in MongoDB.
|
13 |
+
|
14 |
+
The chatbot instructs Gemini Flash to format its answer using markdown.
|
15 |
+
"""
|
16 |
+
|
17 |
+
import os
|
18 |
+
import faiss
|
19 |
+
import numpy as np
|
20 |
+
import gc
|
21 |
+
import time
|
22 |
+
from fastapi import FastAPI
|
23 |
+
from fastapi.responses import HTMLResponse, JSONResponse
|
24 |
+
from pathlib import Path
|
25 |
+
# import streamlit as st
|
26 |
+
# import threading
|
27 |
+
# import requests
|
28 |
+
from dotenv import load_dotenv
|
29 |
+
|
30 |
+
# 🔹 Load environment variables from .env
|
31 |
+
load_dotenv()
|
32 |
+
gemini_flash_api_key = os.getenv("FlashAPI")
|
33 |
+
mongo_uri = os.getenv("MONGO_URI")
|
34 |
+
index_uri = os.getenv("INDEX_URI")
|
35 |
+
# 🔹 Load Streamlit secrets from .toml
|
36 |
+
# gemini_flash_api_key = st.secrets["general"]["FlashAPI"]
|
37 |
+
# mongo_uri = st.secrets["general"]["MONGO_URI"]
|
38 |
+
# index_uri = st.secrets["general"]["INDEX_URI"]
|
39 |
+
if not gemini_flash_api_key:
|
40 |
+
raise ValueError("❌ Gemini Flash API key (FlashAPI) is missing!")
|
41 |
+
# st.error("❌ Gemini Flash API key (FlashAPI) is missing!")
|
42 |
+
# st.stop() # Prevent the app from running without necessary API keys
|
43 |
+
if not mongo_uri:
|
44 |
+
raise ValueError("❌ MongoDB URI (MongoURI) is missing!")
|
45 |
+
# st.error("❌ MongoDB URI (MongoURI) is missing!")
|
46 |
+
# st.stop() # Prevent the app from running without necessary API keys
|
47 |
+
if not index_uri:
|
48 |
+
raise ValueError("❌ INDEX_URI for FAISS index cluster is missing!")
|
49 |
+
# st.error("❌ INDEX_URI for FAISS index cluster is missing!")
|
50 |
+
# st.stop() # Prevent the app from running without necessary API keys
|
51 |
+
|
52 |
+
# 1. Environment variables to mitigate segmentation faults
|
53 |
+
os.environ["OMP_NUM_THREADS"] = "1"
|
54 |
+
os.environ["MKL_NUM_THREADS"] = "1"
|
55 |
+
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
56 |
+
# 2. Setup local project directory (for model cache)
|
57 |
+
project_dir = "./AutoGenRAGMedicalChatbot"
|
58 |
+
os.makedirs(project_dir, exist_ok=True)
|
59 |
+
huggingface_cache_dir = os.path.join(project_dir, "huggingface_models")
|
60 |
+
os.environ["HF_HOME"] = huggingface_cache_dir # Use this folder for HF cache
|
61 |
+
# 3. Download (or load from cache) the SentenceTransformer model
|
62 |
+
from huggingface_hub import snapshot_download
|
63 |
+
print("⏳ Checking or downloading the all-MiniLM-L6-v2 model from huggingface_hub...")
|
64 |
+
# st.write("⏳ Checking or downloading the all-MiniLM-L6-v2 model from huggingface_hub...")
|
65 |
+
model_loc = snapshot_download(
|
66 |
+
repo_id="sentence-transformers/all-MiniLM-L6-v2",
|
67 |
+
cache_dir=os.environ["HF_HOME"],
|
68 |
+
local_files_only=False
|
69 |
+
)
|
70 |
+
print(f"✅ Model directory: {model_loc}")
|
71 |
+
# st.write(f"✅ Model directory: {model_loc}")
|
72 |
+
|
73 |
+
from sentence_transformers import SentenceTransformer
|
74 |
+
print("📥 **Loading Embedding Model...**")
|
75 |
+
# st.write("📥 **Loading Embedding Model...**")
|
76 |
+
embedding_model = SentenceTransformer(model_loc, device="cpu")
|
77 |
+
|
78 |
+
# 🔹 MongoDB Setup
|
79 |
+
from pymongo import MongoClient
|
80 |
+
# 1. QA client
|
81 |
+
client = MongoClient(mongo_uri)
|
82 |
+
db = client["MedicalChatbotDB"] # Use your chosen database name
|
83 |
+
qa_collection = db["qa_data"]
|
84 |
+
# 2. FAISS index client
|
85 |
+
iclient = MongoClient(index_uri)
|
86 |
+
idb = iclient["MedicalChatbotDB"] # Use your chosen database name
|
87 |
+
index_collection = idb["faiss_index_files"]
|
88 |
+
|
89 |
+
##---------------------------##
|
90 |
+
## EMBEDDING AND DATA RETRIEVAL
|
91 |
+
##---------------------------##
|
92 |
+
|
93 |
+
# 🔹 Load or Build QA Data in MongoDB
|
94 |
+
print("⏳ Checking MongoDB for existing QA data...")
|
95 |
+
# st.write("⏳ Checking MongoDB for existing QA data...")
|
96 |
+
if qa_collection.count_documents({}) == 0:
|
97 |
+
print("⚠️ QA data not found in MongoDB. Loading dataset from Hugging Face...")
|
98 |
+
# st.write("⚠️ QA data not found in MongoDB. Loading dataset from Hugging Face...")
|
99 |
+
from datasets import load_dataset
|
100 |
+
dataset = load_dataset("ruslanmv/ai-medical-chatbot", cache_dir=huggingface_cache_dir)
|
101 |
+
df = dataset["train"].to_pandas()[["Patient", "Doctor"]]
|
102 |
+
# Add an index column "i" to preserve order.
|
103 |
+
df["i"] = range(len(df))
|
104 |
+
qa_data = df.to_dict("records")
|
105 |
+
# Insert in batches (e.g., batches of 1000) to avoid document size limits.
|
106 |
+
batch_size = 1000
|
107 |
+
for i in range(0, len(qa_data), batch_size):
|
108 |
+
qa_collection.insert_many(qa_data[i:i+batch_size])
|
109 |
+
print(f"📦 QA data stored in MongoDB. Total entries: {len(qa_data)}")
|
110 |
+
# st.write(f"📦 QA data stored in MongoDB. Total entries: {len(qa_data)}")
|
111 |
+
else:
|
112 |
+
print("✅ Loaded existing QA data from MongoDB.")
|
113 |
+
# st.write("✅ Loaded existing QA data from MongoDB.")
|
114 |
+
# Use an aggregation pipeline with allowDiskUse to sort by "i" without creating an index.
|
115 |
+
qa_docs = list(qa_collection.aggregate([
|
116 |
+
{"$sort": {"i": 1}},
|
117 |
+
{"$project": {"_id": 0}}
|
118 |
+
], allowDiskUse=True))
|
119 |
+
qa_data = qa_docs
|
120 |
+
print("📦 Total QA entries loaded:", len(qa_data))
|
121 |
+
# st.write("📦 Total QA entries loaded:", len(qa_data))
|
122 |
+
|
123 |
+
# 🔹 Build or Load the FAISS Index from MongoDB using GridFS (on the separate cluster)
|
124 |
+
print("⏳ Checking GridFS for existing FAISS index...")
|
125 |
+
# st.write("⏳ Checking GridFS for existing FAISS index...")
|
126 |
+
import gridfs
|
127 |
+
fs = gridfs.GridFS(idb, collection="faiss_index_files") # 'idb' is connected using INDEX_URI
|
128 |
+
# 1. Find the FAISS index file by filename.
|
129 |
+
existing_file = fs.find_one({"filename": "faiss_index.bin"})
|
130 |
+
if existing_file is None:
|
131 |
+
print("⚠️ FAISS index not found in GridFS. Building FAISS index from QA data...")
|
132 |
+
# st.write("⚠️ FAISS index not found in GridFS. Building FAISS index from QA data...")
|
133 |
+
# Compute embeddings for each QA pair by concatenating "Patient" and "Doctor" fields.
|
134 |
+
texts = [item.get("Patient", "") + " " + item.get("Doctor", "") for item in qa_data]
|
135 |
+
batch_size = 512 # Adjust as needed
|
136 |
+
embeddings_list = []
|
137 |
+
for i in range(0, len(texts), batch_size):
|
138 |
+
batch = texts[i:i+batch_size]
|
139 |
+
batch_embeddings = embedding_model.encode(batch, convert_to_numpy=True).astype(np.float32)
|
140 |
+
embeddings_list.append(batch_embeddings)
|
141 |
+
print(f"Encoded batch {i} to {i + len(batch)}")
|
142 |
+
# st.write(f"Encoded batch {i} to {i + len(batch)}")
|
143 |
+
embeddings = np.vstack(embeddings_list)
|
144 |
+
dim = embeddings.shape[1]
|
145 |
+
# Create a FAISS index (using IndexHNSWFlat; or use IVFPQ for compression)
|
146 |
+
index = faiss.IndexHNSWFlat(dim, 32)
|
147 |
+
index.add(embeddings)
|
148 |
+
print("FAISS index built. Total vectors:", index.ntotal)
|
149 |
+
# Serialize the index
|
150 |
+
index_bytes = faiss.serialize_index(index)
|
151 |
+
index_data = np.frombuffer(index_bytes, dtype='uint8').tobytes()
|
152 |
+
# Store in GridFS (this bypasses the 16 MB limit)
|
153 |
+
file_id = fs.put(index_data, filename="faiss_index.bin")
|
154 |
+
print("📦 FAISS index built and stored in GridFS with file_id:", file_id)
|
155 |
+
# st.write("📦 FAISS index built and stored in GridFS with file_id:", file_id)
|
156 |
+
del embeddings
|
157 |
+
gc.collect()
|
158 |
+
else:
|
159 |
+
print("✅ Found FAISS index in GridFS. Loading...")
|
160 |
+
# st.write("✅ Found FAISS index in GridFS. Loading...")
|
161 |
+
stored_index_bytes = existing_file.read()
|
162 |
+
index_bytes_np = np.frombuffer(stored_index_bytes, dtype='uint8')
|
163 |
+
index = faiss.deserialize_index(index_bytes_np)
|
164 |
+
print("📦 FAISS index loaded from GridFS successfully!")
|
165 |
+
# st.write("📦 FAISS index loaded from GridFS successfully!")
|
166 |
+
|
167 |
+
|
168 |
+
##---------------------------##
|
169 |
+
## INFERENCE BACK+FRONT END
|
170 |
+
##---------------------------##
|
171 |
+
|
172 |
+
# 🔹 Prepare Retrieval and Chat Logic
|
173 |
+
def retrieve_medical_info(query):
|
174 |
+
"""Retrieve relevant medical knowledge using the FAISS index."""
|
175 |
+
query_embedding = embedding_model.encode([query], convert_to_numpy=True)
|
176 |
+
_, idxs = index.search(query_embedding, k=3)
|
177 |
+
results = []
|
178 |
+
for i in idxs[0]:
|
179 |
+
if i < len(qa_data):
|
180 |
+
results.append(qa_data[i].get("Doctor", "No answer available."))
|
181 |
+
else:
|
182 |
+
results.append("No answer available.")
|
183 |
+
return results
|
184 |
+
|
185 |
+
# 🔹 Gemini Flash API Call
|
186 |
+
from google import genai
|
187 |
+
def gemini_flash_completion(prompt, model, temperature=0.7):
|
188 |
+
client_genai = genai.Client(api_key=gemini_flash_api_key)
|
189 |
+
try:
|
190 |
+
response = client_genai.models.generate_content(model=model, contents=prompt)
|
191 |
+
return response.text
|
192 |
+
except Exception as e:
|
193 |
+
print(f"⚠️ Error calling Gemini API: {e}")
|
194 |
+
# st.error(f"⚠️ Error calling Gemini API: {e}")
|
195 |
+
return "Error generating response from Gemini."
|
196 |
+
|
197 |
+
# Define a simple language mapping (modify or add more as needed)
|
198 |
+
language_map = {
|
199 |
+
"EN": "English",
|
200 |
+
"VI": "Vietnamese",
|
201 |
+
"ZH": "Chinese"
|
202 |
+
}
|
203 |
+
|
204 |
+
# 🔹 Chatbot Class
|
205 |
+
class RAGMedicalChatbot:
|
206 |
+
def __init__(self, model_name, retrieve_function):
|
207 |
+
self.model_name = model_name
|
208 |
+
self.retrieve = retrieve_function
|
209 |
+
|
210 |
+
def chat(self, user_query, lang="EN"):
|
211 |
+
retrieved_info = self.retrieve(user_query)
|
212 |
+
knowledge_base = "\n".join(retrieved_info)
|
213 |
+
# Construct prompt for Gemini Flash
|
214 |
+
prompt = (
|
215 |
+
"Please format your answer using markdown. Use **bold** for titles, *italic* for emphasis, "
|
216 |
+
"and ensure that headings and paragraphs are clearly separated.\n\n"
|
217 |
+
f"Using the following medical knowledge:\n{knowledge_base} \n(trained with 256,916 data entries).\n\n"
|
218 |
+
f"Answer the following question in a professional and medically accurate manner:\n{user_query}.\n\n"
|
219 |
+
f"Your response answer must be in {lang} language."
|
220 |
+
)
|
221 |
+
completion = gemini_flash_completion(prompt, model=self.model_name, temperature=0.7)
|
222 |
+
return completion.strip()
|
223 |
+
|
224 |
+
# 🔹 Model Class (change to others if needed)
|
225 |
+
chatbot = RAGMedicalChatbot(
|
226 |
+
model_name="gemini-2.0-flash",
|
227 |
+
retrieve_function=retrieve_medical_info
|
228 |
+
)
|
229 |
+
print("✅ Medical chatbot is ready! 🤖")
|
230 |
+
# st.success("✅ Medical chatbot is ready! 🤖")
|
231 |
+
|
232 |
+
# 🔹 FastAPI Server
|
233 |
+
# from fastapi.staticfiles import StaticFiles
|
234 |
+
from fastapi.middleware.cors import CORSMiddleware # Bypassing CORS origin
|
235 |
+
app = FastAPI(title="Medical Chatbot")
|
236 |
+
# 1. Define the origins
|
237 |
+
origins = [
|
238 |
+
"http://localhost:5173", # Vite dev server
|
239 |
+
"http://localhost:3000", # Another vercel dev server
|
240 |
+
"https://medical-chatbot-henna.vercel.app", # ✅ Vercel frontend production URL
|
241 |
+
|
242 |
+
]
|
243 |
+
# 2. Then add the CORS middleware:
|
244 |
+
app.add_middleware(
|
245 |
+
CORSMiddleware,
|
246 |
+
allow_origins=origins, # or ["*"] to allow all
|
247 |
+
allow_credentials=True,
|
248 |
+
allow_methods=["*"],
|
249 |
+
allow_headers=["*"],
|
250 |
+
)
|
251 |
+
# (02/03/2025) Move static files UI to Vercel
|
252 |
+
# 3. Mount static files (make sure the "static" folder exists and contains your images)
|
253 |
+
# app.mount("/static", StaticFiles(directory="static"), name="static")
|
254 |
+
# 4. Get statics template route
|
255 |
+
# @app.get("/", response_class=HTMLResponse)
|
256 |
+
# async def get_home():
|
257 |
+
# return HTML_CONTENT
|
258 |
+
|
259 |
+
# 🔹 Chat route
|
260 |
+
@app.post("/chat")
|
261 |
+
async def chat_endpoint(data: dict):
|
262 |
+
user_query = data.get("query", "")
|
263 |
+
lang = data.get("lang", "EN") # Expect a language code from the request
|
264 |
+
if not user_query:
|
265 |
+
return JSONResponse(content={"response": "No query provided."})
|
266 |
+
start_time = time.time()
|
267 |
+
response_text = chatbot.chat(user_query, lang) # Pass language selection
|
268 |
+
end_time = time.time()
|
269 |
+
response_text += f"\n\n(Response time: {end_time - start_time:.2f} seconds)"
|
270 |
+
return JSONResponse(content={"response": response_text})
|
271 |
+
|
272 |
+
# 🔹 Main Execution
|
273 |
+
# 1. On Streamlit (free-tier allowance 1GB)
|
274 |
+
# 🌐 Start FastAPI server in a separate thread
|
275 |
+
# def run_fastapi():
|
276 |
+
# import uvicorn
|
277 |
+
# uvicorn.run(app, host="0.0.0.0", port=8000)
|
278 |
+
# threading.Thread(target=run_fastapi, daemon=True).start()
|
279 |
+
# # 🔍 Streamlit UI for Testing
|
280 |
+
# st.title("🩺 Medical Chatbot API")
|
281 |
+
# st.info("This is a **FastAPI Backend running on Streamlit Cloud**")
|
282 |
+
# user_query = st.text_input("Enter your medical question:")
|
283 |
+
# selected_lang = st.selectbox("Select Language:", ["English (EN)", "Vietnamese (VI)", "Chinese (ZH)"])
|
284 |
+
# if st.button("Ask Doctor Bot"):
|
285 |
+
# lang_code = selected_lang.split("(")[-1].strip(")")
|
286 |
+
# st.markdown("🤖 **DocBot is thinking...**")
|
287 |
+
# # a) API request to FastAPI
|
288 |
+
# response = requests.post("http://127.0.0.1:8000/chat", json={"query": user_query, "lang": lang_code})
|
289 |
+
# response_json = response.json()
|
290 |
+
# # b) Display response
|
291 |
+
# st.markdown(response_json["response"])
|
292 |
+
|
293 |
+
# 2. On Render (free-tier allowance 521MB)
|
294 |
+
# if __name__ == "__main__":
|
295 |
+
# import uvicorn
|
296 |
+
# print("\n🩺 Starting Medical Chatbot FastAPI server...\n")
|
297 |
+
# # 🌐 Start app
|
298 |
+
# uvicorn.run(app, host="0.0.0.0", port=8000)
|
299 |
+
|
300 |
+
# 3. On Hugging Face with Gradio (limited API request)
|
301 |
+
import gradio as gr
|
302 |
+
import uvicorn
|
303 |
+
gr.mount_gradio_app(app, gr.Interface(fn=chatbot.chat, inputs=["text", "text"], outputs="text"), path="/gradio")
|
304 |
+
if __name__ == "__main__":
|
305 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
clear_mongo.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pymongo import MongoClient
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
import os
|
4 |
+
|
5 |
+
# # Load environment variables from .env
|
6 |
+
# load_dotenv()
|
7 |
+
|
8 |
+
##-------------##
|
9 |
+
# FOR QA CLUSTER
|
10 |
+
##-------------##
|
11 |
+
|
12 |
+
# mongo_uri = os.getenv("MONGO_URI")
|
13 |
+
# if not mongo_uri:
|
14 |
+
# raise ValueError("❌ MongoDB URI (MongoURI) is missing!")
|
15 |
+
|
16 |
+
# client = MongoClient(mongo_uri)
|
17 |
+
# db = client["MedicalChatbotDB"] # Use the same database name as in your main script
|
18 |
+
|
19 |
+
# # To drop just the collection storing the FAISS index:
|
20 |
+
# db.drop_collection("qa_data")
|
21 |
+
# print("Dropped collection 'qa_data' from MedicalChatbotDB.")
|
22 |
+
|
23 |
+
# # Alternatively, to drop the entire database:
|
24 |
+
# client.drop_database("MedicalChatbotDB")
|
25 |
+
# print("Dropped database 'MedicalChatbotDB'.")
|
26 |
+
|
27 |
+
|
28 |
+
##-------------##
|
29 |
+
# FOR INDEX CLUSTER
|
30 |
+
##-------------##
|
31 |
+
|
32 |
+
# Load environment variables from .env
|
33 |
+
# load_dotenv()
|
34 |
+
# index_uri = os.getenv("INDEX_URI")
|
35 |
+
# if not index_uri:
|
36 |
+
# raise ValueError("❌ MongoDB URI (IndexURI) is missing!")
|
37 |
+
|
38 |
+
# iclient = MongoClient(index_uri)
|
39 |
+
# idb = iclient["MedicalChatbotDB"] # Use the same database name as in your main script
|
40 |
+
|
41 |
+
# # To drop just the collection storing the FAISS index:
|
42 |
+
# idb.drop_collection("faiss_index_files.files")
|
43 |
+
# idb.drop_collection("faiss_index_files.chunks")
|
44 |
+
# print("Dropped collection 'faiss_index_files' and chunks from MedicalChatbotDB.")
|
45 |
+
|
46 |
+
# # Alternatively, to drop the entire database:
|
47 |
+
# iclient.drop_database("MedicalChatbotDB")
|
48 |
+
# print("Dropped database 'MedicalChatbotDB'.")
|
connect_mongo.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pymongo import MongoClient
|
2 |
+
from dotenv import load_dotenv
|
3 |
+
import os
|
4 |
+
|
5 |
+
# Test MongoDB connection, and list out all collection.
|
6 |
+
load_dotenv()
|
7 |
+
|
8 |
+
# QA Cluster
|
9 |
+
mongo_uri = os.getenv("MONGO_URI")
|
10 |
+
client = MongoClient(mongo_uri)
|
11 |
+
db = client["MedicalChatbotDB"]
|
12 |
+
# List all collection
|
13 |
+
print("QA Collection: ",db.list_collection_names())
|
14 |
+
# Count document QA related
|
15 |
+
print("QA count: ", db.qa_data.count_documents({}))
|
16 |
+
|
17 |
+
# Index Cluster
|
18 |
+
index_uri = os.getenv("INDEX_URI")
|
19 |
+
iclient = MongoClient(index_uri)
|
20 |
+
idb = iclient["MedicalChatbotDB"]
|
21 |
+
# List all collection
|
22 |
+
print("FAISS Collection: ",idb.list_collection_names())
|
23 |
+
# Count document QA related
|
24 |
+
print("Index count: ", idb.faiss_index_files.files.count_documents({}))
|
migrate.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Running this script to split FAISS index collection to the second/different cluster.
|
2 |
+
from pymongo import MongoClient
|
3 |
+
from dotenv import load_dotenv
|
4 |
+
import os
|
5 |
+
|
6 |
+
# Load environment variables from .env
|
7 |
+
load_dotenv()
|
8 |
+
# Connection strings (update as needed)
|
9 |
+
mongo_uri = os.getenv("MONGO_URI") # QA cluster connection string
|
10 |
+
index_uri = os.getenv("INDEX_URI") # FAISS index cluster connection string
|
11 |
+
|
12 |
+
if not mongo_uri:
|
13 |
+
raise ValueError("MONGO_URI is missing!")
|
14 |
+
if not index_uri:
|
15 |
+
raise ValueError("INDEX_URI is missing!")
|
16 |
+
|
17 |
+
# Connect to the QA cluster (where FAISS data was accidentally stored)
|
18 |
+
qa_client = MongoClient(mongo_uri)
|
19 |
+
qa_db = qa_client["MedicalChatbotDB"]
|
20 |
+
|
21 |
+
# Connect to the FAISS index cluster
|
22 |
+
faiss_client = MongoClient(index_uri)
|
23 |
+
faiss_db = faiss_client["MedicalChatbotDB"] # Use the same database name if desired
|
24 |
+
|
25 |
+
# Define the GridFS collections to move.
|
26 |
+
# In GridFS, files are stored in two collections: "<bucket>.files" and "<bucket>.chunks".
|
27 |
+
source_files = qa_db["faiss_index_files.files"]
|
28 |
+
source_chunks = qa_db["faiss_index_files.chunks"]
|
29 |
+
|
30 |
+
dest_files = faiss_db["faiss_index_files.files"]
|
31 |
+
dest_chunks = faiss_db["faiss_index_files.chunks"]
|
32 |
+
|
33 |
+
print("Moving FAISS index GridFS files...")
|
34 |
+
|
35 |
+
# Copy documents from the source 'files' collection
|
36 |
+
for doc in source_files.find():
|
37 |
+
dest_files.insert_one(doc)
|
38 |
+
|
39 |
+
# Copy documents from the source 'chunks' collection
|
40 |
+
for doc in source_chunks.find():
|
41 |
+
dest_chunks.insert_one(doc)
|
42 |
+
|
43 |
+
print("✅ FAISS GridFS collections moved successfully.")
|
44 |
+
|
45 |
+
# Optionally, drop the old collections from the QA cluster to free up space:
|
46 |
+
qa_db.drop_collection("faiss_index_files.files")
|
47 |
+
qa_db.drop_collection("faiss_index_files.chunks")
|
48 |
+
print("Old FAISS GridFS collections dropped from the QA cluster.")
|
requirements.txt
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# **Agents**
|
2 |
+
google-genai
|
3 |
+
huggingface_hub
|
4 |
+
# autogen-agentchat # Not using Autogen since not implementing multi-agent yet
|
5 |
+
# autogenstudio
|
6 |
+
faiss-cpu
|
7 |
+
sentence-transformers
|
8 |
+
# tiktoken # Not using OpenAI agent
|
9 |
+
# chromadb # Not used for RAG pipeline now
|
10 |
+
# datasets # Expect to load from Mongo only, no need to fetch dataset from HuggingFace unless re-embedding
|
11 |
+
# googletrans # Translate and process multi-language with LLM already
|
12 |
+
# **Environment**
|
13 |
+
python-dotenv # Not used in Streamlit deployment
|
14 |
+
pymongo
|
15 |
+
# **Deployment**
|
16 |
+
uvicorn
|
17 |
+
fastapi
|
18 |
+
gradio # On Huggingface deployment with gradio
|
19 |
+
# streamlit # On streamlit deployment with daemon
|
20 |
+
# requests
|