feat: initial commit

This commit is contained in:
2025-05-09 19:15:53 +05:30
commit 80c61dc127
54 changed files with 2195 additions and 0 deletions
View File
+8
View File
@@ -0,0 +1,8 @@
from fastapi import APIRouter, status
router = APIRouter()
@router.get("/", status_code=status.HTTP_200_OK)
def get_admin():
return {"message": "Admin"}
+117
View File
@@ -0,0 +1,117 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
# database
from database import get_db
from schemas.ResponseSchemas import AppointmentDetailed, AppointmentSchema
from models.Appointments import Appointments
from schemas.CreateSchemas import AppointmentCreate, AppointmentCreateWithNames
from models.Doctors import Doctors
from models.Patients import Patients
router = APIRouter()
@router.get(
"/", response_model=List[AppointmentDetailed], status_code=status.HTTP_200_OK
)
def get_appointments(
doc_name: str | None = None,
patient_name: str | None = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
):
"""
Get a list of appointments with optional pagination.
"""
try:
query = db.query(Appointments)
if doc_name:
query = query.join(Appointments.doctor).filter(
Doctors.name.ilike(f"%{doc_name}%")
)
if patient_name:
query = query.join(Appointments.patient).filter(
Patients.name.ilike(f"%{patient_name}%")
)
appointments = query.offset(skip).limit(limit).all()
return appointments
except Exception as e:
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
# @router.post("/", response_model=AppointmentSchema, status_code=status.HTTP_201_CREATED)
# def create_appointment(appointment: AppointmentCreate, db: Session = Depends(get_db)):
# """
# Create a new appointment.
# """
# try:
# db_appointment = Appointments(**appointment.model_dump())
# db.add(db_appointment)
# db.commit()
# db.refresh(db_appointment)
# return db_appointment
# except Exception as e:
# db.rollback()
# raise HTTPException(
# status_code=500,
# detail=str(e.__cause__),
# ) from e
@router.post("/", response_model=AppointmentSchema, status_code=status.HTTP_201_CREATED)
def create_appointment_with_names(
appointment: AppointmentCreateWithNames, db: Session = Depends(get_db)
):
"""
Create a new appointment using doctor name and patient name instead of IDs.
"""
try:
# Find doctor by name
doctor = (
db.query(Doctors).filter(Doctors.name == appointment.doctor_name).first()
)
if not doctor:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Doctor with name '{appointment.doctor_name}' not found",
)
# Find patient by name
patient = (
db.query(Patients).filter(Patients.name == appointment.patient_name).first()
)
if not patient:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Patient with name '{appointment.patient_name}' not found",
)
# Create appointment with doctor_id and patient_id
db_appointment = Appointments(
doctor_id=doctor.id,
patient_id=patient.id,
appointment_time=appointment.appointment_time,
status=appointment.status,
)
db.add(db_appointment)
db.commit()
db.refresh(db_appointment)
return db_appointment
except HTTPException:
db.rollback()
raise
except Exception as e:
db.rollback()
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
+23
View File
@@ -0,0 +1,23 @@
from fastapi import APIRouter
from services.authService import AuthService
from schemas.CreateSchemas import UserCreate
from schemas.ApiResponse import ApiResponse
router = APIRouter()
@router.post("/login")
async def login(email: str, password: str):
response = await AuthService().login(email, password)
return ApiResponse(
data=response,
message="Login successful"
)
@router.post("/register")
async def register(user_data: UserCreate):
response = await AuthService().register(user_data)
return ApiResponse(
data=response,
message="User registered successfully"
)
+41
View File
@@ -0,0 +1,41 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
# database
from database import get_db
from models.Calendar import Calenders
from schemas.CreateSchemas import CalendarCreate
from schemas.ResponseSchemas import Calendar
router = APIRouter()
@router.get("/", response_model=List[Calendar])
def get_calendar_events(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
"""
Get a list of calendar events with optional pagination.
"""
# Placeholder for actual database query
events = db.query("CalendarEvents").offset(skip).limit(limit).all()
return events
@router.post("/", response_model=Calendar, status_code=status.HTTP_201_CREATED)
def create_calendar_event(event: CalendarCreate, db: Session = Depends(get_db)):
"""
Create a new calendar event.
"""
try:
db_event = Calenders(**event.model_dump())
db.add(db_event)
db.commit()
db.refresh(db_event)
return db_event
except Exception as e:
db.rollback()
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
+79
View File
@@ -0,0 +1,79 @@
from asyncio.log import logger
from typing import List
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
# database
from database import get_db
# schemas
from schemas.ResponseSchemas import Clinic, ClinicWithDoctors
from schemas.CreateSchemas import ClinicCreate
from schemas.UpdateSchemas import ClinicUpdate
from models.Clinics import Clinics
# Constants
from utils.constants import DEFAULT_SKIP, DEFAULT_LIMIT
router = APIRouter()
@router.get("/", response_model=List[Clinic])
async def get_clinics(
skip: int = DEFAULT_SKIP, limit: int = DEFAULT_LIMIT, db: Session = Depends(get_db)
):
clinics = db.query(Clinics).offset(skip).limit(limit).all()
return clinics
@router.get("/{clinic_id}", response_model=ClinicWithDoctors)
async def get_clinic(clinic_id: int, db: Session = Depends(get_db)):
db_clinic = db.query(Clinics).where(Clinics.id == clinic_id).first()
if db_clinic is None:
raise HTTPException(status_code=404, detail="Clinic not found")
return db_clinic
@router.post("/", response_model=Clinic, status_code=status.HTTP_201_CREATED)
async def create_clinic(clinic: ClinicCreate, db: Session = Depends(get_db)):
try:
db_clinic = Clinics(**clinic.model_dump())
db.add(db_clinic)
db.commit()
db.refresh(db_clinic)
return db_clinic
except Exception as e:
db.rollback()
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
@router.put("/{clinic_id}", response_model=Clinic)
async def update_clinic(
clinic_id: int, clinic: ClinicUpdate, db: Session = Depends(get_db)
):
db_clinic = db.query(Clinics).filter(Clinics.id == clinic_id).first()
if db_clinic is None:
raise HTTPException(status_code=404, detail="Clinic not found")
update_data = clinic.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(db_clinic, key, value)
db.commit()
db.refresh(db_clinic)
return db_clinic
@router.delete("/{clinic_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_clinic(clinic_id: int, db: Session = Depends(get_db)):
db_clinic = db.query(Clinics).where(Clinics.id == clinic_id).first()
if db_clinic is None:
raise HTTPException(status_code=404, detail="Clinic not found")
db.delete(db_clinic)
db.commit()
return None
+143
View File
@@ -0,0 +1,143 @@
from asyncio.log import logger
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List, Dict
from datetime import datetime, timedelta
from sqlalchemy import and_
# database
from database import get_db
# schemas
from models.Doctors import Doctors
from models.Appointments import Appointments
from models.Calendar import Calenders
from schemas.ResponseSchemas import (
Doctor,
DoctorWithAppointments,
DoctorWithCalendar,
CalendarTimeSchema,
)
from schemas.CreateSchemas import DoctorCreate
from schemas.UpdateSchemas import DoctorUpdate
from enums.enums import AppointmentStatus
router = APIRouter()
@router.post("/", response_model=Doctor, status_code=status.HTTP_201_CREATED)
def create_doctor(doctor: DoctorCreate, db: Session = Depends(get_db)):
try:
db_doctor = Doctors(**doctor.model_dump())
db.add(db_doctor)
db.commit()
db.refresh(db_doctor)
return db_doctor
except Exception as e:
db.rollback()
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
@router.get("/", response_model=List[DoctorWithCalendar])
def read_doctors(
doctor_name: str | None = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
):
query = db.query(Doctors)
if doctor_name:
query = query.filter(Doctors.name.ilike(f"%{doctor_name}%"))
doctors = query.offset(skip).limit(limit).all()
return doctors
@router.get("/available-slots/{doctor_name}", response_model=Dict[str, List[str]])
def get_available_slots(
doctor_name: str | None = None,
date: str | None = datetime.now().strftime("%Y-%m-%d"),
db: Session = Depends(get_db),
):
"""
Get available slots for a doctor on a specific date.
date format: YYYY-MM-DD
"""
# Get the doctor
print(f"-----------------doctor_name: {doctor_name}")
doctor = db.query(Doctors).filter(Doctors.name.ilike(f"%{doctor_name}%")).first()
if not doctor:
raise HTTPException(status_code=404, detail="Doctor not found")
# Get all calendar slots for the doctor
calendar_slots = db.query(Calenders).filter(Calenders.doc_id == doctor.id).all()
if not calendar_slots:
return {"available_slots": []}
available_slots = [slot.time for slot in calendar_slots]
try:
target_date = datetime.strptime(date, "%Y-%m-%d").date()
except ValueError:
raise HTTPException(
status_code=400, detail="Invalid date format. Use YYYY-MM-DD"
)
# Get all appointments for the doctor on the specified date
appointments = (
db.query(Appointments)
.filter(
and_(
Appointments.doctor_id == doctor.id,
Appointments.appointment_time >= target_date,
Appointments.appointment_time < target_date + timedelta(days=1),
)
)
.all()
)
# Remove slots that have appointments
for appointment in appointments:
appointment_time = appointment.appointment_time.strftime("%H:%M")
if appointment_time in available_slots and (
not appointment.status == AppointmentStatus.COMPLETED
):
available_slots.remove(appointment_time)
return {"available_slots": available_slots}
# @router.get("/{doctor_name}", response_model=DoctorWithAppointments)
# def read_doctor(doctor_name: str, db: Session = Depends(get_db)):
# db_doctor = db.query(Doctors).filter(Doctors.name.ilike(f"%{doctor_name}%")).all()
# return db_doctor
@router.put("/{doctor_id}", response_model=Doctor)
def update_doctor(doctor_id: int, doctor: DoctorUpdate, db: Session = Depends(get_db)):
db_doctor = db.query(Doctors).filter(Doctors.id == doctor_id).first()
if db_doctor is None:
raise HTTPException(status_code=404, detail="Doctor not found")
update_data = doctor.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(db_doctor, key, value)
db.commit()
db.refresh(db_doctor)
return db_doctor
@router.delete("/{doctor_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_doctor(doctor_id: int, db: Session = Depends(get_db)):
db_doctor = db.query(Doctors).filter(Doctors.id == doctor_id).first()
if db_doctor is None:
raise HTTPException(status_code=404, detail="Doctor not found")
db.delete(db_doctor)
db.commit()
return None
+50
View File
@@ -0,0 +1,50 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List
# database
from database import get_db
from models.Patients import Patients
from schemas.CreateSchemas import PatientCreate
from schemas.ResponseSchemas import Patient
router = APIRouter()
@router.get("/", response_model=List[Patient])
def read_patients(
name: str | None = None,
dob: str | None = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
):
"""
Get a list of patients with optional pagination.
"""
query = db.query(Patients)
if name:
query = query.filter(Patients.name.ilike(f"%{name}%"))
if dob:
query = query.filter(Patients.dob == dob)
patients = query.offset(skip).limit(limit).all()
return patients
@router.post("/", response_model=Patient, status_code=status.HTTP_201_CREATED)
def create_patient(patient: PatientCreate, db: Session = Depends(get_db)):
"""
Create a new patient.
"""
try:
db_patient = Patients(**patient.model_dump())
db.add(db_patient)
db.commit()
db.refresh(db_patient)
return db_patient
except Exception as e:
db.rollback()
raise HTTPException(
status_code=500,
detail=str(e.__cause__),
) from e
+183
View File
@@ -0,0 +1,183 @@
# import asyncio
# import json
# import logging
# import os
# from fastapi import APIRouter, Request, WebSocket, status
# from twilio.twiml.voice_response import VoiceResponse, Connect
# from twilio.rest import Client
# from fastapi import WebSocket, Request, Response
# from enum import Enum
# from typing import Optional
# from services.bot import run_bot
# from services.call_state import CallState
# logger = logging.getLogger(__name__)
# router = APIRouter()
# BASE_WS_URL = "wss://13.229.247.61:8000/api/twilio"
# BASE_URL = "http://13.229.247.61:8000/api/twilio"
# DTMF_SWITCH_KEY = "*" # Key to switch between models
# LOG_EVENT_TYPES = [
# "error",
# "response.content.done",
# "rate_limits.updated",
# "response.done",
# "input_audio_buffer.committed",
# "input_audio_buffer.speech_stopped",
# "input_audio_buffer.speech_started",
# "session.created",
# ]
# SHOW_TIMING_MATH = False
# MENU_OPTIONS = """
# Press 1 for Model 1.
# Press 2 for Model 2.
# Press 3 for Model 3.
# Press 4 for Model 4.
# Press 5 for Model 5.
# Press 0 to repeat the options.
# """
# call_state = CallState
# # Define model options as enum for type safety
# class ModelOption(int, Enum):
# MODEL_1 = 1
# MODEL_2 = 2
# MODEL_3 = 3
# MODEL_4 = 4
# MODEL_5 = 5
# @router.post("/call")
# async def get_call():
# SID = os.getenv("TWILIO_SID")
# AUTH_TOKEN = os.getenv("TWILIO_AUTH")
# client = Client(SID, AUTH_TOKEN)
# call = client.calls.create(
# from_="+14149466486",
# to="+917984372159",
# record=True,
# url=f"{BASE_URL}/receive",
# )
# return status.HTTP_200_OK
# # @router.websocket("/media-stream/{id}")
# # async def handle_media_stream(websocket: WebSocket, id: int):
# # """Handle WebSocket connections between Twilio and OpenAI."""
# # print(f"Client connected with id: {id}")
# # await websocket.accept()
# # start_data = websocket.iter_text()
# # await start_data.__anext__()
# # call_data = json.loads(await start_data.__anext__())
# # print(call_data, flush=True)
# # stream_sid = call_data["start"]["streamSid"]
# # print("WebSocket connection accepted")
# # await run_bot(websocket, stream_sid, False, option=id)
# @router.websocket("/media-stream/{id}")
# async def handle_media_stream(websocket: WebSocket, id: int):
# """Handle WebSocket connections between Twilio and OpenAI."""
# logger.info(f"Client connected with id: {id}")
# print(f"Client connected with id: {id}")
# await websocket.accept()
# start_data = websocket.iter_text()
# await start_data.__anext__()
# call_data = json.loads(await start_data.__anext__())
# print(call_data, flush=True)
# logger.info(call_data)
# stream_sid = call_data["start"]["streamSid"]
# print("WebSocket connection accepted")
# logger.info("WebSocket connection accepted")
# await run_bot(websocket, stream_sid, False, option=id)
# # @router.post("/receive")
# # async def receive_call(req: Request):
# # print("----------------- received call -----------------")
# # resp = VoiceResponse()
# # connect = Connect()
# # connect.stream(
# # url=f"wss://allegedly-known-wasp.ngrok-free.app/api/twilio/media-stream"
# # )
# # resp.append(connect)
# # return Response(content=str(resp), media_type="application/xml")
# @router.post("/receive")
# async def receive_call(req: Request):
# print("----------------- received call -----------------")
# resp = VoiceResponse()
# # Gather DTMF input
# gather = resp.gather(
# num_digits=1, action="/api/twilio/handle-key", method="POST", timeout=10
# )
# # Initial greeting and menu options
# gather.say(MENU_OPTIONS)
# # If no input received, redirect back to the main menu
# resp.redirect("/api/twilio/receive")
# return Response(content=str(resp), media_type="application/xml")
# @router.post("/handle-key")
# async def handle_key_press(req: Request):
# """Process the key pressed by the caller and connect to the appropriate model."""
# try:
# form_data = await req.form()
# digits_pressed = form_data.get("Digits", "")
# print(f"User pressed: {digits_pressed}")
# resp = VoiceResponse()
# if digits_pressed == "0":
# # Repeat options
# resp.redirect("/api/twilio/receive")
# elif digits_pressed in "12345":
# # Valid model selection
# model_id = int(digits_pressed)
# resp.say(f"You have selected model {model_id}.")
# # Connect to WebSocket
# connect = Connect()
# connect.stream(url=f"{BASE_WS_URL}/media-stream/{model_id}")
# resp.append(connect)
# else:
# # Invalid selection
# resp.say("Invalid selection. Please try again.")
# resp.redirect("/api/twilio/receive")
# return Response(content=str(resp), media_type="application/xml")
# except Exception as e:
# print(f"Error handling key press: {str(e)}")
# resp = VoiceResponse()
# resp.say(
# "We encountered a problem processing your request. Please try again later."
# )
# return Response(content=str(resp), media_type="application/xml")
# @router.post("/error")
# async def read_item(req: Request):
# print(await req.body())
# print(await req.form())
# logger.error(await req.body())
# return status.HTTP_200_OK