
    jS+                       d dl mZ d dlZd dlmZ d dlmZmZmZm	Z	m
Z
mZmZmZ d dlmZ d dlmZmZ eege	e   f   Z G d de      Zdd	Zdd
Z G d dej0                        Z G d de      Z G d de      Z G d de      Zy)    )annotationsN)Counter)AnyCallableDictIterableListOptionalProtocolSequence)MetricComputationError)base_metricscore_resultc                  &    e Zd Z	 d	 	 	 	 	 	 	 ddZy)_JSDistanceFnc                     y N )selfpqbases       /Users/manta/Documents/Projects/TheRoad-I1/backend/.venv/lib/python3.12/site-packages/opik/evaluation/metrics/heuristics/distribution_metrics.py__call__z_JSDistanceFn.__call__   s         N).)r   Sequence[float]r   r   r   zOptional[float]returnfloat)__name__
__module____qualname__r   r   r   r   r   r      s2      
	 
r   r   c                 N    	 ddl m}  | S # t        $ r}t        d      |d }~ww xY w)Nr   )jensenshannonzDInstall scipy via `pip install scipy` to use Jensen-Shannon metrics.)scipy.spatial.distancer#   ImportError)r#   errors     r   _load_jensen_shannon_distancer'      s7    8   R
	s   
 	$$c                >    | j                         j                         S r   )lowersplit)texts    r   _default_tokenizerr,   #   s    ::<r   c                  R     e Zd ZdZ	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZddZddZ xZS )	_DistributionMetricBasea  
    Internal helper for metrics that compare token distributions.

    Args:
        tokenizer: Optional tokenizer returning an iterable of tokens given text.
        name: Display name for the metric.
        track: Whether to automatically track metric results.
        project_name: Optional tracking project.
        normalize: When ``True`` the histogram is converted to probabilities.
        smoothing: Optional additive constant applied during KL-like computations.
    c                x    t         |   |||       |xs t        | _        || _        t        d|      | _        y )N)nametrackproject_name        )super__init__r,   
_tokenizer
_normalizemax
_smoothing)r   	tokenizerr0   r1   r2   	normalize	smoothing	__class__s          r   r5   z _DistributionMetricBase.__init__4   s;     	d%lK#9'9#c9-r   c                   t        | j                  |            }t        |      dk(  rt        d      t	        |      }| j
                  s-|j                         D ci c]  \  }}|t        |       c}}S t        t        |j                                     }|j                         D ci c]  \  }}|||z   c}}S c c}}w c c}}w )Nr   z4Tokenized text is empty (distribution-based metric).)
listr6   lenr   r   r7   itemsr   sumvalues)r   r+   tokenscountstokencounttotals          r   _build_distributionz+_DistributionMetricBase._build_distributionB   s    dood+,v;!(F  <BLLNKNLE5E5<'NKKc&--/*+9?Huu}$HH L Is   C-Cc                B    | j                   dk(  r|S || j                   z   S Nr3   )r9   )r   values     r   _smoothz_DistributionMetricBase._smoothP   s"    ??c!Lt&&r   )r3   )r:   Optional[TokenizeFn]r0   strr1   boolr2   Optional[str]r;   rP   r<   r   r   None)r+   rO   r   Dict[str, float])rL   r   r   r   )r   r    r!   __doc__r5   rI   rM   __classcell__r=   s   @r   r.   r.   '   sa    
& .'. . 	.
 $. . . 
.I'r   r.   c                       e Zd ZdZ	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZ	 	 	 	 	 	 	 	 ddZ	 	 	 	 	 	 d	dZd
dZ xZS )JSDivergenceuR  
    Compute Jensen–Shannon similarity (``1 - JSD``) between two texts.

    Args:
        tokenizer: Optional tokenizer function. Defaults to whitespace split.
        base: Logarithm base used when computing divergence (> ``1.0``).
        normalize: Whether to normalise token counts to probabilities first.
        name: Display name for the metric result.
        track: Whether to automatically track metric results.
        project_name: Optional tracking project name.

    Note:
        Requires :mod:`scipy` to be installed.

    Example:
        >>> from opik.evaluation.metrics import JSDivergence
        >>> metric = JSDivergence()
        >>> result = metric.score(
        ...     output="cat cat sat",
        ...     reference="cat sat on mat",
        ... )
        >>> round(result.value, 3)  # doctest: +SKIP
        0.812
    c                z    |dk  rt        d      t        | 	  |||||       || _        t	               | _        y )N      ?zbase must be greater than 1.0)r:   r0   r1   r2   r;   )
