Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -65,7 +65,7 @@ def validate_custom_harmful(custom_harmful: str) -> List[str]:
|
|
| 65 |
def calculate_threat_score(harmful_objects: List[dict], custom_weights: dict) -> float:
|
| 66 |
score = 0.0
|
| 67 |
for obj in harmful_objects:
|
| 68 |
-
if obj["object"]
|
| 69 |
weight = custom_weights.get(obj["object"], 1.0)
|
| 70 |
score += obj["confidence"] / 100 * weight
|
| 71 |
return min(score, 100.0) # Cap at 100
|
|
@@ -115,63 +115,68 @@ def cancel_analysis():
|
|
| 115 |
cancel_flag = True
|
| 116 |
return "Analysis cancellation requested. Please wait for the current operation to stop."
|
| 117 |
|
| 118 |
-
# Format results as a detailed report
|
| 119 |
-
def format_detailed_report(results, timestamp, keyword: str = ""):
|
|
|
|
| 120 |
filtered_results = keyword_search(results, keyword)
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
if
|
| 127 |
-
|
| 128 |
-
if
|
| 129 |
-
|
| 130 |
-
if
|
| 131 |
-
|
| 132 |
-
if
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
|
|
|
| 138 |
for result in filtered_results:
|
| 139 |
-
|
|
|
|
|
|
|
| 140 |
if "metadata" in result:
|
| 141 |
-
|
|
|
|
| 142 |
if "description" in result:
|
| 143 |
-
|
| 144 |
if "signs" in result:
|
| 145 |
-
|
| 146 |
if "harmful_objects" in result:
|
| 147 |
harmful_str = ", ".join([f"{obj['object']} ({obj['confidence']}%)" for obj in result['harmful_objects']])
|
| 148 |
-
|
| 149 |
if "similarity_to_image_1" in result:
|
| 150 |
-
|
| 151 |
if "faces" in result:
|
| 152 |
-
|
| 153 |
if "objects" in result:
|
| 154 |
objects_str = ", ".join([f"{obj['object']} at {obj['bbox']}" for obj in result['objects']])
|
| 155 |
-
|
| 156 |
if "clothing" in result:
|
| 157 |
-
|
| 158 |
if "scene_context" in result:
|
| 159 |
-
|
| 160 |
if "activity" in result:
|
| 161 |
-
|
| 162 |
if "threat_score" in result:
|
| 163 |
-
|
| 164 |
if "annotation" in result:
|
| 165 |
-
|
| 166 |
if "flag" in result and result["flag"]:
|
| 167 |
-
|
| 168 |
if "comments" in result:
|
| 169 |
-
|
| 170 |
if "error" in result:
|
| 171 |
-
|
| 172 |
-
|
| 173 |
|
| 174 |
-
return
|
| 175 |
|
| 176 |
@app.post("/predict")
|
| 177 |
async def predict(
|
|
@@ -417,11 +422,19 @@ def gradio_predict(
|
|
| 417 |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 418 |
errors = []
|
| 419 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 420 |
for idx, image in enumerate(images, 1):
|
| 421 |
if cancel_flag:
|
| 422 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 423 |
if results:
|
| 424 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 425 |
return output
|
| 426 |
try:
|
| 427 |
# Convert Gradio image input to PIL and resize
|
|
@@ -438,7 +451,7 @@ def gradio_predict(
|
|
| 438 |
if cancel_flag:
|
| 439 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 440 |
if results:
|
| 441 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 442 |
return output
|
| 443 |
result["metadata"] = extract_metadata(image_data.getvalue())
|
| 444 |
|
|
@@ -446,7 +459,7 @@ def gradio_predict(
|
|
| 446 |
if cancel_flag:
|
| 447 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 448 |
if results:
|
| 449 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 450 |
return output
|
| 451 |
prompt_desc = "<image> Provide a " + ("brief description of the image." if description_level == "basic" else "detailed description of the image, including objects, colors, people, and environmental context.")
|
| 452 |
inputs = processor(text=[prompt_desc], images=[image], return_tensors="pt", padding=True)
|
|
@@ -457,7 +470,7 @@ def gradio_predict(
|
|
| 457 |
if cancel_flag:
|
| 458 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 459 |
if results:
|
| 460 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 461 |
return output
|
| 462 |
prompt_ocr = "<image> Extract all visible text in the image, such as road signs, license plates, or billboards, with exact wording."
|
| 463 |
inputs_ocr = processor(text=[prompt_ocr], images=[image], return_tensors="pt", padding=True)
|
|
@@ -468,7 +481,7 @@ def gradio_predict(
|
|
| 468 |
if cancel_flag:
|
| 469 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 470 |
if results:
|
| 471 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 472 |
return output
|
| 473 |
prompt_detect = f"<image> Identify any harmful objects ({', '.join(harmful_objects)}) in the image. List them explicitly and estimate confidence (0-100%) for each detection based on clarity."
|
| 474 |
inputs_detect = processor(text=[prompt_detect], images=[image], return_tensors="pt", padding=True)
|
|
@@ -480,23 +493,27 @@ def gradio_predict(
|
|
| 480 |
confidence = 90 if obj in detected_objects.split() else 60
|
| 481 |
harmful_detected.append({"object": obj, "confidence": confidence})
|
| 482 |
result["harmful_objects"] = harmful_detected if harmful_detected else [{"object": "None", "confidence": 0}]
|
|
|
|
|
|
|
| 483 |
|
| 484 |
if faces:
|
| 485 |
if cancel_flag:
|
| 486 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 487 |
if results:
|
| 488 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 489 |
return output
|
| 490 |
prompt_faces = "<image> Detect faces and estimate attributes such as age range (e.g., child, adult, senior), gender (male, female, unknown), and emotional cues (e.g., neutral, angry, scared)."
|
| 491 |
inputs_faces = processor(text=[prompt_faces], images=[image], return_tensors="pt", padding=True)
|
| 492 |
faces_outputs = model.generate(**inputs_faces, max_new_tokens=256)
|
| 493 |
result["faces"] = processor.decode(faces_outputs[0], skip_special_tokens=True).replace(prompt_faces, "").strip() or "No faces detected"
|
|
|
|
|
|
|
| 494 |
|
| 495 |
if objects:
|
| 496 |
if cancel_flag:
|
| 497 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 498 |
if results:
|
| 499 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 500 |
return output
|
| 501 |
prompt_objects = "<image> Identify and localize key objects (e.g., vehicles, weapons, bags) in the image. Provide object names and approximate bounding box coordinates (x_min, y_min, x_max, y_max) in the image."
|
| 502 |
inputs_objects = processor(text=[prompt_objects], images=[image], return_tensors="pt", padding=True)
|
|
@@ -507,7 +524,7 @@ def gradio_predict(
|
|
| 507 |
if cancel_flag:
|
| 508 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 509 |
if results:
|
| 510 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 511 |
return output
|
| 512 |
prompt_activity = "<image> Describe any activities or actions occurring in the image, such as walking, running, or driving."
|
| 513 |
inputs_activity = processor(text=[prompt_activity], images=[image], return_tensors="pt", padding=True)
|
|
@@ -519,7 +536,7 @@ def gradio_predict(
|
|
| 519 |
if cancel_flag:
|
| 520 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 521 |
if results:
|
| 522 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 523 |
return output
|
| 524 |
prompt_clothing = "<image> Identify clothing items and their colors worn by people in the image."
|
| 525 |
inputs_clothing = processor(text=[prompt_clothing], images=[image], return_tensors="pt", padding=True)
|
|
@@ -530,7 +547,7 @@ def gradio_predict(
|
|
| 530 |
if cancel_flag:
|
| 531 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 532 |
if results:
|
| 533 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 534 |
return output
|
| 535 |
prompt_scene = "<image> Classify the scene type (e.g., indoor, outdoor, urban, rural) and estimate the time of day (e.g., day, night, dusk)."
|
| 536 |
inputs_scene = processor(text=[prompt_scene], images=[image], return_tensors="pt", padding=True)
|
|
@@ -541,9 +558,11 @@ def gradio_predict(
|
|
| 541 |
if cancel_flag:
|
| 542 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 543 |
if results:
|
| 544 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 545 |
return output
|
| 546 |
result["threat_score"] = calculate_threat_score(result.get("harmful_objects", []), weights)
|
|
|
|
|
|
|
| 547 |
|
| 548 |
# User Options & Controls
|
| 549 |
if annotation.strip():
|
|
@@ -557,7 +576,7 @@ def gradio_predict(
|
|
| 557 |
if cancel_flag:
|
| 558 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 559 |
if results:
|
| 560 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 561 |
return output
|
| 562 |
inputs_emb = processor(images=[image], return_tensors="pt", padding=True)
|
| 563 |
with torch.no_grad():
|
|
@@ -597,12 +616,14 @@ def gradio_predict(
|
|
| 597 |
if cancel_flag:
|
| 598 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 599 |
if results:
|
| 600 |
-
output += "\n**Partial Results**:\n" + format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 601 |
return output
|
| 602 |
sim = np.dot(base_embedding, image_embeddings[i].T) / (
|
| 603 |
np.linalg.norm(base_embedding) * np.linalg.norm(image_embeddings[i])
|
| 604 |
)
|
| 605 |
results[i]["similarity_to_image_1"] = float(sim[0][0])
|
|
|
|
|
|
|
| 606 |
|
| 607 |
# Filter by attributes
|
| 608 |
if filter_attributes.strip():
|
|
@@ -621,14 +642,14 @@ def gradio_predict(
|
|
| 621 |
case_output = manage_case_folder(case_folder, results, case_action)
|
| 622 |
|
| 623 |
# Format output
|
| 624 |
-
output = format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 625 |
|
| 626 |
# Reset cancellation flag
|
| 627 |
cancel_flag = False
|
| 628 |
return output
|
| 629 |
|
| 630 |
# Helper function to format results
|
| 631 |
-
def format_results(results, timestamp, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors):
|
| 632 |
output = f"**Analysis Timestamp**: {timestamp}\n\n"
|
| 633 |
headers = ["Image ID"]
|
| 634 |
if metadata:
|
|
@@ -715,7 +736,7 @@ def format_results(results, timestamp, keyword_search, json_export, detailed_rep
|
|
| 715 |
|
| 716 |
# Handle detailed report
|
| 717 |
if detailed_report:
|
| 718 |
-
output += "\n**Detailed Report**:\n" + format_detailed_report(results, timestamp, keyword_search)
|
| 719 |
|
| 720 |
# Append case folder output
|
| 721 |
if case_folder.strip() and case_output:
|
|
@@ -729,9 +750,9 @@ with gr.Blocks() as iface:
|
|
| 729 |
gr.Markdown("Upload up to 3 images (up to 10MB each, any resolution) ")
|
| 730 |
|
| 731 |
with gr.Row():
|
| 732 |
-
image_1 = gr.Image(label="Upload Image 1 ")
|
| 733 |
-
image_2 = gr.Image(label="Upload Image 2 ")
|
| 734 |
-
image_3 = gr.Image(label="Upload Image 3 ")
|
| 735 |
|
| 736 |
with gr.Row():
|
| 737 |
with gr.Column():
|
|
|
|
| 65 |
def calculate_threat_score(harmful_objects: List[dict], custom_weights: dict) -> float:
|
| 66 |
score = 0.0
|
| 67 |
for obj in harmful_objects:
|
| 68 |
+
if obj["object"] not in ["None", "Error"]:
|
| 69 |
weight = custom_weights.get(obj["object"], 1.0)
|
| 70 |
score += obj["confidence"] / 100 * weight
|
| 71 |
return min(score, 100.0) # Cap at 100
|
|
|
|
| 115 |
cancel_flag = True
|
| 116 |
return "Analysis cancellation requested. Please wait for the current operation to stop."
|
| 117 |
|
| 118 |
+
# Format results as a detailed report (optimized)
|
| 119 |
+
def format_detailed_report(results, timestamp, findings, keyword: str = ""):
|
| 120 |
+
global cancel_flag
|
| 121 |
filtered_results = keyword_search(results, keyword)
|
| 122 |
+
report_lines = [f"# Investigation Report\n**Generated on**: {timestamp}\n\n## Key Findings\n"]
|
| 123 |
+
|
| 124 |
+
# Add key findings from precomputed dictionary
|
| 125 |
+
if findings["harmful_found"]:
|
| 126 |
+
report_lines.append("- Harmful objects detected in one or more images.\n")
|
| 127 |
+
if findings["high_similarity"]:
|
| 128 |
+
report_lines.append("- High similarity (>0.8) detected between images.\n")
|
| 129 |
+
if findings["faces_detected"]:
|
| 130 |
+
report_lines.append("- Faces detected with identifiable attributes.\n")
|
| 131 |
+
if findings["threats_detected"]:
|
| 132 |
+
report_lines.append("- High threat scores (>50) detected in one or more images.\n")
|
| 133 |
+
if not any(findings.values()):
|
| 134 |
+
report_lines.append("- No critical findings detected.\n")
|
| 135 |
+
|
| 136 |
+
if cancel_flag:
|
| 137 |
+
return "".join(report_lines) + "\n**Report Generation Cancelled**"
|
| 138 |
+
|
| 139 |
+
report_lines.append("\n## Analysis Details\n")
|
| 140 |
for result in filtered_results:
|
| 141 |
+
if cancel_flag:
|
| 142 |
+
return "".join(report_lines) + "\n**Report Generation Cancelled**"
|
| 143 |
+
report_lines.append(f"### Image ID: {result['image_id']}\n")
|
| 144 |
if "metadata" in result:
|
| 145 |
+
meta = result["metadata"]
|
| 146 |
+
report_lines.append(f"- **Metadata**: Timestamp: {meta.get('timestamp', 'N/A')}, GPS: {meta.get('gps', {}).get('latitude', 'N/A')}, {meta.get('gps', {}).get('longitude', 'N/A')}, Camera: {meta.get('camera', 'N/A')}\n")
|
| 147 |
if "description" in result:
|
| 148 |
+
report_lines.append(f"- **Description**: {result['description']}\n")
|
| 149 |
if "signs" in result:
|
| 150 |
+
report_lines.append(f"- **Signs**: {result['signs']}\n")
|
| 151 |
if "harmful_objects" in result:
|
| 152 |
harmful_str = ", ".join([f"{obj['object']} ({obj['confidence']}%)" for obj in result['harmful_objects']])
|
| 153 |
+
report_lines.append(f"- **Harmful Objects**: {harmful_str}\n")
|
| 154 |
if "similarity_to_image_1" in result:
|
| 155 |
+
report_lines.append(f"- **Similarity**: {result['similarity_to_image_1']:.2f}\n")
|
| 156 |
if "faces" in result:
|
| 157 |
+
report_lines.append(f"- **Faces**: {result['faces']}\n")
|
| 158 |
if "objects" in result:
|
| 159 |
objects_str = ", ".join([f"{obj['object']} at {obj['bbox']}" for obj in result['objects']])
|
| 160 |
+
report_lines.append(f"- **Objects**: {objects_str}\n")
|
| 161 |
if "clothing" in result:
|
| 162 |
+
report_lines.append(f"- **Clothing/Colors**: {result['clothing']}\n")
|
| 163 |
if "scene_context" in result:
|
| 164 |
+
report_lines.append(f"- **Scene**: {result['scene_context']}\n")
|
| 165 |
if "activity" in result:
|
| 166 |
+
report_lines.append(f"- **Activity**: {result['activity']}\n")
|
| 167 |
if "threat_score" in result:
|
| 168 |
+
report_lines.append(f"- **Threat Score**: {result['threat_score']:.1f}/100\n")
|
| 169 |
if "annotation" in result:
|
| 170 |
+
report_lines.append(f"- **Annotation**: {result['annotation']}\n")
|
| 171 |
if "flag" in result and result["flag"]:
|
| 172 |
+
report_lines.append(f"- **Flagged**: Yes\n")
|
| 173 |
if "comments" in result:
|
| 174 |
+
report_lines.append(f"- **Investigator Comments**: {result['comments']}\n")
|
| 175 |
if "error" in result:
|
| 176 |
+
report_lines.append(f"- **Error**: {result['error']}\n")
|
| 177 |
+
report_lines.append("\n")
|
| 178 |
|
| 179 |
+
return "".join(report_lines)
|
| 180 |
|
| 181 |
@app.post("/predict")
|
| 182 |
async def predict(
|
|
|
|
| 422 |
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 423 |
errors = []
|
| 424 |
|
| 425 |
+
# Precompute key findings
|
| 426 |
+
findings = {
|
| 427 |
+
"harmful_found": False,
|
| 428 |
+
"high_similarity": False,
|
| 429 |
+
"faces_detected": False,
|
| 430 |
+
"threats_detected": False
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
for idx, image in enumerate(images, 1):
|
| 434 |
if cancel_flag:
|
| 435 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 436 |
if results:
|
| 437 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 438 |
return output
|
| 439 |
try:
|
| 440 |
# Convert Gradio image input to PIL and resize
|
|
|
|
| 451 |
if cancel_flag:
|
| 452 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 453 |
if results:
|
| 454 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 455 |
return output
|
| 456 |
result["metadata"] = extract_metadata(image_data.getvalue())
|
| 457 |
|
|
|
|
| 459 |
if cancel_flag:
|
| 460 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 461 |
if results:
|
| 462 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 463 |
return output
|
| 464 |
prompt_desc = "<image> Provide a " + ("brief description of the image." if description_level == "basic" else "detailed description of the image, including objects, colors, people, and environmental context.")
|
| 465 |
inputs = processor(text=[prompt_desc], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 470 |
if cancel_flag:
|
| 471 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 472 |
if results:
|
| 473 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 474 |
return output
|
| 475 |
prompt_ocr = "<image> Extract all visible text in the image, such as road signs, license plates, or billboards, with exact wording."
|
| 476 |
inputs_ocr = processor(text=[prompt_ocr], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 481 |
if cancel_flag:
|
| 482 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 483 |
if results:
|
| 484 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 485 |
return output
|
| 486 |
prompt_detect = f"<image> Identify any harmful objects ({', '.join(harmful_objects)}) in the image. List them explicitly and estimate confidence (0-100%) for each detection based on clarity."
|
| 487 |
inputs_detect = processor(text=[prompt_detect], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 493 |
confidence = 90 if obj in detected_objects.split() else 60
|
| 494 |
harmful_detected.append({"object": obj, "confidence": confidence})
|
| 495 |
result["harmful_objects"] = harmful_detected if harmful_detected else [{"object": "None", "confidence": 0}]
|
| 496 |
+
if harmful_detected and result["harmful_objects"][0]["object"] != "None":
|
| 497 |
+
findings["harmful_found"] = True
|
| 498 |
|
| 499 |
if faces:
|
| 500 |
if cancel_flag:
|
| 501 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 502 |
if results:
|
| 503 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 504 |
return output
|
| 505 |
prompt_faces = "<image> Detect faces and estimate attributes such as age range (e.g., child, adult, senior), gender (male, female, unknown), and emotional cues (e.g., neutral, angry, scared)."
|
| 506 |
inputs_faces = processor(text=[prompt_faces], images=[image], return_tensors="pt", padding=True)
|
| 507 |
faces_outputs = model.generate(**inputs_faces, max_new_tokens=256)
|
| 508 |
result["faces"] = processor.decode(faces_outputs[0], skip_special_tokens=True).replace(prompt_faces, "").strip() or "No faces detected"
|
| 509 |
+
if result["faces"] != "No faces detected":
|
| 510 |
+
findings["faces_detected"] = True
|
| 511 |
|
| 512 |
if objects:
|
| 513 |
if cancel_flag:
|
| 514 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 515 |
if results:
|
| 516 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 517 |
return output
|
| 518 |
prompt_objects = "<image> Identify and localize key objects (e.g., vehicles, weapons, bags) in the image. Provide object names and approximate bounding box coordinates (x_min, y_min, x_max, y_max) in the image."
|
| 519 |
inputs_objects = processor(text=[prompt_objects], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 524 |
if cancel_flag:
|
| 525 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 526 |
if results:
|
| 527 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 528 |
return output
|
| 529 |
prompt_activity = "<image> Describe any activities or actions occurring in the image, such as walking, running, or driving."
|
| 530 |
inputs_activity = processor(text=[prompt_activity], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 536 |
if cancel_flag:
|
| 537 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 538 |
if results:
|
| 539 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 540 |
return output
|
| 541 |
prompt_clothing = "<image> Identify clothing items and their colors worn by people in the image."
|
| 542 |
inputs_clothing = processor(text=[prompt_clothing], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 547 |
if cancel_flag:
|
| 548 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 549 |
if results:
|
| 550 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 551 |
return output
|
| 552 |
prompt_scene = "<image> Classify the scene type (e.g., indoor, outdoor, urban, rural) and estimate the time of day (e.g., day, night, dusk)."
|
| 553 |
inputs_scene = processor(text=[prompt_scene], images=[image], return_tensors="pt", padding=True)
|
|
|
|
| 558 |
if cancel_flag:
|
| 559 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 560 |
if results:
|
| 561 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 562 |
return output
|
| 563 |
result["threat_score"] = calculate_threat_score(result.get("harmful_objects", []), weights)
|
| 564 |
+
if result["threat_score"] > 50:
|
| 565 |
+
findings["threats_detected"] = True
|
| 566 |
|
| 567 |
# User Options & Controls
|
| 568 |
if annotation.strip():
|
|
|
|
| 576 |
if cancel_flag:
|
| 577 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 578 |
if results:
|
| 579 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 580 |
return output
|
| 581 |
inputs_emb = processor(images=[image], return_tensors="pt", padding=True)
|
| 582 |
with torch.no_grad():
|
|
|
|
| 616 |
if cancel_flag:
|
| 617 |
output = f"**Analysis Cancelled at**: {timestamp}\n"
|
| 618 |
if results:
|
| 619 |
+
output += "\n**Partial Results**:\n" + format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 620 |
return output
|
| 621 |
sim = np.dot(base_embedding, image_embeddings[i].T) / (
|
| 622 |
np.linalg.norm(base_embedding) * np.linalg.norm(image_embeddings[i])
|
| 623 |
)
|
| 624 |
results[i]["similarity_to_image_1"] = float(sim[0][0])
|
| 625 |
+
if results[i]["similarity_to_image_1"] > 0.8:
|
| 626 |
+
findings["high_similarity"] = True
|
| 627 |
|
| 628 |
# Filter by attributes
|
| 629 |
if filter_attributes.strip():
|
|
|
|
| 642 |
case_output = manage_case_folder(case_folder, results, case_action)
|
| 643 |
|
| 644 |
# Format output
|
| 645 |
+
output = format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors)
|
| 646 |
|
| 647 |
# Reset cancellation flag
|
| 648 |
cancel_flag = False
|
| 649 |
return output
|
| 650 |
|
| 651 |
# Helper function to format results
|
| 652 |
+
def format_results(results, timestamp, findings, keyword_search, json_export, detailed_report, case_folder, case_action, filter_attributes, annotation, flag_images, comments, errors):
|
| 653 |
output = f"**Analysis Timestamp**: {timestamp}\n\n"
|
| 654 |
headers = ["Image ID"]
|
| 655 |
if metadata:
|
|
|
|
| 736 |
|
| 737 |
# Handle detailed report
|
| 738 |
if detailed_report:
|
| 739 |
+
output += "\n**Detailed Report**:\n" + format_detailed_report(results, timestamp, findings, keyword_search)
|
| 740 |
|
| 741 |
# Append case folder output
|
| 742 |
if case_folder.strip() and case_output:
|
|
|
|
| 750 |
gr.Markdown("Upload up to 3 images (up to 10MB each, any resolution) ")
|
| 751 |
|
| 752 |
with gr.Row():
|
| 753 |
+
image_1 = gr.Image(label="Upload Image 1 (up to 10MB)")
|
| 754 |
+
image_2 = gr.Image(label="Upload Image 2 (up to 10MB)")
|
| 755 |
+
image_3 = gr.Image(label="Upload Image 3 (up to 10MB)")
|
| 756 |
|
| 757 |
with gr.Row():
|
| 758 |
with gr.Column():
|