Coverage for app \ routes \ api.py: 88%
102 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-24 13:18 +0530
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-24 13:18 +0530
1from flask import Blueprint, render_template, request, jsonify
2from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity
3from app.models import db, User
4from app.utils.logger import get_logger
6# Project Imports
7from app.knowledge_graph.patient_graph_reader import get_patient_profile, create_patient
8from app.knowledge_graph.autopilot import analyze_health_intent, apply_graph_update
9from app.knowledge_graph.wearables_graph import get_wearable_summary
10from app.knowledge_graph.drug_interactions import check_drug_interactions
11from app.vector_store.paper_search import search_papers
12from app.rag.prompt_builder import build_medical_prompt
13from app.rag.claim_extractor import extract_claims
14from app.llm.ollama_client import call_ollama
16logger = get_logger(__name__)
18# Create a Blueprint object to hold the routes
19api_bp = Blueprint("api", __name__)
21@api_bp.route("/")
22def index():
23 return render_template("index.html")
25@api_bp.route("/api/register", methods=["POST"])
26def register():
27 try:
28 data = request.get_json()
29 username = data.get("username")
30 password = data.get("password")
32 if not username or not password:
33 return jsonify({"success": False, "error": "Username/Password required"}), 400
35 if User.query.filter_by(username=username).first():
36 return jsonify({"success": False, "error": "User already exists"}), 400
38 new_user = User(username=username)
39 new_user.set_password(password)
40 db.session.add(new_user)
41 db.session.commit()
43 create_patient(user_id=username) # Sync to Neo4j
44 return jsonify({"success": True, "message": "User registered successfully"})
45 except Exception as e:
46 return jsonify({"success": False, "error": str(e)}), 500
48@api_bp.route("/api/login", methods=["POST"])
49def login():
50 try:
51 data = request.get_json()
52 username = data.get("username")
53 password = data.get("password")
55 user = User.query.filter_by(username=username).first()
57 if not user or not user.check_password(password):
58 return jsonify({"success": False, "error": "Invalid credentials"}), 401
60 access_token = create_access_token(identity=username)
61 return jsonify({
62 "success": True,
63 "access_token": access_token,
64 "username": username,
65 })
66 except Exception as e:
67 return jsonify({"success": False, "error": str(e)}), 500
69@api_bp.route("/api/ask", methods=["POST"])
70@jwt_required()
71def ask_question():
72 try:
73 user_id = get_jwt_identity()
74 data = request.json
75 question = data.get("question", "")
77 if not question:
78 return jsonify({"success": False, "error": "question is required"}), 400
80 logger.info(f"Processing question for user: {user_id}")
82 facts = analyze_health_intent(question)
83 suggestions_payload = []
84 if facts:
85 for fact in facts:
86 suggestions_payload.append({
87 "message": (
88 f"I noticed you mentioned '{fact['original_term']}'. "
89 f"Add '{fact['normalized_term']}' to your profile?"
90 ),
91 "data": {
92 "category": fact["category"],
93 "entity": fact["normalized_term"],
94 },
95 })
97 patient_profile = get_patient_profile(user_id)
98 if not patient_profile:
99 create_patient(user_id=user_id)
100 patient_profile = get_patient_profile(user_id)
102 wearables_summary = get_wearable_summary(user_id)
103 wearable_metrics = wearables_summary.get("metrics", [])
104 wearables_count = len(wearable_metrics)
106 papers = search_papers(query=question, top_k=3)
108 medications = patient_profile.get("medications", []) if patient_profile else []
109 drug_interactions = check_drug_interactions(medications=medications)
111 context = {
112 "patient": patient_profile,
113 "wearables": wearables_summary,
114 "papers": papers,
115 "drug_facts": drug_interactions,
116 }
118 prompt = build_medical_prompt(question=question, context=context)
119 response = call_ollama(prompt)
120 claims = extract_claims(response)
122 conditions_count = len(patient_profile.get("conditions", [])) if patient_profile else 0
123 meds_count = len(patient_profile.get("medications", [])) if patient_profile else 0
124 labs_count = len(patient_profile.get("lab_results", [])) if patient_profile else 0
126 drug_warnings = []
127 if drug_interactions:
128 drug_warnings = drug_interactions.get("drug_drug_interactions", [])
130 return jsonify({
131 "success": True,
132 "answer": response,
133 "claims": claims,
134 "suggestions": suggestions_payload,
135 "context": {
136 "patient_id": user_id,
137 "conditions_count": conditions_count,
138 "meds_count": meds_count,
139 "labs_count": labs_count,
140 "wearables_available": wearables_count > 0,
141 "wearables_count": wearables_count,
142 "papers_found": len(papers),
143 "drug_warnings_count": len(drug_warnings),
144 "has_drug_warnings": len(drug_warnings) > 0,
145 },
146 })
148 except Exception as e:
149 logger.exception("Error processing question")
150 return jsonify({"success": False, "error": str(e)}), 500
152@api_bp.route("/api/confirm_update", methods=["POST"])
153@jwt_required()
154def confirm_update():
155 try:
156 user_id = get_jwt_identity()
157 data = request.json
158 success, message = apply_graph_update(
159 user_id,
160 data.get("category"),
161 data.get("entity"),
162 )
164 if success:
165 return jsonify({"success": True, "message": message})
166 else:
167 return jsonify({"success": False, "error": message}), 500
168 except Exception as e:
169 return jsonify({"success": False, "error": str(e)}), 500
171@api_bp.route("/api/health", methods=["GET"])
172def health():
173 return jsonify({"status": "ok", "message": "Medical Assistant API running"})