
    Ng                       d 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
m
Z
mZ ddlmZ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 ddlmZ dd	lmZmZ dd
lm Z m!Z! ddl"m#Z#m$Z$m%Z% ddl"m&Z' ddl"m(Z) ddl*m+Z+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2m3Z3 ddl4m5Z5m6Z6 ddl4m7Z8 ddl9m:Z:m;Z; ddl<m=Z=m>Z>m?Z?m@Z@mAZA ddlBmCZC ddlDmEZE ddlFmGZG ddlHmIZI ddlJmKZK ddlLmMZMmNZNmOZO ddlPmQZR ddlSm&ZT ddlSmUZUmVZV erddlWZX ejY        eZ          Z[eeg eeIe#f         f         eee\gef         e#eIf         Z]eeg eeIe#f         f         ef         Z^ G d de_          Z` G d  d!e\          Za G d" d#e\          Zb	 ddd+Zcdd.Zd G d/ d0eG          Zedd2Zfdd8Zgdd;Zhdd=ZiddEZjddKZkddMZlddOZmddYZndd[Zodd]Zpddddd^ddgZqddddhddkZrddlddoZsddddhddpZtddddhddrZuddlddsZv	 	 	 ddd{Zw G d| d}eGd~          Zxejy         G d d                      ZzddZ{ddZ|dZ}dddddd~ddddZ~dddddd~ddddZdZee_         e                    dd          e~_         dS )z>Utilities for running language models or Chains over datasets.    )annotationsN)datetimetimezone)	TYPE_CHECKINGAnyCallableDictListOptionalTupleUnioncast)warn_deprecated)	Callbacks)BaseLanguageModel)BaseMessagemessages_from_dict)
ChatResult	LLMResult)RunnableRunnableConfigRunnableLambdaconfig)utils)EvaluatorCallbackHandlerwait_for_all_evaluators)LangChainTracer)Client)get_git_infoget_langchain_env_var_metadata)EvaluationResultRunEvaluator)run_evaluator)as_runnableis_traceable_function)DatasetDataTypeExampleRunTracerSession)LangSmithError)	HTTPError)	TypedDict)Chain)load_evaluator)EvaluatorTypePairwiseStringEvaluatorStringEvaluator)
evaluation)name_generationprogressc                      e Zd ZdZdS )InputFormatErrorz(Raised when the input format is invalid.N)__name__
__module____qualname____doc__     c/var/www/html/ai-engine/env/lib/python3.11/site-packages/langchain/smith/evaluation/runner_utils.pyr8   r8   N   s        2222r>   r8   c                  "    e Zd ZdZddZddZdS )
TestResultz1A dictionary of the results of a single test run.returnpd.DataFramec                    |                                  }d |j        D             }|                    d                              |d          S )zReturn quantiles for the feedback scores.

        This method calculates and prints the quantiles for the feedback scores
        across all feedback keys.

        Returns:
            A DataFrame containing the quantiles for each feedback key.
        c                    g | ]G}|                     d           s.|                     d          s|dv s|                     d          E|HS )inputs.outputs.>   inputoutput	reference)
startswith).0cols     r?   
<listcomp>z5TestResult.get_aggregate_feedback.<locals>.<listcomp>e   sp     
 
 
~~i((
 ~~j))	

 )))~~k** *	  *))r>   all)include   )axis)to_dataframecolumnsdescribedrop)selfdfto_drops      r?   get_aggregate_feedbackz!TestResult.get_aggregate_feedbackX   s^       
 
z
 
 
 {{5{))..wQ.???r>   c           	        	 ddl }n"# t          $ r}t          d          |d}~ww xY wg }g }| d                                         D ]g\  }}|d         }|                    d          }t	          |t
                    rd |                                D             }	n	|i }	nd|i}	i d |d	                                         D             |	}
d
|v r^t	          |d
         t
                    r8|
                    d |d
                                         D                        n|d
         |
d
<   |
                    i d |D             |                    d          |d         |                    d          d           |                    |
           |                    |           i |j        ||          S )z#Convert the results to a dataframe.r   NzfPandas is required to convert the results to a dataframe. to install pandas, run `pip install pandas`.resultsfeedbackrI   c                     i | ]\  }}d | |S )rG   r=   rL   kvs      r?   
<dictcomp>z+TestResult.to_dataframe.<locals>.<dictcomp>   s$    HHH1.Q..!HHHr>   c                     i | ]\  }}d | |S )rF   r=   r_   s      r?   rb   z+TestResult.to_dataframe.<locals>.<dictcomp>   s$    HHH1=Q==!HHHr>   rH   rJ   c                     i | ]\  }}d | |S )z
reference.r=   r_   s      r?   rb   z+TestResult.to_dataframe.<locals>.<dictcomp>   s'    UUUA)a))1UUUr>   c                .    i | ]}d |j          |j        S )z	feedback.)keyscore)rL   fs     r?   rb   z+TestResult.to_dataframe.<locals>.<dictcomp>   s'    FFF*15**AGFFFr>   Errorexecution_timerun_id)errorrj   rk   )index)	pandasImportErroritemsget
isinstancedictupdateappend	DataFrame)rW   pdeindicesrecords
example_idresultr]   output_rI   rs              r?   rS   zTestResult.to_dataframeo   s/   	 	 	 	@  	 "&y/"7"7"9"9 	' 	'Jj)Hjj**G'4(( -HHHHH"G,HHw0E0E0G0GHHHA f$$f[1488 9HHUU9L9R9R9T9TUUU    &,K%8AkNHHFFXFFF#ZZ00&,-=&>$jj22	     NN1NN:&&&&r|G73333s    
&!&N)rB   rC   )r9   r:   r;   r<   rZ   rS   r=   r>   r?   rA   rA   U   sF        ;;@ @ @ @.,4 ,4 ,4 ,4 ,4 ,4r>   rA   c                  ,     e Zd ZdZd fdZddZ xZS )	EvalErrorz"Your architecture raised an error.ri   BaseExceptionkwargsr   rB   Nonec                >     t                      j        dd|i| d S )Nri   r=   )super__init__)rW   ri   r   	__class__s      r?   r   zEvalError.__init__   s+    //u//////r>   namestrc                V    	 | |         S # t           $ r t          d| d          w xY w)Nz%'EvalError' object has no attribute '')KeyErrorAttributeError)rW   r   s     r?   __getattr__zEvalError.__getattr__   sK    	R: 	R 	R 	R !P!P!P!PQQQ	Rs   
 ()ri   r   r   r   rB   r   )r   r   rB   r   )r9   r:   r;   r<   r   r   __classcell__)r   s   @r?   r   r      s_        ,,0 0 0 0 0 0R R R R R R R Rr>   r   <my_dataset>llm_or_chain_factoryMODEL_OR_CHAIN_FACTORYdataset_namer   rB   MCFc           	       	
 t          | t                    rD| j        j        }| j        *j        j        j        }t          d| d| d| d          fdS t          | t                    r| S t          | t                    r| 		fdS t          |           r>t          |           r't          t          t          |                     

