ankurdotio/interview-ai-yt: How to Turn an LLM Into a Structured Interview Engine

A look at the schema-first design that powers tailored questions, prep roadmaps, and ATS-friendly resume PDFs without letting the model run wild.

8 min read • View on GitHub • More from ankurdotio

A resume and job description enter a rigid press with labeled compartments, and three clean outputs emerge on the other side: a scorecard, a day-by-day prep plan, and a polished resume page. The image explains the repo’s core idea: treat LLM output like a machine that must produce durable product data, not a freeform chat response.
The repo’s real trick is not generation. It is forcing the model to output artifacts the rest of the app can trust.

Built an AI tool that generates personalized interview questions based on any job description using GPT-3.5.

Ankur Singh, Project Creator · Ankur Singh on X/Twitter
Key Takeaways

Most AI interview tools stop at generated text. This repo keeps going, because it treats the model like a backend service that has to obey contracts. That one decision changes everything: the app can store the output, render it, score it, and turn part of it into a PDF without brittle cleanup code.

The real product is the schema

The repo’s most interesting move is simple. It forces Gemini into a structured shape with zod and JSON schema conversion, then uses that shape as the source of truth for the rest of the app. The model is not chatting. It is filling fields the backend can trust.

The schema is the boundary between noisy model output and everything the app can safely reuse.

const reportSchema = z.object({
  matchScore: z.number(),
  technicalQuestions: z.array(z.object({
    question: z.string(),
    answer: z.string().optional(),
    difficulty: z.string().optional()
  })),
  preparationPlan: z.array(z.object({
    day: z.number(),
    focus: z.string(),
    tasks: z.array(z.string())
  }))
});

const jsonSchema = zodToJsonSchema(reportSchema, 'InterviewReport');
const result = await gemini.generateContent({
  contents: prompt,
  generationConfig: { responseMimeType: 'application/json' },
  responseSchema: jsonSchema
});

That structure matters because the frontend is built to consume it. A report card can map over a nested array. A roadmap can render day by day. A database record can persist the whole object without guessing what a response means. The product gets deterministic behavior out of an otherwise probabilistic system.

A hedcut-style portrait of Ankur Singh, the creator of the repository. The portrait gives a face to the project’s schema-first approach and anchors the origin story in a verified public reference image.

The interview report model is the backbone

The report model is where the app stops being a prompt demo. Nested schemas for technical questions, behavioral prompts, and the prep plan let the backend save a multi-part interview artifact instead of a single blob. That makes the product feel like a reporting system, not a chatbot.

It also explains the UI shape. Once the data is nested and predictable, the frontend can build cards, sections, and timelines without special cases. The result is boring in the best possible way: stable data in, stable interface out.

The PDF pipeline is the cleverest stretch

The resume flow is the repo’s smartest stretch beyond interviews. The backend asks the model for HTML and CSS, then hands that markup to Puppeteer for rendering. That is a serious choice: it uses a browser as a layout engine, which is much more faithful than trying to fake typography with a low-level PDF library.

A browser-like print pipeline transforms a tailored HTML resume into a finished PDF sheet. The scene explains how the repo uses a headless browser as a layout engine instead of trying to draw a document directly from text.
The resume feature is not a text export. It is HTML written by AI and rendered by a browser into a real document.
const html = await ai.generateResumeHtml(profile, jobDescription);
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent(html, { waitUntil: 'networkidle0' });
const pdf = await page.pdf({ format: 'A4', printBackground: true });

That pipeline matters because it lets the AI handle copy and layout together while still landing in a medium people trust. A browser can honor spacing, hierarchy, and pagination. A plain text generator cannot.

Security and state are pragmatic, not flashy

The rest of the stack is plain-spoken and sensible. JWT handles authentication, a token blacklist tightens logout behavior, and React Context carries interview state through the frontend. None of that is novel, but it is the right kind of mundane for a product that needs to hold together around a risky AI core.

That balance is the point. The repo is not trying to impress with infrastructure theater. It uses enough discipline to keep the generated output from leaking into the rest of the app as chaos.

How it compares to interview prep tools

Dimensionankurdotio/interview-ai-ytTypical commercial SaaSTypical prompt wrapper
InputJob description text or URLResume plus job descriptionUsually just pasted text
Output structureStructured report data plus PDFMulti-feature product surfaceFreeform text or thin JSON
PersistenceMongoDB interview reportsCloud account history and analyticsOften none or ad hoc storage
Resume generationHTML/CSS through PuppeteerBranded document workflowsUsually missing
DeploymentSelf-hosted or localHosted subscription serviceSelf-hosted or local
What you getA buildable system with contractsA polished service layerA demo that needs hardening

That middle position is the interesting one. It is lighter than a commercial platform, but much more serious than a prompt toy. You can see the product thinking without paying for a lot of platform overhead.

What this repo teaches builders

The lesson is not “use Gemini” or “use Puppeteer.” It is that LLM apps get much more useful when the model is forced into contracts the rest of the stack can trust. Once you do that, UI, storage, and document generation stop being separate problems and start becoming one product pipeline.

This project helps job seekers practice for interviews by simulating real-world scenarios based on actual job listings.

Ankur Singh, Project Creator · Interview AI Demo - YouTube

That is why this repo is worth studying. It shows how to turn a model from a source of text into a source of application data, and that shift is where many practical AI products begin.