{"version":3,"sources":["constants.js","utils.js","draw.js","model.js","App.js","index.js"],"names":["WORD_INDEX","ANSWERS","CANVAS_SIZE","IMAGE_SIZE","MIN_SHAPE_SIZE","MAX_SHAPE_SIZE","COLORS","black","gray","red","green","blue","yellow","teal","brown","COLOR_NAMES","Object","keys","SHAPES","randint","min","max","Math","floor","random","CANVAS_RATIO","MIN_CANVAS_SHAPE_SIZE","MAX_CANVAS_SHAPE_SIZE","SIN_60","sqrt","drawShape","context","shape","colorName","r","g","b","fillStyle","fillRect","drawBackground","w","h","drawRectangle","beginPath","arc","PI","fill","drawCircle","s","x","y","ceil","moveTo","lineTo","drawTriangle","console","error","loadModelPromise","tf","then","model","getBagOfWords","str","trim","replace","toLowerCase","bagOfWords","Array","length","split","forEach","token","imageData","question","a","questionBOW","imageTensor","fromPixels","expandDims","div","sub","questionTensor","predict","argMax","arraySync","answerIndex","catch","SAMPLE_QUESTIONS","randomQuestion","isEmbedded","URLSearchParams","window","location","search","has","App","useState","color","setColor","setShape","setQuestion","answer","setAnswer","modelLoaded","setModelLoaded","predicting","setPredicting","mainCanvas","useRef","smallCanvas","onPredict","useCallback","useEffect","current","ctx","getContext","ratio","scale","drawImage","getInference","onQuestionChange","e","target","value","randomizeImage","randomizeQuestion","q","className","href","rel","Card","Header","Body","ref","width","height","style","display","Text","Button","onClick","disabled","Form","Group","controlId","Control","as","placeholder","onChange","variant","size","Alert","ReactDOM","render","document","getElementById"],"mappings":"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","file":"static/js/main.3d679468.chunk.js","sourcesContent":["// All of these constants should be kept in sync with their counterparts in easy-VQA,\n// the repo that contains the code to generate the dataset.\n\nconst WORD_INDEX = {'is': 1, 'shape': 2, 'the': 3, 'a': 4, 'image': 5, 'there': 6, 'not': 7, 'what': 8, 'does': 9, 'contain': 10, 'in': 11, 'present': 12, 'color': 13, 'no': 14, 'triangle': 15, 'rectangle': 16, 'circle': 17, 'teal': 18, 'gray': 19, 'brown': 20, 'blue': 21, 'green': 22, 'yellow': 23, 'red': 24, 'black': 25, 'of': 26};\nconst ANSWERS = ['green', 'triangle', 'no', 'rectangle', 'gray', 'red', 'blue', 'yes', 'circle', 'black', 'yellow', 'brown', 'teal'];\n\nconst CANVAS_SIZE = 256;\nconst IMAGE_SIZE = 64;\nconst MIN_SHAPE_SIZE = IMAGE_SIZE / 8;\nconst MAX_SHAPE_SIZE = IMAGE_SIZE / 2;\n\nconst COLORS = {\n  black: 'black',\n  gray: 'rgb(128, 128, 128)',\n  red: 'red',\n  green: 'green',\n  blue: 'blue',\n  yellow: 'yellow',\n  teal: 'teal',\n  brown: 'rgb(165, 42, 42)',\n};\nconst COLOR_NAMES = Object.keys(COLORS);\n\nconst SHAPES = [\n  'rectangle',\n  'circle',\n  'triangle',\n];\n\nexport {\n  WORD_INDEX,\n  ANSWERS,\n  CANVAS_SIZE,\n  IMAGE_SIZE,\n  MIN_SHAPE_SIZE,\n  MAX_SHAPE_SIZE,\n  COLORS,\n  COLOR_NAMES,\n  SHAPES,\n};\n","// Returns a random integer in [min, max] INCLUSIVE (to match Python's randint()).\nexport function randint(min, max) {\n  return Math.floor(min + Math.random() * (max + 1 - min));\n}\n","import { CANVAS_SIZE, IMAGE_SIZE, MIN_SHAPE_SIZE, MAX_SHAPE_SIZE, COLORS } from './constants';\nimport { randint } from './utils';\n\nconst CANVAS_RATIO = CANVAS_SIZE / IMAGE_SIZE;\nconst MIN_CANVAS_SHAPE_SIZE = MIN_SHAPE_SIZE * CANVAS_RATIO;\nconst MAX_CANVAS_SHAPE_SIZE = MAX_SHAPE_SIZE * CANVAS_RATIO;\n\nfunction drawBackground(context) {\n  // The range (230, 255) matches the corresponding range in easy-VQA\n  const r = randint(230, 255);\n  const g = randint(230, 255);\n  const b = randint(230, 255);\n  context.fillStyle = `rgb(${r}, ${g}, ${b})`;\n  context.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE);\n}\n\nfunction drawRectangle(context) {\n  const w = randint(MIN_CANVAS_SHAPE_SIZE, MAX_CANVAS_SHAPE_SIZE);\n  const h = randint(MIN_CANVAS_SHAPE_SIZE, MAX_CANVAS_SHAPE_SIZE);\n  context.fillRect(randint(0, CANVAS_SIZE - w), randint(0, CANVAS_SIZE - h), w, h);\n}\n\nfunction drawCircle(context) {\n  const r = randint(MIN_CANVAS_SHAPE_SIZE, MAX_CANVAS_SHAPE_SIZE) / 2;\n  context.beginPath();\n  context.arc(randint(r, CANVAS_SIZE - r), randint(r, CANVAS_SIZE - r), r, 0, 2 * Math.PI);\n  context.fill();\n}\n\nconst SIN_60 = Math.sqrt(3) / 2;\nfunction drawTriangle(context) {\n  const s = randint(MIN_CANVAS_SHAPE_SIZE, MAX_CANVAS_SHAPE_SIZE);\n  let x = randint(0, CANVAS_SIZE - s);\n  let y = randint(Math.ceil(s * SIN_60), CANVAS_SIZE);\n  context.beginPath();\n  context.moveTo(x, y);\n  context.lineTo(x + s, y);\n  context.lineTo(x + s / 2, y - s * SIN_60);\n  context.lineTo(x, y);\n  context.fill();\n}\n\nexport function drawShape(context, shape, colorName) {\n  drawBackground(context);\n\n  context.fillStyle = COLORS[colorName];\n  switch (shape) {\n    case 'rectangle':\n      drawRectangle(context);\n      break;\n    case 'circle':\n      drawCircle(context);\n      break;\n    case 'triangle':\n      drawTriangle(context);\n      break;\n    default:\n      console.error('Invalid shape name provided', shape);\n      break;\n  }\n}\n","import * as tf from '@tensorflow/tfjs';\n\nimport {WORD_INDEX, ANSWERS} from './constants';\n\nexport const loadModelPromise = tf.loadLayersModel('/model.json')\n  .then(model => {\n    return model;\n  });\n\nfunction getBagOfWords(str) {\n  str = str.trim()\n    .replace(/[^\\w\\s]|_/g, '')\n    .replace(/\\s+/g, ' ')\n    .toLowerCase();\n\n  // We have to add 1 to maintain consistency with how the BOW vectors are\n  // generated in our Python implementation. See easy-VQA-keras for more.\n  const bagOfWords = Array(Object.keys(WORD_INDEX).length + 1).fill(0);\n\n  const tokens = str.split(' ');\n  tokens.forEach(token => {\n    if (token in WORD_INDEX) {\n      bagOfWords[WORD_INDEX[token]] += 1;\n    }\n  });\n  return bagOfWords;\n}\n\nexport async function getInference(imageData, question) {\n  const questionBOW = getBagOfWords(question);\n  return loadModelPromise.then(model => {\n    let imageTensor = tf.browser.fromPixels(imageData, 3);\n    imageTensor = imageTensor.expandDims(0);\n    imageTensor = imageTensor.div(255).sub(0.5);\n\n    let questionTensor = tf.tensor(questionBOW);\n    questionTensor = questionTensor.expandDims(0);\n\n    let output = model.predict([imageTensor, questionTensor]);\n\n    let [answerIndex] = output.argMax(1).arraySync();\n    return ANSWERS[answerIndex];\n  })\n  .catch(console.error);\n}\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\nimport Button from 'react-bootstrap/Button';\nimport Card from 'react-bootstrap/Card';\nimport Form from 'react-bootstrap/Form';\nimport Alert from 'react-bootstrap/Alert';\n\nimport { drawShape } from './draw';\nimport { getInference, loadModelPromise } from './model';\nimport { CANVAS_SIZE, IMAGE_SIZE, COLOR_NAMES, SHAPES } from './constants';\nimport { randint } from './utils';\n\nimport 'bootstrap/dist/css/bootstrap.min.css';\nimport './App.css';\n\nconst SAMPLE_QUESTIONS = [\n  'What color is the shape?',\n  'Is there a blue shape in the image?',\n  'Is there a red shape?',\n  'Is there a green shape in the image?',\n  'Is there a black shape?',\n  'Is there not a teal shape in the image?',\n  'Does the image contain a rectangle?',\n  'Does the image not contain a circle?',\n  'What shape is present?',\n  'Is no triangle present?',\n  'Is a circle present?',\n  'Is a rectangle present?',\n  'Is there a triangle?',\n  'What is the color of the shape?',\n  'What shape does the image contain?',\n];\n\nconst randomQuestion = () => SAMPLE_QUESTIONS[randint(0, SAMPLE_QUESTIONS.length - 1)];\n\nconst urlParams = new URLSearchParams(window.location.search);\nconst isEmbedded = urlParams.has('embed');\n\nfunction App() {\n  const [color, setColor] = useState(null);\n  const [shape, setShape] = useState(null);\n  const [question, setQuestion] = useState(randomQuestion());\n  const [answer, setAnswer] = useState(null);\n  const [modelLoaded, setModelLoaded] = useState(false);\n  const [predicting, setPredicting] = useState(false);\n\n  const mainCanvas = useRef(null);\n  const smallCanvas = useRef(null);\n\n  const onPredict = useCallback(() => {\n    setPredicting(true);\n  }, [setPredicting]);\n\n  useEffect(() => {\n    if (smallCanvas.current) {\n      const ctx = smallCanvas.current.getContext('2d');\n      const ratio = IMAGE_SIZE / CANVAS_SIZE;\n      ctx.scale(ratio, ratio);\n    }\n  }, [smallCanvas]);\n\n  useEffect(() => {\n    if (predicting) {\n      // Draw the main canvas to our smaller, correctly-sized canvas\n      const ctx = smallCanvas.current.getContext('2d');\n      ctx.drawImage(mainCanvas.current, 0, 0);\n\n      getInference(smallCanvas.current, question).then(answer => {\n        setAnswer(answer);\n        setPredicting(false);\n      });\n    }\n  }, [predicting, question]);\n\n  const onQuestionChange = useCallback(\n    e => {\n      setQuestion(e.target.value);\n      setAnswer(null);\n    },\n    [setQuestion]\n  );\n\n  const randomizeImage = useCallback(() => {\n    const context = mainCanvas.current.getContext('2d');\n    const colorName = COLOR_NAMES[randint(0, COLOR_NAMES.length - 1)];\n    const shape = SHAPES[randint(0, SHAPES.length - 1)];\n\n    drawShape(context, shape, colorName);\n\n    setColor(colorName);\n    setShape(shape);\n    setAnswer(null);\n  }, [mainCanvas]);\n\n  const randomizeQuestion = useCallback(() => {\n    let q = question;\n    while (q === question) {\n      q = randomQuestion();\n    }\n    setQuestion(q);\n    setAnswer(null);\n  }, [question, setQuestion]);\n\n  useEffect(() => {\n    randomizeImage();\n\n    loadModelPromise.then(() => {\n      setModelLoaded(true);\n    });\n  }, []);\n\n  return (\n    <div className=\"root\">\n      {!isEmbedded && (\n        <>\n          <h1>easy-VQA Demo</h1>\n          <h2>\n            A Javascript demo of a{' '}\n            <a href=\"https://victorzhou.com/blog/easy-vqa/\">Visual Question Answering (VQA)</a>{' '}\n            model trained on the{' '}\n            <a\n              href=\"https://github.com/vzhou842/easy-VQA\"\n              target=\"_blank\"\n              rel=\"nofollow noreferrer\"\n            >\n              easy-VQA dataset\n            </a>\n            .\n          </h2>\n          <p className=\"description\">\n            <b>Read the <a href=\"https://victorzhou.com/blog/easy-vqa/\">blog post</a></b> or see the source code on{' '}\n            <a\n              href=\"https://github.com/vzhou842/easy-VQA-demo\"\n              target=\"_blank\"\n              rel=\"nofollow noreferrer\"\n            >\n              Github\n            </a>\n            .\n          </p>\n        </>\n      )}\n      <div className=\"container\">\n        <Card>\n          <Card.Header>The Image</Card.Header>\n          <Card.Body>\n            <canvas ref={mainCanvas} width={CANVAS_SIZE} height={CANVAS_SIZE} />\n            <canvas\n              ref={smallCanvas}\n              width={IMAGE_SIZE}\n              height={IMAGE_SIZE}\n              style={{ display: 'none' }}\n            />\n            <figcaption className=\"image-caption\">\n              A <b>{color}</b>, <b>{shape}</b> shape.\n            </figcaption>\n            <br />\n            <Card.Text>Want a different image?</Card.Text>\n            <Button onClick={randomizeImage} disabled={predicting}>\n              Random Image\n            </Button>\n          </Card.Body>\n        </Card>\n        <Card>\n          <Card.Header>The Question</Card.Header>\n          <Card.Body>\n            <Form>\n              <Form.Group controlId=\"formQuestion\">\n                <Form.Control\n                  as=\"textarea\"\n                  placeholder={SAMPLE_QUESTIONS[0]}\n                  value={question}\n                  onChange={onQuestionChange}\n                  disabled={predicting}\n                />\n              </Form.Group>\n            </Form>\n            <Card.Text>Want a different question?</Card.Text>\n            <Button onClick={randomizeQuestion} disabled={predicting}>\n              Random Question\n            </Button>\n          </Card.Body>\n        </Card>\n      </div>\n      <Button variant=\"success\" size=\"lg\" onClick={onPredict} disabled={!modelLoaded || predicting}>\n        {modelLoaded ? (predicting ? 'Predicting...' : 'Predict') : 'Loading model...'}\n      </Button>\n      <br />\n      {!!answer ? (\n        <Alert variant=\"primary\">\n          Prediction: <b>{answer}</b>\n        </Alert>\n      ) : predicting ? (\n        <Alert variant=\"light\">The prediction will appear here soon...</Alert>\n      ) : (\n        <Alert variant=\"light\">Click Predict!</Alert>\n      )}\n    </div>\n  );\n}\n\nexport default App;\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\n\nReactDOM.render(<App />, document.getElementById('root'));\n"],"sourceRoot":""}