{"slug": "one-more-try-a-private-ai-interview-coach-built-for-a-friend", "title": "One More Try: A Private AI Interview Coach Built for a Friend", "summary": "A developer built One More Try, a privacy-first AI interview practice app for a friend preparing for job interviews, using Gemma 3 via Ollama for fully local inference. The app ingests a candidate's CV and a target job description to generate five personalized questions, then structures feedback into \"What worked\" and \"Make it stronger\" so users can immediately re-answer the same question and compare improvement. The stack pairs a React/Vite frontend with a Python FastAPI backend, keeping CVs and answers off hosted LLM APIs.", "body_md": "*This is a submission for the [Hacktoberfest Weekend Challenge: Build for a Friend](https://dev.to/challenges/hacktoberfest-weekend-2026-10-01).*\n\nI built **One More Try**, a privacy-first AI interview practice app for a friend who is preparing for job interviews.\n\nThe idea came from something simple: when someone practises an interview question, their first answer usually isn't their best one.\n\nThey know the experience. They know what happened. But the first answer might be too vague, miss an important result, lack evidence, or simply not explain their contribution clearly enough.\n\nMost interview tools generate questions.\n\nI wanted to build something focused on what happens **after you answer**.\n\nSo One More Try follows this loop:\n\n```\nCV + Job Description\n        ↓\nPersonalised Interview\n        ↓\nAnswer a Question\n        ↓\nAI Feedback\n        ↓\nWhat Worked\n+\nMake It Stronger\n        ↓\nOne More Try\n        ↓\nCompare the Improvement\n```\n\nThe user uploads their real CV and pastes the job description they are preparing for.\n\nGemma then uses both to create five personalised interview questions.\n\nFor every answer, the app evaluates things like:\n\nInstead of just giving a score, the interface separates feedback into **What worked** and **Make it stronger**.\n\nThen comes the feature the whole project is built around:\n\n**One More Try.**\n\nThe candidate answers the same question again while the feedback is still fresh.\n\nAt the end of the five-question interview, the app produces a final practice summary showing strengths and patterns to continue improving.\n\nAnd importantly, the core AI runs **locally**.\n\nYour CV and interview answers don't need to be sent to a hosted LLM API.\n\nThe UI was intentionally designed to feel more like a focused coaching environment than a traditional dashboard.\n\nGitHub:\n\nThe project contains:\n\n```\none-more-try/\n├── backend/\n│   └── FastAPI + Ollama integration\n│\n├── frontend/\n│   └── React + Vite interface\n│\n├── run-local.sh\n├── README.md\n└── LICENSE\n```\n\nRunning the application locally is intentionally simple:\n\n```\nollama pull gemma3:1b\nchmod +x run-local.sh\n./run-local.sh\n```\n\nThe application has a React frontend and a Python FastAPI backend.\n\nThe main AI stack is:\n\nWhen a session begins, the backend extracts text from the CV and combines it with the job description.\n\nGemma analyses that context and prepares the interview.\n\nInstead of generating generic questions like:\n\nTell me about yourself.\n\nthe model can ask questions grounded in the candidate's actual experience and the requirements of the role.\n\nThe interview context is kept compact after the initial preparation so later evaluations do not need to resend the full CV and job description every time.\n\nWhen an answer is submitted, Gemma receives:\n\nIt returns structured feedback containing:\n\n```\nWhat worked\nMake it stronger\nFollow-up\nNext focus\n```\n\nThis makes the AI output predictable enough to build an actual product interface around instead of simply dumping model text into a chat box.\n\nOne of my favourite parts of the project is that the second attempt is not treated as another unrelated answer.\n\nThe system compares it with the previous response.\n\nThat makes the experience closer to coaching:\n\n```\nAttempt 1\n   ↓\nFeedback\n   ↓\nAttempt 2\n   ↓\nImprovement comparison\n```\n\nThe interface was built with React and Vite.\n\nI also used several open-source **React Bits** components to make the experience more interactive without turning it into a visually noisy dashboard.\n\nThese included:\n\nThe animated ColorBends background uses Three.js/WebGL while the rest of the interface stays intentionally restrained.\n\nThis project would be very different if the only option were a closed hosted AI API.\n\nUsing **Gemma 3 as an open-weight model with Ollama** allowed me to make local inference a fundamental part of the product rather than an afterthought.\n\nThat matters especially for this use case.\n\nA CV can contain:\n\nInterview answers can be even more personal.\n\nWith local inference, the core workflow becomes:\n\n```\nCV\n +\nJob Description\n        ↓\nLocal FastAPI Application\n        ↓\nOllama\n        ↓\nGemma 3\n        ↓\nQuestions + Feedback\n```\n\nThere is no requirement to send the candidate's CV to a commercial LLM endpoint just to practise an interview.\n\nOpen innovation also gave me much more control over the product.\n\nI could:\n\nThere were trade-offs.\n\nRunning Gemma locally on CPU forced me to think much more carefully about prompt size, output length, inference time, and how many model calls the experience actually needed.\n\nBut that constraint improved the architecture.\n\nInstead of treating the LLM as unlimited infrastructure, I had to decide:\n\n**What actually needs AI, and what doesn't?**\n\nThat was probably one of the most useful lessons from the weekend.\n\nThis is deliberately an MVP.\n\nI wanted to finish one complete experience rather than build ten half-working features.\n\nThe scope became:\n\n**CV + Job Description → personalised interview → feedback → One More Try**\n\nThat meant saying no to a few tempting features during the weekend.\n\nOne of those was voice.\n\nI experimented with turning the experience into a full spoken interview, but adding speech-to-text, text-to-speech, microphone handling, latency management, and another set of dependencies would have increased the failure surface significantly.\n\nFor a three-day build, I chose to keep the working typed interview experience and make the core loop reliable.\n\nThe next version would turn One More Try into a more complete mock-interview environment.\n\nThe first addition would be local speech-to-text using something like Whisper.\n\n```\nAI Question\n     ↓\nCandidate Speaks\n     ↓\nLocal Speech-to-Text\n     ↓\nGemma Evaluation\n     ↓\nCoaching Feedback\n```\n\nThis would preserve the privacy-first direction while making the practice experience much closer to a real interview.\n\nBeyond the meaning of the answer, the application could analyse observable speech signals such as:\n\nThat would let the system coach both **what you say** and **how you deliver it**.\n\nAn optional camera mode could later provide feedback on observable presentation behaviours such as:\n\nI would keep this focused on observable behaviours rather than trying to infer someone's personality or emotional state from their face.\n\nRight now the interview is prepared at the beginning.\n\nA larger version could dynamically choose later questions based on earlier answers.\n\nFor example:\n\n```\nWeak technical explanation\n        ↓\nTechnical follow-up\n\nStrong project example\n        ↓\nDeeper system-design question\n\nMissing evidence\n        ↓\nQuestion asking for measurable impact\n```\n\nAnother direction would be comparing interview sessions over time.\n\nThe app could identify recurring patterns like:\n\nand show whether those problems are improving.\n\nThe biggest lesson wasn't about prompting.\n\nIt was about turning an LLM into a product.\n\nGenerating text is easy.\n\nBuilding a useful AI experience means thinking about:\n\nFor One More Try, the AI feedback itself is only half the product.\n\nThe important part is what happens next:\n\n**you get another attempt.**\n\nThat's why I called it **One More Try**.", "url": "https://wpnews.pro/news/one-more-try-a-private-ai-interview-coach-built-for-a-friend", "canonical_source": "https://dev.to/navodhyafernando/one-more-try-a-private-ai-interview-coach-built-for-a-friend-27da", "published_at": "2026-10-05 04:39:57+00:00", "updated_at": "2026-10-05 04:42:28.503514+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "ai-products", "developer-tools"], "entities": ["One More Try", "Gemma 3", "Ollama", "FastAPI", "React", "Vite", "React Bits", "Three.js"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/one-more-try-a-private-ai-interview-coach-built-for-a-friend", "markdown": "https://wpnews.pro/news/one-more-try-a-private-ai-interview-coach-built-for-a-friend.md", "text": "https://wpnews.pro/news/one-more-try-a-private-ai-interview-coach-built-for-a-friend.txt", "jsonld": "https://wpnews.pro/news/one-more-try-a-private-ai-interview-coach-built-for-a-friend.jsonld"}}