dylanglenister commited on
Commit
c6b7e35
·
1 Parent(s): b38fca0

Added a database status page

Browse files
src/api/routes/static.py CHANGED
@@ -24,3 +24,13 @@ async def get_health_status():
24
  return HTMLResponse(content=html_content)
25
  except FileNotFoundError:
26
  raise HTTPException(status_code=404, detail="Health status UI not found")
 
 
 
 
 
 
 
 
 
 
 
24
  return HTMLResponse(content=html_content)
25
  except FileNotFoundError:
26
  raise HTTPException(status_code=404, detail="Health status UI not found")
27
+
28
+ @router.get("/database-status", response_class=HTMLResponse)
29
+ async def get_database_status():
30
+ """Serve the database status UI"""
31
+ try:
32
+ with open("static/database.html", "r", encoding="utf-8") as f:
33
+ html_content = f.read()
34
+ return HTMLResponse(content=html_content)
35
+ except FileNotFoundError:
36
+ raise HTTPException(status_code=404, detail="Database status UI not found")
src/api/routes/system.py CHANGED
@@ -5,6 +5,12 @@ import time
5
  from fastapi import APIRouter, Depends
6
 
7
  from src.core.state import MedicalState, get_state
 
 
 
 
 
 
8
 
9
  router = APIRouter()
10
 
@@ -22,3 +28,43 @@ async def health_check(state: MedicalState = Depends(get_state)):
22
  "nvidia_keys_available": len([k for k in state.nvidia_rotator.keys if k]) > 0
23
  }
24
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  from fastapi import APIRouter, Depends
6
 
7
  from src.core.state import MedicalState, get_state
8
+ from src.data.repositories.account import ACCOUNTS_COLLECTION
9
+ from src.data.repositories.medical import (MEDICAL_MEMORY_COLLECTION,
10
+ MEDICAL_RECORDS_COLLECTION)
11
+ from src.data.repositories.message import CHAT_MESSAGES_COLLECTION
12
+ from src.data.repositories.patient import PATIENTS_COLLECTION
13
+ from src.data.repositories.session import CHAT_SESSIONS_COLLECTION
14
 
15
  router = APIRouter()
16
 
 
28
  "nvidia_keys_available": len([k for k in state.nvidia_rotator.keys if k]) > 0
29
  }
30
  }
31
+
32
+ @router.get("/database")
33
+ async def get_database():
34
+ """List meta information about all collections in the database."""
35
+ from src.data.connection import get_collection
36
+
37
+ collections = [
38
+ ACCOUNTS_COLLECTION,
39
+ CHAT_SESSIONS_COLLECTION,
40
+ CHAT_MESSAGES_COLLECTION,
41
+ MEDICAL_RECORDS_COLLECTION,
42
+ MEDICAL_MEMORY_COLLECTION,
43
+ PATIENTS_COLLECTION
44
+ ]
45
+
46
+ result = {}
47
+ for name in collections:
48
+ collection = get_collection(name)
49
+ indexes = []
50
+ for idx in collection.list_indexes():
51
+ indexes.append({
52
+ "name": idx["name"],
53
+ "keys": list(idx["key"].items())
54
+ })
55
+
56
+ stats = collection.estimated_document_count()
57
+ # Get sample document to extract field names
58
+ sample = collection.find_one()
59
+ fields = list(sample.keys()) if sample else []
60
+
61
+ result[name] = {
62
+ "document_count": stats,
63
+ "indexes": indexes,
64
+ "fields": fields
65
+ }
66
+
67
+ return {
68
+ "timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
69
+ "collections": result
70
+ }
static/database.html ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Database Status</title>
5
+ <style>
6
+ body { font-family: Arial, sans-serif; padding: 20px; }
7
+ .collection { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
8
+ .collection h2 { margin-top: 0; color: #333; }
9
+ .index-list { margin-left: 20px; }
10
+ .stats { color: #666; }
11
+ .timestamp { color: #888; font-style: italic; }
12
+ .fields { margin-top: 15px; }
13
+ .fields h3 { color: #444; margin-bottom: 10px; }
14
+ .fields ul { list-style-type: none; padding-left: 20px; }
15
+ .fields li { color: #555; margin: 3px 0; font-family: monospace; }
16
+ </style>
17
+ </head>
18
+ <body>
19
+ <h1>Database Status</h1>
20
+ <div id="timestamp" class="timestamp"></div>
21
+ <div id="collections"></div>
22
+ <script src="/static/js/database.js"></script>
23
+ </body>
24
+ </html>
static/js/database.js ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function fetchDatabaseStatus() {
2
+ try {
3
+ const response = await fetch('/database');
4
+ const data = await response.json();
5
+ displayStatus(data);
6
+ } catch (error) {
7
+ console.error('Error fetching database status:', error);
8
+ document.getElementById('collections').innerHTML =
9
+ '<div class="error">Error fetching database status. Please try again later.</div>';
10
+ }
11
+ }
12
+
13
+ function displayStatus(data) {
14
+ document.getElementById('timestamp').textContent = `Last updated: ${data.timestamp}`;
15
+
16
+ const collectionsDiv = document.getElementById('collections');
17
+ collectionsDiv.innerHTML = '';
18
+
19
+ Object.entries(data.collections).forEach(([name, info]) => {
20
+ const collectionDiv = document.createElement('div');
21
+ collectionDiv.className = 'collection';
22
+
23
+ const html = `
24
+ <h2>${name}</h2>
25
+ <div class="stats">
26
+ <p>Document count: ${info.document_count}</p>
27
+ </div>
28
+ <div class="fields">
29
+ <h3>Document Fields:</h3>
30
+ <ul>
31
+ ${info.fields.map(field => {
32
+ const indexInfo = info.indexes.find(idx =>
33
+ idx.keys.some(([key]) => key === field)
34
+ );
35
+ const indexDetails = indexInfo ?
36
+ ` (Index: ${indexInfo.keys.map(([key, direction]) =>
37
+ `${direction === 1 ? '↑' : '↓'}`).join('')})` : '';
38
+ return `<li>${field}${indexDetails}</li>`;
39
+ }).join('')}
40
+ </ul>
41
+ </div>
42
+ `;
43
+
44
+ collectionDiv.innerHTML = html;
45
+ collectionsDiv.appendChild(collectionDiv);
46
+ });
47
+ }
48
+
49
+ // Fetch status immediately and refresh every 30 seconds
50
+ fetchDatabaseStatus();
51
+ setInterval(fetchDatabaseStatus, 30000);