Spaces:
Sleeping
Sleeping
| from ultralytics import YOLO | |
| from groq import Groq | |
| from .config import MODEL_PATH, MODEL_IMAGE_SIZE, GROQ_API_KEY | |
| import cv2 | |
| import json | |
| import logging | |
| import time | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # Load model once | |
| logger.info(f"Loading model from {MODEL_PATH}") | |
| try: | |
| model = YOLO(MODEL_PATH) | |
| except Exception as e: | |
| logger.error(f"Failed to load model: {e}") | |
| raise | |
| def run_inference(image_path, output_path): | |
| """ | |
| Runs YOLO inference on the image. | |
| Saves the annotated image to output_path. | |
| Returns a dictionary with detections and metadata. | |
| """ | |
| start_time = time.time() | |
| # Run inference | |
| results = model(image_path, imgsz=MODEL_IMAGE_SIZE, conf=0.4) | |
| end_time = time.time() | |
| processing_time_ms = (end_time - start_time) * 1000 | |
| result = results[0] | |
| # Save annotated image | |
| annotated_frame = result.plot() | |
| cv2.imwrite(str(output_path), annotated_frame) | |
| # Severity Mapping Logic | |
| SEVERITY_MAP = { | |
| "scratch": "Low", | |
| "dent": "Medium", | |
| "crack": "High", | |
| "lamp_broken": "High", | |
| "tire_flat": "High", | |
| "glass_shatter": "Critical" | |
| } | |
| # Extract detections for LLM and UI | |
| detections = [] | |
| for box in result.boxes: | |
| cls_id = int(box.cls[0]) | |
| class_name = result.names[cls_id] | |
| confidence = float(box.conf[0]) | |
| # Simple location logic based on box center | |
| x_center = box.xywh[0][0] | |
| img_width = result.orig_shape[1] | |
| if x_center < img_width / 3: | |
| location = "Left Side" | |
| elif x_center > 2 * img_width / 3: | |
| location = "Right Side" | |
| else: | |
| location = "Center" | |
| # Determine Severity | |
| severity = SEVERITY_MAP.get(class_name, "Medium") | |
| # Boost severity if confidence is very high for critical items | |
| if severity == "Critical" and confidence > 0.8: | |
| severity = "CRITICAL (Safety Risk)" | |
| detections.append({ | |
| "class": class_name, | |
| "confidence": confidence, | |
| "location": location, | |
| "severity": severity | |
| }) | |
| return { | |
| "detections": detections, | |
| "processing_time": round(processing_time_ms, 2), | |
| "count": len(detections), | |
| "model_info": f"YOLO11s ({MODEL_IMAGE_SIZE})" | |
| } | |
| def generate_insurance_report(detection_data, make, model_name, year): | |
| """ | |
| Generates a structured JSON report using Groq API based on detections. | |
| """ | |
| if not GROQ_API_KEY: | |
| return {"error": "Groq API Key not configured"} | |
| client = Groq(api_key=GROQ_API_KEY) | |
| vehicle_info = f"{year} {make} {model_name}" | |
| detections = detection_data.get("detections", []) | |
| det_str = json.dumps(detections, indent=2) | |
| # Fallback if no detections | |
| if not detections: | |
| return { | |
| "summary": f"No specific damage patterns were detected by the automated system on the {vehicle_info}.", | |
| "severity_level": "Low", | |
| "severity_reasoning": "No visible dents, scratches, or tears identified by AI.", | |
| "repair_urgency": "None", | |
| "urgency_details": "Vehicle appears to be in good condition based on visual inspection.", | |
| "cost_range": "$0", | |
| "cost_details": "No repairs needed.", | |
| "recommended_action": "Routine maintenance.", | |
| "immediate_actions": ["Verify visual inspection manually.", "Wash vehicle to ensure no hidden marks."], | |
| "secondary_actions": ["Keep regular service schedule."] | |
| } | |
| prompt = f""" | |
| Act as a Senior Automotive Claims Adjuster and Technical Appraiser. | |
| Analyze the following vehicle damage detection data provided by an automated computer vision system. | |
| Vehicle: {vehicle_info} | |
| Detected Damages: {det_str} | |
| Generate a formal, industry-standard damage assessment report in valid JSON format ONLY. | |
| Use professional terminology (e.g., 'refinish', 'R&I', 'structural integrity') and maintain an objective tone. | |
| The JSON must have these exact keys: | |
| {{ | |
| "summary": "A formal executive summary of the visual inspection findings.", | |
| "severity_level": "Low, Medium, High, or Total Loss", | |
| "severity_reasoning": "Technical justification for the severity classification.", | |
| "repair_urgency": "Routine, Urgent, or Safety Critical", | |
| "urgency_details": "Explanation focusing on safety and drivability.", | |
| "cost_range": "Estimated repair cost range (e.g., '$800 - $1,500 USD').", | |
| "cost_details": "Breakdown of cost drivers (e.g., 'Includes body labor, paint supplies, and parts').", | |
| "estimated_labor_hours": "Estimated labor time (e.g., '12-16 hours').", | |
| "likely_parts_needed": ["List of parts likely requiring repair or replacement"], | |
| "recommended_action": "Primary technical recommendation (e.g., 'Tear-down and blueprinting').", | |
| "immediate_actions": ["Action 1", "Action 2"], | |
| "secondary_actions": ["Action 1", "Action 2"] | |
| }} | |
| """ | |
| try: | |
| chat_completion = client.chat.completions.create( | |
| messages=[ | |
| { | |
| "role": "user", | |
| "content": prompt, | |
| } | |
| ], | |
| model="llama-3.3-70b-versatile", | |
| response_format={"type": "json_object"} # Enforce JSON mode | |
| ) | |
| return json.loads(chat_completion.choices[0].message.content) | |
| except Exception as e: | |
| logger.error(f"Groq API error: {e}") | |
| return { | |
| "summary": "Error generating detailed report.", | |
| "severity_level": "Unknown", | |
| "severity_reasoning": str(e), | |
| "repair_urgency": "Unknown", | |
| "urgency_details": "Contact support.", | |
| "cost_range": "Unknown", | |
| "cost_details": "Unknown", | |
| "estimated_labor_hours": "Unknown", | |
| "likely_parts_needed": [], | |
| "recommended_action": "Manual Inspection", | |
| "immediate_actions": ["Contact support"], | |
| "secondary_actions": [] | |
| } | |