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

Merged database and health status.

Browse files
src/api/routes/static.py CHANGED
@@ -15,22 +15,12 @@ async def get_medical_chatbot():
15
  except FileNotFoundError:
16
  raise HTTPException(status_code=404, detail="Medical chatbot UI not found")
17
 
18
- @router.get("/health-status", response_class=HTMLResponse)
19
- async def get_health_status():
20
- """Serve the health status UI"""
21
  try:
22
- with open("static/health.html", "r", encoding="utf-8") as f:
23
  html_content = f.read()
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")
 
15
  except FileNotFoundError:
16
  raise HTTPException(status_code=404, detail="Medical chatbot UI not found")
17
 
18
+ @router.get("/system-status", response_class=HTMLResponse)
19
+ async def get_system_status():
20
+ """Serve the unified system status UI"""
21
  try:
22
+ with open("static/system.html", "r", encoding="utf-8") as f:
23
  html_content = f.read()
24
  return HTMLResponse(content=html_content)
25
  except FileNotFoundError:
26
+ raise HTTPException(status_code=404, detail="System status UI not found")
 
 
 
 
 
 
 
 
 
 
src/api/routes/system.py CHANGED
@@ -12,7 +12,7 @@ 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
 
17
  @router.get("/health")
18
  async def health_check(state: MedicalState = Depends(get_state)):
 
12
  from src.data.repositories.patient import PATIENTS_COLLECTION
13
  from src.data.repositories.session import CHAT_SESSIONS_COLLECTION
14
 
15
+ router = APIRouter(prefix="/system", tags=["System"])
16
 
17
  @router.get("/health")
18
  async def health_check(state: MedicalState = Depends(get_state)):
