Skip to content

Aimagine-life/pdf-analyzer

Repository files navigation

⚡ AuditAI

AI-аудит продающих документов · AI audit for sales documents

🇷🇺 Русский · 🇬🇧 English

Node.js TypeScript React Vite OpenRouter License: MIT

🌐 Live: pdf.supabots.ru


🇷🇺 Русский

Загружаешь PDF — презентацию, коммерческое предложение или лендинг — получаешь жёсткий аудит от ИИ по трём осям: дизайн, копирайтинг, продающая психология. Ответ честный, с конкретными цитатами из документа, готовыми улучшениями текста и приоритизированным планом действий.

✨ Что внутри

  • 🎯 Многогранный анализ. Модель видит страницы PDF как изображения, оценивает общую эффективность 0–100 и разбирает:

    • визуальную иерархию, слепые зоны, читаемость;
    • копирайтинг — слабые заголовки, клише, отсутствие выгод;
    • продающую психологию — барьеры клиента, недостающие приёмы убеждения;
    • конкретные переписывания текста с обоснованием;
    • план действий с приоритетами High / Medium / Low.
  • 🔀 Гибридная цепочка моделей. Сначала пробуем бесплатные vision-модели OpenRouter — если все четыре упали (rate-limit, timeout, schema fail), включается платный google/gemini-3-flash-preview, который принимает PDF нативно одним файлом (~$0.01–0.05 за анализ). В 90% случаев хватает бесплатных.

  • 📺 Живой прогресс через SSE. Вместо тупого спиннера — «Готовим страницу 4 из 10», «Анализируем — модель 2 из 5 (Gemma 4 31B)», «Модель не ответила, переходим к следующей». Никаких «крутится и непонятно».

  • 🔒 Секреты только на сервере. Фронт не знает про OpenRouter в принципе — ни в бандле, ни в DevTools. Бэкенд слушает исключительно на 127.0.0.1, наружу торчит через reverse-proxy того же домена.

  • 📄 Умный лимит страниц. Для документов >10 страниц показывается предупреждение перед анализом и пометка «Проанализировано 10 из 23 страниц» в шапке отчёта. Никаких «тихих» обрезаний.

  • 💾 История на клиенте. Все прошлые отчёты хранятся в localStorage браузера. Бэкенд stateless — никаких файлов на диске, никакой БД.

🏗 Архитектура

flowchart LR
    Browser["🌐 Браузер<br/>React 19 + Vite<br/>SPA"]
    Nginx["Nginx<br/>reverse-proxy + SSL"]
    Node["Node.js Backend<br/>Express + SSE"]
    OR["OpenRouter<br/>vision + file models"]

    Browser -- "POST /api/analyze<br/>multipart PDF" --> Nginx
    Nginx --> Node
    Node -- "HTTPS<br/>fallback chain" --> OR
    OR -- "JSON" --> Node
    Node -- "SSE stream<br/>stage · render_progress<br/>attempt · result · error" --> Browser
Loading

Поток:

  1. Фронт отдаёт PDF multipart'ом на POST /api/analyze.
  2. Бэкенд проверяет magic-байты %PDF-, парсит через pdfjs-dist + @napi-rs/canvas (без системных зависимостей).
  3. Для каждой модели в цепочке: рендерит страницы в JPEG (для vision-моделей) или кодирует PDF в base64 (для file-capable платных), вызывает OpenRouter с response_format: json_object, валидирует ответ через zod.
  4. Между попытками — SSE события attempt / attempt_failed. Успех → событие result с финальным AuditResult, включая метаданные (имя модели, сколько страниц проанализировано).
  5. Фронт стримит события через fetch().body.getReader() + ручной SSE-парсер, обновляет ProgressView в реальном времени.

🧩 Стек

