| """CYPHER V12 M49 — Empathy + Emotional Context. |
| |
| Detects emotional tone of prompt + adapts response style accordingly. |
| """ |
| from __future__ import annotations |
|
|
| import logging |
| import re |
| from typing import Any |
|
|
| logger = logging.getLogger(__name__) |
|
|
|
|
| EMOTIONAL_PROFILES = { |
| "urgent": { |
| "signals": ("urgent", "asap", "now", "quickly", "immediately", |
| "right now", "tout de suite", "vite", "rapide", |
| "emergency", "urgence", "!!", "critical"), |
| "style": "Be concise, action-first. Skip pleasantries. Numbered steps.", |
| "max_tokens": 150, |
| "temperature": 0.25, |
| }, |
| "frustrated": { |
| "signals": ("frustrated", "annoyed", "this is dumb", "why doesn't", |
| "encore", "again?", "still not", "tu te fous", |
| "this isn't working", "ça marche pas", "WTF", "wtf", |
| "merde", "putain"), |
| "style": "Acknowledge frustration briefly. Direct solution. No fluff.", |
| "max_tokens": 180, |
| "temperature": 0.30, |
| }, |
| "exploratory": { |
| "signals": ("curious", "wondering", "what if", "could you explain", |
| "je me demande", "et si", "intéressant", "interesting", |
| "tell me more"), |
| "style": "Engage curiously. Detail + tangents OK. Suggest follow-ups.", |
| "max_tokens": 280, |
| "temperature": 0.45, |
| }, |
| "casual": { |
| "signals": ("hey", "hi", "lol", "btw", "salut", "yo", |
| " :) ", " :( ", " :p "), |
| "style": "Friendly tone. Brief. Match the casual register.", |
| "max_tokens": 120, |
| "temperature": 0.40, |
| }, |
| "formal": { |
| "signals": ("please", "kindly", "could you", "would you", |
| "veuillez", "merci de", "auriez-vous", |
| "respectfully", "respectueusement"), |
| "style": "Formal register. Complete sentences. Avoid contractions.", |
| "max_tokens": 220, |
| "temperature": 0.30, |
| }, |
| "technical_deep": { |
| "signals": ("deep dive", "in detail", "thoroughly", "explain why", |
| "expliquer pourquoi", "en profondeur", "approfondir"), |
| "style": "Detailed technical analysis. Cite specifics. Structured.", |
| "max_tokens": 320, |
| "temperature": 0.30, |
| }, |
| "neutral": { |
| "signals": (), |
| "style": "Balanced direct response.", |
| "max_tokens": 200, |
| "temperature": 0.35, |
| }, |
| } |
|
|
|
|
| def detect_emotional_context(prompt: str) -> dict: |
| """Return detected emotional profile + signals.""" |
| if not prompt: |
| return {"profile": "neutral", "confidence": 0.0, "matched_signals": []} |
| p_lower = prompt.lower() |
| |
| scores: dict[str, int] = {} |
| matched: dict[str, list[str]] = {} |
| for profile_name, info in EMOTIONAL_PROFILES.items(): |
| signals = info["signals"] |
| hits = [s for s in signals if s in p_lower] |
| if hits: |
| scores[profile_name] = len(hits) |
| matched[profile_name] = hits |
| |
| if "!!" in prompt or prompt.count("!") >= 2: |
| scores["urgent"] = scores.get("urgent", 0) + 1 |
| matched.setdefault("urgent", []).append("multi_exclaim") |
| if prompt.isupper() and len(prompt) > 10: |
| scores["frustrated"] = scores.get("frustrated", 0) + 1 |
| matched.setdefault("frustrated", []).append("all_caps") |
| if not scores: |
| return {"profile": "neutral", "confidence": 0.0, "matched_signals": []} |
| top = max(scores, key=lambda k: scores[k]) |
| return { |
| "profile": top, |
| "confidence": min(1.0, scores[top] / 3.0), |
| "matched_signals": matched[top], |
| "all_scores": scores, |
| } |
|
|
|
|
| class EmpathyAdapter: |
| """Adjusts generation params + style based on emotional context.""" |
|
|
| @staticmethod |
| def adapt_params(prompt: str, base_max_tokens: int = 200, |
| base_temperature: float = 0.35) -> dict: |
| detected = detect_emotional_context(prompt) |
| profile_info = EMOTIONAL_PROFILES.get(detected["profile"], EMOTIONAL_PROFILES["neutral"]) |
| return { |
| "profile": detected["profile"], |
| "confidence": detected["confidence"], |
| "matched_signals": detected.get("matched_signals", []), |
| "max_tokens": profile_info["max_tokens"], |
| "temperature": profile_info["temperature"], |
| "style_hint": profile_info["style"], |
| } |
|
|
| @staticmethod |
| def style_prefix(profile: str) -> str: |
| """Optional style prefix injected before User: prompt.""" |
| info = EMOTIONAL_PROFILES.get(profile, EMOTIONAL_PROFILES["neutral"]) |
| return f"[STYLE: {info['style']}]" |
|
|
| @staticmethod |
| def acknowledge_emotion(profile: str, lang: str = "en") -> str | None: |
| """Optional brief emotional acknowledgment to prepend response.""" |
| if profile == "frustrated": |
| return "Compris." if lang == "fr" else "Got it." |
| if profile == "urgent": |
| return "Immédiat:" if lang == "fr" else "Right away:" |
| return None |
|
|
|
|
| __all__ = ["EMOTIONAL_PROFILES", "detect_emotional_context", "EmpathyAdapter"] |
|
|
|
|
| if __name__ == "__main__": |
| logging.basicConfig(level=logging.INFO) |
| print("=== M49 cypher_empathy_context SMOKE ===") |
| tests = [ |
| "URGENT! patch CVE-2024-3400 maintenant!!", |
| "Hey, quick question about SMC.", |
| "Could you kindly explain MITRE T1059?", |
| "wtf this doesn't work again", |
| "I'm curious about how Hopfield networks function in working memory.", |
| "Tell me about Log4Shell in detail and thoroughly.", |
| "What is a firewall?", |
| ] |
| for p in tests: |
| info = EmpathyAdapter.adapt_params(p) |
| print(f"\n'{p[:50]}'") |
| print(f" → profile={info['profile']} conf={info['confidence']:.2f} signals={info['matched_signals']}") |
| print(f" → max_tok={info['max_tokens']} temp={info['temperature']}") |
| ack = EmpathyAdapter.acknowledge_emotion(info["profile"], lang="fr") |
| if ack: |
| print(f" → ack: {ack}") |
| print("\n=== SMOKE PASS ===") |
|
|