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

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 

5 

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 

15 

16logger = get_logger(__name__) 

17 

18# Create a Blueprint object to hold the routes 

19api_bp = Blueprint("api", __name__) 

20 

21@api_bp.route("/") 

22def index(): 

23 return render_template("index.html") 

24 

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") 

31 

32 if not username or not password: 

33 return jsonify({"success": False, "error": "Username/Password required"}), 400 

34 

35 if User.query.filter_by(username=username).first(): 

36 return jsonify({"success": False, "error": "User already exists"}), 400 

37 

38 new_user = User(username=username) 

39 new_user.set_password(password) 

40 db.session.add(new_user) 

41 db.session.commit() 

42 

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 

47 

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") 

54 

55 user = User.query.filter_by(username=username).first() 

56 

57 if not user or not user.check_password(password): 

58 return jsonify({"success": False, "error": "Invalid credentials"}), 401 

59 

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 

68 

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", "") 

76 

77 if not question: 

78 return jsonify({"success": False, "error": "question is required"}), 400 

79 

80 logger.info(f"Processing question for user: {user_id}") 

81 

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 }) 

96 

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) 

101 

102 wearables_summary = get_wearable_summary(user_id) 

103 wearable_metrics = wearables_summary.get("metrics", []) 

104 wearables_count = len(wearable_metrics) 

105 

106 papers = search_papers(query=question, top_k=3) 

107 

108 medications = patient_profile.get("medications", []) if patient_profile else [] 

109 drug_interactions = check_drug_interactions(medications=medications) 

110 

111 context = { 

112 "patient": patient_profile, 

113 "wearables": wearables_summary, 

114 "papers": papers, 

115 "drug_facts": drug_interactions, 

116 } 

117 

118 prompt = build_medical_prompt(question=question, context=context) 

119 response = call_ollama(prompt) 

120 claims = extract_claims(response) 

121 

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 

125 

126 drug_warnings = [] 

127 if drug_interactions: 

128 drug_warnings = drug_interactions.get("drug_drug_interactions", []) 

129 

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 }) 

147 

148 except Exception as e: 

149 logger.exception("Error processing question") 

150 return jsonify({"success": False, "error": str(e)}), 500 

151 

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 ) 

163 

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 

170 

171@api_bp.route("/api/health", methods=["GET"]) 

172def health(): 

173 return jsonify({"status": "ok", "message": "Medical Assistant API running"})