fdS 	  |             }nk# t          $ r^ t          t          |           }t          j        |          }t                               d	| d
           t%          |          fdcY S w xY wt          t          |           t          |t                    r|S t          t          t          |                    r't          t          t          |                    

fdS t          |t                    sfdS S | S )zForgive the user if they pass in a chain without memory instead of a chain
    factory. It's a common mistake. Raise a more helpful error message as well.Na$  Cannot directly evaluate a chain with stateful memory. To evaluate this chain, pass in a chain constructor that initializes fresh memory each time it is called.  This will safegaurd against information leakage between dataset examples.
For example:

def chain_constructor():
    new_memory = z(...)
    return z*(memory=new_memory, ...)

run_on_dataset("z", chain_constructor, ...)c                      S Nr=   )chains   r?   <lambda>z(_wrap_in_chain_factory.<locals>.<lambda>   s    u r>   c                      S r   r=   )lcfs   r?   r   z(_wrap_in_chain_factory.<locals>.<lambda>   s    s r>   c                      S r   r=   	runnable_s   r?   r   z(_wrap_in_chain_factory.<locals>.<lambda>       9 r>   zWrapping function z as RunnableLambda.c                      S r   r=   )wrappeds   r?   r   z(_wrap_in_chain_factory.<locals>.<lambda>   s    7 r>   c                      S r   r=   r   s   r?   r   z(_wrap_in_chain_factory.<locals>.<lambda>   r   r>   c                 "    t                     S r   )r   )constructors   r?   r   z(_wrap_in_chain_factory.<locals>.<lambda>   s    >+66 r>   )rr   r/   r   r9   memory
ValueErrorr   r   callabler&   r%   r   r   	TypeErrorinspect	signatureloggerinfor   )r   r   chain_classmemory_class_model	user_funcsigr   r   r   r   r   s          @@@@@r?   _wrap_in_chain_factoryr      sO    &.. 3$o.&2 <1:L
L %1
L 
L *
L 
L $0
L 
L 
L   }}}	(*;	<	<  ##	((	3	3 "{{{	&	'	'  !566 	%#D3G$H$HIII$$$$$	#))++FF 	# 	# 	#X';<<I#I..CKKESEEEFFF$Y//G"???"""	# 8%9::f/00 	 M"4&#9#9:: 	#D6$:$:;;I$$$$$FH-- 	66666 s   
C$ $A%EEinputsDict[str, Any]c                   | st          d          g }d| v rPt          | d         t                    s*t          dt          | d                   j                   | d         g}n d| v rmt          | d         t
                    rt          d | d         D                       s*t          dt          | d                   j                   | d         }nt          |           dk    rt          t          | 
                                                    }t          |t                    r|g}nUt          |t
                    rt          d |D                       r|}n$t          d	|            t          d
|            t          |          dk    r|d         S t          dt          |           d          )zGet prompt from inputs.

    Args:
        inputs: The input dictionary.

    Returns:
        A string prompt.
    Raises:
        InputFormatError: If the input format is invalid.
    Inputs should not be empty.promptz"Expected string for 'prompt', got promptsc              3  @   K   | ]}t          |t                    V  d S r   rr   r   rL   is     r?   	<genexpr>z_get_prompt.<locals>.<genexpr>   s=       >
 >
#$Jq#>
 >
 >
 >
 >
 >
r>   z,Expected list of strings for 'prompts', got rQ   c              3  @   K   | ]}t          |t                    V  d S r   r   r   s     r?   r   z_get_prompt.<locals>.<genexpr>  s,      .S.Saz!S/A/A.S.S.S.S.S.Sr>   z)LLM Run expects string prompt input. Got z5LLM Run expects 'prompt' or 'prompts' in inputs. Got r   z)LLM Run expects single prompt input. Got z	 prompts.)r8   rr   r   typer9   listrO   lennextitervalues)r   r   prompt_s      r?   _get_promptr      s     ><===G6&*C00 	"6)**36 6   (#$	f		&+T22 	# >
 >
(.y(9>
 >
 >
 ;
 ;
 	 #;VI.//8; ;   #	V		tFMMOO,,--gs## 	YiGG&& 	Y3.S.S7.S.S.S+S+S 	YGG"#Wv#W#WXXXLFLL
 
 	
 7||qqzOGOOO
 
 	
r>   c                      e Zd ZU dZded<   dS )ChatModelInputzVInput for a chat model.

    Parameters:
        messages: List of chat messages.
    zList[BaseMessage]messagesNr9   r:   r;   r<   __annotations__r=   r>   r?   r   r     s*            r>   r   rs   c                &   | st          d          |                                 }d| v r|                    d          |d<   nDt          |           dk    r1t	          t          |                                                     |d<   d|v rv|d         }t          |t                    rt          d |D                       r|g}t          |          dk    rt          |d                   |d<   nt          d          |S t          d|            )	zGet Chat Messages from inputs.

    Args:
        inputs: The input dictionary.

    Returns:
        A list of chat messages.
    Raises:
        InputFormatError: If the input format is invalid.
    r   r   rH   rQ   c              3  @   K   | ]}t          |t                    V  d S r   )rr   rs   r   s     r?   r   z _get_messages.<locals>.<genexpr>9  s=       2
 2
$%Jq$2
 2
 2
 2
 2
 2
r>   r   zGBatch messages not supported. Please provide a single list of messages.zMChat Run expects single List[dict] or List[List[dict]] 'messages' input. Got )r8   copypopr   r   r   r   rr   r   rO   r   )r   
input_copyraw_messagess      r?   _get_messagesr   %  sK     ><===JV(nnZ88
7	V		"4#8#899
7*!'*lD)) 	*c 2
 2
)52
 2
 2
 /
 /
 	* )>L|!!"4\!_"E"EJw",   $!$ $
 
 	
