Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -560,22 +560,50 @@ def analyze_composite(msg1, date1, msg2, date2, msg3, date3, *answers_and_none):
|
|
560 |
sentiments = [r[0][3]['label'] for r in results]
|
561 |
stages = [r[0][4] for r in results]
|
562 |
darvo_scores = [r[0][5] for r in results]
|
563 |
-
tone_tags= [r[0][6] for r in results]
|
564 |
dates_used = [r[1] or "Undated" for r in results] # Store dates for future mapping
|
565 |
-
|
|
|
566 |
escalation_bump = 0
|
567 |
for result, _ in results:
|
568 |
abuse_score, threshold_labels, top_patterns, sentiment, stage, darvo_score, tone_tag = result
|
|
|
569 |
if darvo_score > 0.65:
|
570 |
escalation_bump += 3
|
571 |
-
|
|
|
572 |
escalation_bump += 2
|
|
|
573 |
if abuse_score > 80:
|
574 |
escalation_bump += 2
|
|
|
575 |
if stage == 2:
|
576 |
escalation_bump += 3
|
577 |
|
578 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
579 |
hybrid_score = escalation_score + escalation_bump if escalation_score is not None else 0
|
580 |
risk_level = (
|
581 |
"High" if hybrid_score >= 16 else
|
@@ -583,10 +611,6 @@ def analyze_composite(msg1, date1, msg2, date2, msg3, date3, *answers_and_none):
|
|
583 |
"Low"
|
584 |
)
|
585 |
|
586 |
-
# Now compute scores and allow override
|
587 |
-
abuse_scores = [r[0][0] for r in results]
|
588 |
-
stages = [r[0][4] for r in results]
|
589 |
-
|
590 |
# Post-check override (e.g. stage 2 or high abuse score forces Moderate risk)
|
591 |
if any(score > 70 for score in abuse_scores) or any(stage == 2 for stage in stages):
|
592 |
if risk_level == "Low":
|
@@ -597,27 +621,18 @@ def analyze_composite(msg1, date1, msg2, date2, msg3, date3, *answers_and_none):
|
|
597 |
|
598 |
# --- Composite Abuse Score with Weighted Patterns ---
|
599 |
composite_abuse_scores = []
|
600 |
-
|
601 |
for result, _ in results:
|
602 |
abuse_score, threshold_labels, top_patterns, _, _, _, _ = result
|
603 |
weighted_score = 0
|
604 |
total_weight = 0
|
605 |
-
|
606 |
for label, score in top_patterns:
|
607 |
weight = PATTERN_WEIGHTS.get(label, 1.0)
|
608 |
weighted_score += score * weight
|
609 |
total_weight += weight
|
610 |
-
|
611 |
-
if total_weight > 0:
|
612 |
-
final_score = (weighted_score / total_weight) * 100
|
613 |
-
else:
|
614 |
-
final_score = 0
|
615 |
-
|
616 |
composite_abuse_scores.append(final_score)
|
617 |
|
618 |
composite_abuse = int(round(sum(composite_abuse_scores) / len(composite_abuse_scores)))
|
619 |
-
|
620 |
-
|
621 |
most_common_stage = max(set(stages), key=stages.count)
|
622 |
stage_text = RISK_STAGE_LABELS[most_common_stage]
|
623 |
|
@@ -630,27 +645,27 @@ def analyze_composite(msg1, date1, msg2, date2, msg3, date3, *answers_and_none):
|
|
630 |
out = f"Abuse Intensity: {composite_abuse}%\n"
|
631 |
out += "π This reflects the strength and severity of detected abuse patterns in the message(s).\n\n"
|
632 |
|
633 |
-
# Save this line for later use at the
|
634 |
if escalation_score is None:
|
635 |
escalation_text = "π Escalation Potential: Unknown (Checklist not completed)\n"
|
636 |
escalation_text += "β οΈ *This section was not completed. Escalation potential is unknown.*\n"
|
637 |
-
hybrid_score = 0 # β
fallback so it's defined for generate_risk_snippet
|
638 |
else:
|
639 |
escalation_text = f"𧨠**Escalation Potential: {risk_level} ({escalation_score}/{sum(w for _, w in ESCALATION_QUESTIONS)})**\n"
|
640 |
escalation_text += "This score comes directly from the safety checklist and functions as a standalone escalation risk score.\n"
|
641 |
escalation_text += "It indicates how many serious risk factors are present based on your answers to the safety checklist.\n"
|
642 |
-
|
|
|
643 |
top_label = None
|
644 |
if results:
|
645 |
sorted_patterns = sorted(
|
646 |
[(label, score) for r in results for label, score in r[0][2]],
|
647 |
key=lambda x: x[1],
|
648 |
reverse=True
|
649 |
-
|
650 |
if sorted_patterns:
|
651 |
top_label = f"{sorted_patterns[0][0]} β {int(round(sorted_patterns[0][1] * 100))}%"
|
652 |
if top_label is None:
|
653 |
top_label = "Unknown β 0%"
|
|
|
654 |
out += generate_risk_snippet(composite_abuse, top_label, hybrid_score if escalation_score is not None else 0, most_common_stage)
|
655 |
out += f"\n\n{stage_text}"
|
656 |
out += darvo_blurb
|
@@ -658,6 +673,7 @@ def analyze_composite(msg1, date1, msg2, date2, msg3, date3, *answers_and_none):
|
|
658 |
for i, tone in enumerate(tone_tags):
|
659 |
label = tone if tone else "none"
|
660 |
out += f"β’ Message {i+1}: *{label}*\n"
|
|
|
661 |
print(f"DEBUG: avg_darvo = {avg_darvo}")
|
662 |
pattern_labels = [r[0][2][0][0] for r in results] # top label for each message
|
663 |
timeline_image = generate_abuse_score_chart(dates_used, abuse_scores, pattern_labels)
|
|
|
560 |
sentiments = [r[0][3]['label'] for r in results]
|
561 |
stages = [r[0][4] for r in results]
|
562 |
darvo_scores = [r[0][5] for r in results]
|
563 |
+
tone_tags = [r[0][6] for r in results]
|
564 |
dates_used = [r[1] or "Undated" for r in results] # Store dates for future mapping
|
565 |
+
|
566 |
+
# Calculate escalation bump
|
567 |
escalation_bump = 0
|
568 |
for result, _ in results:
|
569 |
abuse_score, threshold_labels, top_patterns, sentiment, stage, darvo_score, tone_tag = result
|
570 |
+
|
571 |
if darvo_score > 0.65:
|
572 |
escalation_bump += 3
|
573 |
+
|
574 |
+
if tone_tag in ["forced accountability flip", "emotional threat", "aggressive dismissal", "mocking detachment"]:
|
575 |
escalation_bump += 2
|
576 |
+
|
577 |
if abuse_score > 80:
|
578 |
escalation_bump += 2
|
579 |
+
|
580 |
if stage == 2:
|
581 |
escalation_bump += 3
|
582 |
|
583 |
+
if "threat" in threshold_labels or "aggression" in threshold_labels:
|
584 |
+
escalation_bump += 4
|
585 |
+
|
586 |
+
# Helper: score trend of pattern severity
|
587 |
+
def message_severity_index(threshold_labels):
|
588 |
+
weights = {
|
589 |
+
"recovery": 0,
|
590 |
+
"dismissiveness": 1,
|
591 |
+
"deflection": 1,
|
592 |
+
"guilt tripping": 2,
|
593 |
+
"control": 3,
|
594 |
+
"gaslighting": 3,
|
595 |
+
"aggression": 4,
|
596 |
+
"threat": 5,
|
597 |
+
}
|
598 |
+
return max([weights.get(label, 0) for label in threshold_labels], default=0)
|
599 |
+
|
600 |
+
severity_levels = [message_severity_index(r[0][1]) for r in results]
|
601 |
+
if len(severity_levels) >= 2 and severity_levels == sorted(severity_levels):
|
602 |
+
escalation_bump += 2
|
603 |
+
|
604 |
+
escalation_bump = min(escalation_bump, 10)
|
605 |
+
|
606 |
+
# Final escalation score
|
607 |
hybrid_score = escalation_score + escalation_bump if escalation_score is not None else 0
|
608 |
risk_level = (
|
609 |
"High" if hybrid_score >= 16 else
|
|
|
611 |
"Low"
|
612 |
)
|
613 |
|
|
|
|
|
|
|
|
|
614 |
# Post-check override (e.g. stage 2 or high abuse score forces Moderate risk)
|
615 |
if any(score > 70 for score in abuse_scores) or any(stage == 2 for stage in stages):
|
616 |
if risk_level == "Low":
|
|
|
621 |
|
622 |
# --- Composite Abuse Score with Weighted Patterns ---
|
623 |
composite_abuse_scores = []
|
|
|
624 |
for result, _ in results:
|
625 |
abuse_score, threshold_labels, top_patterns, _, _, _, _ = result
|
626 |
weighted_score = 0
|
627 |
total_weight = 0
|
|
|
628 |
for label, score in top_patterns:
|
629 |
weight = PATTERN_WEIGHTS.get(label, 1.0)
|
630 |
weighted_score += score * weight
|
631 |
total_weight += weight
|
632 |
+
final_score = (weighted_score / total_weight) * 100 if total_weight > 0 else 0
|
|
|
|
|
|
|
|
|
|
|
633 |
composite_abuse_scores.append(final_score)
|
634 |
|
635 |
composite_abuse = int(round(sum(composite_abuse_scores) / len(composite_abuse_scores)))
|
|
|
|
|
636 |
most_common_stage = max(set(stages), key=stages.count)
|
637 |
stage_text = RISK_STAGE_LABELS[most_common_stage]
|
638 |
|
|
|
645 |
out = f"Abuse Intensity: {composite_abuse}%\n"
|
646 |
out += "π This reflects the strength and severity of detected abuse patterns in the message(s).\n\n"
|
647 |
|
|
|
648 |
if escalation_score is None:
|
649 |
escalation_text = "π Escalation Potential: Unknown (Checklist not completed)\n"
|
650 |
escalation_text += "β οΈ *This section was not completed. Escalation potential is unknown.*\n"
|
|
|
651 |
else:
|
652 |
escalation_text = f"𧨠**Escalation Potential: {risk_level} ({escalation_score}/{sum(w for _, w in ESCALATION_QUESTIONS)})**\n"
|
653 |
escalation_text += "This score comes directly from the safety checklist and functions as a standalone escalation risk score.\n"
|
654 |
escalation_text += "It indicates how many serious risk factors are present based on your answers to the safety checklist.\n"
|
655 |
+
|
656 |
+
# Derive top label
|
657 |
top_label = None
|
658 |
if results:
|
659 |
sorted_patterns = sorted(
|
660 |
[(label, score) for r in results for label, score in r[0][2]],
|
661 |
key=lambda x: x[1],
|
662 |
reverse=True
|
663 |
+
)
|
664 |
if sorted_patterns:
|
665 |
top_label = f"{sorted_patterns[0][0]} β {int(round(sorted_patterns[0][1] * 100))}%"
|
666 |
if top_label is None:
|
667 |
top_label = "Unknown β 0%"
|
668 |
+
|
669 |
out += generate_risk_snippet(composite_abuse, top_label, hybrid_score if escalation_score is not None else 0, most_common_stage)
|
670 |
out += f"\n\n{stage_text}"
|
671 |
out += darvo_blurb
|
|
|
673 |
for i, tone in enumerate(tone_tags):
|
674 |
label = tone if tone else "none"
|
675 |
out += f"β’ Message {i+1}: *{label}*\n"
|
676 |
+
|
677 |
print(f"DEBUG: avg_darvo = {avg_darvo}")
|
678 |
pattern_labels = [r[0][2][0][0] for r in results] # top label for each message
|
679 |
timeline_image = generate_abuse_score_chart(dates_used, abuse_scores, pattern_labels)
|