Ali2206 commited on
Commit
85965d9
·
1 Parent(s): 1518185

Initial CPS-API deployment with TxAgent integration

Browse files
api/routes/appointments.py CHANGED
@@ -3,6 +3,7 @@ from typing import List, Optional
3
  from datetime import date, time, datetime, timedelta
4
  from bson import ObjectId
5
  from motor.motor_asyncio import AsyncIOMotorClient
 
6
 
7
  from core.security import get_current_user
8
  from db.mongo import db, patients_collection
@@ -12,8 +13,102 @@ from models.schemas import (
12
  DoctorAvailabilityResponse, AvailableSlotsResponse, AppointmentSlot, DoctorListResponse
13
  )
14
 
 
 
15
  router = APIRouter(prefix="/appointments", tags=["appointments"])
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  # --- HELPER FUNCTIONS ---
18
  def is_valid_object_id(id_str: str) -> bool:
19
  try:
@@ -532,93 +627,6 @@ async def create_appointment(
532
  updated_at=appointment_doc["updated_at"]
533
  )
534
 
535
- @router.get("/", response_model=AppointmentListResponse)
536
- async def get_appointments(
537
- page: int = Query(1, ge=1),
538
- limit: int = Query(10, ge=1, le=100),
539
- status_filter: Optional[AppointmentStatus] = Query(None),
540
- date_from: Optional[date] = Query(None),
541
- date_to: Optional[date] = Query(None),
542
- current_user: dict = Depends(get_current_user),
543
- db_client: AsyncIOMotorClient = Depends(lambda: db)
544
- ):
545
- """Get appointments based on user role"""
546
- skip = (page - 1) * limit
547
-
548
- # Build filter based on user role
549
- if 'patient' in current_user.get('roles', []) or current_user.get('role') == 'patient':
550
- # Patients see their own appointments
551
- filter_query = {"patient_id": ObjectId(current_user["_id"])}
552
- elif 'doctor' in current_user.get('roles', []) or current_user.get('role') == 'doctor':
553
- # Doctors see appointments assigned to them
554
- filter_query = {"doctor_id": ObjectId(current_user["_id"])}
555
- elif 'admin' in current_user.get('roles', []) or current_user.get('role') == 'admin':
556
- # Admins see all appointments
557
- filter_query = {}
558
- else:
559
- raise HTTPException(
560
- status_code=status.HTTP_403_FORBIDDEN,
561
- detail="Insufficient permissions"
562
- )
563
-
564
- # Add status filter
565
- if status_filter:
566
- filter_query["status"] = status_filter
567
-
568
- # Add date range filter
569
- if date_from or date_to:
570
- date_filter = {}
571
- if date_from:
572
- date_filter["$gte"] = date_from
573
- if date_to:
574
- date_filter["$lte"] = date_to
575
- filter_query["date"] = date_filter
576
-
577
- # Get appointments
578
- cursor = db_client.appointments.find(filter_query).skip(skip).limit(limit).sort("date", -1)
579
- appointments = await cursor.to_list(length=limit)
580
-
581
- print(f"🔍 Found {len(appointments)} appointments")
582
- for i, apt in enumerate(appointments):
583
- print(f"🔍 Appointment {i}: {apt}")
584
-
585
- # Get total count
586
- total = await db_client.appointments.count_documents(filter_query)
587
-
588
- # Get patient and doctor names
589
- appointment_responses = []
590
- for apt in appointments:
591
- patient = await db_client.users.find_one({"_id": apt["patient_id"]})
592
- doctor = await db_client.users.find_one({"_id": apt["doctor_id"]})
593
-
594
- # Convert string date/time back to objects for response
595
- apt_date = datetime.strptime(apt["date"], '%Y-%m-%d').date() if isinstance(apt["date"], str) else apt["date"]
596
- apt_time = datetime.strptime(apt["time"], '%H:%M:%S').time() if isinstance(apt["time"], str) else apt["time"]
597
-
598
- appointment_responses.append(AppointmentResponse(
599
- id=str(apt["_id"]),
600
- patient_id=str(apt["patient_id"]),
601
- doctor_id=str(apt["doctor_id"]),
602
- patient_name=patient['full_name'] if patient else "Unknown Patient",
603
- doctor_name=doctor['full_name'] if doctor else "Unknown Doctor",
604
- date=apt_date,
605
- time=apt_time,
606
- type=apt.get("type", "consultation"), # Default to consultation if missing
607
- status=apt.get("status", "pending"), # Default to pending if missing
608
- reason=apt.get("reason"),
609
- notes=apt.get("notes"),
610
- duration=apt.get("duration", 30),
611
- created_at=apt.get("created_at", datetime.now()),
612
- updated_at=apt.get("updated_at", datetime.now())
613
- ))
614
-
615
- return AppointmentListResponse(
616
- appointments=appointment_responses,
617
- total=total,
618
- page=page,
619
- limit=limit
620
- )
621
-
622
  @router.get("/{appointment_id}", response_model=AppointmentResponse)
