Ë
    l^(hÖ1  ã                  ó®   — 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 d dl	m
Z
 d dlmZ d dlmZ e
rd dlmZ  ej"                  e«      Z G d	„ d
e«      Zy)é    )ÚannotationsN)Údefaultdict)Únullcontext)ÚTYPE_CHECKING)ÚSentenceEvaluator)Úparaphrase_mining)ÚSentenceTransformerc                  ó¤   ‡ — e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dˆ fd„Z	 d	 	 	 	 	 	 	 	 	 d	d„Zed„ «       Zd„ Zˆ xZ	S )
ÚParaphraseMiningEvaluatoraÒ  
    Given a large set of sentences, this evaluator performs paraphrase (duplicate) mining and
    identifies the pairs with the highest similarity. It compare the extracted paraphrase pairs
    with a set of gold labels and computes the F1 score.

    Args:
        sentences_map (Dict[str, str]): A dictionary that maps sentence-ids to sentences.
            For example, sentences_map[id] => sentence.
        duplicates_list (List[Tuple[str, str]], optional): A list with id pairs [(id1, id2), (id1, id5)]
            that identifies the duplicates / paraphrases in the sentences_map. Defaults to None.
        duplicates_dict (Dict[str, Dict[str, bool]], optional): A default dictionary mapping [id1][id2]
            to true if id1 and id2 are duplicates. Must be symmetric, i.e., if [id1][id2] => True,
            then [id2][id1] => True. Defaults to None.
        add_transitive_closure (bool, optional): If true, it adds a transitive closure,
            i.e. if dup[a][b] and dup[b][c], then dup[a][c]. Defaults to False.
        query_chunk_size (int, optional): To identify the paraphrases, the cosine-similarity between
            all sentence-pairs will be computed. As this might require a lot of memory, we perform
            a batched computation. query_chunk_size sentences will be compared against up to
            corpus_chunk_size sentences. In the default setting, 5000 sentences will be grouped
            together and compared up-to against 100k other sentences. Defaults to 5000.
        corpus_chunk_size (int, optional): The corpus will be batched, to reduce the memory requirement.
            Defaults to 100000.
        max_pairs (int, optional): We will only extract up to max_pairs potential paraphrase candidates.
            Defaults to 500000.
        top_k (int, optional): For each query, we extract the top_k most similar pairs and add it to a sorted list.
            I.e., for one sentence we cannot find more than top_k paraphrases. Defaults to 100.
        show_progress_bar (bool, optional): Output a progress bar. Defaults to False.
        batch_size (int, optional): Batch size for computing sentence embeddings. Defaults to 16.
        name (str, optional): Name of the experiment. Defaults to "".
        write_csv (bool, optional): Write results to CSV file. Defaults to True.
        truncate_dim (Optional[int], optional): The dimension to truncate sentence embeddings to.
            `None` uses the model's current truncation dimension. Defaults to None.

    Example:
        ::

            from datasets import load_dataset
            from sentence_transformers.SentenceTransformer import SentenceTransformer
            from sentence_transformers.evaluation import ParaphraseMiningEvaluator

            # Load a model
            model = SentenceTransformer('all-mpnet-base-v2')

            # Load the Quora Duplicates Mining dataset
            questions_dataset = load_dataset("sentence-transformers/quora-duplicates-mining", "questions", split="dev")
            duplicates_dataset = load_dataset("sentence-transformers/quora-duplicates-mining", "duplicates", split="dev")

            # Create a mapping from qid to question & a list of duplicates (qid1, qid2)
            qid_to_questions = dict(zip(questions_dataset["qid"], questions_dataset["question"]))
            duplicates = list(zip(duplicates_dataset["qid1"], duplicates_dataset["qid2"]))

            # Initialize the paraphrase mining evaluator
            paraphrase_mining_evaluator = ParaphraseMiningEvaluator(
                sentences_map=qid_to_questions,
                duplicates_list=duplicates,
                name="quora-duplicates-dev",
            )
            results = paraphrase_mining_evaluator(model)
            '''
            Paraphrase Mining Evaluation of the model on the quora-duplicates-dev dataset:
            Number of candidate pairs: 250564
            Average Precision: 56.51
            Optimal threshold: 0.8325
            Precision: 52.76
            Recall: 59.19
            F1: 55.79
            '''
            print(paraphrase_mining_evaluator.primary_metric)
            # => "quora-duplicates-dev_average_precision"
            print(results[paraphrase_mining_evaluator.primary_metric])
            # => 0.5650940787776353
    c           
     ó¨  •— t         ‰| �  «        g | _        g | _        |j	                  «       D ];  \  }}| j                  j                  |«       | j                  j                  |«       Œ= || _        |	| _        |
