dylanglenister commited on
Commit
7fbfb89
·
1 Parent(s): 1faabaf

Updating app js file

Browse files
Files changed (1) hide show
  1. static/js/app.js +122 -135
static/js/app.js CHANGED
@@ -599,10 +599,10 @@ How can I assist you today?`;
599
  } else {
600
  // If doctor not found in local list, try to fetch from backend
601
  try {
602
- const resp = await fetch(`/account/search?q=${encodeURIComponent(selectedName)}&limit=1`);
603
  if (resp.ok) {
604
  const data = await resp.json();
605
- const doctor = data.results && data.results[0];
606
  if (doctor) {
607
  if (doctor.role) {
608
  roleEl.value = doctor.role;
@@ -730,12 +730,10 @@ How can I assist you today?`;
730
  const sessionElement = document.createElement('div');
731
  sessionElement.className = `chat-session ${session.id === this.currentSession?.id ? 'active' : ''}`;
732
  sessionElement.addEventListener('click', async () => {
733
- if (session.source === 'backend') {
734
- this.currentSession = { ...session };
735
- await this.hydrateMessagesForSession(session.id);
736
- } else {
737
- this.loadChatSession(session.id);
738
- }
739
  });
740
  const time = this.formatTime(session.lastActivity);
741
  sessionElement.innerHTML = `
@@ -853,9 +851,6 @@ How can I assist you today?`;
853
  throw new Error(`HTTP ${resp.status}`);
854
  }
855
 
856
- const result = await resp.json();
857
- console.log('[DEBUG] Backend deletion result:', result);
858
-
859
  // Remove from backend sessions
860
  this.backendSessions = this.backendSessions.filter(s => s.id !== sessionId);
861
 
@@ -971,13 +966,13 @@ How can I assist you today?`;
971
  const resp = await fetch('/account');
972
  if (resp.ok) {
973
  const data = await resp.json();
974
- this.doctors = data.results || [];
975
  // Ensure each doctor has role and specialty information
976
  this.doctors = this.doctors.map(doctor => ({
977
  name: doctor.name,
978
  role: doctor.role || 'Medical Professional',
979
  specialty: doctor.specialty || '',
980
- _id: doctor._id // API returns _id, not doctor_id
981
  }));
982
  // Also save to localStorage for offline access
983
  localStorage.setItem('medicalChatbotDoctors', JSON.stringify(this.doctors));
@@ -1004,10 +999,10 @@ How can I assist you today?`;
1004
 
