| Question builder
A tool I built when OpenAI first released their API. I used it to create question sets for my class and then expanded into a prototype app.
Mar

About

I built this around the time OpenAI came out with their API, and have only touched it up a little so I could put it out there for others to learn from. I never had any intention of turning it into a product, and if I did, I’d have to come up with a better name than the on-the-nose Question builder, and called it Questzinga! or something equally inane.

You can check out the repo if you’d like to jump straight to the code, but if you want to hear my motivation building it and then a little about the app itself, read on.

Motivation

There are a number of problems in the field of education, but there are no lack of solutions. Many technology companies tend towards a similar model when it comes to the classroom, and it’s primarily predatory in nature. These companies open for free, harvest the labor of teachers in exchange for a modicum of amusement for their students, and then later put up a pay wall.

These are primarily game-based sites, the educational value of which is dubious, though students seem to love them, and thus teachers will often make use of them to fill portions of the class. The labor is the time teachers put in creating questions, which then keep them locked to the platform, and the predatory nature is the slow pay walling of features that later occurs. One could argue that teachers got value from this exchange, but I’d argue that it’s a wholly unfair exchange.

What I’d like to see is some sort of open question format, like a markdown for questions, that could be easily read, manipulated, shared and converted to different formats. The closest I found was something call QTI.

If it were up to me, teachers would be able to create question sets and easily create and upload them to these sorts of question sites.Perhaps they could even be embedded in slide decks or converted to slide decks. I’m not sure exactly what this would look like, but I think it’d be nice if content like the question-answer setup that seems so common in teaching had a format as common as Excel’s xls or Text’s txt is.

One of the reasons I started building tool was I wanted to hold on to my data. The questions I created would be in a format I could later use however I want.

Development

When I started this I wanted to test out TailwindCSS. It makes your HTML look like a hot mess, and causes people, like myself, to reach for vscode plugins in order to stymie panic attacks, but otherwise it’s pretty nice. ChatGPT and similar tools do a pretty good job of ripping out nice components for it, so that’s a nice bonus which speeds development along.

The app itself is not complete, though as is it’s functional. It’s entirely built in SvelteKit, which has been my goto framework for the last few years. The database is Postgres, and I’m using Prisma, which I really like the UX on, though I’ve switched over to Kysely in more recent apps. The nice thing is I’m still able to use Prisma for migrations schema management through this plugin (shout out to valtyr for maintaining this blessing).

During development there wasn’t too much I found difficult, though if you look at the create/add svelte file, you’ll see it took a bit to get the extract information from the PDFs. The app will take copy-pasted data and pull out all text from PDFs.

Images
Starting screen, collection creating and adding content

After I’d done this I realized that with a bit of work I could easily roll out a clone of those “convert PDF” sites you see floating around. Pretty much all the tools in just a few libraries. If you need to get text from a PDF using pdf.js here’s the snippet I used:

export async function getPDFContent(file: File): Promise<string | null> {
  let content = "";
  try {
    const pdfData = new Uint8Array(await file.arrayBuffer());
    const loadingTask = pdfjs.getDocument(pdfData);
    let pdf = await loadingTask.promise;

    for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
      const page = await pdf.getPage(pageNum);
      const textContent = await page.getTextContent();
      content += textContent.items.map(item => (item as TextItem).str).join(" ");
    }

    return content;
  } catch (error) {
    return null;
  }
}

One other thing that I’ve learned over the last year or so, is that there are better ways of extracting data from OpenAI’s API. What you see is me asking for a CSV format and then, for the most part, manually parsing things. In fact, this app I’ve found to be inconsistent enough that it would need to be revised to be useful in production.

After you’ve created the questions they’re grouped in collection which can be edited and added to later on. You can see in the images below the pages related to editing, deleting and finally exporting the questions.

Images
Edit, delete and export

At this point it’ll only export to a Quizziz compatible spreadsheet using a nice library called Exceljs. And that’s about the gist of the app. Personally, I think it looks nice enough, and I was pleasantly surprised with how easily Tailwind was to use, and I’ll likely keep using it for smaller projects.