U
    UcU                     @   s  d Z ddlmZ ddlmZ ddlmZ ddlZddlZddlZddlZddl	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 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dZ dZ!dZ"dZ#G dd dej$Z%dS )z1The plugin serving the interactive inference tab.    )absolute_import)division)print_functionN)wrappers)xrange)json_format)AbortionError)	http_util)base_plugin)common_utils)inference_utils)platform_utilsZtensorboard2   
   i'  c                   @   s.  e Zd ZdZdZg Ze ZdZe	j
jZdZdZg Zdd Zdd	 Zd
d Zdd Zejjdd Zejjdd Zejjdd Zdd Zejjdd Zejjdd Zejjdd Zejjdd Zejjdd Zd d! Z ejjd"d# Z!ejjd$d% Z"ejjd&d' Z#ejjd(d) Z$d*d+ Z%dS ),WhatIfToolPluginz6Plugin for understanding/debugging model inference.
  ZwhatifNzimage/encoded    c              
   C   s   |j | _|jr|jjnd| _d| _|jr|jjrzHddlm} |d|jj}|	|}|j
| |j| _td W nD tk
r } z&tt| td td W 5 d}~X Y nX dS )z|Constructs an interactive inference plugin for TensorBoard.

    Args:
      context: A base_plugin.TBContext instance.
    Nr   custom_predict_fnzcustom_predict_fn loaded.z+Failed to load the custom predict function.z4Have you defined a function named custom_predict_fn?)Zlogdir_logdirflagsZwit_data_dir_wit_data_dirr   Zimportlib.utilutilspec_from_file_locationmodule_from_specloaderexec_moduleloggerinfo	Exceptionerrorstr)selfcontextiuspecmodulee r&   E/tmp/pip-unpacked-wheel-15h0ro02/tensorboard_plugin_wit/wit_plugin.py__init__Q   s    

zWhatIfToolPlugin.__init__c                 C   s6   | j | j| j| j| j| j| j| j| j| j	| j
| jdS )zObtains a mapping between routes and handlers. Stores the logdir.

    Returns:
      A mapping between routes and handlers (functions that respond to
      requests).
    )	/index.jsz/wit_tb_bin.htmlz/wit_tb_bin.jsz/inferz/update_examplez/examples_from_pathz/spritez/duplicate_examplez/delete_examplez/infer_mutantsz/eligible_featuresz/sort_eligible_features)	_serve_js
_serve_wit_serve_wit_js_infer_update_example_examples_from_path_handler_serve_sprite_duplicate_example_delete_example_infer_mutants_handler'_eligible_features_from_example_handler_sort_eligible_features_handlerr    r&   r&   r'   get_plugin_appsi   s    z WhatIfToolPlugin.get_plugin_appsc                 C   s   dS )zlDetermines whether this plugin is active.

    Returns:
      A boolean. Whether this plugin is active.
    Fr&   r6   r&   r&   r'   	is_active   s    zWhatIfToolPlugin.is_activec                 C   s   t jdddS )Nr)   zWhat-If Tool)Zes_module_pathZtab_name)r
   ZFrontendMetadatar6   r&   r&   r'   frontend_metadata   s    z"WhatIfToolPlugin.frontend_metadatac              	   C   sJ   ~t jt jtdd}tj|dd}| }W 5 Q R X tj	|ddS )Nstaticzindex.jsutf-8encodingapplication/javascriptcontent_type
ospathjoindirname__file__ioopenreadwerkzeugResponser    requestfilepathinfilecontentsr&   r&   r'   r*      s
    zWhatIfToolPlugin._serve_jsc              	   C   sJ   ~t jt jtdd}tj|dd}| }W 5 Q R X tj	|ddS )Nr:   zwit_tb_bin.htmlr;   r<   z	text/htmlr?   rA   rL   r&   r&   r'   r+      s
    zWhatIfToolPlugin._serve_witc              	   C   sJ   ~t jt jtdd}tj|dd}| }W 5 Q R X tj	|ddS )Nr:   zwit_tb_bin.jsr;   r<   r>   r?   rA   rL   r&   r&   r'   r,      s
    zWhatIfToolPlugin._serve_wit_jsc                 C   sR   | j tjjkr| jd jjn| jd jj}t| jrH| j	|krHt
