<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aakif Kohari</title>
    <description>The latest articles on DEV Community by Aakif Kohari (@aakif-kohari).</description>
    <link>https://dev.to/aakif-kohari</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160154%2Fab957dd1-c77b-4ff1-b682-513ac946f84d.png</url>
      <title>DEV Community: Aakif Kohari</title>
      <link>https://dev.to/aakif-kohari</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aakif-kohari"/>
    <language>en</language>
    <item>
      <title>PlacePal: an offline mock-interview coach I built for a friend, powered by Gemma and Ollama</title>
      <dc:creator>Aakif Kohari</dc:creator>
      <pubDate>Sun, 04 Oct 2026 13:48:17 +0000</pubDate>
      <link>https://dev.to/aakif-kohari/placepal-an-offline-mock-interview-coach-i-built-for-a-friend-powered-by-gemma-and-ollama-gi4</link>
      <guid>https://dev.to/aakif-kohari/placepal-an-offline-mock-interview-coach-i-built-for-a-friend-powered-by-gemma-and-ollama-gi4</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-weekend-2026-10-01"&gt;Hacktoberfest Weekend Challenge: Build for a Friend&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;A batchmate of mine, has campus placement drives coming up and wants practice with real interview questions about &lt;em&gt;their own&lt;/em&gt; projects, not another generic list from the internet.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;PlacePal&lt;/strong&gt;, an offline mock-interview partner. You upload your resume (or paste its text), pick a target role and difficulty, and PlacePal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;writes 5 questions tailored to your resume: 2 technical, 2 about your projects, 1 HR&lt;/li&gt;
&lt;li&gt;scores each answer from 1 to 10, with strengths, gaps and a stronger sample answer&lt;/li&gt;
&lt;li&gt;tracks your average score per topic and tells you which topics to revise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The problem it solves is simple. A resume has your phone number, email, college and projects, and your interview answers show exactly where you are weak. That is the data you least want to paste into a hosted chatbot. PlacePal never sends it anywhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;There is no hosted demo, on purpose: the whole point is that PlacePal runs on your own machine. You can try it in a few minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama pull gemma3:4b
git clone https://github.com/Aakif-Kohari/placepal.git
&lt;span class="nb"&gt;cd &lt;/span&gt;placepal
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
streamlit run app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Once the model is pulled, you can turn Wi-Fi off and it still works.&lt;/p&gt;
&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Aakif-Kohari" rel="noopener noreferrer"&gt;
        Aakif-Kohari
      &lt;/a&gt; / &lt;a href="https://github.com/Aakif-Kohari/placepal" rel="noopener noreferrer"&gt;
        placepal
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Offline mock-interview coach for campus placements. Runs on a local open-weight model (Gemma via Ollama): resume-aware questions, honest scoring, weak-topic tracking. No cloud, no API key.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🎯 PlacePal&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;An offline mock-interview partner for campus placements, powered by an open-weight model running on your own laptop.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;PlacePal reads your resume, asks questions tailored to &lt;em&gt;your&lt;/em&gt; projects and your target role, scores each answer honestly, and tracks which topics keep dragging your scores down. Everything runs locally through &lt;a href="https://ollama.com" rel="nofollow noopener noreferrer"&gt;Ollama&lt;/a&gt; with a &lt;a href="https://ai.google.dev/gemma" rel="nofollow noopener noreferrer"&gt;Gemma&lt;/a&gt; model. There is no API key, no account, no cloud, and no bill.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Built for the &lt;strong&gt;DEV Hacktoberfest Weekend Challenge: Build for a Friend&lt;/strong&gt; (Oct 2-5, 2026), for a friend preparing for campus placements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why local matters here&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;A resume carries your phone number, email, college and projects. Interview answers carry your weaknesses. That is exactly the data you do not want to paste into a hosted chatbot.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;div class="table-wrapper-paragraph"&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;table&gt;