Слой Технологии
Фронт React 19, Vite 6, TypeScript 5.8, Tailwind CSS, Recharts, Lucide, pdfjs-dist (lazy)
Бэк Node.js 20+, Express 4, Multer, pdfjs-dist (legacy ESM), @napi-rs/canvas, zod, dotenv
LLM OpenRouter: nvidia/nemotron-nano-12b-v2-vl:free, google/gemma-4-*:free, google/gemma-3-27b-it:free, google/gemini-3-flash-preview (paid fallback)
Тесты Vitest (32 unit-тестa)
Деплой systemd unit, nginx reverse-proxy, Let's Encrypt

🚀 Локальный запуск

Требуется Node.js 20+ и npm. Понадобится API-ключ OpenRouter — получить бесплатно на openrouter.ai/keys.

# 1. Зависимости фронта
npm ci

# 2. Зависимости и .env бэкенда
cd server
npm ci
cp .env.example .env
# открой server/.env и впиши реальный OPENROUTER_API_KEY

# 3. Запустить бэкенд (один терминал)
npm run dev
# слушает http://127.0.0.1:3217

# 4. Запустить фронт (другой терминал, из корня репо)
cd ..
npm run dev
# открывается на http://localhost:3000 с dev-прокси /api → 3217

Открывай http://localhost:3000 и загружай PDF.

🧪 Тесты бэкенда

cd server && npm test

Ожидается 32+ passing (parseJsonLoose, zod-схемы, цепочка фолбеков, классификация ошибок, рендер PDF, file/image режимы).

📁 Структура

.
├── App.tsx                     # монолитный корень фронта
├── components/
│   ├── FileUpload.tsx          # дропзона + подсказка о 10 страницах
│   ├── ProgressView.tsx        # живой SSE-прогресс
│   ├── ReportCard.tsx          # карточка одной секции отчёта
│   ├── SaaSSections.tsx        # блок «об авторе»
│   └── ...
├── services/
│   ├── analyzeService.ts       # POST /api/analyze + SSE-парсер
│   ├── historyService.ts       # localStorage история
│   └── pdfService.ts           # экспорт отчёта в PDF (html2canvas + jsPDF)
├── server/
│   ├── src/
│   │   ├── index.ts            # Express bootstrap
│   │   ├── config.ts           # ENV loader
│   │   ├── routes/analyze.ts   # POST /api/analyze + /api/health
│   │   └── lib/
│   │       ├── openrouter.ts   # цепочка моделей, image/file режимы
│   │       ├── pdfRender.ts    # PDF → JPEG через pdfjs-dist
│   │       ├── prompts.ts      # system + user промпты
│   │       ├── sse.ts          # Server-Sent Events helper
│   │       └── validate.ts     # zod-схемы + parseJsonLoose
│   └── .env.example            # шаблон без секретов
├── scripts/
│   ├── deploy.sh               # tar-pipe деплой через SSH
│   ├── deploy.env.example      # шаблон
│   └── auditai.service.template # systemd unit
└── docs/superpowers/
    ├── specs/                  # дизайн-спецификация миграции
    └── plans/                  # пошаговый план реализации

🌍 Деплой на VPS

  1. Скопируй scripts/deploy.env.examplescripts/deploy.env.gitignore), заполни VPS_HOST, VPS_USER, VPS_REMOTE_PATH.
  2. На VPS положи .env с настоящим OPENROUTER_API_KEY в $VPS_REMOTE_PATH/server/.env (chmod 600, вне веб-корня).
  3. Поставь systemd unit из scripts/auditai.service.template.
  4. Настрой nginx vhost — пример location-блока с proxy_buffering off и proxy_read_timeout 360s см. в спецификации.
  5. ./scripts/deploy.sh — собирает, заливает, рестартит сервис, делает health-check.

Минимальные требования VPS: Ubuntu 22.04+ / Debian 12, 2 GB RAM, Node 20+, nginx, certbot.

