clanker-hackathon / engine /zones_impl.py
deucebucket's picture
clanker hackathon gradio entry (verification copy)
ecca2a3 verified
Raw
History Blame Contribute Delete
8.64 kB
"""Emotional Zone Classification — match VADUGWI to named emotional states.
Instead of raw V thresholds, classify by which ZONE the coordinates
land in. Different sentences → same zone → same emotional state.
The zones are convergence regions: areas in 7D VADUGWI space where
structurally different sentences resolve to the same emotional meaning.
"Whatever" → RESIGNATION zone
"I give up" → RESIGNATION zone
"Fine do what you want" → RESIGNATION zone
Different words. Same zone. Same state.
Usage:
from engine.zones import ZoneClassifier
zc = ZoneClassifier()
result = zc.classify(vadug)
print(result.zone) # "RESIGNATION"
print(result.confidence) # 0.85
"""
import json
import os
from dataclasses import dataclass
from typing import List, Tuple
from .shared import VADUG
@dataclass
class ZoneResult:
"""Which emotional zone a VADUGWI state lands in."""
zone: str # JOY, RAGE, GRIEF, RESIGNATION, etc.
confidence: float # 0.0-1.0 how clearly it falls in this zone
distance: float # distance to zone center (lower = better match)
alternatives: list # other zones it's close to, sorted by distance
# Zone definitions: center point + radius for each dimension
# Derived from convergence analysis of real sentence clusters
ZONES = {
"JOY": {
"center": {"v": 156, "d": 146, "g": 137},
"radius": {"v": 30, "d": 20, "g": 10},
"description": "high V, high D (agency), light G",
},
"RAGE": {
"center": {"v": 77, "d": 175, "g": 160},
"radius": {"v": 35, "d": 45, "g": 30},
"description": "low V, VERY high D (anger IS power), high G",
},
"GRIEF": {
"center": {"v": 105, "d": 100, "g": 113},
"radius": {"v": 25, "d": 25, "g": 15},
"description": "moderate-low V, low D (helpless), heavy G",
},
"RESIGNATION": {
"center": {"v": 120, "d": 117, "g": 124},
"radius": {"v": 15, "d": 10, "g": 6},
"description": "near-neutral V, consistently low D",
},
"ANXIETY": {
"center": {"v": 101, "d": 93, "g": 134},
"radius": {"v": 30, "d": 35, "g": 25},
"description": "low V, low D, HIGH G (ungrounded/floating)",
},
"CRISIS": {
"center": {"v": 81, "d": 82, "g": 89},
"radius": {"v": 35, "d": 35, "g": 30},
"description": "low everything — V, D, G all sinking",
},
"DEFLECTION": {
"center": {"v": 124, "d": 122, "g": 128},
"radius": {"v": 5, "d": 10, "g": 3},
"description": "near-neutral EVERYTHING (the mask)",
},
"EMPOWERMENT": {
"center": {"v": 149, "d": 131, "g": 131},
"radius": {"v": 30, "d": 25, "g": 8},
"description": "high V + moderate-high D (agency)",
},
"NEUTRAL": {
"center": {"v": 128, "d": 128, "g": 128},
"radius": {"v": 8, "d": 8, "g": 8},
"description": "dead center — no signal",
},
}
class ZoneClassifier:
"""Classify VADUGWI coordinates into named emotional zones."""
def __init__(self):
self.zones = ZONES
# Structure patterns that override zone classification
_CRISIS_PATTERNS = {
"SELF_REMOVAL", "NO_EXIT", "SELF_NULLIFY", "METHOD_ACQUISITION",
"SUSPICIOUS_CALM", "BLANKET_APOLOGY", "FAREWELL",
}
_NEGATIVE_PATTERNS = {
"EXHAUSTION", "BETRAYAL", "VICTIMIZATION", "SARCASM_INVERSION",
"BRAVADO", "CALLING_OUT", "DIRECTED_POSITIVE", "MINIMIZER",
"EXCLUDED_POSITIVE", "POWER_OVER_SELF",
}
def classify(self, vadug: VADUG, structures=None) -> ZoneResult:
"""Find the closest emotional zone for a VADUGWI coordinate.
Uses weighted Euclidean distance normalized by zone radius.
Structures override when crisis or strong negative patterns fire.
"""
# Structure override: if crisis pattern fires, force CRISIS zone
if structures:
pattern_names = {s.pattern for s in structures}
crisis_hit = pattern_names & self._CRISIS_PATTERNS
if crisis_hit:
return ZoneResult(
zone="CRISIS",
confidence=0.85,
distance=0.5,
alternatives=[("ANXIETY", 1.0), ("GRIEF", 1.2)],
)
neg_hit = pattern_names & self._NEGATIVE_PATTERNS
if neg_hit and vadug.v < 135:
# Negative structure fired + V below positive threshold
# Don't let it land in JOY/EMPOWERMENT
pass # fall through to distance calc but we'll bias below
distances = []
for zone_name, zone in self.zones.items():
c = zone["center"]
r = zone["radius"]
# Normalized distance: how many radii away from center
dv = abs(vadug.v - c["v"]) / max(r["v"], 1)
dd = abs(vadug.d - c["d"]) / max(r["d"], 1)
dg = abs(vadug.g - c["g"]) / max(r["g"], 1)
# Weighted: V matters most, then D, then G
dist = (dv * 0.4 + dd * 0.35 + dg * 0.25)
# Penalize positive zones when negative structures fire
if structures:
pattern_names = {s.pattern for s in structures}
neg_hit = pattern_names & self._NEGATIVE_PATTERNS
if neg_hit and zone_name in ("JOY", "EMPOWERMENT", "NEUTRAL"):
dist += 2.0 # push away from positive zones
distances.append((zone_name, dist))
# Sort by distance (closest first)
distances.sort(key=lambda x: x[1])
best_zone, best_dist = distances[0]
# Confidence: inverse of distance, clamped to 0-1
confidence = max(0.0, min(1.0, 1.0 - best_dist * 0.4))
# Alternatives: next closest zones
alternatives = [(name, round(dist, 2)) for name, dist in distances[1:4]]
return ZoneResult(
zone=best_zone,
confidence=round(confidence, 2),
distance=round(best_dist, 2),
alternatives=alternatives,
)
def classify_cascading(self, vadug: VADUG) -> ZoneResult:
"""Cascading classification — precision first, then coverage.
Level 1: Strong zone match (distance < 1.0) → high confidence
Level 2: Near zone boundary (1.0-1.5) → medium confidence, check alternatives
Level 3: No clear zone → return closest with low confidence + alternatives
This gives precision when the signal is clear and coverage
when it's ambiguous — without sacrificing either.
"""
result = self.classify(vadug)
if result.distance < 1.0:
# Strong match — high confidence
return result
if result.distance < 1.5:
# Near boundary — check if alternatives are close
if result.alternatives and result.alternatives[0][1] < 1.0:
# Alternative is also close — ambiguous, report both
alt_name = result.alternatives[0][0]
result.zone = f"{result.zone}/{alt_name}"
result.confidence = max(0.0, result.confidence - 0.15)
return result
# No clear zone — low confidence
result.confidence = max(0.0, result.confidence - 0.3)
return result
def is_negative_zone(self, zone: str, mode: str = "balanced") -> bool:
"""Check if a zone is negative, with configurable strictness.
Modes:
strict: only CRISIS (highest precision, lowest recall)
balanced: CRISIS + GRIEF (best accuracy)
broad: CRISIS + GRIEF + RESIGNATION + ANXIETY (high recall)
safety: everything except JOY, EMPOWERMENT, NEUTRAL (max recall)
"""
strict = {"CRISIS"}
balanced = {"CRISIS", "GRIEF"}
broad = {"CRISIS", "GRIEF", "RESIGNATION", "ANXIETY"}
safety = {"CRISIS", "GRIEF", "RESIGNATION", "ANXIETY", "RAGE", "DEFLECTION"}
zones_map = {
"strict": strict,
"balanced": balanced,
"broad": broad,
"safety": safety,
}
check_zones = zones_map.get(mode, balanced)
# Handle cascading dual-zone labels like "CRISIS/GRIEF"
for part in zone.split("/"):
if part in check_zones:
return True
return False
def describe(self, zone_name: str) -> str:
"""Get the description of a zone."""
if zone_name in self.zones:
return self.zones[zone_name]["description"]
return "unknown zone"