
    i&                        d dl Z d dlZd dlmZ d dlmZmZmZ d dlm	Z	m
Z
 d dlmZ eeef   Zeeee   f   Zeeeeeeeee   ee   f   f   f   f   Zeeee   f   Zeeeeeeef   f      eeeeee   ee   f   f   f   Zdgdgdd	d
dddZdedefdZdedee   fdZdedede	fdZdedede	fdZdeeege	f   dedee   de	fdZdededeeeef   eeeeeeeeeef      f      f      f   fdZdeeef   deeeeeeeeeef      f      f      dee	e	e	f   fdZd e	d!e	d"e	deee	f   fd#Zdededeee	f   fd$Z y)%    N)Counter)AnyCallableUnion)Tensortensor)rank_zero_warn   zThis is a test text)answer_starttextzThis is a test context.1zIs this a test?z
train test)answerscontextidquestiontitlesreturnc           	          dt         dt         fd}dt         dt         fd}dt         dt         fd}dt         dt         fd} | | | ||                         S )zALower text and remove punctuation, articles and extra whitespace.r   r   c                 0    t        j                  dd|       S )Nz\b(a|an|the)\b )resubr   s    w/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/functional/text/squad.pyremove_articlesz(_normalize_text.<locals>.remove_articles,   s    vv'd33    c                 @    dj                  | j                               S )Nr   )joinsplitr   s    r   white_space_fixz(_normalize_text.<locals>.white_space_fix/   s    xx

%%r   c                 j    t        t        j                        dj                  fd| D              S )N c              3   ,   K   | ]  }|vs|  y wN ).0chexcludes     r   	<genexpr>z7_normalize_text.<locals>.remove_punc.<locals>.<genexpr>4   s     >DbBg,=rDs   	)setstringpunctuationr   )r   r)   s    @r   remove_puncz$_normalize_text.<locals>.remove_punc2   s(    f(()ww>D>>>r   c                 "    | j                         S r%   )lowerr   s    r   r0   z_normalize_text.<locals>.lower6   s    zz|r   )str)r   r   r!   r.   r0   s        r   _normalize_textr2   )   si    4c 4c 4&c &c &?# ?# ?C C  ?;uQx+@ABBr   c                 <    | sg S t        |       j                         S )z&Split a sentence into separate tokens.)r2   r    )r   s    r   _get_tokensr4   <   s    26OA.4466r   predicted_answertarget_answerc                    t        |      }t        |       }t        |      t        |      z  }t        t        |j	                                     }t        |      dk(  st        |      dk(  rt        t        ||k(              S |dk(  rt        d      S d|z  t        t        |            z  }d|z  t        t        |            z  }d|z  |z  ||z   z  S )z#Compute F1 Score for two sentences.r           g      ?   )r4   r   r   sumvalueslenint)r5   r6   target_tokenspredicted_tokenscommonnum_same	precisionrecalls           r   _compute_f1_scorerD   A   s    .M"#34]#g.>&??Fc&--/*+H
=Q#&6"71"<c-+;;<==1}c{h,<(=!>>I8^fS%788F	MF"y6'9::r   
predictionground_truthc                 T    t        t        t        |       t        |      k(              S )z&Compute Exact Match for two sentences.)r   r=   r2   )rE   rF   s     r   _compute_exact_match_scorerH   Q   s!    #oj1_\5RRSTTr   	metric_fnground_truthsc                 0     t         fd|D              S )zJCalculate maximum score for a predicted answer with all reference answers.c              3   0   K   | ]  } |        y wr%   r&   )r'   truthrI   rE   s     r   r*   z1_metric_max_over_ground_truths.<locals>.<genexpr>Z   s     GyU+s   )max)rI   rE   rJ   s   `` r   _metric_max_over_ground_truthsrO   V   s     GGGGr   predstargetsc                    t        | t              r| g} t        |t              r|g}| D ]%  }|j                         }d|vsd|vst        d       |D ]G  }|j                         }d|vsd|vrt        dt               |d   }d|vs7t        dt                | D ci c]  }|d   |d    }}d }	d	d
|D cg c]
  } |	|       c}igig}
||
fS c c}w c c}w )zOCheck for types and convert the input to necessary format to compute the input.prediction_textr   zExpected keys in a single prediction are 'prediction_text' and 'id'.Please make sure that 'prediction_text' maps to the answer string and 'id' maps to the key string.r   zExpected keys in a single target are 'answers' and 'id'.Please make sure that 'answers' maps to a `SQuAD` format dictionary and 'id' maps to the key string.
SQuAD Format: r   zzExpected keys in a 'answers' are 'text'.Please make sure that 'answer' maps to a `SQuAD` format dictionary.
SQuAD Format: c                 H    | d   d   D cg c]  }d|i c}| d   dS c c}w )Nr   r   r   )r   r   r&   )tgttxts     r   <lambda>z$_squad_input_check.<locals>.<lambda>   s2    3y>RXCY)ZCYC63-CY)Zbefjbkl)Zs   
paragraphsqas)
isinstancedictkeysKeyErrorSQuAD_FORMAT)rP   rQ   pred	pred_keystargettarget_keysr   rE   
preds_dict
_fn_answertargets_dicts              r   _squad_input_checkrf   ]   s@    %'4 )IIK	I-Y1Fu   kkmK'4{+B!  ."  ;A:K !  ."  & UZZTYj*T"J/@$AATYJZlJ!Ug,VgFZ-?g,V$W#XYZL|## [,Vs   !C<Cra   c           	      V   t        d      }t        d      }t        d      }|D ]z  }|d   D ]p  }|d   D ]f  }|dz  }|d   | vrt        d|d    d       "|d	   D cg c]  }|d
   	 }	}| |d      }
