Skip to content

A web app to practice interviews (behavioral, coding/LeetCode, and project deep-dives) with streaming AI responses. It supports PDF resume ingestion, strict interview-type enforcement, and cost controls via rate limiting, caching, and token management.

License

Notifications You must be signed in to change notification settings

Shams261/InterviewBuddy

Repository files navigation

Interview Buddy

A web app to practice interviews (behavioral, coding/LeetCode, and project deep-dives) with streaming AI responses. It supports PDF resume ingestion, strict interview-type enforcement, and cost controls via rate limiting, caching, and token management.

Features

  • Multiple interview modes: behavioral, leetcode, and project
  • PDF resume ingestion (client-side text extraction via pdfjs-dist)
  • Streaming chat with OpenAI for real-time responses
  • Enforced interview type with a server-side system directive for consistency
  • Cost controls: GPT‑3.5 default, lower temperature, max token caps, history windowing, and resume trimming
  • In-memory rate limiter and response cache to reduce usage/costs
  • Local chat history saved to the browser (localStorage)
  • Clean chat UI with type switching and history viewer

Tech Stack

  • Framework: Next.js 13 (App Router), React 18, TypeScript
  • Styling: Tailwind CSS + custom CSS
  • AI: OpenAI Chat Completions (via openai + ai streaming helpers)
  • PDFs: pdfjs-dist for client-side text extraction
  • Deployment: Vercel (Edge runtime for API streaming)

Quick Start

Prerequisites:

  • Node.js 18+ and npm
  • An OpenAI API key

Setup:

  1. Clone the repository
  2. Install dependencies
  3. Create a .env file with your OpenAI key
  4. Run the dev server

Commands:

npm install
echo "OPENAI_API_KEY=sk-..." > .env
npm run dev

Available scripts:

  • npm run dev – start the dev server
  • npm run build – build for production
  • npm run start – run the production build
  • npm run lint – run ESLint

Environment variables:

  • OPENAI_API_KEY (required)

How it works

  • You upload a resume (PDF). Text is extracted client-side and kept in memory/localStorage on the client.
  • You choose an interview type. The app crafts a system prompt according to that mode and includes trimmed resume context.
  • Messages are streamed from the Edge API route using OpenAI Chat Completions.
  • The server enforces the selected interview type and applies cost controls (model, temperature, max tokens).
  • A simple in-memory rate limiter and response cache reduce repeated usage and costs.

Architecture

flowchart TD
    %% Client
    subgraph Client["Next.js Client (App Router)"]
        Page["app/page.tsx"]
        ChatPage["app/chat/page.tsx"]
        RequestForm["RequestForm.tsx<br/>(PDF → text via pdfjs-dist)"]
        Chat["Chat.tsx<br/>(UI, history windowing, resume trim)"]
        Markdown["MarkdownRenderer.tsx"]
        ChatHistory["ChatHistory.tsx"]
        LocalStorage["localStorage<br/>resume, interviewType, sessions"]
    end

    %% Server
    subgraph Server["Edge API Routes"]
        Route["app/api/openai-gpt/route.ts<br/>(OpenAIStream, system guard)"]
        RateLimiter["utils/rateLimiter.ts<br/>(in-memory)"]
        Cache["utils/responseCache.ts<br/>(in-memory, TTL)"]
    end

    %% External
    subgraph OpenAI["OpenAI API"]
        Completions["Chat Completions"]
    end

    subgraph Assets["Static Assets"]
        Public["public/*<br/>(avatars)"]
    end

    subgraph Deploy["Vercel"]
        Edge["Vercel Edge Runtime"]
        Env["OPENAI_API_KEY"]
    end

    %% Flows
    RequestForm -->|Extract text| LocalStorage
    Page --> LocalStorage
    Page --> Chat
    ChatPage --> Chat
    Chat -->|streaming fetch| Route
    Route --> RateLimiter
    Route --> Cache
    Cache -->|hit → return cached| Route
    Route -->|OpenAIStream| Completions
    Completions -->|tokens stream| Route
    Route -->|stream + rate-limit headers| Chat
    Chat --> ChatHistory
    Page --> Public
    Edge --- Route
    Env --- Route
Loading

Runtime message flow

sequenceDiagram
    participant U as User (Browser)
    participant C as Chat.tsx (Client)
    participant R as API Route (route.ts)
    participant L as RateLimiter
    participant X as Cache
    participant O as OpenAI

    U->>C: Send message
    C->>R: POST /api/openai-gpt (messages, interviewType)
    R->>L: check()
    L-->>R: allow/deny
    R->>X: get(lastUserMessageKey)
    alt cache hit
        X-->>R: cached response
        R-->>C: stream cached response + headers
    else cache miss
        R->>O: stream completion (system + user history)
        O-->>R: token stream
        R->>X: put(key, response, TTL)
        R-->>C: stream response + rate-limit headers
    end
    C-->>U: Render streaming tokens