|nd | _d S )Nr   )example_classtftrainExampleexamplesfeaturesZfeaturer!   lenimage_feature_namer   Zcreate_sprite_imagesprite)r    example_stringsZfeature_listr&   r&   r'   generate_sprite   s    z WhatIfToolPlugin.generate_spritec           
   
      s  |j drt|j dnd}|s\t|j d}|j d}t|j d}|j ddkrjtjjntjj _z^t	
| j j t	j||d| jd	} fd
d|D  _ | ttt j _W n tjk
r } z*td|j tj||jddd W Y S d}~X Y n> tk
rZ } ztj|t|ddd W Y S d}~X Y nX |t }dd  j|| D }	|t jkrd}t||	 jr|sdnd|ddS )zReturns JSON of the specified examples.

    Args:
      request: A request that should contain 'examples_path' and 'max_examples'.

    Returns:
      JSON of up to max_examples of the examples in the path.
    start_exampler   Zmax_examplesexamples_pathsampling_oddsZsequence_examplestrueF)Zparse_examplesr^   rQ   c                    s   g | ]} j |qS r&   )rQ   Z
FromString.0exr6   r&   r'   
<listcomp>   s    z@WhatIfToolPlugin._examples_from_path_handler.<locals>.<listcomp>zData loading error: %sapplication/json  codeNc                 S   s   g | ]}t |qS r&   )r   ZMessageToJson)ra   exampler&   r&   r'   rc      s    T)rU   rY   next)argsgetintfloatrR   rS   ZSequenceExamplerT   rQ   r   Z throw_if_file_access_not_allowedr   r   Zexample_protos_from_pathrU   r[   setrangerW   updated_example_indicesr   InvalidUserInputErrorr   r   messager	   Respondr   r   MAX_EXAMPLES_TO_SENDrY   )
r    rM   r\   Zexamples_countr]   r^   rZ   r%   end_exampleZjson_examplesr&   r6   r'   r/      sr    

   


   z,WhatIfToolPlugin._examples_from_path_handlerc                 C   s   t || jdS )Nz	image/png)r	   rt   rY   r    rM   r&   r&   r'   r0      s    zWhatIfToolPlugin._serve_spritec                 C   s   |j dkrtj|ddddS |jd }t|jd }|t| jkrTtj|ddd	dS |  }t	|| || j|< | j
| | d
d | jD  t|i dS )zUpdates the specified example.

    Args:
      request: A request that should contain 'index' and 'example'.

    Returns:
      An empty response.
    POSTzinvalid non-POST requestrd     rf   rh   indexinvalid index providedre   c                 S   s   g | ]}|  qS r&   ZSerializeToStringr`   r&   r&   r'   rc      s     z4WhatIfToolPlugin._update_example.<locals>.<listcomp>)methodr	   rt   formrm   rW   rU   rQ   r   Parserq   addr[   )r    rM   Zexample_jsonrz   new_exampler&   r&   r'   r.      s$    

 
 
z WhatIfToolPlugin._update_examplec                 C   s   t |jd}|t| jkr0tj|ddddS |  }|| j|  | j	| | j
t| jd  | dd | jD  t|i dS )	zDuplicates the specified example.

    Args:
      request: A request that should contain 'index'.

    Returns:
      An empty response.
    rz   r{   rd   re   rf      c                 S   s   g | ]}|  qS r&   r|   r`   r&   r&   r'   rc     s     z7WhatIfToolPlugin._duplicate_example.<locals>.<listcomp>)rm   rk   rl   rW   rU   r	   rt   rQ   ZCopyFromappendrq   r   r[   )r    rM   rz   r   r&   r&   r'   r1     s    
 z#WhatIfToolPlugin._duplicate_examplec                    sv   t |jd  t| jkr0tj|ddddS | j = t fdd| jD | _| 	dd | jD  t|i dS )	zDeletes the specified example.

    Args:
      request: A request that should contain 'index'.

    Returns:
      An empty response.
    rz   r{   rd   re   rf   c                    s    g | ]}| k r|n|d  qS )r   r&   )ra   irz   r&   r'   rc   &  s    z4WhatIfToolPlugin._delete_example.<locals>.<listcomp>c                 S   s   g | ]}|  qS r&   r|   r`   r&   r&   r'   rc   (  s     )