r>   first_exampler)   input_mapperOptional[Callable[[Dict], Any]]r   c                   |rz || j                   }t          |t                    sQt          |t                    rt	          d |D                       s%t          d| dt          |           d          d S d S 	 t          | j                    d S # t
          $ r? 	 t          | j                    Y d S # t
          $ r t          d| j          d          w xY ww xY w)Nc              3  @   K   | ]}t          |t                    V  d S r   rr   r   rL   msgs     r?   r   z>_validate_example_inputs_for_language_model.<locals>.<genexpr>U  s,      IISJsK00IIIIIIr>   zWhen using an input_mapper to prepare dataset example inputs for an LLM or chat model, the output must a single string or a list of chat messages.
Got: 	 of type .zvExample inputs do not match language model input format. Expected a dictionary with messages or a single prompt. Got: z Please update your dataset OR provide an input_mapper to convert the example.inputs to a compatible format for the llm or chat model you wish to evaluate.)	r   rr   r   r   rO   r8   r   r   r   )r   r   prompt_inputs      r?   +_validate_example_inputs_for_language_modelr   M  s`     #|M$899,,, 		|T**		IILIIIII		 #G 'G G 26l1C1CG G G  			 		 		 			,----- 	 	 	
m2333333#   &G*1G G G  	s   >B 
CB66#CCr   r/   c                Z   |r || j                   }t          |j                                      |          }t	          |t
                    s#t          d| dt          |           d          |r,t          d|j         d|                                           dS | j         }t          |j                                      |          }t          |          dk    rt          |j                  dk    rdS |r,t          d|j         d|                                           dS )	z<Validate that the example inputs match the chain input keys.zvWhen using an input_mapper to prepare dataset example inputs for a chain, the mapped value must be a dictionary.
Got: r   r   zAMissing keys after loading example using input_mapper.
Expected: z. Got: rQ   zExample inputs missing expected chain input keys. Please provide an input_mapper to convert the example.inputs to a compatible format for the chain you wish to evaluate.Expected: N)
r   set
input_keys
differencerr   rs   r8   r   keysr   )r   r   r   first_inputsmissing_keyss        r?   "_validate_example_inputs_for_chainr   n  s     #|M$8995+,,77EE,-- 	"G&G G15l1C1CG G G  
  	"N$/N N8D8I8I8K8KN N  	 	 %+5+,,77EE|!!c%*:&;&;q&@&@ D 	". #-. . %))++	. .  	 	r>   examplec                    t          |t                    rt          | |           dS  |            }t          |t                    rt	          | ||           dS t          |t
                    rt                              d|            dS dS )z9Validate that the example inputs are valid for the model.zSkipping input validation for N)rr   r   r   r/   r   r   r   debug)r   r   r   r   s       r?   _validate_example_inputsr     s     &(9:: C3G\JJJJJ$$&&eU## 	C.w|LLLLLx(( 	CLLA%AABBBBB	C 	Cr>   examplesList[Example]r4   "Optional[smith_eval.RunEvalConfig]	data_typer(   Optional[List[RunEvaluator]]c           	     P   |rt          | t                    rd\  }}d}nHd} |             }t          |t                    r|j        nd}t          |t                    r|j        nd}t          ||||d         j        rt          |d         j                  nd||          }nd}|S )z<Configure the evaluators to run on the results of the chain.)NNllmr   Nr   )rr   r   r/   r   output_keys_load_run_evaluatorsoutputsr   )	r   r   r4   r   
run_inputsrun_outputsrun_typer   run_evaluatorss	            r?   _setup_evaluationr     s      *,=>> 	R&0#JHHH((**E-7u-E-EO))4J/9%/G/GQ%++TK-)1!)<FD!$%%%$
 
 r>   r   smith_eval.RunEvalConfigr   Optional[List[str]]Optional[str]c                   d }| j         r/| j         }|r%||vr!t                              d| d| d           nQ|rt          |          dk    r	|d         }n3|1t          |          dk    rt                              d| d           |S )Nz
Input key z% not in chain's specified input keys '. Evaluation behavior may be undefined.rQ   r   z#Chain expects multiple input keys: z, Evaluator is likely to fail. Evaluation behavior may be undefined. Specify an input_key in the RunEvalConfig to avoid this warning.)	input_keyr   warningr   )r   r   r   s      r?   _determine_input_keyr    s     I 
$	 	):55NNSY S S)S S S   
 
J1,,qM				C
OOa$7$7P* P P P	
 	
 	
 r>   r   c                   d }| j         r/| j         }|r%||vr!t                              d| d| d           nQ|rt          |          dk    r	|d         }n3|1t          |          dk    rt                              d| d           |S )NzPrediction key z& not in chain's specified output keys r   rQ   r   z$Chain expects multiple output keys: zl, Evaluation behavior may be undefined. Specify a prediction_key in the RunEvalConfig to avoid this warning.)prediction_keyr   r   r   )r   r   r  s      r?   _determine_prediction_keyr    s     N 
. 	><<NNU. U U +U U U   
 
[))Q..$Q		 S%5%5%9%9;; ; ; ;	
 	
 	

 r>   example_outputsc                    | j         r#| j         }|r||vrt          d| d|           n-|r)t          |          dk    rt          |          d         }nd }|S )NzReference key z! not in Dataset example outputs: rQ   r   )reference_keyr   r   r   )r   r  r  s      r?   _determine_reference_keyr    s      
, 	}OCC7 7 7%47 7   
 S11Q66_--a0r>   eval_configYUnion[smith_eval_config.SINGLE_EVAL_CONFIG_TYPE, smith_eval_config.CUSTOM_EVALUATOR_TYPE]eval_llmOptional[BaseLanguageModel]r   r  r   r  r#   c           	        t          | t                    r| S t          | t          t          f          r=t          | t                    st          |           } t	          | |          }| j        }	nt          | t          j                  rld|i|                                 }
t	          | j	        fi |
}| j	        j        }	t          | t          j
                  r| j        p|}| j        p|}| j        p|}n=t          |           rt          |           S t!          dt#          |                      t          |t$                    rG|j        r|t!          d|	 d| d          t(          j                            |||||||	g          }n;t          |t.                    rt1          d|	 d	          t1          d|	 d
          |S )N)r   r   zUnknown evaluator type: zPMust specify reference_key in smith_eval.RunEvalConfig to use evaluator of type z) with dataset with multiple output keys: r   )r   r  r  tagszRun evaluator for z is not implemented. PairwiseStringEvaluators compare the outputs of two different models rather than the output of a single model. Did you mean to use a StringEvaluator instead?
See: https://python.langchain.com/docs/guides/evaluation/string/z is not implemented)rr   r#   r1   r   r0   valuesmith_eval_config
EvalConfig
get_kwargsevaluator_typeSingleKeyEvalConfigr   r  r  r   run_evaluator_decr   r   r3   requires_reference
smith_evalStringRunEvaluatorChainfrom_run_and_data_typer2   NotImplementedError)r	  r  r   r   r  r  r   r  
evaluator_eval_type_tagr   r$   s               r?   _construct_run_evaluatorr    sC    +|,, +s344 I+}55 	5'44K#KX>>>
#)	K!2!=	>	> I>[%;%;%=%=>#K$>II&II
#28k#4#HII 	G#-:I(7I>N'5FM	+		 I ---GD4E4EGGHHH*o.. 
( 	]-BJ&3J J7FJ J J  
 #:QQ)' R 
 
 
J 7	8	8 
!Q Q Q Q
 
 	
 "CCCC
 
 	
 r>   2Tuple[Optional[str], Optional[str], Optional[str]]c                l    t          | |          }t          | |          }t          | |          }|||fS r   )r  r  r  )r   r   r   r  r   r  r  s          r?   	_get_keysr   I  s>     %VZ88I.v{CCN,V_EEMnm33r>   List[RunEvaluator]c                   g }d\  }}}	| j         s%| j        r4t          d | j        D                       rt          | |||          \  }}}	| j         D ]2}
t	          |
| j        ||||	||          }|                    |           3| j        pg }|D ]}t          |t                    r|                    |           -t          |t                    r9|                    t          j                            ||||||	                     {t          |          r#|                    t          |                     t          d| d          |S )z
    Load run evaluators from a configuration.

    Args:
        config: Configuration for the run evaluators.

    Returns:
        A list of run evaluators.
    NNNc                8    g | ]}t          |t                    S r=   )rr   r3   )rL   rx   s     r?   rN   z(_load_run_evaluators.<locals>.<listcomp>j  s"    RRRAA//RRRr>   )r   r  r  zUnsupported custom evaluator: z+. Expected RunEvaluator or StringEvaluator.)
evaluatorscustom_evaluatorsanyr   r  r  ru   rr   r#   r3   r  r  r  r   r  r   )r   r   r   r  r   r   r   r   r  r  r	  r$   r&  custom_evaluators                 r?   r   r   U  s   " N/?,I~} 
 
RR9QRRRSS
 4=J_4
 4
0	>= ( - -0O	
 	
 	m,,,,06B-  &55 	!!"23333(/:: 	!!2II$'#1"/ J  	 	 	 	 &'' 	!!"34D"E"EFFFF>1A > > >  
 r>   r  	callbacksr   metadatar   r   r  r*  r   r+  Optional[Dict[str, Any]]Union[str, BaseMessage]c               J  K   | ||          }t          |t                    s.t          |t                    rJt          d |D                       r1|                     |t          ||pg |pi                      d{V S t          d| d          	 t          |          }|                     |t          ||pg |pi                      d{V }nJ# t          $ r= t          |          }	 | j        di |	dt          ||pg |pi           i d{V }Y nw xY w|S )	a  Asynchronously run the language model.

    Args:
        llm: The language model to run.
        inputs: The input dictionary.
        tags: Optional tags to add to the run.
        callbacks: Optional callbacks to use during the run.
        input_mapper: Optional function to map inputs to the expected format.

    Returns:
        The LLMResult or ChatResult.
    Raises:
        ValueError: If the LLM type is unsupported.
        InputFormatError: If the input format is invalid.
    Nc              3  @   K   | ]}t          |t                    V  d S r   r   r   s     r?   r   z_arun_llm.<locals>.<genexpr>  ,      OOSJsK00OOOOOOr>   r*  r  r+  r   z%Input mapper returned invalid format 3
Expected a single string or list of chat messages.r   r=   )	rr   r   r   rO   ainvoker   r8   r   r   )
r   r   r  r*  r   r+  prompt_or_messagesr   
llm_output
llm_inputss
             r?   	_arun_llmr7    s     0 )\&11)3//	,d33	 OO<NOOOOO	
 "%'djb8>r   %          #G&G G G  	 ((F8;%'djb8>r   9D 9 9 3 3 3 3 3 3JJ   	 	 	&v..J*s{       %'djb8>r             JJJ	 s   A C AD D r  r   r+  Union[Chain, Runnable]Union[dict, str]c                 K   ||n
 ||          }t          | t                    rt          |t                    rzt          |          dk    rg| j        r`t          t          |                                                    }|                     |t          ||pg |pi                      d{V }n3t          |pg ||pi           }	|                     ||	           d{V }|S )z%Run a chain asynchronously on inputs.NrQ   r1  r   r  r*  r+  )
