TheFrogGod commited on
Commit
9783c69
·
verified ·
1 Parent(s): 6e2b6c9

Update backend.py

Browse files
Files changed (1) hide show
  1. backend.py +140 -249
backend.py CHANGED
@@ -1,60 +1,36 @@
 
1
  from ast import List
2
- from fastapi import FastAPI, UploadFile, File, Form, HTTPException,APIRouter, Request
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
5
- from typing import Optional
6
- import pytesseract
7
- from PIL import Image
8
  import io
9
- import fitz
10
- import base64
11
  import traceback
12
  import pandas as pd
 
 
 
13
  import re
14
- import os
 
 
 
15
  import google.generativeai as genai
16
- from dotenv import load_dotenv
17
- from fastapi.responses import RedirectResponse
18
  from fastapi.staticfiles import StaticFiles
19
  import firebase_admin
20
  from firebase_admin import credentials, firestore
21
  from google.generativeai import generative_models
22
-
23
- from api_key import GEMINI_API_KEY
24
- from bert import analyze_with_clinicalBert, classify_disease_and_severity, extract_non_negated_keywords, analyze_measurements, detect_past_diseases
25
- from disease_links import diseases as disease_links
26
- from disease_steps import disease_next_steps
27
- from disease_support import disease_doctor_specialty, disease_home_care
28
  from past_reports import router as reports_router, db_fetch_reports
29
 
30
- model = genai.GenerativeModel('gemini-1.5-flash')
31
- df = pd.read_csv("measurement.csv")
32
- df.columns = df.columns.str.lower()
33
- df['measurement'] = df['measurement'].str.lower()
34
-
35
- disease_links = {"cholesterol": "https://www.webmd.com/cholesterol"}
36
- disease_next_steps = {"cholesterol": ["Consult a doctor for a lipid panel."]}
37
- disease_doctor_specialty = {"cholesterol": "Cardiologist"}
38
- disease_home_care = {"cholesterol": ["Maintain a healthy diet."]}
39
 
40
  app = FastAPI()
41
-
42
  api = APIRouter(prefix="/api")
43
  app.include_router(api)
44
 
45
-
46
- '''app.add_middleware(
47
- CORSMiddleware,
48
- allow_origins=[
49
- "http://localhost:8002"
50
- "http://localhost:9000"
51
- "http://localhost:5501"
52
- ],
53
- allow_credentials=True,
54
- allow_methods=["*"],
55
- allow_headers=["*"],
56
- )'''
57
-
58
 
59
  app.mount("/app", StaticFiles(directory="web", html=True), name="web")
60
  app.include_router(reports_router)