rm   rk   rl   rW   rU   r	   rt   ro   rq   r[   rw   r&   r   r'   r2     s    
 
z WhatIfToolPlugin._delete_examplec                 C   sn   |j dd}|j dd}|j dd}|j dd}t|t|krbtd||||fS )zParses comma separated request arguments

    Args:
      request: A request that should contain 'inference_address', 'model_name',
        'model_version', 'model_signature'.

    Returns:
      A tuple of lists for model parameters
    Zinference_address,Z
model_nameZmodel_versionZmodel_signaturez+Every model should have a name and address.)rk   rl   splitrW   r   rr   )r    rM   inference_addressesmodel_namesmodel_versionsmodel_signaturesr&   r&   r'   _parse_request_arguments+  s    

z)WhatIfToolPlugin._parse_request_argumentsc                    s  j drtj dndstj d}zjdkrhtdj tj	dddd	W S 
\}}}}tj_fd
djD }g _g _tt|D ]~}tj|| || j d|| || j ddkj dj djd	}	t||	\}
}j|
 j| qt _W n tk
r } z*tt| tj	|jddd	 W Y S d}~X Y nL tk
r } z,tt| tj	t|ddd	 W Y S d}~X Y nX t   fdd} fdd}zf| }| }t|t|d} tjkr4d dkrLt||d<  |d< t	|dW S  tk
r } z(t| tj	t|ddd	 W Y S d}~X Y nX dS )a$  Returns JSON for the `vz-line-chart`s for a feature.

    Args:
      request: A request that should contain 'inference_address', 'model_name',
        'model_type, 'model_version', 'model_signature' and 'label_vocab_path'.

    Returns:
      A list of JSON objects, one for each chart.
    r\   r   Zlabel_vocab_pathGET%s requests are forbidden.invalid non-GET requestrd   ry   rf   c                    s   g | ]} j | qS r&   )rU   )ra   rz   r6   r&   r'   rc   X  s     z+WhatIfToolPlugin._infer.<locals>.<listcomp>
model_typeuse_predictr_   predict_input_tensorpredict_output_tensorr   re   Nc                     s   dd j D } jddkrP| D ](}|d d   |d d d d < q$n.| D ](}|d d   |d d d d < qTj  | d	S )
Nc                 S   s   g | ]}t |qS r&   copydeepcopyra   Z	infer_objr&   r&   r'   rc   y  s    zHWhatIfToolPlugin._infer.<locals>.get_inferences_resp.<locals>.<listcomp>r   ZclassificationZclassificationResultZclassificationsZregressionResultZregressions)indicesresults)
infer_objsrk   rl   indices_to_infer)Zsliced_infer_objsobjrv   rM   r    r\   r&   r'   get_inferences_respx  s.      z4WhatIfToolPlugin._infer.<locals>.get_inferences_respc                     sL   dd j D } | D ]2}|d k	r|D ] }||   || d d < q$q| S )Nc                 S   s   g | ]}t |qS r&   r   r   r&   r&   r'   rc     s    zKWhatIfToolPlugin._infer.<locals>.get_extra_outputs_resp.<locals>.<listcomp>)extra_outputs)Zsliced_extra_objsr   key)rv   r    r\   r&   r'   get_extra_outputs_resp  s     z7WhatIfToolPlugin._infer.<locals>.get_extra_outputs_resp)Z
inferencesZextraOutputsri   Zvocabrj   ) rk   rl   rm   r   Zget_label_vocabr}   r   r   r	   rt   r   sortedrq   r   r   r   r   rW   ServingBundler   Z#run_inference_for_inference_resultsr   ro   r   loggingr   detailsr   ru   jsondumpsrU   )r    rM   label_vocabr   r   r   r   Zexamples_to_infer	model_numZserving_bundleZpredictionsZextra_outputr%   r   r   Zinferences_respZextra_outputs_resprespr&   r   r'   r-   >  s    


 



 
  	

 zWhatIfToolPlugin._inferc                 C   s$   t | jdt t}t||dS )aE  Returns a list of JSON objects for each feature in the example.

    Args:
      request: A request for features.

    Returns:
      A list with a JSON object for each feature.
      Numeric features are represented as {name: observedMin: observedMax:}.
      Categorical features are represented as {name: samples:[]}.
    r   rd   )r   get_eligible_featuresrU   NUM_EXAMPLES_TO_SCANNUM_MUTANTSr	   rt   )r    rM   features_listr&   r&   r'   r4     s
     z8WhatIfToolPlugin._eligible_features_from_example_handlerc                 C   s\  zt | jdt t}t|jdd}| |\}}}}i }|D ]|}	| j	|	d ||||jd|||jddk|jd|jd	d
