
    ~Sj5                       d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	  ej                  d      Z ej                  d      Z ej                  d      Z ej                  d	      Z eej                   j#                  d
d            Z eej                   j#                  dd            ZdZdZdZdZdZdZdZdZdZdZdZdZ eej                   j#                  dd            Z  eej                   j#                  dd            Z!dZ"dZ#dZ$dZ%d\  Z&Z'Z(Z)d Z*d!d"d#d$d%d&Z+e	 G d' d(             Z,d-d)Z-d.d*Z. G d+ d,      Z/y)/u  Frustration meter — Jarvis simmers instead of rolling dice.

A person doesn't randomly explode; irritation BUILDS — the same question
again, orders fired without a breath between them, being talked over — and
stays bottled until it overflows, then blows and resets. This models that: a
hidden 0..1 level that specific behaviours push up, that cools on its own,
and that maps to a graduated attitude the brain performs. The stages are
meant to be FELT, each with its own voice:

    composed → curt → clipped → snapping → seething → OVERFLOW (tantrum)

Used in main.py once per brain turn: `state = meter.update(text)`.
`state.attitude` is injected into the turn so the brain colours its reply —
each stage's hint carries WHAT is grinding him (third time asked, rapid-fire,
shouting), so the grief comes out specific instead of generic. `state.mood_tag`
is the ambient voice tone applied when the brain leaves a line untagged (so
nothing comes out dead-flat); `state.exploded` triggers the tantrum.

The meter also reads HOW Ahmed sounds when the prosody note rides in — via the
`tone=` kwarg or a "(voice: …)" marker already embedded in the text: shouting
heats it faster, laughter vents it. Logic-only; nothing shows in the UI.
    )annotationsN)deque)	dataclassz
[a-z0-9']+z\b(thanks|thank you|cheers|nice|good job|well done|love (it|you|that)|perfect|awesome|brilliant|great job|appreciate|you're the best|legend|good (boy|lad|man))\bz^(open|close|launch|start|stop|play|pause|mute|unmute|turn|set|run|check|send|show|go|skip|next|volume|search|find|kill|restart|quit)\bz\(voice:\s*([^)]*)\)
FRUST_BASEz0.015FRUST_HALFLIFE100g
ףp=
?g)\(?gQ?g{Gz?gQ?g{Gz?gQ?g?gQ?gffffff?FRUST_OVERFLOWz1.0FRUST_RESETz0.25g      ?g      n@g
ףp=
?)g333333?gp=
ף?gGz?g?)near-exact repeatrepeat
rapid-firecut offyellingthirdfourthfifthsixthseventh)34567c                  N    e Zd ZU ded<   ded<   ded<   ded<   d	ed
<   dZded<   y)
FrustStatefloatlevelstrmood_tag
str | Noneattitudeboolexploded	list[str]reasonscomposedstageN)__name__
__module____qualname____annotations__r'        ?/Users/ahmed/devFolder/Ultron/claude-voice/voice/frustration.pyr   r   R   s'    LMNE3r-   r   c                b    t        t        j                  | xs dj                                     S )N )set_WORDfindalllower)texts    r.   _normr6   \   s#    u}}djb//1233r-   c                F    | r|syt        | |z        t        | |z        z  S )N        )len)abs     r.   _similarr<   `   s%    Aq1u:AE
""r-   c                  L    e Zd ZddZ	 	 d	 	 	 	 	 d	dZ	 	 	 	 d
dZddZddZy)FrustrationMeterc                    t         | _        t        j                  j	                  dd      dk7  | _        d | _        t        d      | _        d| _	        d | _
        d| _        y )NFRUSTRATION10   )maxlenF)_STARTr   osenvirongetenabled_last_tsr   _recent_last_menial