1005
  async searchDoctors(query) {
1006
  try {
1007
- const resp = await fetch(`/account/search?q=${encodeURIComponent(query)}&limit=10`);
1008
  if (resp.ok) {
1009
  const data = await resp.json();
1010
- return data.results || [];
1011
  }
1012
  } catch (e) {
1013
  console.warn('Doctor search failed:', e);
@@ -1025,8 +1020,7 @@ How can I assist you today?`;
1025
  if (resp.ok) {
1026
  const data = await resp.json();
1027
  // Add to local doctors list
1028
- // FIX: Use account_id from the response
1029
- this.doctors.push({ name: data.name, _id: data.account_id });
1030
  this.saveDoctors();
1031
  return data;
1032
  }
@@ -1089,26 +1083,25 @@ How can I assist you today?`;
1089
  if (!this.doctors.find(d => d.name === name)) {
1090
  // Get current role and specialty from the form
1091
  const role = document.getElementById('profileRole').value || 'Medical Professional';
1092
- const specialty = document.getElementById('profileSpecialty').value.trim() || '';
1093
 
1094
  // Create doctor in MongoDB
1095
  const result = await this.createDoctor({
1096
  name,
1097
  role,
1098
- specialty,
1099
- medical_roles: [role]
1100
  });
1101
- if (result && result.account_id) {
1102
  this.doctors.unshift({
1103
  name,
1104
  role,
1105
  specialty,
1106
- _id: result.account_id // FIX: Use account_id from response
1107
  });
1108
  this.saveDoctors();
1109
 
1110
  // Update current user profile
1111
- this.currentUser.id = result.account_id; // FIX: CRITICAL - Update the user ID
1112
  this.currentUser.name = name;
1113
  this.currentUser.role = role;
1114
  this.currentUser.specialty = specialty;
@@ -1134,10 +1127,13 @@ How can I assist you today?`;
1134
  }
1135
 
1136
  // Check if doctor exists in MongoDB first
1137
- let doctorExists = false;
1138
  try {
1139
- const resp = await fetch(`/account/${encodeURIComponent(name)}`);
1140
- doctorExists = resp.ok;
 
 
 
1141
  } catch (e) {
1142
  console.warn('Failed to check doctor existence:', e);
1143
  }
@@ -1148,12 +1144,11 @@ How can I assist you today?`;
1148
  this.currentUser.specialty = specialty;
1149
 
1150
  // Only create new doctor in MongoDB if it doesn't exist
1151
- if (!doctorExists) {
1152
  const doctorPayload = {
1153
  name: name,
1154
  role: role,
1155
- specialty: specialty || null,
1156
- medical_roles: [role]
1157
  };
1158
 
1159
  try {
@@ -1167,17 +1162,16 @@ How can I assist you today?`;
1167
  const data = await resp.json();
1168
  console.log('[Doctor] Created new doctor in backend:', data);
1169
 
1170
- // FIX: CRITICAL - Update the current user's ID with the one from the database
1171
- if (data.account_id) {
1172
- this.currentUser.id = data.account_id;
1173
  }
1174
 
1175
  // Update local doctor list with the ID from backend
1176
  const existingDoctorIndex = this.doctors.findIndex(d => d.name === name);
1177
  if (existingDoctorIndex === -1) {
1178
- this.doctors.unshift({ name, role, specialty, _id: data.account_id });
1179
  } else {
1180
- this.doctors[existingDoctorIndex]._id = data.account_id;
1181
  }
1182
 
1183
  } catch (err) {
@@ -1185,9 +1179,8 @@ How can I assist you today?`;
1185
  }
1186
  } else {
1187
  // If doctor exists, find their ID and update currentUser
1188
- const existingDoctor = this.doctors.find(d => d.name === name);
1189
- if (existingDoctor && existingDoctor._id) {
1190
- this.currentUser.id = existingDoctor._id;
1191
  }
1192
  console.log('[Doctor] Doctor already exists in backend, no creation needed');
1193
  }
@@ -1208,8 +1201,7 @@ How can I assist you today?`;
1208
  const storedPatients = JSON.parse(localStorage.getItem('medicalChatbotPatients') || '[]');
1209
  return storedPatients.filter(p => {
1210
  const nameMatch = p.name.toLowerCase().includes(query.toLowerCase());
1211
- // FIX: Check _id field which is what the API returns
1212
- const idMatch = p._id && p._id.includes(query);
1213
  return nameMatch || idMatch;
1214
  });
1215
  } catch (e) {
@@ -1222,14 +1214,12 @@ How can I assist you today?`;
1222
  const resultMap = new Map();
1223
  // Add MongoDB results first (they take priority)
1224
  mongoResults.forEach(patient => {
1225
- // FIX: Use _id as the unique key
1226
- if(patient._id) resultMap.set(patient._id, patient);
1227
  });
1228
  // Add localStorage results only if not already present
1229
  localResults.forEach(patient => {
1230
- // FIX: Use _id as the unique key
1231
- if (patient._id && !resultMap.has(patient._id)) {
1232
- resultMap.set(patient._id, patient);
1233
  }
1234
  });
1235
  return Array.from(resultMap.values());
@@ -1265,7 +1255,7 @@ How can I assist you today?`;
1265
  const resp = await fetch(`/patient/${pid}`);
1266
  if (resp.ok) {
1267
  const patient = await resp.json();
1268
- status.textContent = `Patient: ${patient.name || 'Unknown'} (${patient._id})`;
1269
  } else {
1270
  status.textContent = `Patient: ${pid}`;
1271
  }
@@ -1324,18 +1314,18 @@ How can I assist you today?`;
1324
  // Search for patient by name or ID
1325
  console.log('[DEBUG] Searching for patient');
1326
  try {
1327
- const resp = await fetch(`/patient/search?q=${encodeURIComponent(value)}&limit=1`);
1328
  console.log('[DEBUG] Search response status:', resp.status);
1329
  if (resp.ok) {
1330
  const data = await resp.json();
1331
  console.log('[DEBUG] Search results:', data);
1332
- const first = (data.results || [])[0];
1333
- if (first && first._id) { // FIX: Check for _id
1334
  console.log('[DEBUG] Found patient, setting as current:', first);
1335
- this.currentPatientId = first._id; // FIX: Use _id from search result
1336
  this.savePatientId();
1337
- input.value = first._id;
1338
- this.updatePatientDisplay(first._id, first.name || 'Unknown');
1339
  await this.fetchAndRenderPatientSessions();
1340
  return;
1341
  }
@@ -1378,7 +1368,7 @@ How can I assist you today?`;
1378
  const resp = await fetch(`/patient/${this.currentPatientId}/session`);
1379
  if (resp.ok) {
1380
  const data = await resp.json();
1381
- sessions = Array.isArray(data.sessions) ? data.sessions : [];
1382
 
1383
  // Cache the sessions
1384
  localStorage.setItem(cacheKey, JSON.stringify({
@@ -1396,12 +1386,11 @@ How can I assist you today?`;
1396
 
1397
  // Process sessions
1398
  this.backendSessions = sessions.map(s => ({
1399
- // FIX: Add a fallback to _id to make the frontend more robust
1400
- id: s.session_id || s._id,
1401
  title: s.title || 'New Chat',
1402
  messages: [],
1403
  createdAt: s.created_at || new Date().toISOString(),
1404
- lastActivity: s.last_activity || new Date().toISOString(),
1405
  source: 'backend'
1406
  }));
1407
 
@@ -1414,7 +1403,6 @@ How can I assist you today?`;
1414
  }
1415
 
1416
  hydrateMessagesForSession = async function (sessionId) {
1417
- // FIX: Add a guard clause to prevent calling the API with an invalid ID
1418
  if (!sessionId || sessionId === 'undefined') {
1419
  console.error('[DEBUG] hydrateMessagesForSession was called with an invalid session ID:', sessionId);
1420
  return;
@@ -1442,16 +1430,16 @@ How can I assist you today?`;
1442
 
1443
  // If no cache or cache is stale, fetch from backend
1444
  if (messages.length === 0) {
1445
- const resp = await fetch(`/session/${sessionId}/messages?limit=1000`);
1446
  if (!resp.ok) {
1447
  console.warn(`Failed to fetch messages for session ${sessionId}:`, resp.status);
1448
  return;
1449
  }
1450
  const data = await resp.json();
1451
- const msgs = Array.isArray(data.messages) ? data.messages : [];
1452
  messages = msgs.map(m => ({
1453
- id: m._id || this.generateId(),
1454
- role: m.role,
1455
  content: m.content,
1456
  timestamp: m.timestamp
1457
  }));
@@ -1506,15 +1494,13 @@ How can I assist you today?`;
1506
  items.forEach(p => {
1507
  const div = document.createElement('div');
1508
  div.className = 'patient-suggestion';
1509
- // FIX: Use _id for display as it's the consistent identifier
1510
- div.textContent = `${p.name || 'Unknown'} (${p._id})`;
1511
  div.addEventListener('click', async () => {
1512
- // FIX: Use _id from the patient object
1513
- this.currentPatientId = p._id;
1514
  this.savePatientId();
1515
- patientInput.value = p._id;
1516
  hideSuggestions();
1517
- this.updatePatientDisplay(p._id, p.name || 'Unknown');
1518
  await this.fetchAndRenderPatientSessions();
1519
  });
1520
  suggestionsEl.appendChild(div);
@@ -1529,7 +1515,7 @@ How can I assist you today?`;
1529
  debounceTimer = setTimeout(async () => {
1530
  try {
1531
  console.log('[DEBUG] Searching patients with query:', q);
1532
- const url = `/patient/search?q=${encodeURIComponent(q)}&limit=8`;
1533
  console.log('[DEBUG] Search URL:', url);
1534
  const resp = await fetch(url);
1535
  console.log('[DEBUG] Search response status:', resp.status);
@@ -1537,7 +1523,7 @@ How can I assist you today?`;
1537
  let mongoResults = [];
1538
  if (resp.ok) {
1539
  const data = await resp.json();
1540
- mongoResults = data.results || [];
1541
  console.log('[DEBUG] MongoDB search results:', mongoResults);
1542
  } else {
1543
  console.warn('MongoDB search request failed', resp.status);
@@ -1689,23 +1675,25 @@ How can I assist you today?`;
1689
  this.addMessage('user', message);
1690
  this.showLoading(true);
1691
  try {
1692
- const isNewSession = this.currentSession && this.currentSession.id === 'default';
1693
- const responseData = await this.callMedicalAPI(message);
1694
 
1695
  if (isNewSession && responseData.session_id) {
1696
- console.log(`[DEBUG] New session created on backend. Updating session ID from 'default' to '${responseData.session_id}'`);
1697
- const oldId = this.currentSession.id;
1698
- this.currentSession.id = responseData.session_id;
1699
 
1700
- // Update the session ID in the locally stored array
1701
- const sessions = this.getChatSessions();
1702
- const sessionIndex = sessions.findIndex(s => s.id === oldId);
1703
- if (sessionIndex !== -1) {
1704
- sessions[sessionIndex].id = this.currentSession.id;
1705
- localStorage.setItem(`chatSessions_${this.currentUser.id}`, JSON.stringify(sessions));
1706
  }
1707
- // Re-render the session list to reflect the new ID
1708
- this.loadChatSessions();
 
 
 
 
 
1709
  }
1710
 
1711
  this.addMessage('assistant', responseData.response || 'I apologize, but I received an empty response. Please try again.');
@@ -1728,27 +1716,46 @@ How can I assist you today?`;
1728
  }
1729
  }
1730
 
1731
- callMedicalAPI = async function (message) {
1732
  try {
1733
- const payload = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1734
  account_id: this.currentUser.id,
1735
  patient_id: this.currentPatientId,
1736
  message: message
1737
  };
1738
 
1739
- // Only include session_id if it's not the default placeholder
1740
- if (this.currentSession?.id && this.currentSession.id !== 'default') {
1741
- payload.session_id = this.currentSession.id;
1742
- }
1743
-
1744
- const response = await fetch('/chat', {
1745
  method: 'POST',
1746
  headers: { 'Content-Type': 'application/json' },
1747
- body: JSON.stringify(payload)
1748
  });
1749
- if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
1750
- const data = await response.json();
 
1751
  return data;
 
1752
  } catch (error) {
1753
  console.error('API call failed:', error);
1754
  console.error('Error details:', {
@@ -1830,15 +1837,15 @@ How can I assist you today?`;
1830
  messageElement.id = `message-${message.id}`;
1831
  const avatar = message.role === 'user' ? '<i class="fas fa-user"></i>' : '<i class="fas fa-robot"></i>';
1832
  const time = this.formatTime(message.timestamp);
1833
-
1834
  // Add EMR icon for assistant messages (system-generated)
1835
- const emrIcon = message.role === 'assistant' ?
1836
  `<div class="message-actions">
1837
  <button class="emr-extract-btn" onclick="app.extractEMR('${message.id}')" title="Extract to EMR" data-message-id="${message.id}">
1838
  <i class="fas fa-file-medical"></i>
1839
  </button>
1840
  </div>` : '';
1841
-
1842
  messageElement.innerHTML = `
1843
  <div class="message-avatar">${avatar}</div>
1844
  <div class="message-content">
@@ -1849,11 +1856,6 @@ How can I assist you today?`;
1849
  chatMessages.appendChild(messageElement);
1850
  chatMessages.scrollTop = chatMessages.scrollHeight;
1851
  if (this.currentSession) this.currentSession.lastActivity = new Date().toISOString();
1852
-
1853
- // Check EMR status for assistant messages
1854
- if (message.role === 'assistant' && this.currentPatientId) {
1855
- this.checkEMRStatus(message.id);
1856
- }
1857
  }
1858
 
1859
  formatMessageContent(content) {
@@ -1915,25 +1917,28 @@ How can I assist you today?`;
1915
  button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
1916
  }
1917
 
 
 
 
 
 
 
 
 
 
 
1918
  // Call EMR extraction API
1919
- const response = await fetch('/emr/extract', {
1920
  method: 'POST',
1921
  headers: {
1922
- 'Content-Type': 'application/json',
1923
- },
1924
- body: JSON.stringify({
1925
- patient_id: this.currentPatientId,
1926
- doctor_id: this.currentUser.id || 'default-doctor',
1927
- message_id: messageId,
1928
- session_id: this.currentSession?.id || 'default-session',
1929
- message: message.content
1930
- })
1931
  });
1932
 
1933
  if (response.ok) {
1934
  const result = await response.json();
1935
  console.log('EMR extraction successful:', result);
1936
-
1937
  // Show success message
1938
  if (button) {
1939
  button.innerHTML = '<i class="fas fa-check"></i>';
@@ -1944,7 +1949,7 @@ How can I assist you today?`;
1944
  button.disabled = false;
1945
  }, 2000);
1946
  }
1947
-
1948
  // Show notification
1949
  this.showNotification('EMR data extracted successfully!', 'success');
1950
  } else {
@@ -1955,37 +1960,19 @@ How can I assist you today?`;
1955
 
1956
  } catch (error) {
1957
  console.error('Error extracting EMR:', error);
1958
-
1959
  // Reset button state
1960
  const button = document.querySelector(`[onclick="app.extractEMR('${messageId}')"]`);
1961
  if (button) {
1962
  button.innerHTML = '<i class="fas fa-file-medical"></i>';
1963
  button.disabled = false;
1964
  }
1965
-
1966
  // Show error message
1967
  this.showNotification('Failed to extract EMR data. Please try again.', 'error');
1968
  }
1969
  }
1970
 
1971
- async checkEMRStatus(messageId) {
1972
- try {
1973
- const response = await fetch(`/emr/check/${messageId}`);
1974
- if (response.ok) {
1975
- const result = await response.json();
1976
- const button = document.querySelector(`[data-message-id="${messageId}"]`);
1977
- if (button && result.emr_exists) {
1978
- button.innerHTML = '<i class="fas fa-check"></i>';
1979
- button.style.color = 'var(--success-color)';
1980
- button.title = 'EMR data already extracted';
1981
- button.disabled = true;
1982
- }
1983
- }
1984
- } catch (error) {
1985
- console.warn('Could not check EMR status:', error);
1986
- }
1987
- }
1988
-
1989
  showNotification(message, type = 'info') {
1990
  // Create notification element
1991
  const notification = document.createElement('div');
@@ -1996,13 +1983,13 @@ How can I assist you today?`;
1996
  <span>${message}</span>
1997
  </div>
1998
  `;
1999
-
2000
  // Add to page
2001
  document.body.appendChild(notification);
2002
-
2003
  // Show notification
2004
  setTimeout(() => notification.classList.add('show'), 100);
2005
-
2006
  // Remove after 3 seconds
2007
  setTimeout(() => {
2008
  notification.classList.remove('show');
 
599
  } else {
600
  // If doctor not found in local list, try to fetch from backend
601
  try {
602
+ const resp = await fetch(`/account?q=${encodeURIComponent(selectedName)}&limit=1`);
603
  if (resp.ok) {
604
  const data = await resp.json();
605
+ const doctor = data && data[0];
606
  if (doctor) {
607
  if (doctor.role) {
608
  roleEl.value = doctor.role;
 
730
  const sessionElement = document.createElement('div');
731
  sessionElement.className = `chat-session ${session.id === this.currentSession?.id ? 'active' : ''}`;
732
  sessionElement.addEventListener('click', async () => {
733
+ // Avoid re-loading if the session is already active
734
+ if (session.id === this.currentSession?.id) return;
735
+
736
+ await this.switchToSession(session);
 
 
737
  });
738
  const time = this.formatTime(session.lastActivity);
739
  sessionElement.innerHTML = `
 
851
  throw new Error(`HTTP ${resp.status}`);
852
  }
853
 
 
 
 
854
  // Remove from backend sessions
855
  this.backendSessions = this.backendSessions.filter(s => s.id !== sessionId);
856
 
 
966
  const resp = await fetch('/account');
967
  if (resp.ok) {
968
  const data = await resp.json();
969
+ this.doctors = data || [];
970
  // Ensure each doctor has role and specialty information
971
  this.doctors = this.doctors.map(doctor => ({
972
  name: doctor.name,
973
  role: doctor.role || 'Medical Professional',
974
  specialty: doctor.specialty || '',
975
+ id: doctor.id
976
  }));
977
  // Also save to localStorage for offline access
978
  localStorage.setItem('medicalChatbotDoctors', JSON.stringify(this.doctors));
 
999
 
1000
  async searchDoctors(query) {
1001
  try {
1002
+ const resp = await fetch(`/account?q=${encodeURIComponent(query)}&limit=10`);
1003
  if (resp.ok) {
1004
  const data = await resp.json();
1005
+ return data || [];
1006
  }
1007
  } catch (e) {
1008
  console.warn('Doctor search failed:', e);
 
1020
  if (resp.ok) {
1021
  const data = await resp.json();
1022
  // Add to local doctors list
1023
+ this.doctors.push({ name: data.name, id: data.id });
 
1024
  this.saveDoctors();
1025
  return data;
1026
  }
 
1083
  if (!this.doctors.find(d => d.name === name)) {
1084
  // Get current role and specialty from the form
1085
  const role = document.getElementById('profileRole').value || 'Medical Professional';
1086
+ const specialty = document.getElementById('profileSpecialty').value.trim() || null;
1087
 
1088
  // Create doctor in MongoDB
1089
  const result = await this.createDoctor({
1090
  name,
1091
  role,
1092
+ specialty
 
1093
  });
1094
+ if (result && result.id) {
1095
  this.doctors.unshift({
1096
  name,
1097
  role,
1098
  specialty,
1099
+ id: result.id
1100
  });
1101
  this.saveDoctors();
1102
 
1103
  // Update current user profile
1104
+ this.currentUser.id = result.id;
1105
  this.currentUser.name = name;
1106
  this.currentUser.role = role;
1107
  this.currentUser.specialty = specialty;
 
1127
  }
1128
 
1129
  // Check if doctor exists in MongoDB first
1130
+ let existingDoctor = null;
1131
  try {
1132
+ const resp = await fetch(`/account?q=${encodeURIComponent(name)}`);
1133
+ if(resp.ok) {
1134
+ const accounts = await resp.json();
1135
+ existingDoctor = accounts.find(acc => acc.name === name);
1136
+ }
1137
  } catch (e) {
1138
  console.warn('Failed to check doctor existence:', e);
1139
  }
 
1144
  this.currentUser.specialty = specialty;
1145
 
1146
  // Only create new doctor in MongoDB if it doesn't exist
1147
+ if (!existingDoctor) {
1148
  const doctorPayload = {
1149
  name: name,
1150
  role: role,
1151
+ specialty: specialty || null
 
1152
  };
1153
 
1154
  try {
 
1162
  const data = await resp.json();
1163
  console.log('[Doctor] Created new doctor in backend:', data);
1164
 
1165
+ if (data.id) {
1166
+ this.currentUser.id = data.id;
 
1167
  }
1168
 
1169
  // Update local doctor list with the ID from backend
1170
  const existingDoctorIndex = this.doctors.findIndex(d => d.name === name);
1171
  if (existingDoctorIndex === -1) {
1172
+ this.doctors.unshift({ name, role, specialty, id: data.id });
1173
  } else {
1174
+ this.doctors[existingDoctorIndex].id = data.id;
1175
  }
1176
 
1177
  } catch (err) {
 
1179
  }
1180
  } else {
1181
  // If doctor exists, find their ID and update currentUser
1182
+ if (existingDoctor && existingDoctor.id) {
1183
+ this.currentUser.id = existingDoctor.id;
 
1184
  }
1185
  console.log('[Doctor] Doctor already exists in backend, no creation needed');
1186
  }
 
1201
  const storedPatients = JSON.parse(localStorage.getItem('medicalChatbotPatients') || '[]');
1202
  return storedPatients.filter(p => {
1203
  const nameMatch = p.name.toLowerCase().includes(query.toLowerCase());
1204
+ const idMatch = p.id && p.id.includes(query);
 
1205
  return nameMatch || idMatch;
1206
  });
1207
  } catch (e) {
 
1214
  const resultMap = new Map();
1215
  // Add MongoDB results first (they take priority)
1216
  mongoResults.forEach(patient => {
1217
+ if(patient.id) resultMap.set(patient.id, patient);
 
1218
  });
1219
  // Add localStorage results only if not already present
1220
  localResults.forEach(patient => {
1221
+ if (patient.id && !resultMap.has(patient.id)) {
1222
+ resultMap.set(patient.id, patient);
 
1223
  }
1224
  });
1225
  return Array.from(resultMap.values());
 
1255
  const resp = await fetch(`/patient/${pid}`);
1256
  if (resp.ok) {
1257
  const patient = await resp.json();
1258
+ status.textContent = `Patient: ${patient.name || 'Unknown'} (${patient.id})`;
1259
  } else {
1260
  status.textContent = `Patient: ${pid}`;
1261
  }
 
1314
  // Search for patient by name or ID
1315
  console.log('[DEBUG] Searching for patient');
1316
  try {
1317
+ const resp = await fetch(`/patient?q=${encodeURIComponent(value)}&limit=1`);
1318
  console.log('[DEBUG] Search response status:', resp.status);
1319
  if (resp.ok) {
1320
  const data = await resp.json();
1321
  console.log('[DEBUG] Search results:', data);
1322
+ const first = (data || [])[0];
1323
+ if (first && first.id) {
1324
  console.log('[DEBUG] Found patient, setting as current:', first);
1325
+ this.currentPatientId = first.id;
1326
  this.savePatientId();
1327
+ input.value = first.id;
1328
+ this.updatePatientDisplay(first.id, first.name || 'Unknown');
1329
  await this.fetchAndRenderPatientSessions();
1330
  return;
1331
  }
 
1368
  const resp = await fetch(`/patient/${this.currentPatientId}/session`);
1369
  if (resp.ok) {
1370
  const data = await resp.json();
1371
+ sessions = Array.isArray(data) ? data : [];
1372
 
1373
  // Cache the sessions
1374
  localStorage.setItem(cacheKey, JSON.stringify({
 
1386
 
1387
  // Process sessions
1388
  this.backendSessions = sessions.map(s => ({
1389
+ id: s.id,
 
1390
  title: s.title || 'New Chat',
1391
  messages: [],
1392
  createdAt: s.created_at || new Date().toISOString(),
1393
+ lastActivity: s.updated_at || new Date().toISOString(),
1394
  source: 'backend'
1395
  }));
1396
 
 
1403
  }
1404
 
1405
  hydrateMessagesForSession = async function (sessionId) {
 
1406
  if (!sessionId || sessionId === 'undefined') {
1407
  console.error('[DEBUG] hydrateMessagesForSession was called with an invalid session ID:', sessionId);
1408
  return;
 
1430
 
1431
  // If no cache or cache is stale, fetch from backend
1432
  if (messages.length === 0) {
1433
+ const resp = await fetch(`/session/${sessionId}/messages`);
1434
  if (!resp.ok) {
1435
  console.warn(`Failed to fetch messages for session ${sessionId}:`, resp.status);
1436
  return;
1437
  }
1438
  const data = await resp.json();
1439
+ const msgs = Array.isArray(data) ? data : [];
1440
  messages = msgs.map(m => ({
1441
+ id: m.id || this.generateId(),
1442
+ role: m.sent_by_user ? 'user' : 'assistant',
1443
  content: m.content,
1444
  timestamp: m.timestamp
1445
  }));
 
1494
  items.forEach(p => {
1495
  const div = document.createElement('div');
1496
  div.className = 'patient-suggestion';
1497
+ div.textContent = `${p.name || 'Unknown'} (${p.id})`;
 
1498
  div.addEventListener('click', async () => {
1499
+ this.currentPatientId = p.id;
 
1500
  this.savePatientId();
1501
+ patientInput.value = p.id;
1502
  hideSuggestions();
1503
+ this.updatePatientDisplay(p.id, p.name || 'Unknown');
1504
  await this.fetchAndRenderPatientSessions();
1505
  });
1506
  suggestionsEl.appendChild(div);
 
1515
  debounceTimer = setTimeout(async () => {
1516
  try {
1517
  console.log('[DEBUG] Searching patients with query:', q);
1518
+ const url = `/patient?q=${encodeURIComponent(q)}&limit=8`;
1519
  console.log('[DEBUG] Search URL:', url);
1520
  const resp = await fetch(url);
1521
  console.log('[DEBUG] Search response status:', resp.status);
 
1523
  let mongoResults = [];
1524
  if (resp.ok) {
1525
  const data = await resp.json();
1526
+ mongoResults = data || [];
1527
  console.log('[DEBUG] MongoDB search results:', mongoResults);
1528
  } else {
1529
  console.warn('MongoDB search request failed', resp.status);
 
1675
  this.addMessage('user', message);
1676
  this.showLoading(true);
1677
  try {
1678
+ const isNewSession = !this.currentSession || this.currentSession.id === 'default' || this.currentSession.source !== 'backend';
1679
+ const responseData = await this.callMedicalAPI(message, isNewSession);
1680
 
1681
  if (isNewSession && responseData.session_id) {
1682
+ console.log(`[DEBUG] New session created on backend. Updating session ID to '${responseData.session_id}'`);
 
 
1683
 
1684
+ // If it was a local session, remove it
1685
+ if (this.currentSession.id !== 'default' && this.currentSession.source !== 'backend') {
1686
+ const localSessions = this.getChatSessions();
1687
+ const updatedLocalSessions = localSessions.filter(s => s.id !== this.currentSession.id);
1688
+ localStorage.setItem(`chatSessions_${this.currentUser.id}`, JSON.stringify(updatedLocalSessions));
 
1689
  }
1690
+
1691
+ // Update current session to reflect backend reality
1692
+ this.currentSession.id = responseData.session_id;
1693
+ this.currentSession.source = 'backend';
1694
+
1695
+ // Add to backend sessions list and re-render
1696
+ await this.fetchAndRenderPatientSessions();
1697
  }
1698
 
1699
  this.addMessage('assistant', responseData.response || 'I apologize, but I received an empty response. Please try again.');
 
1716
  }
1717
  }
1718
 
1719
+ callMedicalAPI = async function (message, isNewSession) {
1720
  try {
1721
+ let sessionId = this.currentSession?.id;
1722
+
1723
+ // Step 1: Create a new session if required
1724
+ if (isNewSession) {
1725
+ const createSessionPayload = {
1726
+ account_id: this.currentUser.id,
1727
+ patient_id: this.currentPatientId,
1728
+ title: "New Chat" // Title can be updated later
1729
+ };
1730
+ const sessionResponse = await fetch('/session', {
1731
+ method: 'POST',
1732
+ headers: { 'Content-Type': 'application/json' },
1733
+ body: JSON.stringify(createSessionPayload)
1734
+ });
1735
+ if (!sessionResponse.ok) throw new Error(`HTTP error! status: ${sessionResponse.status}`);
1736
+ const newSessionData = await sessionResponse.json();
1737
+ sessionId = newSessionData.id;
1738
+ this.currentSession.id = sessionId; // Update current session immediately
1739
+ this.currentSession.source = 'backend';
1740
+ }
1741
+
1742
+ // Step 2: Post the message to the (potentially new) session
1743
+ const messagePayload = {
1744
  account_id: this.currentUser.id,
1745
  patient_id: this.currentPatientId,
1746
  message: message
1747
  };
1748
 
1749
+ const messageResponse = await fetch(`/session/${sessionId}/messages`, {
 
 
 
 
 
1750
  method: 'POST',
1751
  headers: { 'Content-Type': 'application/json' },
1752
+ body: JSON.stringify(messagePayload)
1753
  });
1754
+
1755
+ if (!messageResponse.ok) throw new Error(`HTTP error! status: ${messageResponse.status}`);
1756
+ const data = await messageResponse.json();
1757
  return data;
1758
+
1759
  } catch (error) {
1760
  console.error('API call failed:', error);
1761
  console.error('Error details:', {
 
1837
  messageElement.id = `message-${message.id}`;
1838
  const avatar = message.role === 'user' ? '<i class="fas fa-user"></i>' : '<i class="fas fa-robot"></i>';
1839
  const time = this.formatTime(message.timestamp);
1840
+
1841
  // Add EMR icon for assistant messages (system-generated)
1842
+ const emrIcon = message.role === 'assistant' ?
1843
  `<div class="message-actions">
1844
  <button class="emr-extract-btn" onclick="app.extractEMR('${message.id}')" title="Extract to EMR" data-message-id="${message.id}">
1845
  <i class="fas fa-file-medical"></i>
1846
  </button>
1847
  </div>` : '';
1848
+
1849
  messageElement.innerHTML = `
1850
  <div class="message-avatar">${avatar}</div>
1851
  <div class="message-content">
 
1856
  chatMessages.appendChild(messageElement);
1857
  chatMessages.scrollTop = chatMessages.scrollHeight;
1858
  if (this.currentSession) this.currentSession.lastActivity = new Date().toISOString();
 
 
 
 
 
1859
  }
1860
 
1861
  formatMessageContent(content) {
 
1917
  button.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
1918
  }
1919
 
1920
+ // Build URL with query parameters
1921
+ const params = new URLSearchParams({
1922
+ patient_id: this.currentPatientId,
1923
+ doctor_id: this.currentUser.id || 'default-doctor',
1924
+ message_id: messageId,
1925
+ session_id: this.currentSession?.id || 'default-session',
1926
+ message: message.content
1927
+ });
1928
+ const url = `/emr/extract?${params.toString()}`;
1929
+
1930
  // Call EMR extraction API
1931
+ const response = await fetch(url, {
1932
  method: 'POST',
1933
  headers: {
1934
+ 'Content-Type': 'application/json', // Header might still be needed by middleware
1935
+ }
 
 
 
 
 
 
 
1936
  });
1937
 
1938
  if (response.ok) {
1939
  const result = await response.json();
1940
  console.log('EMR extraction successful:', result);
1941
+
1942
  // Show success message
1943
  if (button) {
1944
  button.innerHTML = '<i class="fas fa-check"></i>';
 
1949
  button.disabled = false;
1950
  }, 2000);
1951
  }
1952
+
1953
  // Show notification
1954
  this.showNotification('EMR data extracted successfully!', 'success');
1955
  } else {
 
1960
 
1961
  } catch (error) {
1962
  console.error('Error extracting EMR:', error);
1963
+
1964
  // Reset button state
1965
  const button = document.querySelector(`[onclick="app.extractEMR('${messageId}')"]`);
1966
  if (button) {
1967
  button.innerHTML = '<i class="fas fa-file-medical"></i>';
1968
  button.disabled = false;
1969
  }
1970
+
1971
  // Show error message
1972
  this.showNotification('Failed to extract EMR data. Please try again.', 'error');
1973
  }
1974
  }
1975
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1976
  showNotification(message, type = 'info') {
1977
  // Create notification element
1978
  const notification = document.createElement('div');
 
1983
  <span>${message}</span>
1984
  </div>
1985
  `;
1986
+
1987
  // Add to page
1988
  document.body.appendChild(notification);
1989
+
1990
  // Show notification
1991
  setTimeout(() => notification.classList.add('show'), 100);
1992
+
1993
  // Remove after 3 seconds
1994
  setTimeout(() => {
1995
  notification.classList.remove('show');