Loading

Project structure

app/
	api/openai-gpt/route.ts       # Edge API: streaming to OpenAI, cost guard, rate limit, cache
	components/
		Chat.tsx                    # Chat UI, history windowing, rate-limit UI
		ChatHistory.tsx             # Local session viewer
		MarkdownRenderer.tsx        # Markdown + code highlighting
		RequestForm.tsx             # PDF → text, interview type selector
		Wrapper.tsx                 # Home page wrapper
	chat/page.tsx                 # Chat page
	globals.css                   # Global styles + imports
	chat-page.css                 # Chat layout styles
	clean-chat.css                # Chat visual polish
	chat-history.css              # History drawer styles
	layout.tsx                    # Root layout & metadata
	page.tsx                      # Home page
	utils/
		fetchOpenAIResponse.ts      # Streaming fetch helper
		rateLimiter.ts              # In-memory rate limiter
		responseCache.ts            # In-memory response cache (TTL)
public/
	bob.jpg, user-avatar.jpg      # Avatars

Cost controls and limits

  • Model: defaults to gpt-3.5-turbo-1106 (see app/api/openai-gpt/route.ts)
  • Temperature: 0.5 to reduce rambling
  • Max tokens: tighter caps (e.g., ~400 for LeetCode, ~180 for others)
  • History windowing: keeps first system + last ~8 messages
  • Resume trimming: limits resume context to ~2000 chars
  • Rate limiting: 20 requests/hour per (cookie) session by default
  • Response cache: 24h TTL, up to 100 recent keys (last user message)

Customization

  • Change model/temperature/tokens in app/api/openai-gpt/route.ts
  • Adjust rate limits in app/utils/rateLimiter.ts
  • Tune cache TTL/size in app/utils/responseCache.ts
  • Update interview prompts in app/components/Chat.tsx (getSystemPrompt)

Deployment (Vercel)

  1. Push to GitHub (ensure .env is not committed)
  2. Import the repo in Vercel
  3. Set Environment Variable OPENAI_API_KEY
  4. Deploy (build uses Next.js App Router defaults)

Notes:

  • The API route runs on the Edge runtime for low-latency streaming
  • Consider moving rate limit/cache to Redis for production

Privacy

  • Resume text is extracted client-side. The trimmed resume content and your chat messages are sent to the API route to generate responses.
  • No server-side database is used here; rate limiting and caching are in-memory.

Troubleshooting

  • PDF text didn’t extract: The PDF may be scanned (image-based). Try a text-based PDF.
  • Streaming doesn’t start: Check your OPENAI_API_KEY and that your account has access/credits.
  • Rate limit reached: Wait until the reset time shown in the UI or reduce frequency.
  • Build warnings: You can safely ignore minor Next.js metadata warnings; they don’t affect functionality.

Contributing

Contributions are welcome!

  1. Fork the repository and create a feature branch
  2. Make changes and keep them focused (small PRs are easier to review)
  3. Run lint/build locally to validate
  4. Open a Pull Request with a clear description and screenshots when UI changes

Guidelines:

  • Use clear commit messages (e.g., feat:, fix:, docs:, refactor:)
  • Don’t commit secrets or .env
  • Keep formatting consistent; run npm run lint
  • Prefer small, incremental changes over large refactors

Future scope / Roadmap

  • Move rate limiter and cache from memory to Redis for production
  • Add export/share for transcripts (Markdown/PDF)
  • Model selector (with quotas) and temperature controls in UI
  • i18n support and accessibility improvements (ARIA, keyboard nav)
  • UI performance: dynamic import for syntax highlighter
  • Session persistence across devices (optional server store)
  • Conversation starters and structured evaluation rubrics
  • Add tests (unit/integration) and CI for lint/build
  • Optional: theme support and CSS consolidation

License

This project is licensed under the MIT License. See LICENSE for details.

Acknowledgements

  • Next.js, React, Tailwind CSS
  • OpenAI API and the ai streaming helpers
  • pdfjs-dist for client-side PDF text extraction
  • react-markdown and react-syntax-highlighter

Happy coding — 👨‍💻

About

A web app to practice interviews (behavioral, coding/LeetCode, and project deep-dives) with streaming AI responses. It supports PDF resume ingestion, strict interview-type enforcement, and cost controls via rate limiting, caching, and token management.

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published