rr   r/   rs   r   r   r   r   r   r3  r   
r   r   r*  r  r   r+  inputs_valrI   runnable_configs
             r?   _arun_chainrA    s4      %,ff,,v2F2FG5%  Fw%%F LLA  4(())**}}!#$*"x~2   % 
 
 
 
 
 
 
 
 )y8>r
 
 
 }}W_}EEEEEEEEMr>   )r   r   'Union[dict, str, LLMResult, ChatResult]c               J  K   t          |t                    rdnd}d}	 t          |t                    r@t          || j        |d         |d         ||                    d                     d{V }nI |            }t          || j        |d         |d         ||                    d                     d{V }|}nc# t          $ rV}t                              | d| j	         d	| j         d
t          |                      t          |          }Y d}~nd}~ww xY w|S )a  Asynchronously run the Chain or language model.

    Args:
        example: The example to run.
        llm_or_chain_factory: The Chain or language model constructor to run.
        tags: Optional tags to add to the run.
        callbacks: Optional callbacks to use during the run.
        input_mapper: Optional function to map the input to the expected format.

    Returns:
        A list of outputs.
    LLMr/   Nr  r*  r+  r)   failed for example  with inputs 
ri   )rr   r   r7  r   rq   rA  	Exceptionr   r   idreprr   )	r   r   r   r   chain_or_llmr|   rI   r   rx   s	            r?   _arun_llm_or_chainrM    s     ( 02CDDQ'  F$*,=>> 	 )$F^ -)J//! ! !      FF )(**E&F^ -)J//        F  $ $ $    "> a 	
 	
 	

 ###$ Ms   B C   
D 
ADD c          
        | ||          }t          |t                    s.t          |t                    rEt          d |D                       r,|                     |t          ||pg |pi                     }nt          d| d          	 t          |          }|                     |t          ||pg |pi                     }nA# t          $ r4 t          |          }	 | j        d	i |	dt          ||pi           i}Y nw xY w|S )