623
  async def get_appointment(
624
  appointment_id: str,
 
3
  from datetime import date, time, datetime, timedelta
4
  from bson import ObjectId
5
  from motor.motor_asyncio import AsyncIOMotorClient
6
+ import logging
7
 
8
  from core.security import get_current_user
9
  from db.mongo import db, patients_collection
 
13
  DoctorAvailabilityResponse, AvailableSlotsResponse, AppointmentSlot, DoctorListResponse
14
  )
15
 
16
+ logger = logging.getLogger(__name__)
17
+
18
  router = APIRouter(prefix="/appointments", tags=["appointments"])
19
 
20
+ # --- MAIN APPOINTMENTS ENDPOINT ---
21
+
22
+ @router.get("/", response_model=AppointmentListResponse)
23
+ async def get_appointments(
24
+ page: int = Query(1, ge=1, description="Page number"),
25
+ limit: int = Query(10, ge=1, le=100, description="Number of appointments per page"),
26
+ status_filter: Optional[str] = Query(None, description="Filter by status"),
27
+ date_from: Optional[date] = Query(None, description="Filter from date"),
28
+ date_to: Optional[date] = Query(None, description="Filter to date"),
29
+ current_user: dict = Depends(get_current_user),
30
+ db_client: AsyncIOMotorClient = Depends(lambda: db)
31
+ ):
32
+ """Get appointments with pagination and filters"""
33
+ try:
34
+ # Build query based on user role and filters
35
+ query = {}
36
+
37
+ # Add status filter
38
+ if status_filter:
39
+ query["status"] = status_filter
40
+
41
+ # Add date filters
42
+ if date_from or date_to:
43
+ date_query = {}
44
+ if date_from:
45
+ date_query["$gte"] = date_from.isoformat()
46
+ if date_to:
47
+ date_query["$lte"] = date_to.isoformat()
48
+ query["date"] = date_query
49
+
50
+ # Add user-specific filters
51
+ if 'patient' in current_user.get('roles', []) or current_user.get('role') == 'patient':
52
+ # Patients can only see their own appointments
53
+ query["patient_id"] = ObjectId(current_user["_id"])
54
+ elif 'doctor' in current_user.get('roles', []) or current_user.get('role') == 'doctor':
55
+ # Doctors can see appointments assigned to them
56
+ query["doctor_id"] = ObjectId(current_user["_id"])
57
+ # Admins can see all appointments (no additional filter)
58
+
59
+ # Calculate skip for pagination
60
+ skip = (page - 1) * limit
61
+
62
+ # Get appointments
63
+ cursor = db_client.appointments.find(query).sort("date", -1).skip(skip).limit(limit)
64
+ appointments = await cursor.to_list(length=None)
65
+
66
+ # Get total count for pagination
67
+ total_count = await db_client.appointments.count_documents(query)
68
+
69
+ # Convert to response models
70
+ appointment_responses = []
71
+ for apt in appointments:
72
+ # Get patient and doctor names
73
+ patient = await db_client.users.find_one({"_id": apt["patient_id"]})
74
+ doctor = await db_client.users.find_one({"_id": apt["doctor_id"]})
75
+
76
+ # Convert string date/time back to objects for response
77
+ apt_date = datetime.strptime(apt["date"], '%Y-%m-%d').date() if isinstance(apt["date"], str) else apt["date"]
78
+ apt_time = datetime.strptime(apt["time"], '%H:%M:%S').time() if isinstance(apt["time"], str) else apt["time"]
79
+
80
+ appointment_responses.append(AppointmentResponse(
81
+ id=str(apt["_id"]),
82
+ patient_id=str(apt["patient_id"]),
83
+ doctor_id=str(apt["doctor_id"]),
84
+ patient_name=patient['full_name'] if patient else "Unknown Patient",
85
+ doctor_name=doctor['full_name'] if doctor else "Unknown Doctor",
86
+ date=apt_date,
87
+ time=apt_time,
88
+ type=apt.get("type", "consultation"),
89
+ status=apt.get("status", "pending"),
90
+ reason=apt.get("reason"),
91
+ notes=apt.get("notes"),
92
+ duration=apt.get("duration", 30),
93
+ created_at=apt.get("created_at", datetime.now()),
94
+ updated_at=apt.get("updated_at", datetime.now())
95
+ ))
96
+
97
+ return AppointmentListResponse(
98
+ appointments=appointment_responses,
99
+ total=total_count,
100
+ page=page,
101
+ limit=limit,
102
+ total_pages=(total_count + limit - 1) // limit
103
+ )
104
+
105
+ except Exception as e:
106
+ logger.error(f"Error fetching appointments: {e}")
107
+ raise HTTPException(
108
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
109
+ detail="Failed to fetch appointments"
110
+ )
111
+
112
  # --- HELPER FUNCTIONS ---
