Architecture

How the code works.

High-Level Overview

┌─────────────────────────────────────────────────┐
│           CLI Entry Point (index.ts)             │
│  - Loads config                                  │
│  - Validates environment                         │
│  - Starts QuizHelper                             │
└─────────────────┬───────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────┐
│         QuizHelper (ai-quiz-automation.ts)              │
│  Main orchestration loop:                        │
│  1. Connect to browser                           │
│  2. While questions exist:                       │
│     - Extract question                           │
│     - Get AI answer                              │
│     - Click answer                               │
│     - Click confirm                              │
└────────┬──────────────────────┬─────────────────┘
         │                      │
         ▼                      ▼
┌──────────────────┐   ┌──────────────────┐
│  BrowserHelper   │   │    AIHelper      │
│  (browser.ts)    │   │    (ai.ts)       │
│                  │   │                  │
│ Controls Chrome  │   │ Talks to OpenAI  │
│ via Playwright   │   │                  │
└────────┬─────────┘   └────────┬─────────┘
         │                      │
         ▼                      ▼
┌──────────────────┐   ┌──────────────────┐
│  Chrome Browser  │   │   OpenAI API     │
└──────────────────┘   └──────────────────┘

Key Components

1. CLI Entry Point (src/index.ts)

The script that runs when you execute npm start.

Responsibilities:

2. QuizHelper (src/ai-quiz-automation.ts)

The main coordinator that runs the automation loop.

Responsibilities:

Key method: start() - The main loop

3. BrowserHelper (src/browser.ts)

Handles all browser interactions via Playwright.

Key methods:

Human-like behavior:

4. AIHelper (src/ai.ts)

Interfaces with OpenAI to analyze questions.

Key method:

How it works:

  1. Builds a prompt with question text and answer options
  2. Instructs AI to identify if it’s single or multi-select
  3. Uses structured output (Zod schema) to ensure valid response
  4. Returns answer index/indices and reasoning

AI Instructions:

5. Type Definitions (src/types.ts)

TypeScript interfaces for type safety:

Data Flow

1. User runs: npm start

2. index.ts loads config.json and .env
   └─> Creates QuizHelper instance

3. QuizHelper.start() begins
   └─> BrowserHelper.connect()
       └─> Connects to Chrome on port 9222

4. Main loop begins:
   
   ┌─> BrowserHelper.hasMoreQuestions()
   │   └─> Checks if question container exists
   │
   ├─> BrowserHelper.extractQuestion()
   │   ├─> Finds question container
   │   ├─> Extracts all text content
   │   ├─> Finds all answer buttons
   │   └─> Returns Question object
   │
   ├─> BrowserHelper.simulateReading()
   │   └─> Waits 4-8 seconds with micro-delays
   │
   ├─> AIHelper.analyzeQuestion()
   │   ├─> Builds prompt
   │   ├─> Calls OpenAI API
   │   ├─> Parses structured response
   │   └─> Returns AIResponse
   │
   ├─> BrowserHelper.clickAnswer(index)
   │   ├─> Waits 800-2000ms
   │   ├─> Maybe hesitates (15% chance)
   │   └─> Clicks the button
   │
   └─> BrowserHelper.clickConfirm()
       ├─> Waits 1200-2500ms
       ├─> Clicks confirm button
       └─> Waits for next page (1500-2500ms)

5. Loop continues until hasMoreQuestions() returns false

6. Browser disconnects, process exits

Design Decisions

Why Chrome DevTools Protocol?

Using CDP (via Playwright’s connectOverCDP) lets us:

Alternative would be launching a new browser, which would require re-authentication for each run.

Why Random Delays?

To make automation less detectable:

Why Configurable Selectors?

Every quiz site has different HTML structure. Making selectors configurable means:

Why TypeScript?

Why OpenAI’s Structured Output?

Using generateObject() with a Zod schema ensures:

Extension Points

Want to modify the tool? Here’s what to change:

Use a Different AI Provider

Edit src/ai.ts:

Add More Human-Like Behaviors

Edit src/browser.ts:

Support Different Question Types

Edit src/ai.ts:

Add Logging/Analytics

Edit src/ai-quiz-automation.ts:

Security

API Key Handling

No Vulnerable Dependencies

Project uses:

Minimal Permissions

The tool only:

File Structure

ai-quiz-automation/
├── src/
│   ├── index.ts          # Entry point
│   ├── ai-quiz-automation.ts    # Main orchestrator
│   ├── browser.ts        # Browser automation
│   ├── ai.ts             # OpenAI integration
│   └── types.ts          # TypeScript interfaces
├── test/
│   └── config-validation.ts  # Config checker
├── docs/
│   ├── SETUP.md          # Installation guide
│   ├── ADAPTING.md       # How to adapt for your site
│   ├── CONFIG.md         # Configuration reference
│   ├── TROUBLESHOOTING.md  # Common problems
│   └── ARCHITECTURE.md   # This file
├── config.example.json   # Example configuration
├── example-quiz.html     # Test quiz page
├── package.json          # Dependencies & scripts
└── tsconfig.json         # TypeScript config

Build Process

npm run build

This runs TypeScript compiler (tsc) which:

  1. Reads tsconfig.json
  2. Compiles all .ts files in src/
  3. Outputs to dist/ directory
  4. Includes type checking and error reporting

The compiled JavaScript in dist/ is what actually runs when you use npm start.