static/css/system.css ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ font-family: Arial, sans-serif;
3
+ padding: 20px;
4
+ }
5
+
6
+ .tab-bar {
7
+ margin-bottom: 20px;
8
+ }
9
+
10
+ .tab-button {
11
+ padding: 10px 20px;
12
+ border: none;
13
+ background: #f0f0f0;
14
+ cursor: pointer;
15
+ margin-right: 5px;
16
+ border-radius: 4px;
17
+ }
18
+
19
+ .tab-button.active {
20
+ background: #007bff;
21
+ color: white;
22
+ }
23
+
24
+ .tab-content {
25
+ display: none;
26
+ }
27
+
28
+ .tab-content.active {
29
+ display: block;
30
+ }
31
+
32
+ /* Health status styles */
33
+ .status-ok {
34
+ color: green;
35
+ }
36
+
37
+ .status-error {
38
+ color: red;
39
+ }
40
+
41
+ .component {
42
+ margin: 10px 0;
43
+ }
44
+
45
+ /* Database status styles */
46
+ .collection {
47
+ margin: 20px 0;
48
+ padding: 15px;
49
+ border: 1px solid #ddd;
50
+ border-radius: 4px;
51
+ }
52
+
53
+ .collection h2 {
54
+ margin-top: 0;
55
+ color: #333;
56
+ }
57
+
58
+ .stats {
59
+ color: #666;
60
+ }
61
+
62
+ .timestamp {
63
+ color: #888;
64
+ font-style: italic;
65
+ }
66
+
67
+ .fields {
68
+ margin-top: 15px;
69
+ }
70
+
71
+ .fields h3 {
72
+ color: #444;
73
+ margin-bottom: 10px;
74
+ }
75
+
76
+ .fields ul {
77
+ list-style-type: none;
78
+ padding-left: 20px;
79
+ }
80
+
81
+ .fields li {
82
+ color: #555;
83
+ margin: 3px 0;
84
+ font-family: monospace;
85
+ }
static/database.html DELETED
@@ -1,24 +0,0 @@
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/health.html DELETED
@@ -1,17 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>System Health Status</title>
5
- <style>
6
- .status-ok { color: green; }
7
- .status-error { color: red; }
8
- body { font-family: Arial, sans-serif; padding: 20px; }
9
- .component { margin: 10px 0; }
10
- </style>
11
- </head>
12
- <body>
13
- <h1>System Health Status</h1>
14
- <div id="status"></div>
15
- <script src="/static/js/health.js"></script>
16
- </body>
17
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/js/database.js DELETED
@@ -1,51 +0,0 @@
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);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/js/health.js DELETED
@@ -1,24 +0,0 @@
1
- async function updateHealth() {
2
- try {
3
- const response = await fetch('/health');
4
- const data = await response.json();
5
- const statusHtml = `
6
- <p>Status: <span class="status-${data.status === 'healthy' ? 'ok' : 'error'}">${data.status}</span></p>
7
- <p>Timestamp: ${data.timestamp}</p>
8
- <h3>Components:</h3>
9
- ${Object.entries(data.components).map(([key, value]) => `
10
- <div class="component">
11
- ${key}: <span class="status-${value === 'operational' ? 'ok' : 'error'}">${value}</span>
12
- </div>
13
- `).join('')}
14
- `;
15
- document.getElementById('status').innerHTML = statusHtml;
16
- } catch (error) {
17
- document.getElementById('status').innerHTML = '<p class="status-error">Error fetching health status</p>';
18
- }
19
- }
20
-
21
- document.addEventListener('DOMContentLoaded', () => {
22
- updateHealth();
23
- setInterval(updateHealth, 30000);
24
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
static/js/system.js ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Tab switching functionality
2
+ function setupTabs() {
3
+ const tabs = document.querySelectorAll('.tab-button');
4
+ tabs.forEach(tab => {
5
+ tab.addEventListener('click', () => {
6
+ // Deactivate all tabs
7
+ tabs.forEach(t => {
8
+ t.classList.remove('active');
9
+ document.getElementById(t.dataset.tab).classList.remove('active');
10
+ });
11
+ // Activate clicked tab
12
+ tab.classList.add('active');
13
+ document.getElementById(tab.dataset.tab).classList.add('active');
14
+ });
15
+ });
16
+ }
17
+
18
+ // Health status functionality
19
+ async function updateHealth() {
20
+ try {
21
+ const response = await fetch('/system/health');
22
+ const data = await response.json();
23
+ const statusHtml = `
24
+ <p>Status: <span class="status-${data.status === 'healthy' ? 'ok' : 'error'}">${data.status}</span></p>
25
+ <p>Timestamp: ${data.timestamp}</p>
26
+ <h3>Components:</h3>
27
+ ${Object.entries(data.components).map(([key, value]) => `
28
+ <div class="component">
29
+ ${key}: <span class="status-${value === 'operational' ? 'ok' : 'error'}">${value}</span>
30
+ </div>
31
+ `).join('')}
32
+ `;
33
+ document.getElementById('health-status').innerHTML = statusHtml;
34
+ } catch (error) {
35
+ document.getElementById('health-status').innerHTML = '<p class="status-error">Error fetching health status</p>';
36
+ }
37
+ }
38
+
39
+ // Database status functionality
40
+ async function updateDatabase() {
41
+ try {
42
+ const response = await fetch('/system/database');
43
+ const data = await response.json();
44
+ displayDatabaseStatus(data);
45
+ } catch (error) {
46
+ console.error('Error fetching database status:', error);
47
+ document.getElementById('collections').innerHTML =
48
+ '<div class="error">Error fetching database status. Please try again later.</div>';
49
+ }
50
+ }
51
+
52
+ function displayDatabaseStatus(data) {
53
+ document.getElementById('db-timestamp').textContent = `Last updated: ${data.timestamp}`;
54
+
55
+ const collectionsDiv = document.getElementById('collections');
56
+ collectionsDiv.innerHTML = '';
57
+
58
+ Object.entries(data.collections).forEach(([name, info]) => {
59
+ const collectionDiv = document.createElement('div');
60
+ collectionDiv.className = 'collection';
61
+
62
+ const html = `
63
+ <h2>${name}</h2>
64
+ <div class="stats">
65
+ <p>Document count: ${info.document_count}</p>
66
+ </div>
67
+ <div class="fields">
68
+ <h3>Document Fields:</h3>
69
+ <ul>
70
+ ${info.fields.map(field => {
71
+ const indexInfo = info.indexes.find(idx =>
72
+ idx.keys.some(([key]) => key === field)
73
+ );
74
+ const indexDetails = indexInfo ?
75
+ ` (Index: ${indexInfo.keys.map(([key, direction]) =>
76
+ `${direction === 1 ? '↑' : '↓'}`).join('')})` : '';
77
+ return `<li>${field}${indexDetails}</li>`;
78
+ }).join('')}
79
+ </ul>
80
+ </div>
81
+ `;
82
+
83
+ collectionDiv.innerHTML = html;
84
+ collectionsDiv.appendChild(collectionDiv);
85
+ });
86
+ }
87
+
88
+ // Initialize everything
89
+ document.addEventListener('DOMContentLoaded', () => {
90
+ setupTabs();
91
+ updateHealth();
92
+ updateDatabase();
93
+ // Refresh data every 30 seconds
94
+ setInterval(updateHealth, 30000);
95
+ setInterval(updateDatabase, 30000);
96
+ });
static/system.html ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>System Status</title>
5
+ <link rel="stylesheet" href="/static/css/system.css">
6
+ </head>
7
+ <body>
8
+ <h1>System Status</h1>
9
+ <div class="tab-bar">
10
+ <button class="tab-button active" data-tab="health">Health Status</button>
11
+ <button class="tab-button" data-tab="database">Database Status</button>
12
+ </div>
13
+
14
+ <div id="health" class="tab-content active">
15
+ <div id="health-status"></div>
16
+ </div>
17
+
18
+ <div id="database" class="tab-content">
19
+ <div id="db-timestamp" class="timestamp"></div>
20
+ <div id="collections"></div>
21
+ </div>
22
+
23
+ <script src="/static/js/system.js"></script>
24
+ </body>
25
+ </html>