Spaces:
Runtime error
Runtime error
dylanglenister
commited on
Commit
·
4624a2d
1
Parent(s):
a00215a
Unifying doctors and users routes as accounts
Browse files- src/api/routes/{doctors.py → account.py} +27 -27
- src/api/routes/user.py +0 -72
- src/data/repositories/account.py +6 -3
- src/main.py +2 -4
- src/models/user.py +1 -6
- static/js/app.js +6 -6
src/api/routes/{doctors.py → account.py}
RENAMED
|
@@ -1,61 +1,61 @@
|
|
| 1 |
-
# api/routes/
|
| 2 |
|
| 3 |
from fastapi import APIRouter, HTTPException
|
| 4 |
|
| 5 |
-
from src.data.repositories.account import (create_account,
|
| 6 |
-
|
| 7 |
-
from src.models.user import
|
| 8 |
from src.utils.logger import logger
|
| 9 |
|
| 10 |
-
router = APIRouter(prefix="/
|
| 11 |
|
| 12 |
@router.get("")
|
| 13 |
-
async def
|
| 14 |
try:
|
| 15 |
-
logger().info(f"GET /
|
| 16 |
results = get_all_accounts(limit=limit)
|
| 17 |
-
logger().info(f"Retrieved {len(results)}
|
| 18 |
return {"results": results}
|
| 19 |
except Exception as e:
|
| 20 |
-
logger().error(f"Error getting all
|
| 21 |
raise HTTPException(status_code=500, detail=str(e))
|
| 22 |
|
| 23 |
@router.post("")
|
| 24 |
-
async def
|
| 25 |
try:
|
| 26 |
-
logger().info(f"POST /
|
| 27 |
-
|
| 28 |
name=req.name,
|
| 29 |
role=req.role,
|
| 30 |
specialty=req.specialty
|
| 31 |
)
|
| 32 |
-
logger().info(f"Created
|
| 33 |
-
return {"
|
| 34 |
except Exception as e:
|
| 35 |
-
logger().error(f"Error creating
|
| 36 |
raise HTTPException(status_code=500, detail=str(e))
|
| 37 |
|
| 38 |
-
@router.get("/{
|
| 39 |
-
async def
|
| 40 |
try:
|
| 41 |
-
logger().info(f"GET /
|
| 42 |
-
|
| 43 |
-
if not
|
| 44 |
-
raise HTTPException(status_code=404, detail="
|
| 45 |
-
return
|
| 46 |
except HTTPException:
|
| 47 |
raise
|
| 48 |
except Exception as e:
|
| 49 |
-
logger().error(f"Error getting
|
| 50 |
raise HTTPException(status_code=500, detail=str(e))
|
| 51 |
|
| 52 |
@router.get("/search")
|
| 53 |
-
async def
|
| 54 |
try:
|
| 55 |
-
logger().info(f"GET /
|
| 56 |
results = search_accounts(q, limit=limit)
|
| 57 |
-
logger().info(f"
|
| 58 |
return {"results": results}
|
| 59 |
except Exception as e:
|
| 60 |
-
logger().error(f"Error searching
|
| 61 |
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
| 1 |
+
# api/routes/account.py
|
| 2 |
|
| 3 |
from fastapi import APIRouter, HTTPException
|
| 4 |
|
| 5 |
+
from src.data.repositories.account import (create_account, get_account_by_name,
|
| 6 |
+
get_all_accounts, search_accounts)
|
| 7 |
+
from src.models.user import AccountCreateRequest
|
| 8 |
from src.utils.logger import logger
|
| 9 |
|
| 10 |
+
router = APIRouter(prefix="/account", tags=["Account"])
|
| 11 |
|
| 12 |
@router.get("")
|
| 13 |
+
async def get_all_accounts_route(limit: int = 50):
|
| 14 |
try:
|
| 15 |
+
logger(tag="All").info(f"GET /account limit={limit}")
|
| 16 |
results = get_all_accounts(limit=limit)
|
| 17 |
+
logger().info(f"Retrieved {len(results)} accounts")
|
| 18 |
return {"results": results}
|
| 19 |
except Exception as e:
|
| 20 |
+
logger().error(f"Error getting all accounts: {e}")
|
| 21 |
raise HTTPException(status_code=500, detail=str(e))
|
| 22 |
|
| 23 |
@router.post("")
|
| 24 |
+
async def create_account_profile(req: AccountCreateRequest):
|
| 25 |
try:
|
| 26 |
+
logger().info(f"POST /account name={req.name}")
|
| 27 |
+
account_id = create_account(
|
| 28 |
name=req.name,
|
| 29 |
role=req.role,
|
| 30 |
specialty=req.specialty
|
| 31 |
)
|
| 32 |
+
logger().info(f"Created account {req.name} id={account_id}")
|
| 33 |
+
return {"account_id": account_id, "name": req.name}
|
| 34 |
except Exception as e:
|
| 35 |
+
logger().error(f"Error creating account: {e}")
|
| 36 |
raise HTTPException(status_code=500, detail=str(e))
|
| 37 |
|
| 38 |
+
@router.get("/{account_name}")
|
| 39 |
+
async def get_account(account_name: str):
|
| 40 |
try:
|
| 41 |
+
logger(tag="By name").info(f"GET /account/{account_name}")
|
| 42 |
+
account = get_account_by_name(account_name)
|
| 43 |
+
if not account:
|
| 44 |
+
raise HTTPException(status_code=404, detail="account not found")
|
| 45 |
+
return account
|
| 46 |
except HTTPException:
|
| 47 |
raise
|
| 48 |
except Exception as e:
|
| 49 |
+
logger().error(f"Error getting account: {e}")
|
| 50 |
raise HTTPException(status_code=500, detail=str(e))
|
| 51 |
|
| 52 |
@router.get("/search")
|
| 53 |
+
async def search_accounts_route(q: str, limit: int = 10):
|
| 54 |
try:
|
| 55 |
+
logger().info(f"GET /account/search q='{q}' limit={limit}")
|
| 56 |
results = search_accounts(q, limit=limit)
|
| 57 |
+
logger().info(f"account search returned {len(results)} results")
|
| 58 |
return {"results": results}
|
| 59 |
except Exception as e:
|
| 60 |
+
logger().error(f"Error searching accounts: {e}")
|
| 61 |
raise HTTPException(status_code=500, detail=str(e))
|
src/api/routes/user.py
DELETED
|
@@ -1,72 +0,0 @@
|
|
| 1 |
-
# api/routes/user.py
|
| 2 |
-
|
| 3 |
-
from fastapi import APIRouter, Depends, HTTPException
|
| 4 |
-
|
| 5 |
-
from src.core.state import MedicalState, get_state
|
| 6 |
-
from src.data.repositories.account import create_account
|
| 7 |
-
from src.models.user import UserProfileRequest
|
| 8 |
-
from src.utils.logger import logger
|
| 9 |
-
|
| 10 |
-
router = APIRouter(prefix="/users", tags=["Users"])
|
| 11 |
-
|
| 12 |
-
@router.post("")
|
| 13 |
-
async def create_user_profile(
|
| 14 |
-
request: UserProfileRequest,
|
| 15 |
-
state: MedicalState = Depends(get_state)
|
| 16 |
-
):
|
| 17 |
-
"""Create or update user profile"""
|
| 18 |
-
try:
|
| 19 |
-
# Persist to in-memory profile (existing behavior)
|
| 20 |
-
#state.memory_system.create_user(name=request.name, role=request.role, speciality=request.specialty)
|
| 21 |
-
|
| 22 |
-
# Persist to MongoDB accounts collection
|
| 23 |
-
account_id = create_account(
|
| 24 |
-
request.name,
|
| 25 |
-
request.role,
|
| 26 |
-
request.specialty
|
| 27 |
-
)
|
| 28 |
-
|
| 29 |
-
return {"message": "User profile created successfully", "account_id": account_id}
|
| 30 |
-
except Exception as e:
|
| 31 |
-
logger().error(f"Error creating user profile: {e}")
|
| 32 |
-
raise HTTPException(status_code=500, detail=str(e))
|
| 33 |
-
|
| 34 |
-
@router.get("/{user_id}")
|
| 35 |
-
async def get_user_profile(
|
| 36 |
-
user_id: str,
|
| 37 |
-
state: MedicalState = Depends(get_state)
|
| 38 |
-
):
|
| 39 |
-
"""Get user profile and sessions"""
|
| 40 |
-
try:
|
| 41 |
-
user = state.memory_system.get_user(user_id)
|
| 42 |
-
if not user:
|
| 43 |
-
raise HTTPException(status_code=404, detail="User not found")
|
| 44 |
-
|
| 45 |
-
sessions = state.memory_system.get_user_sessions(user_id)
|
| 46 |
-
|
| 47 |
-
return {
|
| 48 |
-
"user": {
|
| 49 |
-
"id": user.user_id,
|
| 50 |
-
"name": user.name,
|
| 51 |
-
"role": user.preferences.get("role", "Unknown"),
|
| 52 |
-
"specialty": user.preferences.get("specialty", ""),
|
| 53 |
-
"medical_roles": user.preferences.get("medical_roles", []),
|
| 54 |
-
"created_at": user.created_at,
|
| 55 |
-
"last_seen": user.last_seen
|
| 56 |
-
},
|
| 57 |
-
"sessions": [
|
| 58 |
-
{
|
| 59 |
-
"id": session.session_id,
|
| 60 |
-
"title": session.title,
|
| 61 |
-
"created_at": session.created_at,
|
| 62 |
-
"last_activity": session.last_activity,
|
| 63 |
-
"message_count": len(session.messages)
|
| 64 |
-
}
|
| 65 |
-
for session in sessions if session is not None
|
| 66 |
-
]
|
| 67 |
-
}
|
| 68 |
-
except HTTPException:
|
| 69 |
-
raise
|
| 70 |
-
except Exception as e:
|
| 71 |
-
logger().error(f"Error getting user profile: {e}")
|
| 72 |
-
raise HTTPException(status_code=500, detail=str(e))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/data/repositories/account.py
CHANGED
|
@@ -39,6 +39,7 @@ VALID_ROLES = [
|
|
| 39 |
]
|
| 40 |
|
| 41 |
def create():
|
|
|
|
| 42 |
create_collection(
|
| 43 |
ACCOUNTS_COLLECTION,
|
| 44 |
"schemas/account_validator.json"
|
|
@@ -68,7 +69,7 @@ def create_account(
|
|
| 68 |
user_data: dict[str, Any] = {
|
| 69 |
"name": name,
|
| 70 |
"role" : role,
|
| 71 |
-
"specialty": specialty,
|
| 72 |
"created_at": now,
|
| 73 |
"updated_at": now
|
| 74 |
}
|
|
@@ -120,10 +121,12 @@ def get_account(
|
|
| 120 |
|
| 121 |
def get_account_by_name(name: str) -> dict[str, Any] | None:
|
| 122 |
"""Get account by name from accounts collection"""
|
|
|
|
| 123 |
collection = get_collection(ACCOUNTS_COLLECTION)
|
| 124 |
account = collection.find_one({"name": name})
|
| 125 |
-
#
|
| 126 |
-
|
|
|
|
| 127 |
return account
|
| 128 |
|
| 129 |
def search_accounts(query: str, limit: int = 10) -> list[dict[str, Any]]:
|
|
|
|
| 39 |
]
|
| 40 |
|
| 41 |
def create():
|
| 42 |
+
#get_collection(ACCOUNTS_COLLECTION).drop()
|
| 43 |
create_collection(
|
| 44 |
ACCOUNTS_COLLECTION,
|
| 45 |
"schemas/account_validator.json"
|
|
|
|
| 69 |
user_data: dict[str, Any] = {
|
| 70 |
"name": name,
|
| 71 |
"role" : role,
|
| 72 |
+
"specialty": specialty or "",
|
| 73 |
"created_at": now,
|
| 74 |
"updated_at": now
|
| 75 |
}
|
|
|
|
| 121 |
|
| 122 |
def get_account_by_name(name: str) -> dict[str, Any] | None:
|
| 123 |
"""Get account by name from accounts collection"""
|
| 124 |
+
logger().info("Trying to retrieve account: " + name)
|
| 125 |
collection = get_collection(ACCOUNTS_COLLECTION)
|
| 126 |
account = collection.find_one({"name": name})
|
| 127 |
+
# HACK This somehow stops some unusual bug with creating a new account.
|
| 128 |
+
if account:
|
| 129 |
+
account["_id"] = str(account.get("_id")) if account.get("_id") else None
|
| 130 |
return account
|
| 131 |
|
| 132 |
def search_accounts(query: str, limit: int = 10) -> list[dict[str, Any]]:
|
src/main.py
CHANGED
|
@@ -24,14 +24,13 @@ except Exception as e:
|
|
| 24 |
logger(tag="env").warning(f"Error loading .env file: {e}")
|
| 25 |
|
| 26 |
# Import project modules after trying to load environment variables
|
|
|
|
| 27 |
from src.api.routes import audio as audio_route
|
| 28 |
from src.api.routes import chat as chat_route
|
| 29 |
-
from src.api.routes import doctors as doctors_route
|
| 30 |
from src.api.routes import patients as patients_route
|
| 31 |
from src.api.routes import session as session_route
|
| 32 |
from src.api.routes import static as static_route
|
| 33 |
from src.api.routes import system as system_route
|
| 34 |
-
from src.api.routes import user as user_route
|
| 35 |
from src.core.state import MedicalState, get_state
|
| 36 |
from src.data.repositories import account as account_repo
|
| 37 |
from src.data.repositories import medical as medical_repo
|
|
@@ -124,10 +123,9 @@ app.mount("/static", StaticFiles(directory="static"), name="static")
|
|
| 124 |
|
| 125 |
# Include routers
|
| 126 |
app.include_router(chat_route.router)
|
| 127 |
-
app.include_router(user_route.router)
|
| 128 |
app.include_router(session_route.router)
|
| 129 |
app.include_router(patients_route.router)
|
| 130 |
-
app.include_router(
|
| 131 |
app.include_router(system_route.router)
|
| 132 |
app.include_router(static_route.router)
|
| 133 |
app.include_router(audio_route.router)
|
|
|
|
| 24 |
logger(tag="env").warning(f"Error loading .env file: {e}")
|
| 25 |
|
| 26 |
# Import project modules after trying to load environment variables
|
| 27 |
+
from src.api.routes import account as account_route
|
| 28 |
from src.api.routes import audio as audio_route
|
| 29 |
from src.api.routes import chat as chat_route
|
|
|
|
| 30 |
from src.api.routes import patients as patients_route
|
| 31 |
from src.api.routes import session as session_route
|
| 32 |
from src.api.routes import static as static_route
|
| 33 |
from src.api.routes import system as system_route
|
|
|
|
| 34 |
from src.core.state import MedicalState, get_state
|
| 35 |
from src.data.repositories import account as account_repo
|
| 36 |
from src.data.repositories import medical as medical_repo
|
|
|
|
| 123 |
|
| 124 |
# Include routers
|
| 125 |
app.include_router(chat_route.router)
|
|
|
|
| 126 |
app.include_router(session_route.router)
|
| 127 |
app.include_router(patients_route.router)
|
| 128 |
+
app.include_router(account_route.router)
|
| 129 |
app.include_router(system_route.router)
|
| 130 |
app.include_router(static_route.router)
|
| 131 |
app.include_router(audio_route.router)
|
src/models/user.py
CHANGED
|
@@ -3,12 +3,7 @@
|
|
| 3 |
from pydantic import BaseModel
|
| 4 |
|
| 5 |
|
| 6 |
-
class
|
| 7 |
-
name: str
|
| 8 |
-
role: str
|
| 9 |
-
specialty: str | None = None
|
| 10 |
-
|
| 11 |
-
class DoctorCreateRequest(BaseModel):
|
| 12 |
name: str
|
| 13 |
role: str
|
| 14 |
specialty: str | None = None
|
|
|
|
| 3 |
from pydantic import BaseModel
|
| 4 |
|
| 5 |
|
| 6 |
+
class AccountCreateRequest(BaseModel):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
name: str
|
| 8 |
role: str
|
| 9 |
specialty: str | None = None
|
static/js/app.js
CHANGED
|
@@ -599,7 +599,7 @@ 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(`/
|
| 603 |
if (resp.ok) {
|
| 604 |
const data = await resp.json();
|
| 605 |
const doctor = data.results && data.results[0];
|
|
@@ -968,7 +968,7 @@ How can I assist you today?`;
|
|
| 968 |
async loadDoctors() {
|
| 969 |
try {
|
| 970 |
// Fetch doctors from MongoDB
|
| 971 |
-
const resp = await fetch('/
|
| 972 |
if (resp.ok) {
|
| 973 |
const data = await resp.json();
|
| 974 |
this.doctors = data.results || [];
|
|
@@ -1004,7 +1004,7 @@ How can I assist you today?`;
|
|
| 1004 |
|
| 1005 |
async searchDoctors(query) {
|
| 1006 |
try {
|
| 1007 |
-
const resp = await fetch(`/
|
| 1008 |
if (resp.ok) {
|
| 1009 |
const data = await resp.json();
|
| 1010 |
return data.results || [];
|
|
@@ -1017,7 +1017,7 @@ How can I assist you today?`;
|
|
| 1017 |
|
| 1018 |
async createDoctor(doctorData) {
|
| 1019 |
try {
|
| 1020 |
-
const resp = await fetch('/
|
| 1021 |
method: 'POST',
|
| 1022 |
headers: { 'Content-Type': 'application/json' },
|
| 1023 |
body: JSON.stringify(doctorData)
|
|
@@ -1134,7 +1134,7 @@ How can I assist you today?`;
|
|
| 1134 |
// Check if doctor exists in MongoDB first
|
| 1135 |
let doctorExists = false;
|
| 1136 |
try {
|
| 1137 |
-
const resp = await fetch(`/
|
| 1138 |
doctorExists = resp.ok;
|
| 1139 |
} catch (e) {
|
| 1140 |
console.warn('Failed to check doctor existence:', e);
|
|
@@ -1176,7 +1176,7 @@ How can I assist you today?`;
|
|
| 1176 |
};
|
| 1177 |
|
| 1178 |
try {
|
| 1179 |
-
const resp = await fetch('/
|
| 1180 |
method: 'POST',
|
| 1181 |
headers: { 'Content-Type': 'application/json' },
|
| 1182 |
body: JSON.stringify(doctorPayload)
|
|
|
|
| 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];
|
|
|
|
| 968 |
async loadDoctors() {
|
| 969 |
try {
|
| 970 |
// Fetch doctors from MongoDB
|
| 971 |
+
const resp = await fetch('/account');
|
| 972 |
if (resp.ok) {
|
| 973 |
const data = await resp.json();
|
| 974 |
this.doctors = data.results || [];
|
|
|
|
| 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 || [];
|
|
|
|
| 1017 |
|
| 1018 |
async createDoctor(doctorData) {
|
| 1019 |
try {
|
| 1020 |
+
const resp = await fetch('/account', {
|
| 1021 |
method: 'POST',
|
| 1022 |
headers: { 'Content-Type': 'application/json' },
|
| 1023 |
body: JSON.stringify(doctorData)
|
|
|
|
| 1134 |
// Check if doctor exists in MongoDB first
|
| 1135 |
let doctorExists = false;
|
| 1136 |
try {
|
| 1137 |
+
const resp = await fetch(`/account/${encodeURIComponent(name)}`);
|
| 1138 |
doctorExists = resp.ok;
|
| 1139 |
} catch (e) {
|
| 1140 |
console.warn('Failed to check doctor existence:', e);
|
|
|
|
| 1176 |
};
|
| 1177 |
|
| 1178 |
try {
|
| 1179 |
+
const resp = await fetch('/account', {
|
| 1180 |
method: 'POST',
|
| 1181 |
headers: { 'Content-Type': 'application/json' },
|
| 1182 |
body: JSON.stringify(doctorPayload)
|