|	kr|	d
 ndd
|	kr|	d ndd| j
d||	d < qDt ||}t||dW S  tjk
r }
 ztj||
jddd W Y S d}
~
X Y n> tk
rV }
 ztj|t|
ddd W Y S d}
~
X Y nX dS )a!  Returns a sorted list of JSON objects for each feature in the example.

    The list is sorted by interestingness in terms of the resulting change in
    inference values across feature values, for partial dependence plots.

    Args:
      request: A request for sorted features.

    Returns:
      A sorted list with a JSON object for each feature.
      Numeric features are represented as
      {name: observedMin: observedMax: interestingness:}.
      Categorical features are represented as
      {name: samples:[] interestingness:}.
    r   example_index0namer   r   r_   r   r   ZobservedMinZobservedMaxNr   rd   re   rf   )r   r   rU   r   r   rm   rk   rl   r   _infer_mutants_implr   Zsort_eligible_featuresr	   rt   r   rr   rs   r   r   )r    rM   r   r   r   r   r   r   Z
chart_dataZfeatr%   r&   r&   r'   r5     sT        
 

 
 
  z0WhatIfToolPlugin._sort_eligible_features_handlerc           
      C   sP  z|j dkr.td|j  tj|ddddW S t|jdd}|jd	}| |\}}}}| j	|||||jd
|||jddk|jd|jd|jd|jd|jd| j
d}t||dW S  tjk
r }	 ztj||	jddd W Y S d}	~	X Y n> tk
rJ }	 ztj|t|	ddd W Y S d}	~	X Y nX dS )aE  Returns JSON for the partial dependence plots for a feature.

    Args:
      request: A request that should contain 'feature_name', 'example_index',
         'inference_address', 'model_name', 'model_type', 'model_version', and
         'model_signature'.

    Returns:
      A list of JSON objects, one for each chart.
    r   r   r   rd   ry   rf   r   r   feature_namer   r   r_   r   r   x_minx_maxfeature_index_patternr   re   N)r}   r   r   r	   rt   rm   rk   rl   r   r   r   r   rr   rs   r   r   )
r    rM   r   r   r   r   r   r   Zjson_mappingr%   r&   r&   r'   r3     sJ    
   
 


 

	
  z'WhatIfToolPlugin._infer_mutants_handlerc                 C   s   |dkr| j n
| j | g}g }tt|D ]6}|tj|| || ||| || ||	|
|d	 q*t||| j dt t|}t	||||S )z-Helper for generating PD plots for a feature.ri   r   r   )
rU   r   rW   r   r   r   Z	VizParamsr   r   Zmutant_charts_for_feature)r    r   r   r   r   r   r   r   r   r   r   r   r   r   r   rU   Zserving_bundlesr   Z
viz_paramsr&   r&   r'   r     s:    

     z$WhatIfToolPlugin._infer_mutants_impl)&__name__
__module____qualname____doc__Zplugin_namerU   ro   rq   rY   rR   rS   rT   rQ   rX   Zsprite_thumbnail_dim_pxr   r(   r7   r8   r9   r   RequestZapplicationr*   r+   r,   r[   r/   r0   r.   r1   r2   r   r-   r4   r5   r3   r   r&   r&   r&   r'   r   :   sP   	



5




a

,
&r   )&r   
__future__r   r   r   r   rG   r   r   mathZnumpynprB   rJ   r   Z	six.movesr   Zgoogle.protobufr   Z#grpc.framework.interfaces.face.facer   Z
tensorflowrR   Ztensorboard.backendr	   Ztensorboard.pluginsr
   Ztensorboard_plugin_wit._utilsr   r   r   	getLoggerr   r   r   ru   ZTBPluginr   r&   r&   r&   r'   <module>   s6   