ValueErrorr4   r5   _baser'   _js_distance_fnr   r:   r   r;   r0   r1   r2   r=   s          r   r5   zJSDivergence.__init__p   sM     3;<==% 	 	
 
<>r   c                   |j                         st        d      |j                         st        d      | j                  |      }| j                  |      }| j                  ||      }t	        dt        dd|z
              }t        j                  || j                  d| j                  dd|dd	|dd
|t        j                  |      | j                  d      S )Nz/Candidate is empty (Jensen-Shannon divergence).z/Reference is empty (Jensen-Shannon divergence).r3   rZ   z Jensen-Shannon similarity (base=g): .4fz (divergence=))
divergencedistancer   rL   r0   reasonmetadata)stripr   rI   _js_divergencer8   minr   ScoreResultr0   r\   mathsqrt)r   output	referenceignored_kwargsoutput_distreference_distrd   scores           r   rt   zJSDivergence.score   s     ||~(A   (A  ..v611)<((nE
CS#
"234''24::a.E#; O)#.a1 ) IIj1


 	
r   c                t   t        t        |      t        |      z        }|sy|D cg c]  }|j                  |d       }}|D cg c]  }|j                  |d       }}| j                  |      }| j                  |      }t	        | j                  ||| j                              }	|	dz  S c c}w c c}w )Nr3   )r      )sortedsetget_ensure_probability_vectorr   r]   r\   )
r   p_distq_dist
vocabularyrF   p_vectorq_vectorp_probsq_probsre   s
             r   rj   zJSDivergence._js_divergence   s    
 CK#f+56
8BC
uFJJuc*
C8BC
uFJJuc*
C11(;11(;--gwTZZ-PQ{ DCs   B0B5c                h    t        |      }|dk  rt        d      |D cg c]  }||z  	 c}S c c}w )Nr3   zADistribution is empty after tokenisation (Jensen-Shannon metric).)rB   r   )r   rC   rH   rL   s       r   rz   z'JSDivergence._ensure_probability_vector   s@    FC<(S  ,226%6222s   /)N       @Tjs_divergence_metricTNr:   rN   r   r   r;   rP   r0   rO   r1   rP   r2   rQ   r   rR   ro   rO   rp   rO   rq   r   r   zscore_result.ScoreResultr{   rS   r|   rS   r   r   )rC   r   r   zList[float])	r   r    r!   rT   r5   rt   rj   rz   rU   rV   s   @r   rX   rX   V   s    6 +/*&*?'? ? 	?
 ? ? $? 
?*!
!
 !
 	!

 
"!
F  ! 
	$3r   rX   c                  h     e Zd ZdZ	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZ	 	 	 	 	 	 	 	 d fdZ xZS )
JSDistanceu  
    Return the raw Jensen–Shannon divergence instead of similarity.

    Args:
        tokenizer: Optional tokenizer function.
        base: Logarithm base used for the divergence calculation.
        normalize: Whether to normalise counts into probabilities.
        name: Display name for the metric result.
        track: Whether to automatically track metric results.
        project_name: Optional tracking project name.

    Example:
        >>> from opik.evaluation.metrics import JSDistance
        >>> metric = JSDistance()
        >>> result = metric.score("a a b", reference="a b b")
        >>> round(result.value, 3)  # doctest: +SKIP
        0.188
    c                0    t         |   ||||||       y )N)r:   r   r;   r0   r1   r2   )r4   r5   r^   s          r   r5   zJSDistance.__init__   s)     	% 	 	