| _        || _	        || _
        || _        || _        || _        |�|nt        d„ «      | _        |�8|D ]3  \  }}||v sŒ||v sŒd| j                  |   |<   d| j                  |   |<   Œ5 |r | j!                  | j                  «      | _        t#        «       }| j                  D ]j  }| j                  |   D ]V  }||v sŒ||v sŒ| j                  |   |   s| j                  |   |   sŒ2|j%                  t'        t)        ||g«      «      «       ŒX Œl t+        |«      | _        |rd|z   }d|z   dz   | _        g d¢| _        || _        d| _        y )Nc                 ó    — t        t        «      S )N)r   Úbool© ó    úx/var/www/skyplay_api_hub/venv/lib/python3.12/site-packages/sentence_transformers/evaluation/ParaphraseMiningEvaluator.pyú<lambda>z4ParaphraseMiningEvaluator.__init__.<locals>.<lambda>~   s   € ÔbmÔnrÓbs€ r   TÚ_Úparaphrase_mining_evaluationz_results.csv)ÚepochÚstepsÚ	precisionÚrecallÚf1Ú	thresholdÚaverage_precisionr   )ÚsuperÚ__init__Ú	sentencesÚidsÚitemsÚappendÚnameÚshow_progress_barÚ
batch_sizeÚquery_chunk_sizeÚcorpus_chunk_sizeÚ	max_pairsÚtop_kÚtruncate_dimr   Ú
duplicatesÚadd_transitive_closureÚsetÚaddÚtupleÚsortedÚlenÚtotal_num_duplicatesÚcsv_fileÚcsv_headersÚ	write_csvÚprimary_metric)ÚselfÚsentences_mapÚduplicates_listÚduplicates_dictr+   r%   r&   r'   r(   r#   r$   r"   r4   r)   ÚidÚsentenceÚid1Úid2Úpositive_key_pairsÚkey1Úkey2Ú	__class__s                        €r   r   z"ParaphraseMiningEvaluator.__init__]   sß  ø€ ô  	‰ÑÔØˆŒØˆŒà)×/Ñ/Ó1ò 	 ‰LˆB�Ø�N‰N×!Ñ! (Ô+Ø�H‰H�O‰O˜BÕð	 ð ˆŒ	Ø!2ˆÔØ$ˆŒØ 0ˆÔØ!2ˆÔØ"ˆŒØˆŒ
Ø(ˆÔà-<Ð-H™/ÌkÑZsÓNtˆŒØÐ&Ø+ò 5‘��SØ˜-Ò'¨C°=Ò,@Ø04�D—O‘O CÑ(¨Ñ-Ø04�D—O‘O CÑ(¨Ò-ð5ñ "Ø"×9Ñ9¸$¿/¹/ÓJˆDŒOä ›UÐØ—O‘Oò 	HˆDØŸ™¨Ñ-ò H�à˜MÒ)Ø Ò-ØŸ™¨Ñ.¨tÒ4¸¿¹ÈÑ8MÈdÓ8Sà&×*Ñ*¬5´¸¸t¸Ó1EÓ+FÕGñHð	Hô %(Ð(:Ó$;ˆÔ!áØ˜‘:ˆDà;¸dÑBÀ^ÑSˆŒÚlˆÔØ"ˆŒØ1ˆÕr   c                óà  — |dk7  r|dk(  rd|› �}nd|› d|› d�}nd}| j                   �|d| j                   › d�z  }t        j                  d	| j                  › d
|› d�«       | j                   €
t	        «       n|j                  | j                   «      5  t        || j                  | j                  | j                  | j                  | j                  | j                  | j                  «      }d d d «       t        j                  dt        t        «      «      z   «       dx}}d}	dx}
x}}d}t!        t        |«      «      D ]¸  }||   \  }}}| j"                  |   }| j"                  |   }|dz  }| j$                  |   |   s| j$                  |   |   sŒT|dz  }||z  }|| j&                  z  }d|z  |z  ||z   z  }||z  }||
kD  sŒ†|}
|}|}||   d   |t)        |dz   t        |«      dz
  «         d   z   dz  }	Œº || j&                  z  }t        j                  d|dz  d›�«       t        j                  d|	d›�«       t        j                  d|dz  d›�«       t        j                  d|dz  d›�«       t        j                  d|
