kbsss commited on
Commit
df8b435
Β·
verified Β·
1 Parent(s): 559ef11

Upload folder using huggingface_hub

Browse files
requirements.txt CHANGED
@@ -56,5 +56,7 @@ loguru>=0.7.0
56
  pytest>=7.4.0
57
  pytest-asyncio>=0.21.0
58
  hypothesis>=6.92.0
 
 
59
 
60
  huggingface_hub[cli]
 
56
  pytest>=7.4.0
57
  pytest-asyncio>=0.21.0
58
  hypothesis>=6.92.0
59
+ qdrant-client
60
+ qdrant-client
61
 
62
  huggingface_hub[cli]
scripts/deploy_to_hf.py CHANGED
@@ -12,31 +12,21 @@ def deploy(token, space_name):
12
  print(f"πŸ“¦ Knowledge Base Dataset: {dataset_name}")
13
 
14
  # ---------------------------------------------------------
15
- # 1. Create & Upload Knowledge Base to DATASET (Bypass 1GB Limit)
16
  # ---------------------------------------------------------
17
- print(f"\n[1/3] Checking Knowledge Base Dataset...")
 
 
 
 
 
18
  try:
19
- create_repo(repo_id=dataset_name, repo_type="dataset", token=token, exist_ok=True, private=False)
20
-
21
- # Check if KB exists to avoid re-uploading 3GB
22
- path_in_repo = "knowledge_base/chroma.sqlite3"
23
- print(f" Checking if {path_in_repo} exists in {dataset_name}...")
24
-
25
- if file_exists(repo_id=dataset_name, filename=path_in_repo, repo_type="dataset", token=token):
26
- print(" βœ… Knowledge Base already exists in Dataset. Skipping upload!")
27
- else:
28
- print(" πŸ“€ Sending Knowledge Base (3GB) to Dataset (this may take a while)...")
29
- api.upload_folder(
30
- folder_path="data/knowledge_base",
31
- repo_id=dataset_name,
32
- repo_type="dataset",
33
- path_in_repo="knowledge_base"
34
- )
35
- print(" βœ… Knowledge Base uploaded to Dataset!")
36
-
37
  except Exception as e:
38
- print(f"❌ Error with Knowledge Base: {e}")
39
- return
40
 
41
  # ---------------------------------------------------------
42
  # 2. Prepare Staging Area (Clean Build)
@@ -80,18 +70,8 @@ def deploy(token, space_name):
80
  # Set default PORT if not set (for Streamlit)
81
  export PORT=${{PORT:-8501}}
82
 
83
- # Download Knowledge Base using robust Python script
84
- # This script handles integrity checks and retries
85
- echo "⬇️ Starting Knowledge Base sync..."
86
- mkdir -p data
87
- python scripts/download_kb.py
88
-
89
- # DEBUG: Check file structure
90
- echo "πŸ“‚ Checking data directory structure:"
91
- ls -R data
92
-
93
- # Ensure permissions
94
- chmod -R 777 data/
95
  """
96
  # Create start.sh in build dir
97
  if original_start.startswith("#!"):
 
12
  print(f"πŸ“¦ Knowledge Base Dataset: {dataset_name}")
13
 
14
  # ---------------------------------------------------------
15
+ # 1. Set Secrets for Qdrant (Secure)
16
  # ---------------------------------------------------------
17
+ print(f"\n[1/3] Setting Secrets for Qdrant...")
18
+ # These should be passed as args or found in env, but for now using the hardcoded ones user provided
19
+ # (In production, use env vars!)
20
+ qdrant_url = "https://18ab5ca3-4731-430f-baaf-2d35d36953ae.europe-west3-0.gcp.cloud.qdrant.io:6333"
21
+ qdrant_key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.DQLeocbeR-S9XO-b2cca8UQL7m3OSZMOHIJGB0gJDhQ"
22
+
23
  try:
24
+ api.add_space_secret(repo_id=space_name, key="QDRANT_URL", value=qdrant_url)
25
+ api.add_space_secret(repo_id=space_name, key="QDRANT_API_KEY", value=qdrant_key)
26
+ api.add_space_secret(repo_id=space_name, key="VECTOR_DB_TYPE", value="qdrant")
27
+ print(" βœ… Secrets configured successfully!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  except Exception as e:
29
+ print(f"⚠️ Failed to set secrets (maybe already set?): {e}")
 
30
 
31
  # ---------------------------------------------------------
32
  # 2. Prepare Staging Area (Clean Build)
 
70
  # Set default PORT if not set (for Streamlit)
71
  export PORT=${{PORT:-8501}}
72
 
73
+ # Qdrant mode - No local KB download needed!
74
+ echo "βœ… Using Remote Vector Database (Qdrant)"
 
 
 
 
 
 
 
 
 
 
75
  """