r   c           
     |   t         |   ||      }|j                  xs i }t        |j	                  dd            }t        |j	                  dt        j                  |                  }t        j                  || j                  d| j                  dd|d||j	                  d	| j                        d
      S )N)ro   rp   rd   r3   re   z Jensen-Shannon divergence (base=r`   ra   rb   r   )re   r   rf   )r4   rt   rh   r   ry   rm   rn   r   rl   r0   r\   )	r   ro   rp   rq   
similarityrh   rd   re   r=   s	           r   rt   zJSDistance.score   s     W]&I]F
&&,"8<<c:;
j$))J2GHI''5djj^3zRUFVW$ VTZZ8	
 	
r   )Nr   Tjs_distance_metricTNr   r   )r   r    r!   rT   r5   rt   rU   rV   s   @r   r   r      s    * +/(&*
'
 
 	

 
 
 $
 

$

 
 	

 
"
 
r   r   c                  r     e Zd ZdZ	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 d fdZ	 	 	 	 	 	 	 	 ddZddZ xZS )	KLDivergenceac  
    Compute the (optionally symmetric) KL divergence between token distributions.

    Args:
        tokenizer: Optional tokenizer function. Defaults to whitespace split.
        direction: Direction to compute (``"pq"``, ``"qp"``, or ``"avg"`` for
            symmetric).
        normalize: Whether to normalise token counts to probabilities first.
        smoothing: Additive smoothing constant to avoid divide-by-zero.
        name: Display name for the metric result.
        track: Whether to automatically track metric results.
        project_name: Optional tracking project name.

    Example:
        >>> from opik.evaluation.metrics import KLDivergence
        >>> metric = KLDivergence(direction="avg")
        >>> result = metric.score("hello hello world", reference="hello world")
        >>> round(result.value, 4)  # doctest: +SKIP
        0.0583
    c                \    |dvrt        d      t        | 	  ||||||       || _        y )N>   pqqpavgz,direction must be one of {'pq', 'qp', 'avg'})r:   r0   r1   r2   r;   r<   )r[   r4   r5   
_direction)	r   r:   	directionr;   r<   r0   r1   r2   r=   s	           r   r5   zKLDivergence.__init__  sG     //KLL% 	 	
 $r   c           	        |j                         st        d      |j                         st        d      | j                  |      }| j                  |      }| j                  dk(  r| j	                  ||      }nJ| j                  dk(  r| j	                  ||      }n(d| j	                  ||      | j	                  ||      z   z  }t        j                  || j                  d| j                   d|d	      S )
Nz*Candidate is empty (KL divergence metric).z*Reference is empty (KL divergence metric).r   r   g      ?zKL divergence (ra   rb   )rL   r0   rg   )ri   r   rI   r   _klr   rl   r0   )r   ro   rp   rq   r{   r|   rd   s          r   rt   zKLDivergence.score*  s     ||~()UVV ()UVV))&1)))4??d"&&1J__$&&1J 8488FF;S STJ''$T__$5SC8HI
 	
r   c                    d}|j                         D ]U  \  }}| j                  |      }| j                  |j                  |d            }||t        j                  ||z        z  z  }W |S rK   )rA   rM   ry   rm   log)r   r{   r|   rd   rF   p_valq_vals          r   r   zKLDivergence._klE  sf    
"LLNLE5LL'ELLE3!78E%$((55="999J + r   )Nr   Tg-q=kl_divergence_metricTN)r:   rN   r   rO   r;   rP   r<   r   r0   rO   r1   rP   r2   rQ   r   rR   r   r   )r   r    r!   rT   r5   rt   r   rU   rV   s   @r   r   r      s    . +/ *&*$'$ $ 	$
 $ $ $ $$ 
$,

 
 	

 
"
6r   r   )r   r   )r+   rO   r   zIterable[str])
__future__r   rm   collectionsr   typingr   r   r   r   r	   r
   r   r   opik.exceptionsr   opik.evaluation.metricsr   r   rO   
TokenizeFnr   r'   r,   
BaseMetricr.   rX   r   r   r   r   r   <module>r      s    "   T T T 2 =seXc]*+
H  ,'k44 ,'^j3* j3Z8
 8
vM* Mr   