dz  d›d�«       |�û| j*                  rït,        j.                  j1                  || j2                  «      }t,        j.                  j5                  |«      sat7        |ddd¬«      5 }t9        j:                  |«      }|j=                  | j>                  «       |j=                  |||||
|	|g«       d d d «       nEt7        |ddd¬«      5 }t9        j:                  |«      }|j=                  |||||
|	|g«       d d d «       ||
|||	dœ}| jA                  || j                  «      }| jC                  ||||«       |S # 1 sw Y   �ŒáxY w# 1 sw Y   ŒPxY w# 1 sw Y   Œ\xY w)Néÿÿÿÿz after epoch z
 in epoch z after z stepsÚ z (truncated to ú)z1Paraphrase Mining Evaluation of the model on the z datasetú:zNumber of candidate pairs: r   é   é   zAverage Precision: éd   z.2fzOptimal threshold: z.4fzPrecision: zRecall: zF1: ú
Úwzutf-8)ÚnewlineÚmodeÚencodingÚa)r   r   r   r   r   )"r)   ÚloggerÚinfor"   r   Útruncate_sentence_embeddingsr   r   r#   r$   r%   r&   r'   r(   Ústrr0   Úranger   r*   r1   Úminr4   ÚosÚpathÚjoinr2   ÚisfileÚopenÚcsvÚwriterÚwriterowr3   Úprefix_name_to_metricsÚ store_metrics_in_model_card_data)r6   ÚmodelÚoutput_pathr   r   Úout_txtÚ
pairs_listÚ	n_extractÚ	n_correctr   Úbest_f1Úbest_recallÚbest_precisionr   ÚidxÚscoreÚiÚjr<   r=   r   r   r   Úcsv_pathÚfr\   Úmetricss                              r   Ú__call__z"ParaphraseMiningEvaluator.__call__�   s!  € ð �BŠ;Ø˜Š{Ø)¨%¨Ð1‘à& u g¨W°U°G¸6ÐB‘àˆGØ×ÑÐ(Ø˜¨×):Ñ):Ð(;¸1Ð=Ñ=ˆGä�‰ÐGÈÏ	É	À{ÐRZÐ[bÐZcÐcdÐeÔfð #×/Ñ/Ð7Œ[Œ]¸U×=_Ñ=_Ð`d×`qÑ`qÓ=rñ 
	Ü*ØØ—‘Ø×&Ñ&Ø—‘Ø×%Ñ%Ø×&Ñ&Ø—‘Ø—
‘
ó	ˆJ÷
	ô 	�‰Ð1´C¼¸J»Ó4HÑHÔIð !"Ð!ˆ	�IØˆ	Ø12Ð2ˆÐ2�+ àÐäœ˜Z›Ó)ò 	lˆCØ$ S™/‰KˆE�1�aØ—(‘(˜1‘+ˆCØ—(‘(˜1‘+ˆCð ˜‰NˆIØ�‰˜sÑ# CÒ(¨D¯O©O¸CÑ,@ÀÓ,EØ˜Q‘�	Ø%¨	Ñ1�	Ø" T×%>Ñ%>Ñ>�Ø˜‘] VÑ+¨y¸6Ñ/AÑB�Ø! YÑ.Ð!Ø˜“<Ø �GØ%.�NØ"(�KØ!+¨C¡°Ñ!3°jÄÀSÈ1ÁWÌcÐR\ËoÐ`aÑNaÓAbÑ6cÐdeÑ6fÑ!fÐjkÑ k‘Ið#	lð& .°×0IÑ0IÑIÐä�‰Ð)Ð*;¸cÑ*AÀ#Ð)FÐGÔHÜ�‰Ð)¨)°C¨Ð9Ô:Ü�‰�k .°3Ñ"6°sÐ!;Ð<Ô=Ü�‰�h˜{¨SÑ0°Ð5Ð6Ô7Ü�‰�d˜7 S™=¨Ð-¨RÐ0Ô1àÐ" t§~¢~Ü—w‘w—|‘| K°·±Ó?ˆHÜ—7‘7—>‘> (Ô+Ü˜(¨B°SÀ7ÔKð xÈqÜ ŸZ™Z¨›]�FØ—O‘O D×$4Ñ$4Ô5Ø—O‘O U¨E°>À;ÐPWÐYbÐduÐ$vÔw÷xð xô
 ˜(¨B°SÀ7ÔKð xÈqÜ ŸZ™Z¨›]�FØ—O‘O U¨E°>À;ÐPWÐYbÐduÐ$vÔw÷xð
 "3ØØ'Ø!Ø"ñ
ˆð ×-Ñ-¨g°t·y±yÓAˆØ×-Ñ-¨e°W¸eÀUÔKØˆ÷K
	ñ 
	ú÷fxð xú÷
xð xús&   ÂAOË:A	OÍ.O$ÏOÏO!Ï$O-c                ót  — t        «       }t        | j                  «       «      D �]  }||vsŒ	t        «       }|j                  |«       t        | |   «      }t	        |«      dkD  rI|j                  d«      }||vr%|j                  |«       |j                  | |   «       t	        |«      dkD  rŒIt        |«      }t        t	        |«      dz
  «      D ]c  }t        |dz   t	        |«      «      D ]F  }d| ||      ||   <   d| ||      ||   <   |j                  ||   «       |j                  ||   «       ŒH Œe �Œ | S )Nr   rG   T)r,   ÚlistÚkeysr-   r0   ÚpopÚextendrT   )ÚgraphÚnodes_visitedrO   Úconnected_subgraph_nodesÚneighbor_nodes_queueÚnoderk   rl   s           r   r+   z0ParaphraseMiningEvaluator.add_transitive_closureô   sb  € ä›ˆÜ�e—j‘j“lÓ#ó 	GˆAØ˜Ò%Ü+.«5Ð(Ø(×,Ñ,¨QÔ/ô (,¨E°!©H£~Ð$ÜÐ.Ó/°!Ò3Ø/×3Ñ3°AÓ6�DØÐ#;Ñ;Ø0×4Ñ4°TÔ:Ø,×3Ñ3°E¸$±KÔ@ô	 Ð.Ó/°!Ó3ô ,0Ð0HÓ+IÐ(ÜœsÐ#;Ó<¸qÑ@ÓAò G�AÜ" 1 q¡5¬#Ð.FÓ*GÓHò G˜ØZ^˜Ð6°qÑ9Ñ:Ð;SÐTUÑ;VÑWØZ^˜Ð6°qÑ9Ñ:Ð;SÐTUÑ;VÑWà%×)Ñ)Ð*BÀ1Ñ*EÔFØ%×)Ñ)Ð*BÀ1Ñ*EÕFñGòGð	Gð, ˆr   c                ó„   — | j                   | j                  | j                  dœ}| j                  �| j                  |d<   |S )N)r+   r'   r(   r)   )r+   r'   r(   r)   )r6   Úconfig_dicts     r   Úget_config_dictz)ParaphraseMiningEvaluator.get_config_dict  sD   € à&*×&AÑ&AØŸ™Ø—Z‘Zñ
ˆð
 ×ÑÐ(Ø*.×*;Ñ*;ˆK˜Ñ'ØÐr   )NNFiˆ  i † i ¡ rI   Fé   rD   TN)r7   zdict[str, str]r8   zlist[tuple[str, str]]r9   zdict[str, dict[str, bool]]r+   r   r%   Úintr&   r   r'   r   r(   r   r#   r   r$   r   r"   rS   r4   r   r)   z
int | None)NrC   rC   )
r`   r	   ra   rS   r   r   r   r   Úreturnzdict[str, float])
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   rp   Ústaticmethodr+   r}   Ú__classcell__)rA   s   @r   r   r      s
  ø„ ñGðX 26Ø6:Ø',Ø $Ø!'ØØØ"'ØØØØ#'ð>2à%ð>2ð /ð>2ð 4ð	>2ð
 !%ð>2ð ð>2ð ð>2ð ð>2ð ð>2ð  ð>2ð ð>2ð ð>2ð ð>2ð !õ>2ðB bdðUØ(ðUØ7:ðUØJMðUØ[^ðUà	óUðn ñó ðö4r   r   )Ú
__future__r   r[   ÚloggingrV   Úcollectionsr   Ú
contextlibr   Útypingr   Ú2sentence_transformers.evaluation.SentenceEvaluatorr   Úsentence_transformers.utilr   Ú)sentence_transformers.SentenceTransformerr	   Ú	getLoggerr�   rP   r   r   r   r   ú<module>r�      sG   ðÝ "ã 
Û Û 	Ý #Ý "Ý  å PÝ 8áÝMà	ˆ×	Ñ	˜8Ó	$€ôDÐ 1õ Dr   