Я собрал онлайн генератор коммерческих предложений: 12 слайдов, GPT-4o и админка без деплоя
Ручная подготовка КП для каждого клиента - это узкое место, которое убивает одновременно скорость и качество. Я прошёл через это и понял: нужен онлайн генератор коммерческих предложений, который работает как код - персонализированный, воспроизводимый, с настройками через UI.
В итоге получился kp-generator — модуль внутри платформы germanyun.online, который превращает результаты диагностического звонка в полноценную, персонализированную презентацию из 12 слайдов. Под капотом: Next.js, Supabase, GPT-4o, двухфазная генерация промтов и полная админ-панель для тонкой настройки каждого слайда.
Почему КП — это продуктовая задача, а не дизайнерская
Началось всё с простого вопроса: почему конверсия после диагностического звонка не такая, как хотелось бы? Ответ оказался неожиданным — не потому что плохо ведём встречи, а потому что КП после них выглядит как типовой документ, а не как точный ответ на боль конкретного клиента.
Я провёл небольшое исследование: изучил структуры B2B-презентаций по материалам Gong (67К записей звонков), Prospeo 2026, Brixon Group, подходы McKinsey и Forrester. Ключевой вывод — персонализация даёт 3.2x рост конверсии. Не просто «вставить имя клиента», а реально отвечать на конкретные боли, которые он озвучил на звонке.
При этом каждый слайд должен работать по своей логике: титул с обещанием, точка А (где клиент сейчас), цена бездействия, before/after по релевантным модулям, социальные доказательства, ROI-расчёт, оффер. Это не «красивый PDF», это нарративная структура с конкретной целью.
Архитектурно задача звучала так: взять транскрипт звонка → обработать существующим промтом → получить структурированную диагностику → объединить с данными программы → сгенерировать 12 персонализированных Stitch-промтов → получить слайды.
Архитектура: от транскрипта до слайда
Первое решение, которое пришло в голову — сделать «набор промтов в документе». Быстро, без кода. Но это тупик: нет воспроизводимости, нет версионирования, нет возможности итерировать на основе данных.
Поэтому выбрал путь полноценного модуля. Вот итоговая схема:
Транскрипт звонка
↓ (существующий GPT-промт)
Структурированная диагностика (pointA[], keyFindings[])
+
program-content.ts (10 модулей программы)
+
Реальные кейсы клиентов
+
Данные клиента (имя, бизнес, тариф)
↓
МЕТА-ПРОМТ (двухфазная генерация)
↓
12 персонализированных Stitch-промтов
↓
Готовые слайды презентации
Двухфазная генерация — ключевое архитектурное решение. Фаза 1: мета-промт анализирует диагностику и определяет какие боли наиболее критичны для этого клиента, какие кейсы релевантны, какой тариф рекомендовать. Фаза 2: на основе этого контекста генерируются конкретные промты для каждого слайда с подставленными данными.
Почему не один промт на всё? Потому что контекстное окно ограничено, и качество сильно падает когда просишь GPT сделать 12 разных вещей за раз. Разбивка на фазы даёт лучший контроль над каждым элементом.
База данных: схема kp в Supabase
Для хранения всего, что связано с KP-модулем, создал отдельную схему kp в Supabase. Пять таблиц:
-- Конфигурация слайдов
CREATE TABLE kp.slides (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
order_index integer NOT NULL,
title text NOT NULL,
is_active boolean DEFAULT true,
prompt_template text NOT NULL,
created_at timestamptz DEFAULT now()
);
-- Дизайн-система
CREATE TABLE kp.design_settings (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
key text UNIQUE NOT NULL,
value text NOT NULL
);
-- Кейсы клиентов
CREATE TABLE kp.cases (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
client_name text NOT NULL,
business_type text,
result_text text NOT NULL,
is_active boolean DEFAULT true
);
-- Настройки промтов
CREATE TABLE kp.prompt_settings (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
key text UNIQUE NOT NULL,
value text NOT NULL
);
-- Сгенерированные КП
CREATE TABLE kp.generated_kps (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
client_name text NOT NULL,
generated_prompts jsonb,
metadata jsonb,
created_at timestamptz DEFAULT now()
);Отдельная схема вместо таблиц в public — это сознательный выбор. Изолирует KP-логику, проще управлять правами через PostgREST, и не засоряет основную схему.
Seed-данные включают 12 дефолтных слайдов с детальными Stitch-промтами и настройками дизайн-системы (цвета, шрифты, отступы).
Backend: 6 API роутов
Весь backend — это 6 Next.js API Routes под /api/generator/kp/:
GET/POST /slides— список слайдов и создание новогоPUT/DELETE /slides/[id]— обновление и удаление слайдаPOST /slides/reorder— изменение порядка (drag-and-drop)GET/PUT /design— дизайн-настройкиGET/PUT /cases— кейсы клиентовGET/PUT /settings— настройки промтовPOST /generate— основной эндпоинт генерации КП
Ключевой роут — /generate. Принимает данные клиента + результаты диагностики, запускает двухфазную генерацию, возвращает массив промтов для каждого слайда:
// app/api/generator/kp/generate/route.ts
export async function POST(req: Request) {
const { clientData, diagnosticResults } = await req.json();
// Фаза 1: анализ контекста
const contextAnalysis = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: META_PROMPT },
{ role: 'user', content: JSON.stringify({ clientData, diagnosticResults }) }
]
});
const context = JSON.parse(contextAnalysis.choices[0].message.content);
// Фаза 2: генерация промтов для каждого слайда
const slides = await getActiveSlides(); // из Supabase
const generatedPrompts = await Promise.all(
slides.map(slide => generateSlidePrompt(slide, context, clientData))
);
// Сохраняем результат
await saveGeneratedKP(clientData.name, generatedPrompts, context);
return Response.json({ prompts: generatedPrompts });
}Функция generateSlidePrompt берёт шаблон из БД и интерполирует плейсхолдеры — {{client_name}}, {{business_type}}, {{top_pain}}, {{relevant_case}} и т.д. Здесь была одна из ранних ошибок: шаблон для слайда с ROI-расчётом содержал {{monthly_loss}}, который мог быть undefined если диагностика не выявила чётких финансовых потерь. Добавил fallback-логику и проверку обязательных полей перед генерацией.
Frontend: трёхтабный layout
Пользовательский интерфейс разбит на три таба, добавленных поверх существующего визарда генератора:
- Документы — существующий PDF-генератор (диагностика, КП-документ, дорожная карта)
- Презентация — новый KP-модуль с формой клиента и просмотром промтов
- Админ — полная настройка системы
Стейт шарится между табами через React Context. Это позволяет, например, заполнить данные клиента в «Презентации» и не терять их при переключении в «Админ» для проверки настроек.
// context/KPContext.tsx
interface KPContextType {
clientData: ClientData;
setClientData: (data: ClientData) => void;
generatedPrompts: SlidePrompt[] | null;
isGenerating: boolean;
generate: () => Promise<void>;
}
export const KPContext = createContext<KPContextType | null>(null);Админ-панель: тонкая настройка через UI
Админ-панель — это то, ради чего всё и затевалось. Четыре секции:
Слайды — drag-and-drop менеджер с inline-редактором. Можно менять порядок слайдов, включать/выключать отдельные, редактировать шаблон промта прямо в браузере без деплоя.
┌─────────────────────────────────────────────────────┐
│ Слайды презентации [+ Добавить] │
│─────────────────────────────────────────────────────│
│ ≡ 1. Титул + Обещание 🟢 [✏️] [🗑️] │
│ ≡ 2. Контекст рынка 🟢 [✏️] [🗑️] │
│ ≡ 3. Точка А клиента 🟢 [✏️] [🗑️] │
│ ≡ 4. Цена бездействия 🟡 [✏️] [🗑️] │
│ ≡ 5. Before / After 🟢 [✏️] [🗑️] │
└─────────────────────────────────────────────────────┘
Дизайн-система — настройка визуального стиля. Цвет акцента (выбрали насыщенный благородный красный), шрифты, отступы — всё через UI, сохраняется в kp.design_settings.
Кейсы — управление реальными историями успеха клиентов. Их подставляет AI в релевантные слайды.
Настройки промтов — параметры мета-промта: тон, длина описаний, акценты в нарративе.
Главная ценность: я могу итерировать на промтах и структуре слайдов без единой строки кода и без деплоя. Это критично для экспериментов с конверсией.
Деплой: Dokploy и ручной триггер
Деплой проходил через Dokploy на VPS. Пуш в main должен был автоматически триггерить деплой через вебхук, но после нескольких коммитов обнаружилось, что контейнер не обновился — вебхук не сработал.
Диагностика показала: Dokploy не знал о новой ветке. Пришлось:
- Убедиться что вебхук настроен на нужную ветку
- Запустить деплой вручную через API Dokploy
- Отслеживать логи билда через SSH
Билд занял около 4 минут (клонирование + npm ci + next build). После завершения все 6 KP API роутов появились в /api/generator/kp/*, страница /generator с тремя табами отдавала 200.
Полезный урок: всегда проверяй что вебхук деплоя привязан к нужной ветке, особенно после реорганизации репозитория.
Что получилось: 21 файл, 3261 строка
За несколько сессий разработки (от идеи до деплоя) получили:
- 5 таблиц в Supabase схеме
kp - 6 API роутов с полным CRUD и генерацией
- 12 дефолтных слайдов с детальными Stitch-промтами
- Трёхтабный UI с общим стейтом
- Полная админ-панель — слайды, дизайн, кейсы, настройки
- 21 файл, 3261 строк нового кода
- 2 коммита в
main, автодеплой через Dokploy
Визуальный стиль: светлый минимал, акцентный цвет — насыщенный благородный красный. Структура слайдов — гибрид из Data-Driven Spine (Gong) и нарративного подхода: обещание → контекст рынка → точка А → цена бездействия → before/after → кейсы → ROI → оффер.
Выводы и уроки
Главный урок этого проекта — итерируемость важнее идеальности. Когда промты живут в БД и редактируются через UI, я могу за 10 минут протестировать другой нарратив на следующем клиенте. Если бы они были захардкожены в коде, каждый эксперимент требовал бы PR и деплоя.
Второй урок — двухфазная генерация бьёт одно большое задание. Это контринтуитивно: кажется, что один промт «сделай КП» проще. Но качество ответа на 12 разных задач в одном контексте значительно ниже, чем последовательное: сначала «пойми клиента», потом «напиши этот конкретный слайд с этим конкретным контекстом». GPT-4o работает лучше когда задача сфокусирована.
Третий урок — отдельная схема в БД для фичи стоит своих затрат. Изоляция kp.* от основного public.* сделала работу чище: отдельные права, отдельный PostgREST-эндпоинт, нет риска случайно задеть другие таблицы. Когда фича разрастается — это окупается.
Четвёртый урок — деплой нужно проверять сразу после пуша. Мы обнаружили что вебхук не сработал только когда пошли проверять результат. Следующий шаг — добавить мониторинг деплоя: после каждого пуша в main автоматически дёргать /api/health и сравнивать версию сборки. Это сэкономит время диагностики.
По сути, kp-generator — это хороший пример того, как AI-фича должна быть устроена в продакшене: не просто «вызвать GPT», а полноценная система с версионированием промтов, настройками через UI, логированием результатов и возможностью итерировать без кода. Именно такой подход позволит со временем оптимизировать конверсию на основе реальных данных, а не интуиции.

AI-инженер, предприниматель, маркетолог. Основатель feberra.com и x10seo.ru. 13 лет в перфоманс-маркетинге, 3 года в системной интеграции AI в бизнес.
Связанный проект
Slides Generator →