a  
    Run the language model on the example.

    Args:
        llm: The language model to run.
        inputs: The input dictionary.
        callbacks: The callbacks to use during the run.
        tags: Optional tags to add to the run.
        input_mapper: function to map to the inputs dictionary from an Example
    Returns:
        The LLMResult or ChatResult.
    Raises:
        ValueError: If the LLM type is unsupported.
        InputFormatError: If the input format is invalid.
    Nc              3  @   K   | ]}t          |t                    V  d S r   r   r   s     r?   r   z_run_llm.<locals>.<genexpr>O  r0  r>   r1  r   z'Input mapper returned invalid format:  r2  r   )r*  r+  r=   )	rr   r   r   rO   invoker   r8   r   r   )
r   r   r*  r  r   r+  r4  r5  llm_promptsr6  s
             r?   _run_llmrR  1  s   2 )\&11)3//	,d33	 OO<NOOOOO	
 36**"%'djb8>r   3= 3 3JJ #G&G G G  	%f--K%'djb8>r   $  JJ   	 	 	&v..J#   %	HNPRSSS  JJJ	 s   :C ;D
	D
Union[Dict, str]c                  ||n
 ||          }t          | t                    rt          |t                    rtt          |          dk    ra| j        rZt          t          |                                                    }|                     |t          ||pg |pi                     }n-t          |pg ||pi           }	|                     ||	          }|S )zRun a chain on inputs.NrQ   r1  r   r<  )
rr   r/   rs   r   r   r   r   r   rP  r   r=  s
             r?   
_run_chainrU  o  s     %,ff,,v2F2FG5%  ?w%%? LLA  4(())**!#$*"x~2    
 
 )y8>r
 
 
 go>>Mr>   c               B   t          |t                    rdnd}d}	 t          |t                    r:t          || j        |d         |d         ||                    d                    }nC |            }t          || j        |d         |d         ||                    d                    }|}nm# t          $ r`}t          |          j        }	t          
                    | d| j         d	| j         d
|	 d| 	           t          |          }Y d}~nd}~ww xY w|S )a  
    Run the Chain or language model synchronously.

    Args:
        example: The example to run.
        llm_or_chain_factory: The Chain or language model constructor to run.
        tags: Optional tags to add to the run.
        callbacks: Optional callbacks to use during the run.

    Returns:
        Union[List[dict], List[str], List[LLMResult], List[ChatResult]]:
          The outputs of the model or chain.
    rD  r/   Nr*  r  r+  r8  rE  rF  z
Error Type: z, Message: rH  )rr   r   rR  r   rq   rU  rI  r   r9   r   r   rJ  r   )
r   r   r   r   rL  r|   rI   r   rx   
error_types
             r?   _run_llm_or_chainrX    s   * 02CDDQ'  F$*,=>> 	"${#F^)J//  FF )(**E{#F^)J//  F  $ $ $!WW%
 8 8 8 8">8 8'8 8458 8	
 	
 	

 ###$ Ms   BB2 2
D<ADDclientr   project_nameproject_metadatadataset_versionOptional[Union[str, datetime]]1Tuple[MCF, TracerSession, Dataset, List[Example]]c           
        t          ||          }|                     |          }t          |                     |j        |                    }	|	st          d| d          d |	D             }
|
rt          |
          nd }|r|                                nd }	 |pi }t                      }|ri |d|i}||d<   | 	                    ||j        |rd|ini |	          }nf# t          t
          t          f$ rL}d
t          |          vr|t          j                    }d| d| d| d}t          d| d|           d }~ww xY w|j        d|j         z   }t!          d| d| d| d|j         d           ||||	fS )N)r   )
dataset_idas_ofzDataset z has no example rows.c                *    g | ]}|j         	|j         S r=   )modified_at)rL   exs     r?   rN   z%_prepare_eval_run.<locals>.<listcomp>  s!    GGGbG2>GGGr>   gitr\  r  )reference_dataset_idproject_extrar+  zalready exists z+
run_on_dataset(
    ...
    project_name="z - z", # Update since z already exists
)
zTest project z/ already exists. Please use a different name:

z/compare?selectedSessions=z)View the evaluation results for project 'z' at:
z

View all tests for Dataset z at:
T)flush)r   read_datasetr   list_examplesrJ  r   max	isoformatr    create_projectr-   r,   r   uuiduuid4urlprint)rY  r   r   rZ  r[  r  r\  wrapped_modeldatasetr   rc  max_modified_atinferred_versiongit_infoprojectrx   uidexample_msgcomparison_urls                      r?   _prepare_eval_runr{    sz    ++?NNM!!|!<<GF((GJo(VVWWH IGLGGGHHHGGHGGGK +6?c+&&&4O6EO002224
+1r>> 	 " x   
 /?*+''!(,0864..b%	 ( 
 
 z>2 
 
 
CFF**Gjll    %(  <H   !L ! !! !
 
 	

 [#L
#L#LLN		HL 	H 	H	H 	H&2	H 	H:A+	H 	H 	    '7H44s   AC# #E:AEEc                  2    e Zd ZU dZded<   ded<   ded<   dS )	
_RowResultz5A dictionary of the results for a single example row.z Optional[List[EvaluationResult]]r]   zOptional[float]rj   r   rk   Nr   r=   r>   r?   r}  r}    s<         ??....####r>   r}  F)totalc                      e Zd ZU dZded<   ded<   ded<   ded	<   d
ed<   dZded<   d8dZd9dZd:dZd;dZ	d<d=d"Z
e	 	 	 	 	 	 	 d>d?d7            ZdS )@_DatasetRunContainerz3A container to help manage the state of a eval run.r   rY  r+   rw  r   rr  r   r   zList[RunnableConfig]configsNz6Optional[List[smith_eval_config.BATCH_EVALUATOR_LIKE]]batch_evaluatorsbatch_resultsr   all_eval_resultsDict[str, _RowResult]rB   rs   c           	     l   i }t          | j        |          D ]\  }}t          t          |                    t          |j                  i                     }|j        |                    dg           |                    d          |                    d          d|t          |j                  <   t          |t                    r#|j
        |t          |j                           d<   n||t          |j                           d<   |j        r"|j        |t          |j                           d<   |S )Nr]   rj   rk   )rH   r]   rj   rk   ri   rI   rJ   )zipr   r   r}  rq   r   rJ  r   rr   r   ri   r   )rW   r  r  r\   r   rI   