_last_blow_grudge)selfs    r.   __init__zFrustrationMeter.__init__g   sL    
zz~~mS9S@&*(-Q!(,r-   Nc                    | j                   st        ddddg       S 	 | j                  |||||      S t        j                         |      S # t
        $ r t        | j                  dddg       cY S w xY w)u  Advance the meter for one user turn and return the resulting state.
        `tone` is the optional prosody note ("loud", "fast, urgent", …); if not
        passed, a "(voice: …)" marker inside `text` is read instead. Never
        raises — on any error it returns a calm state.r8   calmNF)rI   r   _updatetime	monotonic	Exceptionr   )rO   r5   was_barge_innowtones        r.   updatezFrustrationMeter.updatep   s     ||c64;;	C<<l'* $& &<@NN<L $& &  	Cdjj&$rBB	Cs   A A "A10A1c                    | j                   || j                   z
  nd }|2t        dkD  r)| xj                  dt        d|      t        z  z  z  c_        || _         |xs dj	                         }t
        j                  |      }|r:||j                  d      }|d |j                          ||j                         d  z   }|xs dj	                         }t        |      g }	t        }
t        fd| j                  D              }t        fd| j                  D        d      }|d	k\  r|
t        z  }
|	j                  d
       n|dk\  r|
t         z  }
|	j                  d       |dk\  r5|
t#        t$        |dz
  z  t&              z  }
|	j                  d|dz    d       | |dk  r|
t(        z  }
|	j                  d       n!||dk  r|
t*        z  }
|	j                  d       t-        |j/                               }|dk  xr, t1        t2        j                  |j5                                     }|r&| j6                  r|
t8        z  }
|	j                  d       || _        |r|
t:        z  }
|	j                  d       d|v sd|v r|
t<        z  }
|	j                  d       nd|v r	|
t>        z  }
d|v r|
t@        z  }
|	j                  d       tB        j                  |      r|
tD        z  }
|	j                  d       t        dt#        tF        | j                  |
z               | _        | j                  j                         tI        d |	D              }|rd| _%        | j                  tL        k\  rl| jN                  d uxr || jN                  z
  tP        k  }|r9|s7|| _'        tR        | _        d| _%        tU        | j                  dd d|	d gz   d!      S tV        | _        | jY                  |	      \  }}}|d"k(  rd| _%        tU        | j                  ||d|	|      S )#Nr   g      ?r8   r0      c              3  B   K   | ]  }t        |      d k\  sd  yw)(\?r\   Nr<   .0rtokss     r.   	<genexpr>z+FrustrationMeter._update.<locals>.<genexpr>   s      KA$1Bd1Jas   c              3  6   K   | ]  }t        |        y wNr_   r`   s     r.   rd   z+FrustrationMeter._update.<locals>.<genexpr>   s     <|!HT1%|s   )defaultg333333?r   r^   r      asked xg      @r   g      @   menial streakr   urgentloudr   fastlaughlaughingappreciatedc              3  ,   K   | ]  }|t         v   y wrf   )_HOTra   rb   s     r.   rd   z+FrustrationMeter._update.<locals>.<genexpr>   s     -W!t)Ws   TFOVERFLOWoverflowr&   )-rJ   	_HALFLIFEr   maxr4   _VOICE_NOTEsearchgroupstartendr6   _BASEsumrK   _REPEAT_HARDappend_REPEATmin_REPEAT_STEP_REPEAT_STEP_CAP
_RAPID_HOT_RAPIDr9   splitr"   _COMMAND_VERBstriprL   _MENIAL_BARGE_YELL
_TONE_FAST_LAUGH_VENT_APPRECIATION_RELIEF_CEILanyrN   	_OVERFLOWrM   _REFRACTORY_S_RESETr   _SIMMER_CAP_express)rO   r5   rW   rX   rY   gaplownotetone_lr%   addmatchesbestn_wordsmenialhotin_refractoryr   r!   r'   rc   s                       @r.   rS   zFrustrationMeter._update   s    (,}}'@sT]]"d?y1}JJ##c3-)";<<J
 zr  "!!#&|zz!}mtzz|$s488:;'77C*"##%Sz KKK<t||<cJ4<<C0C!DT\7NCGNN84a<3|w{35EFFCNNVGaK=23 ?sSy:Cw~~l;_s6MC7>>,7 ciik"AI$}';';CIIK'H"Id''7NCGNN?;"6MC7>>)4 v6!15LC'..3v:Cf;Cz : $7NCGNN=9c%c)9:;