113
  def is_valid_object_id(id_str: str) -> bool:
114
  try:
 
627
  updated_at=appointment_doc["updated_at"]
628
  )
629
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  @router.get("/{appointment_id}", response_model=AppointmentResponse)
631
  async def get_appointment(
632
  appointment_id: str,
api/routes/txagent.py CHANGED
@@ -47,14 +47,12 @@ async def get_patient_analysis_results(
47
  # Use the integrated TxAgent service to get analysis results
48
  results = await txagent_service.get_analysis_results(name)
49
 
50
- return {
51
- "status": "success",
52
- "results": results,
53
- "mode": txagent_service.config.get_txagent_mode()
54
- }
55
  except Exception as e:
56
  logger.error(f"Error getting analysis results: {e}")
57
- raise HTTPException(status_code=500, detail="Failed to get analysis results")
 
58
 
59
  @router.post("/txagent/chat")
60
  async def chat_with_txagent(
 
47
  # Use the integrated TxAgent service to get analysis results
48
  results = await txagent_service.get_analysis_results(name)
49
 
50
+ # Return the results directly (not wrapped in status/mode)
51
+ return results
 
 
 
52
  except Exception as e:
53
  logger.error(f"Error getting analysis results: {e}")
54
+ # Return empty array instead of throwing error to prevent 500
55
+ return []
56
 
57
  @router.post("/txagent/chat")
58
  async def chat_with_txagent(
api/services/txagent_service.py CHANGED
@@ -99,17 +99,24 @@ class TxAgentService:
99
 
100
  async def get_analysis_results(self, name: Optional[str] = None) -> List[Dict[str, Any]]:
101
  """Get patient analysis results from TxAgent service"""
102
- params = {}
103
- if name:
104
- params['name'] = name
105
-
106
- # Build URL with query parameters
107
- endpoint = "/patients/analysis-results"
108
- if params:
109
- query_string = "&".join([f"{k}={v}" for k, v in params.items()])
110
- endpoint = f"{endpoint}?{query_string}"
111
-
112
- return await self._make_request(endpoint, "GET")
 
 
 
 
 
 
 
113
 
114
  async def get_chats(self) -> List[Dict[str, Any]]:
115
  """Obtient l'historique des chats"""
 
99
 
100
  async def get_analysis_results(self, name: Optional[str] = None) -> List[Dict[str, Any]]:
101
  """Get patient analysis results from TxAgent service"""
102
+ try:
103
+ # Try to call the external TxAgent API first
104
+ params = {}
105
+ if name:
106
+ params['name'] = name
107
+
108
+ # Build URL with query parameters
109
+ endpoint = "/patients/analysis-results"
110
+ if params:
111
+ query_string = "&".join([f"{k}={v}" for k, v in params.items()])
112
+ endpoint = f"{endpoint}?{query_string}"
113
+
114
+ return await self._make_request(endpoint, "GET")
115
+ except Exception as e:
116
+ logger.warning(f"Failed to get analysis results from external TxAgent API: {e}")
117
+ # Return empty results if external API is not available
118
+ # In a real implementation, you would query your local database
119
+ return []
120
 
121
  async def get_chats(self) -> List[Dict[str, Any]]:
122
  """Obtient l'historique des chats"""