row_results          r?   _merge_test_outputsz(_DatasetRunContainer._merge_test_outputs  s   
 "4=-@@ 	H 	HOGVj*:*>*>s7:PR*S*STTJ &NN:r::",..1A"B"B$..22	( (GC
OO$ &),, <4:LGJ(115;GJ(2 H8?GJ(5r>   runsDict[str, Run]
List[dict]c           	     \   | j         }|sg S fd| j        D             }g }t          j                                        5 }|D ]}	  ||| j                  }t          |t                    r|                                }|                    t          t          |                      |j
        | j        j        fi |d | j        j        d # t          $ r7}t                               dt%          |           d|            Y d }~d }~ww xY w	 d d d            n# 1 swxY w Y   |S )Nc                D    g | ]}t          |j                           S r=   )r   rJ  )rL   r   r  s     r?   rN   z>_DatasetRunContainer._run_batch_evaluators.<locals>.<listcomp>1  s&    HHHwT#gj//*HHHr>   )rk   
project_idzError running batch evaluator z: )r  r   
concurrentfuturesThreadPoolExecutorrr   r"   rs   ru   r   submitrY  create_feedbackrw  rJ  rI  r   rl   rK  )	rW   r  r%  	runs_listaggregate_feedbackexecutor	evaluatorr|   rx   s	    `       r?   _run_batch_evaluatorsz*_DatasetRunContainer._run_batch_evaluators-  s   *
 	IHHHH$-HHH	2244 	'  	&Yy$-@@F!&*:;; /!'&--d4.@.@AAA#HO3    $#'<?	      !   LLOiOOAOO       	 	 	 	 	 	 	 	 	 	 	 	 	 	 	" "!s=    D!B	CD!
D-DD!DD!!D%(D%,Tuple[Dict[str, _RowResult], Dict[str, Run]]c                   i }i }| j         D ]K}t          t          |d                   D ]+}t          |t                    r]|j        }|                                D ]@\  \  }}}|                    t          |          i           	                    d|i           Aut          |t                    r|j        }	|	r(|	j        r!|	j        |	j        z
                                  nd }
|	rt          |	j                  nd }|                    t          |j                  i           	                    |
||	d           |	|t          |j                  <   -Mt          t"          t          t$          f         |          |fS )Nr*  r]   )rj   rk   run)r  r   r   rr   r   logged_eval_resultsrp   
setdefaultr   rt   r   
latest_runend_time
start_timetotal_secondsrJ  r{   r	   r}  )rW   r  all_runsccallbackeval_results_r{   ra   r  rj   rk   s               r?   _collect_metricsz%_DatasetRunContainer._collect_metricsF  s   !# 	= 	=A q~66 = =h(@AA =#+#?L.:.@.@.B.B  *J(33C
OORHHOO'O     /:: ="-C "#&<"6EEGGG! #
 -09S[[[TF$//H4G0H0H"MMTT.<&,#&    :=HS!4556-=. Dj)+;<<hFFr>   -List[Union[dict, str, LLMResult, ChatResult]]rA   c                T   t                               d           t                       |                                 \  }}d }| j        r/t                               d           |                     |          }|                     ||          }t          | j        j	        ||          S )Nz#Waiting for evaluators to complete.zRunning session evaluators.)rZ  r\   aggregate_metrics)
r   r   r   r  r  r  r  rA   rw  r   )rW   r  r  r  r  r\   s         r?   _collect_test_resultsz*_DatasetRunContainer._collect_test_resultsc  s     	9:::!!!%)%:%:%<%<"(!  	FKK5666!%!;!;H!E!E**=:JKK*0
 
 
 	
r>   Fverboseboolc                
   |                      |          }|rf	 |                                }t          |           nA# t          $ r4}t                              dt          |                      Y d }~nd }~ww xY w	 | j                            | j	        j
        t          j        t          j                             nA# t          $ r4}t                              dt          |                      Y d }~nd }~ww xY w|S )Nz$Failed to print aggregate feedback: )r  zFailed to close project: )r  rZ   _display_aggregate_resultsrI  r   r   rK  rY  update_projectrw  rJ  r   nowr   utc)rW   r  r  r\   agg_feedbackrx   s         r?   finishz_DatasetRunContainer.finishu  s2   ,,];; 	OO&==??*<8888 O O OMDGGMMNNNNNNNNO	@K&&(,x|*D*D '      	@ 	@ 	@LL>T!WW>>????????	@s.   #= 
A;*A66A;?AC 
D *C;;D    r   r   r   r   rZ  r   r4   r   r  r   r   r   concurrency_levelintr[  r,  revision_idr\  Optional[Union[datetime, str]]c           	        |pt          j                    }|
r|	si }	|	                    d|
i           t          ||||	|          \  }}}pg j                            d          pi                                 D ] \  }}                    d| d|            !dj        d         i|
r|
d<   t          |          }t          ||||j
        pt          j                  t          |d         ||           t          j        t!          |                    fd|D             } | ||||r|j        nd 	          S )
