Skip to main content

Project 02: LLM using Hugging Face for Beginners

LLM and Hugging Face: Table Question Answering

Table Question Answering (Table QA) is the answering a question about an information on a given table.7

In this project upload a '.csv' file and ask a question about the data on a given table to get answers based on the uploaded table.

Setup Backend code

Install multer and csv-parser to upload a file and parse .csv files. Also fs library to process the file at backend.

npm install multer csv-parser

Continue from initial backend setup as shown here and then process file and route hugging face API as shown below.

const multer = require('multer')
const csv = require('csv-parser')
const fs = require('fs')

const upload = multer({dest: 'uploads/')

app.post('api/table-question-answer', upload.single("file"), async(req, res) => {
  const { ques } = req.body
  const file = req.file

  console.log(file)
  if (!file || !fs.existsSync(file.path)) {
    return res.status(400).send('File not found or inaccessible.');
  }
  // parse csv file
  if(file.mimetype === 'text/csv') {
    const table = []
    fs.createReadStream(file.path)
      .on('error', () => {
        console.log('Error in reaind a file ', error)
        res.status(500).json({message: `Error in reading file ${error.message}`})
      })
      .pipe(csv())
      .on('data', (row) => table.push(row))
      .on('end', async() => {
        try {
          const response = await hf.tableQuestionAnswering({
            model: "google/tapas-large-finetuned-wtq",
            inputs: {
              query: ques,
              table: table
            }
          })
          fs.unlink(file.path, (err) => {
            if (err) console.error('Error deleting file:', err);
          });
          res.status(200).json(response);
       }catch(error) {
          console.error('Error processing query:', error);
          res.status(500).json({ message: `Error processing query: ${error.message}` });  
       }
     }) // end on
   } // end if
})

The output format for file and hf.tableQuestionAnswering is:

// for file:
// {
//  fieldname: 'file',
// originalname: 'example.csv',
//  encoding: '7bit',
//  mimetype: 'text/csv',
//  destination: 'C:\\Users\\...\\llm_backend\\uploads',
// filename: '7dfa8072d3829a4851992e8a0455dthw2',
 // path: 'C:\\Users\...\\llm_backend\\uploads\\7dfa8072d3829a4851992e8a0455dthw2',
 // size: 12473
}
// for hf table QA output
//  {
//     answer: '...',
//     coordinates: [ [.., .. ] ],
//     cells: [ '...' ],
//     aggregator: 'NONE'
//   }

Setup frontend UI [ REACT ]

For frontend used FormData to process a file and sent to backend server. In headers use multipart/form-data to process file at backend or else you will encounter error.

import React, { useState } from 'react'
import axios from 'axios'

const TableQA = () => {
    const [ques, setQues] = useState('')
    const [file, setFile] = useState(null)
    const [answer, setAnswer] = useState('')

    const handleFileChange = (e) => {
        setFile(e.target.files[0])
    }

    const handleTableQA = async (e) => {
        e.preventDefault()
        // const tableData = JSON.parse(table)
        if(!file) {
            alert("Please upload a file")
            return
        }
        const formData = new FormData()
        formData.append('file', file)
        formData.append('ques', ques)
        try {
            const response = await axios.post('http://localhost:5000/api/table-question-answer', formData, {
                headers: {'Content-Type': 'multipart/form-data' },
            })
            setAnswer(response.data.answer)
        } catch(err) {
            console.error(`Error: ${err.message}`)
        }
    }

  return (
    <>
        <form onSubmit={handleTableQA}>
            <h2>Table Question Answer</h2>
            <p>Your question</p>
            <textarea
                className='qa'
                rows='3'
                cols='50'
                value={ques}
                onChange={(e) => setQues(e.target.value)}
            >
            </textarea>
            <input 
                type='file'
                onChange={handleFileChange}
            />
            <button>Get Answer</button>
        </form>

        <div className='result'>
            <h3>Answer ?</h3>
            <p>{answer}</p>     
        </div>
    </>
  )
}

export default TableQA

Run the application

  • Backend
// if nodemon installed
// in package.json
{
....,
  "scripts": {
      "start": "nodemon server.js",
      ----------,
  }
}

// in commage prompt
npm start 


// if nodemon not installed
node server.js
  • Frontend
npm start

The output of Table Question Answering renders as below

Fig - Table_QA web application