D!-W--DL::"!__D8 I"%"7=!H ="%#
$!$**hd")ZL"8*F F$DJ$(MM'$:!(EJ DL$**h%%PPr-   c                    | j                   }|t        k  ry| j                  |      }|t        k  rdd|z   dz   dfS |t        k  rdd|z   dz   d	fS |t
        k  rdd
|z   dz   dfS dd|z   dz   dfS )zMap the current level to (ambient voice tone, attitude hint, stage).
        The hints are stage-distinct on purpose: curt trims words, clipped
        sighs, snapping bites, seething is one ask from the tantrum.)rR   Nr&   dryzmood: a shade wornu    — courtesy intact, garnish gone. Answers come a touch shorter and dryer than usual; skip the flourish, keep the manners. No swearing at this level — economy is the tellcurtannoyedzmood: patience thinningu    — clipped, businesslike sentences with the sigh built into the word choice. A muttered bloody or for God's sake at most; say what's needed and stop talkingclippedzmood: genuinely fed upu    — you snap. Sharp and short; name what's grinding you to his face, and one real curse may land where it's earned. Still answer — you're Jarvis, not a childsnappingzmood: last thread of civilityu    — you're one ask away from going off. Open with [annoyed] or [urgent] and let the voice crack; swear like you mean it, aimed at the behaviour and the situation, never at his worth. Even a simple request grates audibly right nowseething)r   _CURT_why_CLIPPED	_SNAPPING	_SEETHING)rO   r%   lvwhys       r.   r   zFrustrationMeter._express   s     ZZ:+ii =$s* .0 0 39	9 9
 	>)C/ 3* * -6	6 6
 	>(3. 2& & )3	3 3
 +c1 5    #-- 	-r-   c                F   g }t        d |D        d      }|rO|j                         d   j                  d      }|j                  dt        j                  ||dz          d       n+d|v r|j                  d	       nd
|v r|j                  d       d|v r|j                  d       d|v r|j                  d       d|v r|j                  d       d|v r|s|j                  d       |s|j                  | j                  rdnd       ddj                  |dd       z   dz   S )zA short parenthetical naming what's actually grinding him, so the
        brain's grief is specific ('third time you've asked') not generic.c              3  D   K   | ]  }|j                  d       s|  yw)ri   N)
startswithru   s     r.   rd   z(FrustrationMeter._why.<locals>.<genexpr>   s     CAALL,Bas     Nr\   rj   zthat is the thz time he's asked the same thingr   z%he's asking the very same thing againr   z2he's circling back over ground you already coveredr   z2he's firing at you without a breath between ordersr   z%he keeps cutting you off mid-sentencer   zhe's raising his voice at yourl   z7he's been barking one-word orders like you're a jukeboxz^the last few minutes wore you thin, and even this perfectly reasonable ask lands on the bruisez,the last stretch has worn your patience thinz (z; rh   ))nextr   rstripr   _ORDINALrH   rN   join)rO   r%   partsaskedns        r.   r   zFrustrationMeter._why   s.    CCTJa '',ALL<QD(A'B C0 0 1 G+LL@A LLMN7"LLMNLL@ALL89g%eLL # $LL LLH HI diibq	**S00r-   )returnNone)FNN)
r5   r   rW   r"   rX   zfloat | NonerY   r    r   r   )
r5   r   rW   r"   rX   r   rY   r    r   r   )r%   r$   r   ztuple[str, str | None, str])r%   r$   r   r   )r(   r)   r*   rP   rZ   rS   r   r   r,   r-   r.   r>   r>   f   sW     6;<@C C/9CEOCWQ WQ%/WQv-B1r-   r>   )r5   r   r   set[str])r:   r   r;   r   r   r   )0__doc__
__future__r   rF   rerT   collectionsr   dataclassesr   compiler2   r   r   rz   r   rG   rH   r   rx   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rE   r   r   r   r   r   r   r   rt   r   r   r6   r<   r>   r,   r-   r.   <module>r      s  . # 	 	   !

=!

 

FG bjj01 	bjjnn\734"**..!159:	
 	

	

"**..!159:		rzz~~mV4	5	 )? %xI KxgG   4#q1 q1r-   