Nr  )r[  r  r\  re  zgit:=r\  r   c                    g | ]J}t          t          j        |j                   t	          pg |j        d          g          KS ))rZ  rY  r{   r   )r%  rY  r{   max_concurrency)r*  r  r  r+  )r   r   r   rJ  r   )	rL   r   rY  r  progress_barrw  r   run_metadatar  s	     r?   rN   z0_DatasetRunContainer.prepare.<locals>.<listcomp>  s     
 
 
( ' #%,\%#*:  
 -#1#7R%#*:()	   !  1%#  
 
 
r>   )rY  rw  rr  r   r  r  )r5   random_namert   r{  r+  rq   rp   ru   r   r   r   r(   kvr   r6   ProgressBarCallbackr   r  )clsrY  r   r   rZ  r4   r  r   r  r[  r  r\  rr  rs  r   r`   ra   r  r  rw  r   r  s    `    ` `         @@@@r?   preparez_DatasetRunContainer.prepare  s    $D'B'D'D 	B# &#% ##]K$@AAA4E -+5
 5
 5
1w zr%))%006B==?? 	( 	(DAqKKq1'''')7+;<M+NO 	6*5L'./CDD*8Z1B1Qhk
 
 	!!m\JJJ3CMMBB
 
 
 
 
 
 
 
 
 
( $)
 
 
, s'<FPZ88D
 
 
 	
r>   )r  r   r  r  rB   rs   )r  r  rB   r  )rB   r  )r  r  rB   rA   )F)r  r   r  r  rB   rA   )NNNr  NNN)rY  r   r   r   r   r   rZ  r   r4   r   r  r   r   r   r  r  r[  r,  r  r   r\  r  rB   r  )r9   r:   r;   r<   r   r  r  r  r  r  r  classmethodr  r=   r>   r?   r  r    s        ==NNN!!!!OSSSSS   ," " " "2G G G G:
 
 
 
$    "  :>$(8<!"59%):>E
 E
 E
 E
 [E
 E
 E
r>   r  r  c                     	 ddl m}   |             } |             d uodt          t          |                    v S # t          $ r Y dS w xY w)Nr   )get_ipythonzmqshellF)IPythonr  r   r   ro   )r  ress     r?   _is_jupyter_environmentr    sm    ''''''kmm{}}D(IZ3tCyy>>-II   uus   9< 
A
	A
aggregate_resultsrC   c                    t                      r)ddlm}m}  | |d                      ||            d S |                     d d          }t          d           t          |           d S )Nr   )HTMLdisplayz<h3>Experiment Results:</h3>c                
    | dS )Nz.2fr=   )xs    r?   r   z,_display_aggregate_results.<locals>.<lambda>  s
    a:: r>   right)float_formatjustifyz
 Experiment Results:)r  IPython.displayr  r  	to_stringrq  )r  r  r  formatted_strings       r?   r  r    s       
 11111111344555!""""",66--w 7 
 
 	&'''r>   a  The input_mapper argument is deprecated and will be removed in a future release. Please add a  RunnableLambda to your chain to map inputs to the expected format instead. Example:
def construct_chain():
    my_chain = ...
    input_mapper = {'other_key': 'MyOtherInput', 'my_input_key': x}
    return input_mapper | my_chain
run_on_dataset(..., llm_or_chain_factory=construct_chain)
(See https://api.python.langchain.com/en/latest/schema/langchain.schema.runnable.base.RunnableLambda.html)r  )r4   r\  r  rZ  r[  r  r  Optional[Client]r  r  r  r  r  r   r   c                 K   |
                     dd           }|rt          dt          d           |	!t                                          d          }	|
                     dd           }|rt          ddd           |
r(t          dd	|
                                 d
d           | pt                      } t                              | |||||||||	|          }t          j
        |j        d                             d          gt          t          j        t          |j        |          |j        |j                  R   d {V }|                    ||          S )Nr   0.0.305Tmessagependingr  r  0.1.9qThe tags argument is deprecated and will be removed in a future release. Please specify project_metadata instead.PThe following arguments are deprecated and will be removed in a future release: r   r  removalr[  r  r\  r   r  r   r   r  )r   r   _INPUT_MAPPER_DEP_WARNINGr!   rq   r   r   r  r  runnable_utilsgather_with_concurrencyr  map	functoolspartialrM  rr  r   r  )rY  r   r   r4   r\  r  rZ  r[  r  r  r   r   r  	containerr  s                  r?   arun_on_datasetr    s      ::nd33L T	+DdSSSS466::=II::fd##D 
U		
 	
 	
 	
  
 {{}}      	
 	
 	
 	
 vxxF$,,)' -  I )@!  !233	"%.%<)  
 

 

        M M7;;;r>   c               N   |
                     dd           rt          dt          d           |
                     dd           }|rt          ddd           |	!t                                          d          }	|
r(t          dd	|
                                 d
d           | pt                      } t                              | ||||||||	|          |dk    r(fdt          j
        j                  D             }nt          j        j        d                   5 }t          |                    t!          j        t$          j                  j
        j                            }d d d            n# 1 swxY w Y                       ||          S )Nr   r  Tr  r  r  r  r  r  r   r  r  r   c                F    g | ]\  }}t          ||j                   S )r  )rX  rr  )rL   r   r   r  r   s      r?   rN   z"run_on_dataset.<locals>.<listcomp>l  sM     
 
 
   %.%<)	  
 
 
r>   r  r  )r   r   r  r!   rq   r   r   r  r  r  r   r  r@  get_executor_for_configr   r  r  r  rX  rr  r  )rY  r   r   r4   r\  r  rZ  r[  r  r  r   r  r  r  r  r   s                 @@r?   run_on_datasetr  9  sM    ::nd33L T	+DdSSSS::fd##D 
U		
 	
 	
 	
 466::=II 
 {{}}      	
 	
 	
 	
 vxxF$,,)' -  I A
 
 
 
 
 $'y'99;L#M#M
 
 
 4Y5Fq5IJJ 	h %)-6-D%1  
 &% 
 
M	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 M7;;;s   +AFF	F	a1  
Run the Chain or language model on a dataset and store traces
to the specified project name.

Args:
    dataset_name: Name of the dataset to run the chain on.
    llm_or_chain_factory: Language model or Chain constructor to run
        over the dataset. The Chain constructor is used to permit
        independent calls on each example without carrying over state.
    evaluation: Configuration for evaluators to run on the
        results of the chain
    concurrency_level: The number of async tasks to run concurrently.
    project_name: Name of the project to store the traces in.
        Defaults to {dataset_name}-{chain class name}-{datetime}.
    project_metadata: Optional metadata to add to the project.
        Useful for storing information the test variant.
        (prompt version, model version, etc.)
    client: LangSmith client to use to access the dataset and to
        log feedback and run traces.
    verbose: Whether to print progress.
    tags: Tags to add to each run in the project.
    revision_id: Optional revision identifier to assign this test run to
        track the performance of different versions of your system.
