
    j                        d Z ddlmZ ddlZddlmZmZmZmZ ddl	m
Z
 ddlmZ ddlmZ h dZh d	Zh d
Z G d de      ZddZy)z/Rule-based tone metric for assistant responses.    )annotationsN)AnyIterableOptionalSequence)MetricComputationError)
BaseMetric)ScoreResult>   gladgreathappythankassistpleasehelpfulsupportwelcome	excellent	wonderful
appreciate>   badhateangryawfulidiotstupiduselesscomplainterrible
frustratedincompetent>   shut upnot my problemthis is pointlessi refuse to assistc                  n     e Zd ZdZ	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZddZddZ xZS )	Tonea&  
    Flag tone issues like excessive negativity, shouting, or forbidden phrases.

    Args:
        name: Display name for the metric result. Defaults to ``"tone_metric"``.
        track: Whether to automatically track results. Defaults to ``True``.
        project_name: Optional tracking project name. Defaults to ``None``.
        min_sentiment: Minimum sentiment score required (``-1.0`` to ``1.0`` scale).
        max_upper_ratio: Maximum allowed ratio of uppercase characters.
        max_exclamations: Cap on the number of exclamation marks.
        positive_lexicon: Optional iterable of positive tokens counted for sentiment.
        negative_lexicon: Optional iterable of negative tokens counted for sentiment.
        forbidden_phrases: Optional sequence of phrases that immediately fail the
            check.

    Example:
        >>> from opik.evaluation.metrics import Tone
        >>> metric = Tone(max_exclamations=2)
        >>> result = metric.score("THANK YOU for your patience!!!")
        >>> result.value  # doctest: +SKIP
        0.0
    c
                4   t         |   |||       || _        || _        || _        t        d |xs t        D              | _        t        d |xs t        D              | _	        |	xs t        }
|
D cg c]  }|j                          c}| _        y c c}w )N)nametrackproject_namec              3  <   K   | ]  }|j                           y wNlower.0words     /Users/manta/Documents/Projects/TheRoad-I1/backend/.venv/lib/python3.12/site-packages/opik/evaluation/metrics/heuristics/tone.py	<genexpr>z Tone.__init__.<locals>.<genexpr>Z         
&KTDJJL&K   c              3  <   K   | ]  }|j                           y wr-   r.   r0   s     r3   r4   z Tone.__init__.<locals>.<genexpr>]   r5   r6   )super__init___min_sentiment_max_upper_ratio_max_exclamationsset_POSITIVE_LEXICON	_positive_NEGATIVE_LEXICON	_negative_FORBIDDEN_PHRASESr/   
_forbidden)selfr)   r*   r+   min_sentimentmax_upper_ratiomax_exclamationspositive_lexiconnegative_lexiconforbidden_phrasesphrasesphrase	__class__s               r3   r9   zTone.__init__J   s     	d%lK+ /!1 
&6&K:K&K
 
  
&6&K:K&K
 
 $9'98?@f6<<>@@s   5Bc                @   rj                         st        d      t        j                  dj	                               }|st        d      | j                  |      }t              }j                  d      }t        fd| j                  D              }|| j                  k\  xr% || j                  k  xr || j                  k  xr | }||||| j                  | j                  | j                  dd}	|rdnd	}
|rd
nd}t        || j                  |
|	      S )NzText is empty (Tone metric).z\b\w+\bz(Unable to tokenize text for Tone metric.!c              3  B   K   | ]  }|j                         v   y wr-   r.   )r1   rL   outputs     r3   r4   zTone.score.<locals>.<genexpr>n   s     S?Fflln4?s   )rE   rF   rG   )sentiment_scoreuppercase_ratioexclamation_countforbidden_hit
thresholdsz$Tone is within configured guardrailszTone violates guardrailsg      ?        )valuer)   reasonmetadata)stripr   refindallr/   _compute_sentiment_uppercase_ratiocountanyrC   r:   r;   r<   r
   r)   )rD   rQ   ignored_kwargstokensrR   upper_ratiorT   rU   passesrZ   rY   rX   s    `          r3   scorez
Tone.scorec   s0   V\\^()GHHJ7()STT11&9&v."LL-S4??SS t222 "t444"!T%;%;;" "!	 	  /*!2*!%!4!4#'#8#8$($:$:

  3+ 	
 3dii
 	
    c                z     t         fd|D              }t         fd|D              }||z   }|dk(  ry||z
  |z  S )Nc              3  :   K   | ]  }|j                   v   y wr-   )r?   r1   tokenrD   s     r3   r4   z*Tone._compute_sentiment.<locals>.<genexpr>        CF5u.F   c              3  :   K   | ]  }|j                   v   y wr-   )rA   rj   s     r3   r4   z*Tone._compute_sentiment.<locals>.<genexpr>   rl   rm   r   rW   )sum)rD   rc   pos_hitsneg_hitstotals   `    r3   r^   zTone._compute_sentiment   sG    CFCCCFCC8#A:8#u,,rg   )	tone_metricTNgɿg333333?   NNN)r)   strr*   boolr+   zOptional[str]rE   floatrF   rw   rG   intrH   Optional[Iterable[str]]rI   ry   rJ   zOptional[Sequence[str]]returnNone)rQ   ru   rb   r   rz   r
   )rc   zSequence[str]rz   rw   )__name__
__module____qualname____doc__r9   rf   r^   __classcell__)rM   s   @r3   r'   r'   2   s    2 "&*#!$ !484859AA A $	A
 A A A 2A 2A 3A 
A2(
T-rg   r'   c                    | D cg c]  }|j                         s| }}|syt        d |D              }|t        |      z  S c c}w )NrW   c              3  B   K   | ]  }|j                         sd   yw)   N)isupper)r1   chars     r3   r4   z#_uppercase_ratio.<locals>.<genexpr>   s     8gdgs   )isalpharo   len)textr   lettersuppers       r3   r_   r_      sH     $7tG78g88E3w<	 8s
   AA)r   ru   rz   rw   )r   
__future__r   r\   typingr   r   r   r   opik.exceptionsr   #opik.evaluation.metrics.base_metricr	   $opik.evaluation.metrics.score_resultr
   r>   r@   rB   r'   r_    rg   r3   <module>r      sI    5 " 	 4 4 2 : <   a-: a-H rg   