o
    }oi                     @   sL   d dl Z d dlmZ d dlZd dlmZ G dd deZG dd deZ	dS )    N)Counter)corpus_bleuc                   @   s<   e Zd Zedd Zedd Zedd Zedd Zd	S )
DialogueGenerationMetricsc                 C   s   g }t t|D ]}||| || || d qt| ddd}|D ]}|t|d  q$W d   dS 1 s<w   Y  dS )
        Save predictions as a jsonl file

        Args:
            Each arg is a list of strings (all args have the same length)
        )inputground_truth	generatedwUTF-8encoding
Nrangelenappendopenwritejsondumps)filenamegenerated_fieldground_truth_fieldinputsdocsifitem r   a/home/ubuntu/.local/lib/python3.10/site-packages/nemo/collections/nlp/metrics/dialogue_metrics.pysave_predictions   s   
"z*DialogueGenerationMetrics.save_predictionsc           	      C   s   |   }|  }t|t|@ }t| }|dkrdS d| t| }d| t| }d| | ||  }t|d |d |d gS )zn
        Get precision, recall, f1 based on token overlap between generated and ground_truth sequence
        r   )r   r   r   g      ?   d   )splitr   sumvaluesr   nparray)	r   r   generated_tokensground_truth_tokenscommonnum_same	precisionrecallf1r   r   r   _get_one_f1+   s   z%DialogueGenerationMetrics._get_one_f1c                    s4   t  fddttD }t j|dd}|S )Nc                    s    g | ]}t  | | qS r   )r   r/   .0r   generated_fieldsground_truth_fieldsr   r   
<listcomp>?   s    z4DialogueGenerationMetrics.get_f1.<locals>.<listcomp>r   )axis)r&   r'   r   r   mean)r3   r4   total_p_r_f1
avg_p_r_f1r   r2   r   get_f1<   s   
z DialogueGenerationMetrics.get_f1c                    sV    fddt t D } fdd|D  fdd|D t gdd}|jS )z
        Referenced from NMT evaluation
        Note 13a is the default tokenizer for English for WMT
        Known issue that it doesn't hand edge case of None or '' 
        https://github.com/mjpost/sacrebleu/issues/161
        c                    s    g | ]} | r| r|qS r   r   r0   r   r   r   r   r5   O   s     z6DialogueGenerationMetrics.get_bleu.<locals>.<listcomp>c                       g | ]} | qS r   r   r0   )r   r   r   r5   P       c                    r<   r   r   r0   )r   r   r   r5   Q   r=   13a)tokenize)r   r   r   score)r   r   valid_indices
sacre_bleur   r;   r   get_bleuG   s
   z"DialogueGenerationMetrics.get_bleuN)__name__
__module____qualname__staticmethodr    r/   r:   rC   r   r   r   r   r      s    



r   c                   @   s2   e Zd Zedd Zed	ddZedd ZdS )
DialogueClassificationMetricsc                 C   s   g }t t|D ]}	|||	 ||	 ||	 ||	 ||	 ||	 ||	 d qt| ddd}
|D ]}|
t|d  q0W d   dS 1 sHw   Y  dS )r   )r   r   ground_truth_slotsground_truth_labelsr   generated_slotsgenerated_labelsr	   r
   r   r   Nr   )r   rL   rK   rJ   rI   r   r   r   r   r   r   r   r   r   r   r    W   s"   "z.DialogueClassificationMetrics.save_predictionsFc                 C   s   g }g }| D ]P}|rHdd | ddD }d}t|dkr"|\}}nt|dkr.|d }d}t|trDd|v r>| dd }| d	}nd
g}n|}g }|| || q||fS )am  
        Split target into label and slots when doing joint label (i.e. intent) classificaiton and slot filling

        For instance, split "reserve_restaurant
slots: time_of_day(7pm), number_of_people(3)" into 
        label = "reserve_restaurant" and slots = ["time_of_day(7pm)", "number_of_people(3)"]
        Args:
            fields: list of strings 
        c                 S   s   g | ]}|  qS r   )stripr0   r   r   r   r5      r=   zGDialogueClassificationMetrics.split_label_and_slots.<locals>.<listcomp>zslots:   noner!   r   zpossible intents:z, None)r#   r   
isinstancestrr   )fields
with_slotslabels
slots_listfieldcombolabelslotsr   r   r   split_label_and_slotsy   s*   



z3DialogueClassificationMetrics.split_label_and_slotsc                    s  g }g }g }t t| D ]T}ttt||  ttt| | } fdd|D }t dkr9t|t  nd}t|dkrIt|t| nd}	t |k}
|| ||	 ||
 qt|d }t|d }t|d }d||  || d  }||||fS )z
        Args:
            generated_slots: list of list of strings. 
                Each string is slot-name and slot-value pair e.g. location(Seattle)
            ground_truth_slots: list of list of strings
        c                    s   g | ]}| v r|qS r   r   )r1   r   r   r   r   r5      s    zJDialogueClassificationMetrics.get_slot_filling_metrics.<locals>.<listcomp>r   r"   r!   g#B;)	r   r   sortedlistsetintr   r&   r7   )rK   rI   
all_recallall_precisionall_joint_goal_accuracyr   	predictedcorrectr-   r,   joint_goal_accuracyavg_joint_goal_accuracyavg_precision
avg_recallavg_f1r   r\   r   get_slot_filling_metrics   s$     

z6DialogueClassificationMetrics.get_slot_filling_metricsN)F)rD   rE   rF   rG   r    r[   rk   r   r   r   r   rH   V   s    
!#rH   )
r   collectionsr   numpyr&   	sacrebleur   objectr   rH   r   r   r   r   <module>   s   ?