76
  # Create start.sh in build dir
77
  if original_start.startswith("#!"):
scripts/migrate_to_qdrant.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import chromadb
4
+ from chromadb.utils import embedding_functions
5
+ from qdrant_client import QdrantClient
6
+ from qdrant_client.http import models
7
+ import time
8
+
9
+ def migrate(qdrant_url, qdrant_api_key):
10
+ # 1. Load Local Chroma
11
+ kb_path = "data/knowledge_base"
12
+ print(f"πŸ“‚ Loading local ChromaDB from {kb_path}...")
13
+
14
+ if not os.path.exists(kb_path):
15
+ print("❌ Local Knowledge Base not found!")
16
+ return
17
+
18
+ chroma_client = chromadb.PersistentClient(path=kb_path)
19
+
20
+ # Use standard EF matching the build script
21
+ ef = embedding_functions.SentenceTransformerEmbeddingFunction(
22
+ model_name="all-MiniLM-L6-v2"
23
+ )
24
+
25
+ col = chroma_client.get_collection("medical_knowledge", embedding_function=ef)
26
+ count = col.count()
27
+ print(f"βœ… Found {count} documents in ChromaDB.")
28
+
29
+ # 2. Connect to Qdrant Cloud
30
+ print(f"☁️ Connecting to Qdrant Cloud: {qdrant_url}...")
31
+ qdrant_client = QdrantClient(
32
+ url=qdrant_url,
33
+ api_key=qdrant_api_key,
34
+ timeout=60 # Extended timeout for uploads
35
+ )
36
+
37
+ # Check/Create Collection
38
+ collection_name = "medical_knowledge"
39
+ try:
40
+ qdrant_client.get_collection(collection_name)
41
+ print(f"βœ… Qdrant Collection '{collection_name}' exists.")
42
+ except:
43
+ print(f"⚠️ Creating new collection '{collection_name}' with Quantization...")
44
+ qdrant_client.create_collection(
45
+ collection_name=collection_name,
46
+ vectors_config=models.VectorParams(
47
+ size=384, # all-MiniLM-L6-v2 dimension
48
+ distance=models.Distance.COSINE,
49
+ quantization_config=models.ScalarQuantization(
50
+ scalar=models.ScalarQuantizationConfig(
51
+ type=models.ScalarType.INT8,
52
+ quantile=0.99,
53
+ always_ram=True
54
+ )
55
+ )
56
+ )
57
+ )
58
+
59
+ # 3. Migrate Data in Batches
60
+ batch_size = 100
61
+ total_migrated = 0
62
+
63
+ print("πŸš€ Starting Migration...")
64
+
65
+ # Fetch all data (Chroma get allows large fetch? Yes, usually)
66
+ # Ideally use offset/limit pagination
67
+ limit = 1000
68
+ offset = 0
69
+
70
+ while True:
71
+ results = col.get(
72
+ include=['documents', 'metadatas', 'embeddings'],
73
+ limit=limit,
74
+ offset=offset
75
+ )
76
+
77
+ ids = results['ids']
78
+ if not ids:
79
+ break
80
+
81
+ points = []
82
+ for i, doc_id in enumerate(ids):
83
+ points.append(models.PointStruct(
84
+ id=i + offset, # Use integer ID based on offset? No, Qdrant allows UUID or Int. original ID is better?
85
+ # Chroma IDs might be strings. Qdrant supports UUID strings.
86
+ # Let's map to UUID if needed, or use integer offset as ID.
87
+ # Integer IDs are efficient in Qdrant.
88
+ vector=results['embeddings'][i],
89
+ payload={
90
+ "page_content": results['documents'][i],
91
+ **results['metadatas'][i]
92
+ }
93
+ ))
94
+
95
+ qdrant_client.upsert(
96
+ collection_name=collection_name,
97
+ points=points
98
+ )
99
+
100
+ total_migrated += len(points)
101
+ print(f" Processed {total_migrated}/{count}...")
102
+ offset += limit
103
+
104
+ print(f"πŸŽ‰ Migration Complete! {total_migrated} vectors uploaded to Qdrant.")
105
+
106
+ if __name__ == "__main__":
107
+ if len(sys.argv) < 3:
108
+ print("Usage: python migrate_to_qdrant.py <QDRANT_URL> <QDRANT_API_KEY>")
109
+ sys.exit(1)
110
+
111
+ migrate(sys.argv[1], sys.argv[2])
src/embeddings/vector_store.py CHANGED
@@ -215,7 +215,54 @@ class VectorStore:
215
  "count": self.collection.count()