&lt;thead&gt;

&lt;tr&gt;

&lt;th&gt;PlacePal (local open-weight model)&lt;/th&gt;

&lt;th&gt;Typical hosted chatbot&lt;/th&gt;

&lt;/tr&gt;

&lt;/thead&gt;

&lt;tbody&gt;

&lt;tr&gt;

&lt;td&gt;Resume leaves your machine&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Yes&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Works with Wi-Fi off&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;No&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Cost per practice session&lt;/td&gt;

&lt;td&gt;&lt;strong&gt;Zero&lt;/strong&gt;&lt;/td&gt;

&lt;td&gt;Credits / subscription&lt;/td&gt;

&lt;/tr&gt;

&lt;tr&gt;

&lt;td&gt;Swap&lt;/td&gt;

&lt;/tr&gt;

&lt;/tbody&gt;

&lt;/table&gt;&lt;/div&gt;…&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Aakif-Kohari/placepal" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The open-source AI:&lt;/strong&gt; &lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt;, Google's open-weight model, served locally by &lt;a href="https://ollama.com" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;. The default is &lt;code&gt;gemma3:4b&lt;/code&gt; (about a 3.3 GB download). The UI is Streamlit and resumes are parsed locally with pypdf.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The flow:&lt;/strong&gt; resume text goes into a prompt along with the role's focus areas and the difficulty. Gemma returns JSON, which I validate and show in the UI. Finished sessions are saved to a local JSON file, and a progress tab aggregates scores by topic.&lt;/p&gt;

&lt;p&gt;Most of the work was making a small local model behave reliably:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Defensive JSON handling.&lt;/strong&gt; Small models sometimes wrap JSON in markdown fences, add chatter, or return a score like &lt;code&gt;"7/10"&lt;/code&gt;. I extract the first valid JSON object, validate and clamp every field, and if the reply is unusable I tell the model what was wrong and retry twice before showing a clear error.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scoring I can trust a bit more.&lt;/strong&gt; Prompts alone didn't stop a small model from rewarding a one-line answer, so answers under 5 words are capped at 2/10 and under 15 words at 4/10, deterministically in code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An honest privacy claim.&lt;/strong&gt; The app checks &lt;code&gt;OLLAMA_HOST&lt;/code&gt; and shows a warning banner if the server is not on the same machine. I also turned off Streamlit's anonymous usage stats so "nothing leaves this laptop" is actually true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests.&lt;/strong&gt; 34 tests run in CI, including the full Streamlit flow using Streamlit's &lt;code&gt;AppTest&lt;/code&gt;. The model call is a single function that tests replace with a fake.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used an AI assistant to help write the code, and I reviewed and tested it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;A hosted API would have worked technically. For this project, it would have been the wrong tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by architecture.&lt;/strong&gt; With a local open-weight model, the resume and every answer stay on the laptop. I don't have to trust a privacy policy because there is no server to send the data to.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Works offline.&lt;/strong&gt; Placement prep happens in hostels, trains and places with bad Wi-Fi.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Costs nothing to run.&lt;/strong&gt; My friend can practice 20 rounds without credits, rate limits or a subscription.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Swappable.&lt;/strong&gt; The model is one environment variable. &lt;code&gt;PLACEPAL_MODEL=qwen3:4b streamlit run app.py&lt;/code&gt; changes the model without touching code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inspectable.&lt;/strong&gt; Every prompt the model sees is in one readable file, &lt;code&gt;placepal/prompts.py&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trade-off is real. A 4B model is a more generous and less consistent grader than the biggest hosted models, which is why I added code-level guardrails and documented the limitation. People with more RAM can point &lt;code&gt;PLACEPAL_MODEL&lt;/code&gt; at a larger Gemma and get stricter feedback, which a closed API wouldn't let them choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Best Use of Gemma&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>hf26challenge</category>
    </item>
  </channel>
</rss>