@@ -70,38 +46,60 @@ app.add_middleware(
70
  @app.get("/")
71
  def root():
72
  return RedirectResponse(url="/app/")
73
-
74
- EXTRACTED_TEXT_CACHE: str = ""
75
-
76
- try:
77
- gemini_api_key = os.environ.get("GEMINI_API_KEY", GEMINI_API_KEY)
78
- if not gemini_api_key:
79
- raise ValueError("No Gemini API key found in environment or api_key.py")
80
- genai.configure(api_key=gemini_api_key)
81
- except Exception as e:
82
- raise RuntimeError(f"Failed to configure Gemini API: {e}")
83
-
84
- try:
85
- cred_path = os.environ.get("FIREBASE_SERVICE_ACCOUNT_KEY_PATH", "firebase_key.json")
86
-
87
- if not os.path.exists(cred_path):
88
- raise ValueError(
89
- f"Firebase service account key not found. Looked for: {cred_path}. "
90
- "Set FIREBASE_SERVICE_ACCOUNT_KEY_PATH or place firebase_key.json in project root."
91
- )
92
 
93
- cred = credentials.Certificate(cred_path)
94
- firebase_admin.initialize_app(cred)
95
- db = firestore.client()
96
- except Exception as e:
97
- raise RuntimeError(f"Failed to configure Firebase: {e}")
 
 
 
 
 
 
 
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  class ChatRequest(BaseModel):
100
  user_id: Optional[str] = "anonymous"
101
  question: str
102
-
103
  class ChatResponse(BaseModel):
104
  answer: str
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  system_prompt_chat = """
107
  *** Role: Medical Guidance Facilitator
@@ -112,7 +110,9 @@ Analyze medical data, provide concise, evidence-based insights, and recommend ac
112
  2. Historical Context – Compare current findings with any available previous reports.
113
  3. Medical Q&A – Answer specific questions about the report using trusted medical sources.
114
  4. Specialist Matching – Recommend relevant physician specialties for identified conditions.
115
- 5. Safety ProtocolsInclude a brief disclaimer encouraging users to verify information, confirm insurance coverage, and consult providers directly.
 
 
116
  *** Response Structure:
117
  Start with a direct answer to the user’s primary question (maximum 4 concise sentences, each on a new line).
118
  If a physician/specialist is needed, recommend at least two local providers within the requested radius (include name, specialty, address, distance, and contact info).
@@ -124,55 +124,56 @@ User Question: {user_question}
124
  Assistant Answer:
125
  """
126
 
127
- def extract_images_from_pdf_bytes(pdf_bytes: bytes) -> list:
128
- print("***Start of Code***")
129
- doc = fitz.open(stream=pdf_bytes, filetype="pdf")
130
- images = []
131
- for page in doc:
132
- pix = page.get_pixmap()
133
- buf = io.BytesIO()
134
- buf.write(pix.tobytes("png"))
135
- images.append(buf.getvalue())
136
- return images
137
-
138
-
139
- def clean_ocr_text(text: str) -> str:
140
- text = text.replace("\x0c", " ")
141
- text = text.replace("\u00a0", " ")
142
- text = re.sub(r'(\d)\s*\.\s*(\d)', r'\1.\2', text)
143
- text = re.sub(r'\s+', ' ', text)
144
- return text.strip()
145
-
146
- def ocr_text_from_image(image_bytes: bytes) -> str:
147
- base64_image = base64.b64encode(image_bytes).decode('utf-8')
148
-
149
- image_content = {
150
- 'mime_type': 'image/jpeg',
151
- 'data': base64_image
152
- }
153
-
154
- prompt = "Could you read this document and just take all the text that is in it and just paste it back to me in text format. Open and read this document:"
155
-
156
- response = model.generate_content(
157
- [prompt, image_content]
158
  )
 
 
159
 
160
- response_text = response.text
161
- print(response_text)
162
 
163
- return response_text
164
- def get_past_reports_from_firestore(user_id: str):
 
 
 
 
 
 
 
165
  try:
166
- reports_ref = db.collection('users').document(request.user_id).collection('reports')
167
- docs = reports_ref.order_by('timestamp', direction=firestore.Query.DESCENDING).limit(10).stream()
168
-
169
- history_text = ""
170
- for doc in docs:
171
- report_data = doc.to_dict()
172
- history_text += f"Report from {report_data.get('timestamp', 'N/A')}:\n{report_data.get('ocr_text', 'No OCR text found')}\n\n"
173
  except Exception as e:
174
- history_text = "No past reports found for this user."
175
- return history_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
  def get_past_reports_from_sqllite(user_id: str):
178
  try:
@@ -187,156 +188,46 @@ def get_past_reports_from_sqllite(user_id: str):
187
 
188
  @app.post("/chat/", response_model=ChatResponse)
189
  async def chat_endpoint(request: ChatRequest):
190
- """
191
- Chatbot endpoint that answers questions based on the last analyzed document and user history.
192
- """
193
- print("Received chat request for user:", request.user_id)
194
- #history_text = get_past_reports_from_firestore(request.user_id)
195
- history_text = get_past_reports_from_sqllite(request.user_id)
196
-
197
- full_document_text = EXTRACTED_TEXT_CACHE + "\n\n" + "PAST REPORTS:\n" + history_text
198
-
199
- if not full_document_text:
200
- raise HTTPException(status_code=400, detail="No past reports or current data exists for this user")
201
-
202
-
203
-
204
-
205
  try:
 
206
  full_prompt = system_prompt_chat.format(
207
- document_text=full_document_text,
208
  user_question=request.question
209
  )
 
 
 
 
 
210
  response = model.generate_content(full_prompt)
211
  return ChatResponse(answer=response.text)
212
  except Exception as e:
213
- print(f"Gemini API error: {traceback.format_exc()}")
214
- raise HTTPException(status_code=500, detail=f"An error occurred during chat response generation: {e}")
215
-
216
- @app.post("/analyze/")
217
- async def analyze(
218
- file: UploadFile = File(...),
219
- model: Optional[str] = Form("bert"),
220
- mode: Optional[str] = Form(None)
221
- ):
222
- global resolution, EXTRACTED_TEXT_CACHE
223
- if not file.filename:
224
- raise HTTPException(status_code=400, detail="No file uploaded.")
225
-
226
- filename = file.filename.lower()
227
- detected_diseases = set()
228
- ocr_full = ""
229
- print("Received request for file:", filename)
230
- if filename.endswith(".pdf"):
231
- pdf_bytes = await file.read()
232
- image_bytes_list = extract_images_from_pdf_bytes(pdf_bytes)
233
- else:
234
- content = await file.read()
235
- image_bytes_list = [content]
236
-
237
- for img_bytes in image_bytes_list:
238
- ocr_text = ocr_text_from_image(img_bytes)
239
- ocr_full += ocr_text + "\n\n"
240
- ocr_full = clean_ocr_text(ocr_full)
241
- print(f"CALLING OCR FULL: {ocr_full}")
242
-
243
- EXTRACTED_TEXT_CACHE = ocr_full
244
-
245
-
246
- if model.lower() == "gemini":
247
- return {"message": "Gemini model not available; please use BERT model."}
248
 
249
- found_diseases = extract_non_negated_keywords(ocr_full)
250
- past = detect_past_diseases(ocr_full)
251
-
252
- for disease in found_diseases:
253
- if disease in past:
254
- severity = classify_disease_and_severity(disease)
255
- detected_diseases.add(((f"{disease}(detected as historical condition, but still under risk.)"), severity))
256
- else:
257
- severity = classify_disease_and_severity(disease)
258
- detected_diseases.add((disease, severity))
259
-
260
-
261
-
262
- print("Detected diseases:", detected_diseases)
263
- ranges = analyze_measurements(ocr_full, df)
264
-
265
-
266
- resolution = []
267
- detected_ranges = []
268
- for disease, severity in detected_diseases:
269
- link = disease_links.get(disease.lower(), "https://www.webmd.com/")
270
- next_steps = disease_next_steps.get(disease.lower(), ["Consult a doctor."])
271
- specialist = disease_doctor_specialty.get(disease.lower(), "General Practitioner")
272
- home_care = disease_home_care.get(disease.lower(), [])
273
-
274
- resolution.append({
275
- "findings": disease.upper(),
276
- "severity": severity,
277
- "recommendations": next_steps,
278
- "treatment_suggestions": f"Consult a specialist: {specialist}",
279
- "home_care_guidance": home_care,
280
- "info_link": link
281
-
282
- })
283
-
284
- for i in ranges:
285
- condition = i[0]
286
- measurement = i[1]
287
- unit = i[2]
288
- severity = i[3]
289
- value = i[4]
290
- range_value = i[5] # renamed to avoid overwriting Python's built-in "range"
291
-
292
- link_range = disease_links.get(condition.lower(), "https://www.webmd.com/")
293
- next_steps_range = disease_next_steps.get(condition.lower(), ['Consult a doctor'])
294
- specialist_range = disease_doctor_specialty.get(condition.lower(), "General Practitioner")
295
- home_care_range = disease_home_care.get(condition.lower(), [])
296
-
297
- condition_version = condition.upper()
298
- severity_version = severity.upper()
299
-
300
- resolution.append({
301
- "findings": f"{condition_version} -- {measurement}",
302
- "severity": f"{value} {unit} - {severity_version}",
303
- "recommendations": next_steps_range,
304
- "treatment_suggestions": f"Consult a specialist: {specialist_range}",
305
- "home_care_guidance": home_care_range,
306
- "info_link": link_range
307
- })
308
-
309
-
310
- ranges = analyze_measurements(ocr_full, df)
311
- print(analyze_measurements(ocr_full, df))
312
- # print ("Ranges is being printed", ranges)
313
- historical_med_data = detect_past_diseases(ocr_full)
314
-
315
- return {
316
- "ocr_text": ocr_full.strip(),
317
- "Detected_Anomolies": resolution,
318
- }
319
-
320
- class TextRequest(BaseModel):
321
- text: str
322
-
323
- @app.post("/analyze-text")
324
- async def analyze_text_endpoint(request: TextRequest):
325
  try:
326
- return analyze_text(request.text)
327
  except Exception as e:
328
- print("ERROR in /analyze-text:", traceback.format_exc())
329
- raise HTTPException(status_code=500, detail=f"Error analyzing text: {str(e)}")
330
-
331
-
332
- def analyze_text(text):
333
- severity, disease = classify_disease_and_severity(text)
334
- return {
335
- "extracted_text": text,
336
- "summary": f"Detected Disease: {disease}, Severity: {severity}"
337
- }
338
-
339
-
340
  @app.get("/health/")
341
  def health():
342
  return {"response": "ok"}
@@ -347,4 +238,4 @@ def _log_routes():
347
  print("Mounted routes:")
348
  for r in app.routes:
349
  if isinstance(r, APIRoute):
350
- print(" ", r.path, r.methods)
 
1
+ import os
2
  from ast import List
 
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
 
 
 
5
  import io
6
+ import fitz
 
7
  import traceback
8
  import pandas as pd
9
+
10
+ import base64
11
+ import json
12
  import re
13
+ import asyncio
14
+ import functools
15
+ from typing import Any, Optional
16
+
17
  import google.generativeai as genai
18
+ from fastapi import FastAPI, UploadFile, File, Form, HTTPException, APIRouter, Request
19
+ from fastapi.responses import JSONResponse, RedirectResponse
20
  from fastapi.staticfiles import StaticFiles
21
  import firebase_admin
22
  from firebase_admin import credentials, firestore
23
  from google.generativeai import generative_models
24
+ from pydantic import BaseModel
 
 
 
 
 
25
  from past_reports import router as reports_router, db_fetch_reports
26
 
27
+ from api_key import GEMINI_API_KEY
 
 
 
 
 
 
 
 
28
 
29
  app = FastAPI()
 
30
  api = APIRouter(prefix="/api")
31
  app.include_router(api)
32
 
33
+ EXTRACTED_TEXT_CACHE = ""
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  app.mount("/app", StaticFiles(directory="web", html=True), name="web")
36
  app.include_router(reports_router)
 
46
  @app.get("/")
47
  def root():
48
  return RedirectResponse(url="/app/")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ class AnalyzeRequest(BaseModel):
51
+ image_base64: str
52
+ prompt: Optional[str] = None
53
+
54
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY", GEMINI_API_KEY)
55
+
56
+ if not GEMINI_API_KEY:
57
+ raise RuntimeError(
58
+ "No Gemini API key found. Put it in api_key.py as `GEMINI_API_KEY = '...'` or set env var GEMINI_API_KEY."
59
+ )
60
+
61
+ genai.configure(api_key=GEMINI_API_KEY)
62
 
63
+ generation_config = {
64
+ "temperature": 0.2,
65
+ "top_p": 0.95,
66
+ "top_k": 40,
67
+ "max_output_tokens": 2048,
68
+ }
69
+
70
+ safety_settings = [
71
+ {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
72
+ {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
73
+ {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
74
+ {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"},
75
+ ]
76
+
77
+ # --- Pydantic Models for API Endpoints ---
78
  class ChatRequest(BaseModel):
79
  user_id: Optional[str] = "anonymous"
80
  question: str
81
+
82
  class ChatResponse(BaseModel):
83
  answer: str
84
+
85
+ class TextRequest(BaseModel):
86
+ text: str
87
+
88
+ system_prompt = """ As a highly skilled medical practitioner specializing in image analysis, you are tasked with examining medical images for a renowned hospital. Your expertise is crucial in identifying any anomalies, diseases, or health issues that may be present in the images. Your responsibilities include:
89
+ 1. Detailed Analysis: Thoroughly analyze each image, focusing on identifying any abnormal findings that may indicate underlying medical conditions.
90
+ 2. Finding Report: Document all observed anomalies or signs of disease. Clearly articulate these findings in a structured report format, ensuring accuracy and clarity. Also include any measurement found such as trygliceride, HBa1c, and hdl levels. When presenting any found measurement, relay it in this format: {"findings": "Condition that this measurement could affect only if the value is in a risky rang: masurement type -- value with unit(current range). For example: {"findings": "Diabetes: Hba1c -- 8%(diabetic)", "ldl -- 80mg/dL(optimal)"}"
91
+ At the beginning of every finding, if needed try to simplify the information given in 3 words.
92
+ 3. Checking for Past: If a disease is considered family history or is a disease that the patient recovered from(anything anomoly that is historical), please mention this in severity using this format: "severity" : "severity of the anomoly (Past Anomoly but Still Under Risk)"
93
+ 4. Recommendations and Next Steps: Provide detailed recommendations based on your findings. Outline the necessary follow-up actions or additional tests required to confirm diagnoses or assess treatment options.
94
+ 5. Treatment Suggestions: Offer preliminary treatment suggestions or interventions based on the identified conditions, collaborating with the healthcare team to develop comprehensive patient care plans.
95
+ 6. Output Format: Your output should be a JSON array (list) of objects, each describing one disease or medical finding using the structure below:
96
+ [{"findings": "Description of the first disease or condition.", "severity": "MILD/SEVERE/CRITICAL", "recommendations": ["Follow-up test 1", "Follow-up test 2"], "treatment_suggestions": ["Treatment 1", "Treatment 2"], "home_care_guidance": ["Care tip 1", "Care tip 2"] }, { "findings": "Description of the second disease or condition.", "severity": "MILD/SEVERE/CRITICAL", "recommendations": ["Follow-up test A", "Follow-up test B"], "treatment_suggestions": ["Treatment A", "Treatment B"], "home_care_guidance": ["Care tip A", "Care tip B"] } ]
97
+ Important Notes:
98
+ 1. Scope of Response: Only respond if the image pertains to a human health issue.
99
+ 2. Clarity of Image: Ensure the image is clear and suitable for accurate analysis.
100
+ 3. As an AI, don't produce any output than doesn't follow this format and also remember that we need your input on the medical report for a team of renowned doctors to recheck your readings and determine AI's role in the medical industry.
101
+ 4. Your Insights are Invaluable: Your insights play a crucial role in guiding clinical decisions. Please proceed with your analysis, adhering to the structured approach outlined above.
102
+ 5. Completely UPPERCASE the main concern in the finding """
103
 
104
  system_prompt_chat = """
105
  *** Role: Medical Guidance Facilitator
 
110
  2. Historical Context – Compare current findings with any available previous reports.
111
  3. Medical Q&A – Answer specific questions about the report using trusted medical sources.
112
  4. Specialist Matching – Recommend relevant physician specialties for identified conditions.
113
+ 5. Local Physician Recommendations List at least two real physician or clinic options within the user-specified mile radius (include name, specialty, address, distance from user, and contact info) based on the patient’s location and clinical need.
114
+ 6. Insurance Guidance – If insurance/network information is provided, prioritize in-network physicians.
115
+ 7. Safety Protocols – Include a brief disclaimer encouraging users to verify information, confirm insurance coverage, and consult providers directly.
116
  *** Response Structure:
117
  Start with a direct answer to the user’s primary question (maximum 4 concise sentences, each on a new line).
118
  If a physician/specialist is needed, recommend at least two local providers within the requested radius (include name, specialty, address, distance, and contact info).
 
124
  Assistant Answer:
125
  """
126
 
127
+ # Initialize model
128
+ model = genai.GenerativeModel(model_name="gemini-2.5-flash-lite")
129
+
130
+ async def _call_model_blocking(request_inputs, generation_cfg, safety_cfg):
131
+ """Run blocking model call in threadpool (so uvicorn's event loop isn't blocked)."""
132
+ fn = functools.partial(
133
+ model.generate_content,
134
+ request_inputs,
135
+ generation_config=generation_cfg,
136
+ safety_settings=safety_cfg,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  )
138
+ loop = asyncio.get_event_loop()
139
+ return await loop.run_in_executor(None, fn)
140
 
 
 
141
 
142
+ async def analyze_image(image_bytes: bytes, mime_type: str, prompt: Optional[str] = None) -> Any:
143
+ base64_img = base64.b64encode(image_bytes).decode("utf-8")
144
+ text_prompt = (prompt or system_prompt).strip()
145
+
146
+ request_inputs = [
147
+ {"inline_data": {"mime_type": mime_type, "data": base64_img}},
148
+ {"text": text_prompt},
149
+ ]
150
+
151
  try:
152
+ response = await _call_model_blocking(request_inputs, generation_config, safety_settings)
 
 
 
 
 
 
153
  except Exception as e:
154
+ raise RuntimeError(f"Model call failed: {e}")
155
+
156
+ text = getattr(response, "text", None)
157
+ if not text and isinstance(response, dict):
158
+ candidates = response.get("candidates") or []
159
+ if candidates:
160
+ text = candidates[0].get("content") or candidates[0].get("text")
161
+ if not text:
162
+ text = str(response)
163
+
164
+ clean = re.sub(r"```(?:json)?", "", text).strip()
165
+
166
+ try:
167
+ parsed = json.loads(clean)
168
+ return parsed
169
+ except json.JSONDecodeError:
170
+ match = re.search(r"(\[.*\]|\{.*\})", clean, re.DOTALL)
171
+ if match:
172
+ try:
173
+ return json.loads(match.group(1))
174
+ except json.JSONDecodeError:
175
+ return {"raw_found_json": match.group(1)}
176
+ return {"raw_output": clean}
177
 
178
  def get_past_reports_from_sqllite(user_id: str):
179
  try:
 
188
 
189
  @app.post("/chat/", response_model=ChatResponse)
190
  async def chat_endpoint(request: ChatRequest):
191
+ global result
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  try:
193
+ document_text = json.dumps(result) if result else "No parsed text available"
194
  full_prompt = system_prompt_chat.format(
195
+ document_text=document_text,
196
  user_question=request.question
197
  )
198
+ data = await request.json()
199
+ question = data.get("question")
200
+ report_text = data.get("report_text")
201
+ user_id = data.get("user_id")
202
+
203
  response = model.generate_content(full_prompt)
204
  return ChatResponse(answer=response.text)
205
  except Exception as e:
206
+ raise HTTPException(status_code=500, detail=f"Chat error: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
+ @app.post("/analyze")
209
+ async def analyze_endpoint(file: UploadFile = File(...), prompt: str = Form(None)):
210
+ global result
211
+ """
212
+ Upload an image file (field name `file`) and optional text `prompt`.
213
+ Returns parsed JSON (or raw model output if JSON couldn't be parsed).
214
+ """
215
+ contents = await file.read() # <-- this gets the uploaded file bytes
216
+ mime = file.content_type or "image/png"
217
+ result = await analyze_image(contents, mime, prompt)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  try:
219
+ result = await analyze_image(contents, mime, prompt)
220
  except Exception as e:
221
+ raise HTTPException(status_code=500, detail=str(e))
222
+ return JSONResponse(content={"Detected_Anomolies": result})
223
+
224
+ @app.post("/analyze_json")
225
+ async def analyze_json(req: AnalyzeRequest):
226
+ import base64
227
+ image_bytes = base64.b64decode(req.image_base64)
228
+ result = await analyze_image(image_bytes, "image/png", req.prompt)
229
+ return {"result": result}
230
+
 
 
231
  @app.get("/health/")
232
  def health():
233
  return {"response": "ok"}
 
238
  print("Mounted routes:")
239
  for r in app.routes:
240
  if isinstance(r, APIRoute):
241
+ print(" ", r.path, r.methods)