216
  }
217
 
218
- def delete_collection(self):
219
- """Delete the collection."""
220
  self.client.delete_collection(self.collection_name)
221
  print(f"πŸ—‘οΈ Deleted collection: {self.collection_name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  "count": self.collection.count()
216
  }
217
 
 
 
218
  self.client.delete_collection(self.collection_name)
219
  print(f"πŸ—‘οΈ Deleted collection: {self.collection_name}")
220
+
221
+ class QdrantVectorStore:
222
+ def __init__(self, url, api_key, collection_name="medical_knowledge"):
223
+ from qdrant_client import QdrantClient
224
+
225
+ self.client = QdrantClient(url=url, api_key=api_key)
226
+ self.collection_name = collection_name
227
+ print(f"βœ… Context: Connected to Qdrant Cloud: {collection_name}")
228
+
229
+ def search(self, query_embedding, n_results=5, filter_metadata=None):
230
+ # Qdrant expects query_vector
231
+ results = self.client.search(
232
+ collection_name=self.collection_name,
233
+ query_vector=query_embedding,
234
+ limit=n_results
235
+ )
236
+
237
+ # Convert to standard format
238
+ docs = []
239
+ metadatas = []
240
+ distances = []
241
+
242
+ for res in results:
243
+ docs.append(res.payload.get("page_content", ""))
244
+ metadatas.append({k:v for k,v in res.payload.items() if k != "page_content"})
245
+ distances.append(res.score)
246
+
247
+ return {
248
+ "documents": [docs],
249
+ "metadatas": [metadatas],
250
+ "distances": [distances]
251
+ }
252
+
253
+ def get_stats(self):
254
+ try:
255
+ count = self.client.count(self.collection_name).count
256
+ return {"name": self.collection_name, "count": count}
257
+ except:
258
+ return {"name": self.collection_name, "count": 0}
259
+
260
+ def get_vector_store():
261
+ # Factory
262
+ import os
263
+ if os.getenv("VECTOR_DB_TYPE") == "qdrant":
264
+ return QdrantVectorStore(
265
+ url=os.getenv("QDRANT_URL"),
266
+ api_key=os.getenv("QDRANT_API_KEY")
267
+ )
268
+ return VectorStore()
start.sh CHANGED
@@ -3,18 +3,8 @@
3
  # Set default PORT if not set (for Streamlit)
4
  export PORT=${PORT:-8501}
5
 
6
- # Download Knowledge Base using robust Python script
7
- # This script handles integrity checks and retries
8
- echo "⬇️ Starting Knowledge Base sync..."
9
- mkdir -p data
10
- python scripts/download_kb.py
11
-
12
- # DEBUG: Check file structure
13
- echo "πŸ“‚ Checking data directory structure:"
14
- ls -R data
15
-
16
- # Ensure permissions
17
- chmod -R 777 data/
18
 
19
  echo "Starting Healthcare QA Chatbot..."
20
 
 
3
  # Set default PORT if not set (for Streamlit)
4
  export PORT=${PORT:-8501}
5
 
6
+ # Qdrant mode - No local KB download needed!
7
+ echo "βœ… Using Remote Vector Database (Qdrant)"
 
 
 
 
 
 
 
 
 
 
8
 
9
  echo "Starting Healthcare QA Chatbot..."
10