Returns:
    A dictionary containing the run's project name and the resulting model outputs.


For the (usually faster) async version of this function, see :func:`arun_on_dataset`.

Examples
--------

.. code-block:: python

    from langsmith import Client
    from langchain_openai import ChatOpenAI
    from langchain.chains import LLMChain
    from langchain.smith import smith_eval.RunEvalConfig, run_on_dataset

    # Chains may have memory. Passing in a constructor function lets the
    # evaluation framework avoid cross-contamination between runs.
    def construct_chain():
        llm = ChatOpenAI(temperature=0)
        chain = LLMChain.from_string(
            llm,
            "What's the answer to {your_input_key}"
        )
        return chain

    # Load off-the-shelf evaluators via config or the EvaluatorType (string or enum)
    evaluation_config = smith_eval.RunEvalConfig(
        evaluators=[
            "qa",  # "Correctness" against a reference answer
            "embedding_distance",
            smith_eval.RunEvalConfig.Criteria("helpfulness"),
            smith_eval.RunEvalConfig.Criteria({
                "fifth-grader-score": "Do you have to be smarter than a fifth grader to answer this question?"
            }),
        ]
    )

    client = Client()
    run_on_dataset(
        client,
        dataset_name="<my_dataset_name>",
        llm_or_chain_factory=construct_chain,
        evaluation=evaluation_config,
    )

You can also create custom evaluators by subclassing the
:class:`StringEvaluator <langchain.evaluation.schema.StringEvaluator>`
or LangSmith's `RunEvaluator` classes.

.. code-block:: python

    from typing import Optional
    from langchain.evaluation import StringEvaluator

    class MyStringEvaluator(StringEvaluator):

        @property
        def requires_input(self) -> bool:
            return False

        @property
        def requires_reference(self) -> bool:
            return True

        @property
        def evaluation_name(self) -> str:
            return "exact_match"

        def _evaluate_strings(self, prediction, reference=None, input=None, **kwargs) -> dict:
            return {"score": prediction == reference}


    evaluation_config = smith_eval.RunEvalConfig(
        custom_evaluators = [MyStringEvaluator()],
    )

    run_on_dataset(
        client,
        dataset_name="<my_dataset_name>",
        llm_or_chain_factory=construct_chain,
        evaluation=evaluation_config,
    )
zrun_on_dataset(zawait arun_on_dataset()r   )r   r   r   r   rB   r   )r   r   rB   r   )r   r   rB   rs   )r   r)   r   r   rB   r   )r   r)   r   r/   r   r   rB   r   )r   r)   r   r   r   r   rB   r   )
r   r   r   r   r4   r   r   r(   rB   r   )r   r   r   r   rB   r   )r   r   r   r   rB   r   )r   r   r  r   rB   r   )r	  r
  r  r  r   r   r   r(   r  r   r  r   r   r   r  r   rB   r#   )
r   r   r   r   r   r   r  r   rB   r  )r   r   r   r   r   r(   r  r   r   r   r   r   rB   r!  )r   r   r   r   r  r   r*  r   r   r   r+  r,  rB   r-  )r   r9  r   r   r*  r   r  r   r   r   r+  r,  rB   r:  )
r   r)   r   r   r   r   r   r   rB   rB  )r   r   r   r   r*  r   r  r   r   r   r+  r,  rB   r-  )r   r9  r   r   r*  r   r  r   r   r   r+  r,  rB   rS  r#  )rY  r   r   r   r   r   rZ  r   r[  r,  r  r   r\  r]  rB   r^  )rB   r  )r  rC   rB   r   )rY  r  r   r   r   r   r4   r   r\  r  r  r  rZ  r   r[  r,  r  r  r  r   r   r   rB   r   )r<   
__future__r   concurrent.futuresr  dataclassesr  r   loggingrn  r   r   typingr   r   r   r	   r
   r   r   r   r   langchain_core._apir    langchain_core.callbacks.managerr   langchain_core.language_modelsr   langchain_core.messagesr   r   langchain_core.outputsr   r   langchain_core.runnablesr   r   r   r   r@  r   r  !langchain_core.tracers.evaluationr   r    langchain_core.tracers.langchainr   langsmith.clientr   langsmith.envr    r!   langsmith.evaluationr"   r#   r$   r  langsmith.run_helpersr%   r&   langsmith.schemasr'   r(   r)   r*   r+   langsmith.utilsr,   requestsr-   typing_extensionsr.   langchain.chains.baser/   langchain.evaluation.loadingr0   langchain.evaluation.schemar1   r2   r3   langchain.smithr4   r  langchain.smith.evaluationr  r5   r6   rn   rw   	getLoggerr9   r   rs   r   r   rI  r8   rA   r   r   r   r   r   r   r   r   r   r  r  r  r  r   r   r7  rA  rM  rR  rU  rX  r{  r}  	dataclassr  r  r  r  r  r  _RUN_ON_DATASET_DOCSTRINGreplacer=   r>   r?   <module>r     s   D D " " " " " "                ' ' ' ' ' ' ' '
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 0 / / / / / 6 6 6 6 6 6 < < < < < < C C C C C C C C 8 8 8 8 8 8 8 8 M M M M M M M M M M > > > > > > < < < < < <        = < < < < < # # # # # # F F F F F F F F             E D D D D D D D L L L L L L L L L L L L L L * * * * * *       ' ' ' ' ' ' ' ' ' ' ' ' 7 7 7 7 7 7         
 5 4 4 4 4 4 B B B B B B @ @ @ @ @ @ @ @ 		8	$	$Ruh''(dVS[		  HRuh//02CCD3 3 3 3 3y 3 3 3F4 F4 F4 F4 F4 F4 F4 F4R
R 
R 
R 
R 
R 
R 
R 
R ':  :  :  :  : z0
 0
 0
 0
f         Y      $
 $
 $
 $
P   B" " " "JC C C C(   <   0   .   $@ @ @ @F	4 	4 	4 	4= = = =N !%48)-= = = = = =J !%48)-     J 593 3 3 3 3 3| !%48)-; ; ; ; ; ;F !%48)-     J 595 5 5 5 5 5z 26 $6::5 :5 :5 :5 :5z    %     
 
 
 
 
 
 
 
D          
: , 6:6:"&15!%>< >< >< >< >< ><L 6:6:"&15!%J< J< J< J< J< J<Zj V 3 3;;/    r>   