import React from 'react' ; import { TextWithHighlight , Output , ArithmeticEquation } from '@allenai/tugboat/components' ; import { Model } from '@allenai/tugboat/lib' ; import { InvalidModelResponseError , UnexpectedModelError , UnexpectedOutputError , } from '@allenai/tugboat/error' ; import { DebugInfo } from '../../components' ; import { ModelId } from '../../lib' ; import { Input , Prediction , NAQANetAnswerType , BiDAFPrediction , NAQANetPrediction , TransformerQAPrediction , isBiDAFPrediction , isNAQANetPrediction , isTransformerQAPrediction , isNMNPrediction , isNAQANetPredictionSpan , isNAQANetPredictionCount , isNAQANetPredictionArithmetic , getBasicAnswer , } from './types' ; import { NMNOutput } from './nmn' ; interface Props { input : Input ; model : Model ; output : Prediction ; } export const Predictions = ( { input , model , output } ) => { return ( < Output . Section > < OutputByModel input = { input } output = { output } model = { model } / > < DebugInfo input = { input } output = { output } model = { model } / > < /Output.Section>); } ; const OutputByModel = ( { input , output , model , } ) => { switch ( model . id ) { case ModelId . Bidaf : case ModelId . BidafELMO : case ModelId . TransformerQA : { if ( ! isBiDAFPrediction ( output ) && ! isTransformerQAPrediction ( output ) ) { throw new UnexpectedOutputError ( model . id ) ; } return < BasicPrediction input = { input } output = { output } / > ; } case ModelId . Naqanet : { if ( ! isNAQANetPrediction ( output ) ) { throw new UnexpectedOutputError ( model . id ) ; } return < NaqanetPrediction input = { input } output = { output } model = { model } / > ; } case ModelId . NMN : { if ( ! isNMNPrediction ( output ) ) { throw new UnexpectedOutputError ( model . id ) ; } return < NMNOutput { ... output } / > ; } } throw new UnexpectedModelError ( model . id ) ; } ; const BasicAnswer = ( { output } ) => { return ( < Output . SubSection title = "Answer" > < div > { getBasicAnswer ( output ) } < /div> < /Output.SubSection>); } ; const BasicPrediction = ( { input , output , } ) => { const start = input . passage . indexOf ( output . best_span_str ) ; const highlightSpan = [ start , start + output . best_span_str . length ] ; const hasBestSpan = output . best_span_str !== '' ; if ( hasBestSpan && ( highlightSpan [ 0 ] < 0 || highlightSpan [ 1 ] <= highlightSpan [ 0 ] ) ) { throw new InvalidModelResponseError ( `"${ output . best_span_str }" does not exist in the passage.` ) ; } return ( < > < BasicAnswer output = { output } / > < Output . SubSection title = "Passage Context" > { hasBestSpan ? ( < TextWithHighlight text = { input . passage } highlights = { [ { start : highlightSpan [ 0 ] , end : highlightSpan [ 1 ] , } , ] } / > ) : ( < div > { input . passage } < /div>)} < /Output.SubSection> < Output . SubSection title = "Question" > < div > { input . question } < /div> < /Output.SubSection> < />); } ; const NaqanetPrediction = ( { input , output , model , } ) => { if ( isNAQANetPredictionSpan ( output ) && output . answer . answer_type === NAQANetAnswerType . PassageSpan ) { return ( < > < BasicAnswer output = { output } / > < Output . SubSection title = "Explanation" > The model decided the answer was in the passage . < /Output.SubSection> < Output . SubSection title = "Passage Context" > < TextWithHighlight text = { input . passage } highlights = { output . answer . spans . map ( ( s ) => { return { start : s [ 0 ] , end : s [ 1 ] , } ; } ) } / > < /Output.SubSection> < Output . SubSection title = "Question" > < div > { input . question } < /div> < /Output.SubSection> < />); } if ( isNAQANetPredictionSpan ( output ) && output . answer . answer_type === NAQANetAnswerType . QuestionSpan ) { return ( < > < BasicAnswer output = { output } / > < Output . SubSection title = "Explanation" > The model decided the answer was in the question . < /Output.SubSection> < Output . SubSection title = "Passage Context" > < div > { input . passage } < /div> < /Output.SubSection> < Output . SubSection title = "Question" > < TextWithHighlight text = { input . question } highlights = { output . answer . spans . map ( ( s ) => { return { start : s [ 0 ] , end : s [ 1 ] , } ; } ) } / > < /Output.SubSection> < />); } if ( isNAQANetPredictionCount ( output ) ) { return ( < > < BasicAnswer output = { output } / > < Output . SubSection title = "Explanation" > The model decided this was a counting problem . < /Output.SubSection> < Output . SubSection title = "Passage Context" > < div > { input . passage } < /div> < /Output.SubSection> < Output . SubSection title = "Question" > < div > { input . question } < /div> < /Output.SubSection> < />); } if ( isNAQANetPredictionArithmetic ( output ) ) { const releventNumbers = ( output . answer . numbers || [ ] ) . filter ( ( n ) => n . sign !== 0 ) ; return ( < > < BasicAnswer output = { output } / > < Output . SubSection title = "Explanation" > { releventNumbers . length ? ( < div > The model used the arithmetic expression { ' ' } < ArithmeticEquation numbersWithSign = { releventNumbers } answer = { output . answer . value } answerAtEnd = { true } / > < /div>) : (<div>The model decided this was an arithmetic problem.</div > ) } < /Output.SubSection> < Output . SubSection title = "Passage Context" > { releventNumbers . length ? ( < TextWithHighlight text = { input . passage } highlights = { releventNumbers . map ( ( n ) => { return { start : n . span [ 0 ] , end : n . span [ 1 ] , color : n . sign > 0 ? 'G6' : 'R6' , } ; } ) } / > ) : ( < div > { input . passage } < /div>)} < /Output.SubSection> < Output . SubSection title = "Question" > < div > { input . question } < /div> < /Output.SubSection> < />); } throw new InvalidModelResponseError ( model . id ) ; } ;