🛡 Безопасность

  • Никаких секретов в git-истории и во фронт-бандле. Проверяется через grep -r "sk-or" dist/ на каждый билд.
  • Backend слушает только 127.0.0.1:PORT.
  • Upload лимит 20 MB, валидация magic-байтов %PDF- до парсинга.
  • Санитизация пользовательского контекста (audience / goal) перед интерполяцией в промпт.
  • CORS не нужен — фронт и бэк на одном origin через nginx.

📜 Лицензия

MIT — делай что хочешь, но на свой страх и риск.


🇬🇧 English

Upload a PDF — a pitch deck, sales proposal or landing page — and get a brutal AI audit across three axes: design, copywriting, sales psychology. Honest answers, specific quotes from your document, ready-to-use rewrites and a prioritised action plan.

✨ What's inside

  • 🎯 Multi-angle analysis. The model sees PDF pages as images, scores overall effectiveness 0–100 and dissects:

    • visual hierarchy, blind spots, readability;
    • copywriting — weak headlines, clichés, missing benefits;
    • sales psychology — customer barriers, missing persuasion techniques;
    • concrete text rewrites with reasoning;
    • action plan with High / Medium / Low priorities.
  • 🔀 Hybrid fallback chain. First tries free OpenRouter vision models — if all four fail (rate-limit, timeout, schema mismatch), activates paid google/gemini-3-flash-preview which accepts the PDF natively as a single file (~$0.01–0.05 per analysis). Free tier is enough in ~90% of cases.

  • 📺 Live SSE progress. No silent spinner — real status: "Rendering page 4 of 10", "Analysing — model 2 of 5 (Gemma 4 31B)", "Model didn't respond, moving on". You always know what's happening.

  • 🔒 Secrets on the server only. Frontend has zero knowledge of OpenRouter — nothing in the bundle, nothing in DevTools. Backend listens only on 127.0.0.1, exposed externally only via reverse-proxy on the same domain.

  • 📄 Smart page cap. For documents longer than 10 pages, a warning pops up before analysis and a "10 of 23 pages analysed" badge appears in the report header. No silent truncation.

  • 💾 Client-side history. All past reports live in browser localStorage. The backend is stateless — no files on disk, no database.

🏗 Architecture

flowchart LR
    Browser["🌐 Browser<br/>React 19 + Vite<br/>SPA"]
    Nginx["Nginx<br/>reverse-proxy + SSL"]
    Node["Node.js Backend<br/>Express + SSE"]
    OR["OpenRouter<br/>vision + file models"]

    Browser -- "POST /api/analyze<br/>multipart PDF" --> Nginx
    Nginx --> Node
    Node -- "HTTPS<br/>fallback chain" --> OR
    OR -- "JSON" --> Node
    Node -- "SSE stream<br/>stage · render_progress<br/>attempt · result · error" --> Browser
Loading

Flow:

  1. Frontend sends the PDF as multipart to POST /api/analyze.
  2. Backend verifies %PDF- magic bytes, parses via pdfjs-dist + @napi-rs/canvas (no system deps).
  3. For each model in the chain: renders pages to JPEG (for vision models) or base64-encodes the whole PDF (for file-capable paid models), calls OpenRouter with response_format: json_object, validates response with zod.
  4. Between attempts — SSE events attempt / attempt_failed. Success → result event with final AuditResult including metadata (which model served, how many pages analysed).
  5. Frontend streams events via fetch().body.getReader() + hand-rolled SSE parser, updates ProgressView in real time.

🧩 Stack

Layer Tech
Frontend React 19, Vite 6, TypeScript 5.8, Tailwind CSS, Recharts, Lucide, pdfjs-dist (lazy)
Backend Node.js 20+, Express 4, Multer, pdfjs-dist (legacy ESM), @napi-rs/canvas, zod, dotenv
LLM OpenRouter: nvidia/nemotron-nano-12b-v2-vl:free, google/gemma-4-*:free, google/gemma-3-27b-it:free, google/gemini-3-flash-preview (paid fallback)
Tests Vitest (32 unit tests)
Deploy systemd unit, nginx reverse-proxy, Let's Encrypt

