from flask import Flask, request, send_from_directory, render_template_string, jsonify import os from datetime import datetime import cv2 import torch from ultralytics import YOLO import base64 import numpy as np import google.generativeai as genai import json import time import requests # Initialize Flask app app = Flask(__name__) UPLOAD_FOLDER = '/tmp/received_images' os.makedirs(UPLOAD_FOLDER, exist_ok=True) latest_filename = None last_extraction_result = [] # Gemini API setup genai.configure(api_key="AIzaSyD7aLN4NphvsPuyB6N3FwVw5Nxzv7gxzv4") gemma_model = genai.GenerativeModel(model_name="models/gemma-3-12b-it") # Supabase credentials SUPABASE_URL = "https://vynkcgoqjotnhtshbrdf.supabase.co" SUPABASE_API_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InZ5bmtjZ29xam90bmh0c2hicmRmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTAxMzEwMzEsImV4cCI6MjA2NTcwNzAzMX0.TEC0I2WtCMcUTt6xo5RYIHUuiOcfsJLIiYdFuUVXZI4" # Truncated for brevity def insert_to_supabase(values_dict): url = f"{SUPABASE_URL}/rest/v1/vitals" headers = { "apikey": SUPABASE_API_KEY, "Authorization": f"Bearer {SUPABASE_API_KEY}", "Content-Type": "application/json" } try: response = requests.post(url, headers=headers, json=values_dict) if response.status_code == 201: print("✅ Successfully inserted to Supabase.") else: print("❌ Failed to insert to Supabase:", response.text) except Exception as e: print("❌ Error sending data to Supabase:", e) def prompt_engineered_extraction(base64_image): try: response = gemma_model.generate_content([{ "role": "user", "parts": [ {"text": "Extract only the exact text from this image. Return the result as a plain JSON array like [\"value1\"]"}, {"inline_data": {"mime_type": "image/jpeg", "data": base64_image}} ] }]) text = response.text.strip() values = json.loads(text) if text.startswith("[") else text.strip('[]').split(',') return ", ".join(v.strip().strip('"').strip("'") for v in values) except Exception as e: print("⚠️ Error during text extraction:", e) return "Error" def detect_and_extract_text(image_path, yolo_model_path): img = cv2.imread(image_path) if img is None: return [] yolo = YOLO(yolo_model_path) results = yolo(image_path) output = [] vitals_dict = {} for r in results: for box, cls in zip(r.boxes.xyxy, r.boxes.cls): x1, y1, x2, y2 = map(int, box) class_name = yolo.names[int(cls)].lower() cropped_img = img[y1:y2, x1:x2] _, buffer = cv2.imencode('.jpg', cv2.cvtColor(cropped_img, cv2.COLOR_BGR2RGB)) image_data = base64.b64encode(buffer).decode('utf-8') extracted = prompt_engineered_extraction(image_data) try: if class_name == "heart rate": vitals_dict["heart_rate"] = int(extracted) elif class_name == "respiratory rate": vitals_dict["respiratory_rate"] = int(extracted) elif class_name == "oxygen saturation": vitals_dict["oxygen_saturation"] = int(extracted) elif class_name == "blood pressure": vitals_dict["blood_pressure"] = extracted if "/" in extracted else None except Exception as ve: print(f"⚠️ Could not parse {class_name}: {extracted}") output.append({ "class_name": class_name, "extracted_text": extracted, "bounding_box": [x1, y1, x2, y2] }) if vitals_dict: vitals_dict["mrd_number"] = request.headers.get("MRD", "unknown") vitals_dict["timestamp"] = datetime.utcnow().isoformat() insert_to_supabase(vitals_dict) return output @app.route('/upload', methods=['POST']) def upload_file(): global latest_filename, last_extraction_result img_data = request.data filename = datetime.now().strftime("%Y%m%d_%H%M%S") + ".jpeg" filepath = os.path.join(UPLOAD_FOLDER, filename) with open(filepath, 'wb') as f: f.write(img_data) latest_filename = filename last_extraction_result = detect_and_extract_text(filepath, "best.pt") return 'OK', 200 @app.route('/images/') def uploaded_file(filename): return send_from_directory(UPLOAD_FOLDER, filename) @app.route('/latest') def latest(): return jsonify({"filename": latest_filename, "result": last_extraction_result}) @app.route('/') def show_latest_image(): html = ''' Monitor

Latest Image


Waiting...

''' return render_template_string(html) @app.route('/vitals_data') def vitals_data(): mrd = request.args.get("mrd") url = f"{SUPABASE_URL}/rest/v1/vitals" headers = { "apikey": SUPABASE_API_KEY, "Authorization": f"Bearer {SUPABASE_API_KEY}" } params = {} if not mrd else {"mrd_number": f"eq.{mrd}"} response = requests.get(url, headers=headers, params=params) return jsonify(response.json()) if response.status_code == 200 else jsonify({"error": response.text}), 500 @app.route('/dashboard') def dashboard(): html = ''' Vitals Dashboard

Vitals Dashboard (Filter by MRD)

''' return render_template_string(html) if __name__ == '__main__': app.run(host='0.0.0.0', port=7860)