|t        t        |
|	      z  }|t        t        |
|	      z  }h r | |||fS c c}w )au  Compute F1 Score and Exact Match for a collection of predictions and references.

    Args:
        preds: A dictionary mapping an `id` to the predicted `answer`.
        target:
            A list of dictionary mapping `paragraphs` to list of dictionary mapping `qas` to a list of dictionary
            containing `id` and list of all possible `answers`.

    Return:
        Tuple containing F1 score, Exact match score and total number of examples.

    Example:
        >>> from torchmetrics.functional.text.squad import _squad_update
        >>> preds = [{"prediction_text": "1976", "id": "56e10a3be3433e1400422b22"}]
        >>> target = [{"answers": {"answer_start": [97], "text": ["1976"]}, "id": "56e10a3be3433e1400422b22"}]
        >>> preds_dict = {pred["id"]: pred["prediction_text"] for pred in preds}
        >>> targets_dict = [
        ...     dict(paragraphs=[dict(qas=[dict(answers=[
        ...         {"text": txt} for txt in tgt["answers"]["text"]], id=tgt["id"]) for tgt in target
        ...     ])])
        ... ]
        >>> _squad_update(preds_dict, targets_dict)
        (tensor(1.), tensor(1.), tensor(1))

    r8   r   rX   rY   r
   r   zUnanswered question z will receive score 0.r   r   )r   r	   rO   rH   rD   )rP   ra   f1exact_matchtotalarticle	paragraphqaxrJ   r_   s              r   _squad_updatero      s    : 
B+K1IE .I&
d85("%9"T(CY#Z[46yM BMq6M BRX=>XZ^`mnn45Fm\\ ' /  {E!! !Cs   B&
rh   ri   rj   c                 ,    d|z  |z  }d| z  |z  } || dS )zAggregate the F1 Score and Exact match for the batch.

    Return:
        Dictionary containing the F1 score, Exact match score for the batch.

    g      Y@)ri   rh   r&   )rh   ri   rj   s      r   _squad_computerq      s,     +%-K	e	B&b11r   c                 Z    t        | |      \  }}t        ||      \  }}}t        |||      S )a  Calculate `SQuAD Metric`_ .

    Args:
        preds: A Dictionary or List of Dictionary-s that map `id` and `prediction_text` to the respective values.

            Example prediction:

            .. code-block:: python

                {"prediction_text": "TorchMetrics is awesome", "id": "123"}

        target: A Dictionary or List of Dictionary-s that contain the `answers` and `id` in the SQuAD Format.

            Example target:

            .. code-block:: python

                {
                    'answers': [{'answer_start': [1], 'text': ['This is a test answer']}],
                    'id': '1',
                }

            Reference SQuAD Format:

            .. code-block:: python

                {
                    'answers': {'answer_start': [1], 'text': ['This is a test text']},
                    'context': 'This is a test context.',
                    'id': '1',
                    'question': 'Is this a test?',
                    'title': 'train test'
                }


    Return:
        Dictionary containing the F1 score, Exact match score for the batch.

    Example:
        >>> from torchmetrics.functional.text.squad import squad
        >>> preds = [{"prediction_text": "1976", "id": "56e10a3be3433e1400422b22"}]
        >>> target = [{"answers": {"answer_start": [97], "text": ["1976"]},"id": "56e10a3be3433e1400422b22"}]
        >>> squad(preds, target)
        {'exact_match': tensor(100.), 'f1': tensor(100.)}

    Raises:
        KeyError:
            If the required keys are missing in either predictions or targets.

    References:
        [1] SQuAD: 100,000+ Questions for Machine Comprehension of Text by Pranav Rajpurkar, Jian Zhang, Konstantin
        Lopyrev, Percy Liang `SQuAD Metric`_ .

    )rf   ro   rq   )rP   ra   rc   target_dictrh   ri   rj   s          r   squadrt      s8    n 1?J*:{CBU"k511r   )!r   r,   collectionsr   typingr   r   r   torchr   r   torchmetrics.utilitiesr	   r[   r1   SINGLE_PRED_TYPElist
PREDS_TYPEr=   SINGLE_TARGET_TYPETARGETS_TYPEUPDATE_METHOD_SINGLE_PRED_TYPEr^   r2   r4   rD   rH   rO   tuplerf   ro   rq   rt   r&   r   r   <module>r      s  " 
   ' '   1S> #T*:%;;<
#uS$sE$s)T#Y:N4O/O*P%PQQR '.@)AAB!&tDeCHo1E,F'GdSVX]^bcf^gimnqir^rXsSsNt't!u  "#.C-DE(
!Cs Cs C&73 749 7
; ;C ;F ; U3 Uc Uf U
Hc
F*+H9<HMQRUYHH($($ ,($
4S>4S$tCd38n9M4M/N*O%O PQQR($V,"S>,"c4S$tCH~*>%> ?@@AB," 666!","^	2v 	2F 	26 	2d3PV;FW 	292 92\ 92d3;6G 92r   