🚀 Local development

Requires Node.js 20+ and npm. You'll need an OpenRouter API key — free at openrouter.ai/keys.

# 1. Frontend deps
npm ci

# 2. Backend deps and .env
cd server
npm ci
cp .env.example .env
# open server/.env and paste your OPENROUTER_API_KEY

# 3. Run backend (terminal 1)
npm run dev
# listens on http://127.0.0.1:3217

# 4. Run frontend (terminal 2, from repo root)
cd ..
npm run dev
# opens at http://localhost:3000 with dev proxy /api → 3217

Open http://localhost:3000 and upload a PDF.

🧪 Backend tests

cd server && npm test

Expect 32+ passing (parseJsonLoose, zod schemas, fallback chain, error classification, PDF rendering, file/image modes).

📁 Layout

.
├── App.tsx                     # monolithic frontend root
├── components/
│   ├── FileUpload.tsx          # dropzone + 10-page hint
│   ├── ProgressView.tsx        # live SSE progress
│   ├── ReportCard.tsx          # single report section card
│   ├── SaaSSections.tsx        # author bio block
│   └── ...
├── services/
│   ├── analyzeService.ts       # POST /api/analyze + SSE parser
│   ├── historyService.ts       # localStorage history
│   └── pdfService.ts           # report export to PDF (html2canvas + jsPDF)
├── server/
│   ├── src/
│   │   ├── index.ts            # Express bootstrap
│   │   ├── config.ts           # ENV loader
│   │   ├── routes/analyze.ts   # POST /api/analyze + /api/health
│   │   └── lib/
│   │       ├── openrouter.ts   # model chain, image/file modes
│   │       ├── pdfRender.ts    # PDF → JPEG via pdfjs-dist
│   │       ├── prompts.ts      # system + user prompts
│   │       ├── sse.ts          # Server-Sent Events helper
│   │       └── validate.ts     # zod schemas + parseJsonLoose
│   └── .env.example            # template without secrets
├── scripts/
│   ├── deploy.sh               # tar-pipe deploy over SSH
│   ├── deploy.env.example      # template
│   └── auditai.service.template # systemd unit
└── docs/superpowers/
    ├── specs/                  # migration design spec
    └── plans/                  # step-by-step implementation plan

🌍 VPS deployment

  1. Copy scripts/deploy.env.examplescripts/deploy.env (gitignored), fill in VPS_HOST, VPS_USER, VPS_REMOTE_PATH.
  2. On the VPS put .env with a real OPENROUTER_API_KEY at $VPS_REMOTE_PATH/server/.env (chmod 600, outside web root).
  3. Install the systemd unit from scripts/auditai.service.template.
  4. Configure nginx vhost — location block with proxy_buffering off and proxy_read_timeout 360s, see spec.
  5. ./scripts/deploy.sh — builds, uploads, restarts the service, runs health check.

Minimum VPS specs: Ubuntu 22.04+ / Debian 12, 2 GB RAM, Node 20+, nginx, certbot.

🛡 Security

  • Zero secrets in git history or frontend bundle. Verified with grep -r "sk-or" dist/ on every build.
  • Backend listens only on 127.0.0.1:PORT.
  • 20 MB upload limit, %PDF- magic-byte validation before parsing.
  • User context (audience / goal) sanitised before prompt interpolation.
  • No CORS needed — frontend and backend on the same origin via nginx.

📜 License

MIT — do whatever you want, at your own risk.


Author: Konstantin · YouTube · Telegram

About

AI audit for sales PDFs — design, copy and sales-psychology critique via OpenRouter free+paid vision models, with SSE live progress. Live at pdf.supabots.ru

Topics

Resources

License

Stars

1 star

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors