Перейти к основному содержимому

Бесплатный аудит — конвертер лидов

Роль аудита в воронке

Бесплатный аудит — это главный конвертер в нашей системе. Лид, который получил персонализированный аудит с конкретными цифрами и прогнозом роста, конвертируется в клиента с вероятностью 25–35%. Без аудита — менее 5%.


Структура аудита

Содержание отчёта (12 страниц)

graph TD
A["📄 Титульная страница\n+ лого + данные клиента"] --> B["📊 Executive Summary\n(1 стр)"]
B --> C["🔍 Анализ 3 SKU\n(3 стр × 1 стр)"]
C --> D["📈 Конкурентный бенчмарк\n(2 стр)"]
D --> E["💰 Расчёт потенциала\n(1 стр)"]
E --> F["📋 Рекомендации\n(2 стр)"]
F --> G["🎯 Коммерческое предложение\n(1 стр)"]
G --> H["📎 Приложение:\nметодология + источники"]

style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#fce4ec
style D fill:#e8f5e9
style E fill:#c8e6c9
style F fill:#f3e5f5
style G fill:#ffecb3

Секции детально

#СекцияСтрЦельДанные из SF
1Титульная1Первое впечатлениеЛоготип, дата, бренд клиента
2Executive Summary1Якорь: показать масштаб потерьСуммарная упущенная выручка
3Анализ SKU #11Детальный разбор лучшей карточкиproduct/info, overview, keywords
4Анализ SKU #21Вторая карточкаproduct/info, overview, keywords
5Анализ SKU #31Третья карточкаproduct/info, overview, keywords
6Конкурентный бенчмарк2Контраст: показать успех конкурентовcategory/products (TOP-3)
7Расчёт потенциала1Визуализация ростаРасчётные метрики
8Рекомендации2Конкретные шагиЭкспертиза + данные
9Коммерческое предложение1Закрытие сделкиПакеты услуг
10Приложение1Доверие к даннымМетодология SalesFinder

SF API данные для аудита

Эндпоинты и данные

# Для каждого из 3 SKU:

# 1. Информация о товаре
product_info = await sf.post("/product/info", {
"sku": sku,
"marketplace": marketplace,
})
# → name, brand, photos_count, has_video, description, price,
# rating, reviews_count, has_rich_content, category

# 2. Обзор продаж (за 30 дней)
product_overview = await sf.post("/product/overview", {
"sku": sku,
"marketplace": marketplace,
"period": "month",
})
# → views, orders, revenue, conversion_rate, avg_position,
# sales_trend, position_trend, ad_spend, ad_ctr, ad_conversion

# 3. Ключевые слова
product_keywords = await sf.post("/product/keywords", {
"sku": sku,
"marketplace": marketplace,
})
# → keywords[]: keyword, search_volume, position, trend

# 4. ТОП конкуренты в категории
competitors = await sf.post("/category/products", {
"category_id": category_id,
"marketplace": marketplace,
"limit": 3,
"sort": "revenue_desc",
})
# → products[]: sku, name, revenue, conversion_rate,
# photos_count, has_video, position

# 5. Динамика продаж (для графика)
sales_history = await sf.post("/product/sales-history", {
"sku": sku,
"marketplace": marketplace,
"period": "90d",
})
# → data[]: date, orders, revenue, views, conversion

Python-реализация

AuditReportGenerator

import json
import asyncio
from dataclasses import dataclass, field
from datetime import datetime, date
from typing import Optional
from pathlib import Path


@dataclass
class SKUAnalysis:
"""Результат анализа одного SKU."""
sku: int
name: str
brand: str
marketplace: str
price: float
rating: float
reviews_count: int

# Контент
photos_count: int
has_video: bool
has_rich_content: bool
description_length: int

# Метрики
views: int
orders: int
revenue: float
conversion_rate: float
position: int

# Проблемы
problems: list[str] = field(default_factory=list)
recommendations: list[str] = field(default_factory=list)

# Потенциал
target_conversion: float = 0.0
potential_orders: int = 0
potential_revenue: float = 0.0
lost_revenue: float = 0.0
growth_percent: float = 0.0

# Ключевые слова
top_keywords: list[dict] = field(default_factory=list)
missing_keywords: list[str] = field(default_factory=list)


@dataclass
class CompetitorData:
"""Данные о конкуренте."""
sku: int
name: str
brand: str
revenue: float
conversion_rate: float
photos_count: int
has_video: bool
has_rich_content: bool
position: int
reviews_count: int


@dataclass
class AuditReport:
"""Полный аудит-отчёт."""
# Мета
report_id: str
created_at: datetime
lead_id: int
seller_name: str
marketplace: str

# Данные
sku_analyses: list[SKUAnalysis]
competitors: list[CompetitorData]

# Агрегаты
total_lost_revenue: float = 0.0
total_potential_revenue: float = 0.0
avg_growth_percent: float = 0.0

# Рекомендации
priority_actions: list[dict] = field(default_factory=list)
package_recommendation: str = ""
estimated_roi: float = 0.0


class AuditReportGenerator:
"""
Генератор бесплатных аудит-отчётов.

Автоматически анализирует 3 SKU клиента, сравнивает с ТОП-3
конкурентами и генерирует персонализированный PDF-отчёт.
"""

def __init__(self, sf_client, calculator):
self.sf = sf_client
self.calculator = calculator

async def generate_audit(
self,
lead_id: int,
skus: list[int],
marketplace: str = "wb",
seller_name: str = "",
) -> AuditReport:
"""
Генерирует полный аудит-отчёт для 3 SKU.

Args:
lead_id: ID лида в CRM
skus: список из 3 SKU для анализа
marketplace: "wb" или "ozon"
seller_name: название продавца/бренда

Returns:
AuditReport с полными данными для рендеринга
"""
if len(skus) > 3:
skus = skus[:3] # максимум 3 SKU в бесплатном аудите

# 1. Анализируем каждый SKU
analyses = await asyncio.gather(
*[self.analyze_product(sku, marketplace) for sku in skus]
)

# 2. Получаем конкурентов (из категории первого SKU)
category_id = await self._get_category_id(skus[0], marketplace)
competitors = await self.benchmark_competitors(
category_id, marketplace
)

# 3. Рассчитываем потенциал роста
for analysis in analyses:
self._calculate_growth_potential(analysis, competitors)

# 4. Генерируем рекомендации
priority_actions = self._generate_recommendations(analyses, competitors)

# 5. Подбираем пакет услуг
total_lost = sum(a.lost_revenue for a in analyses)
package = self._recommend_package(total_lost, len(skus))

report = AuditReport(
report_id=f"AUDIT-{lead_id}-{datetime.now().strftime('%Y%m%d')}",
created_at=datetime.now(),
lead_id=lead_id,
seller_name=seller_name,
marketplace=marketplace,
sku_analyses=analyses,
competitors=competitors,
total_lost_revenue=total_lost,
total_potential_revenue=sum(a.potential_revenue for a in analyses),
avg_growth_percent=sum(a.growth_percent for a in analyses) / max(len(analyses), 1),
priority_actions=priority_actions,
package_recommendation=package["name"],
estimated_roi=package["estimated_roi"],
)

return report

async def analyze_product(self, sku: int, marketplace: str) -> SKUAnalysis:
"""Полный анализ одного SKU."""

# Параллельно загружаем все данные
info, overview, keywords = await asyncio.gather(
self.sf.get_product_info(sku, marketplace),
self.sf.get_product_overview(sku, marketplace),
self.sf.get_product_keywords(sku, marketplace),
)

# Определяем проблемы
problems = []
recommendations = []

if info.get("photos_count", 0) < 7:
problems.append(
f"Мало фотографий: {info.get('photos_count', 0)} (рекомендуется 7–10)"
)
recommendations.append(
"Добавьте профессиональные фото с разных ракурсов, "
"фото в использовании, фото деталей"
)

if not info.get("has_video"):
problems.append("Нет видео-обзора")
recommendations.append(
"Создайте видео 30–60 сек: распаковка, демонстрация, "
"ключевые преимущества"
)

if not info.get("has_rich_content"):
problems.append("Нет rich-content (инфографики)")
recommendations.append(
"Добавьте инфографику: УТП, характеристики, сравнение "
"с аналогами, инструкция"
)

desc_len = len(info.get("description", ""))
if desc_len < 500:
problems.append(f"Короткое описание: {desc_len} символов (мин. 500)")
recommendations.append(
"Расширьте описание: добавьте ключевые слова, УТП, "
"сценарии использования, преимущества"
)

# Ключевые слова
product_kws = keywords.get("keywords", [])
top_kws = sorted(
product_kws, key=lambda k: k.get("search_volume", 0), reverse=True
)[:10]

# Позиция в поиске
avg_position = overview.get("avg_position", 100)
if avg_position > 30:
problems.append(f"Низкая позиция в поиске: {avg_position}")
recommendations.append(
"Оптимизируйте заголовок и характеристики с высокочастотными "
"ключевыми словами"
)

analysis = SKUAnalysis(
sku=sku,
name=info.get("name", ""),
brand=info.get("brand", ""),
marketplace=marketplace,
price=info.get("price", 0),
rating=info.get("rating", 0),
reviews_count=info.get("reviews_count", 0),
photos_count=info.get("photos_count", 0),
has_video=info.get("has_video", False),
has_rich_content=info.get("has_rich_content", False),
description_length=desc_len,
views=overview.get("views", 0),
orders=overview.get("orders", 0),
revenue=overview.get("revenue", 0),
conversion_rate=overview.get("conversion_rate", 0),
position=avg_position,
problems=problems,
recommendations=recommendations,
top_keywords=top_kws,
)

return analysis

async def benchmark_competitors(
self, category_id: int, marketplace: str
) -> list[CompetitorData]:
"""Получает данные ТОП-3 конкурентов в категории."""

top_products = await self.sf.get_category_products(
category_id=category_id,
marketplace=marketplace,
limit=3,
sort="revenue_desc",
)

competitors = []
for p in top_products:
info = await self.sf.get_product_info(p["sku"], marketplace)
overview = await self.sf.get_product_overview(p["sku"], marketplace)

competitors.append(CompetitorData(
sku=p["sku"],
name=info.get("name", ""),
brand=info.get("brand", ""),
revenue=overview.get("revenue", 0),
conversion_rate=overview.get("conversion_rate", 0),
photos_count=info.get("photos_count", 0),
has_video=info.get("has_video", False),
has_rich_content=info.get("has_rich_content", False),
position=overview.get("avg_position", 0),
reviews_count=info.get("reviews_count", 0),
))

return competitors

def _calculate_growth_potential(
self, analysis: SKUAnalysis, competitors: list[CompetitorData]
):
"""Рассчитывает потенциал роста на основе конкурентного бенчмарка."""

# Целевая конверсия = среднее ТОП-3 конкурентов
if competitors:
target_conv = sum(c.conversion_rate for c in competitors) / len(competitors)
else:
target_conv = analysis.conversion_rate * 2.5 # fallback: x2.5

analysis.target_conversion = target_conv

# Потенциальные заказы при целевой конверсии
if analysis.views > 0:
potential_orders = int(analysis.views * target_conv / 100)
else:
potential_orders = analysis.orders * 3 # fallback

analysis.potential_orders = potential_orders
analysis.potential_revenue = potential_orders * analysis.price
analysis.lost_revenue = max(0, analysis.potential_revenue - analysis.revenue)
analysis.growth_percent = (
(analysis.potential_revenue / max(analysis.revenue, 1) - 1) * 100
)

def _generate_recommendations(
self,
analyses: list[SKUAnalysis],
competitors: list[CompetitorData],
) -> list[dict]:
"""Генерирует приоритизированные рекомендации."""

actions = []

# 1. Фото (если у конкурентов больше)
avg_competitor_photos = sum(c.photos_count for c in competitors) / max(len(competitors), 1)
for a in analyses:
if a.photos_count < avg_competitor_photos:
impact = (avg_competitor_photos - a.photos_count) / avg_competitor_photos
actions.append({
"priority": 1,
"action": "Профессиональная фотосъёмка",
"sku": a.sku,
"detail": (
f"Текущее: {a.photos_count} фото. Конкуренты: "
f"{avg_competitor_photos:.0f} фото. "
f"Добавить: {max(0, int(avg_competitor_photos) - a.photos_count + 3)} фото"
),
"expected_impact": f"+{impact * 20:.0f}% к конверсии",
"estimated_cost": "15 000–25 000 ₽",
"timeline": "3–5 рабочих дней",
})

# 2. Видео
for a in analyses:
if not a.has_video:
actions.append({
"priority": 2,
"action": "Создание видео-обзора",
"sku": a.sku,
"detail": (
"Видео 30–60 сек: распаковка, демонстрация, "
"ключевые преимущества. Повышает конверсию на 15–25%."
),
"expected_impact": "+15–25% к конверсии",
"estimated_cost": "10 000–20 000 ₽",
"timeline": "5–7 рабочих дней",
})

# 3. Инфографика
for a in analyses:
if not a.has_rich_content:
actions.append({
"priority": 3,
"action": "Rich-content и инфографика",
"sku": a.sku,
"detail": (
"Инфографика с УТП, характеристиками, "
"сравнением. Повышает время на карточке на 40%."
),
"expected_impact": "+10–15% к конверсии",
"estimated_cost": "8 000–15 000 ₽",
"timeline": "3–5 рабочих дней",
})

# 4. SEO-оптимизация
for a in analyses:
if a.missing_keywords:
actions.append({
"priority": 4,
"action": "SEO-оптимизация карточки",
"sku": a.sku,
"detail": (
f"Недостающие ключевые слова: {len(a.missing_keywords)}. "
"Оптимизация заголовка, описания, характеристик."
),
"expected_impact": "+20–50 позиций в поиске",
"estimated_cost": "5 000–10 000 ₽",
"timeline": "1–2 рабочих дня",
})

actions.sort(key=lambda x: x["priority"])
return actions

def _recommend_package(self, total_lost_revenue: float, sku_count: int) -> dict:
"""Рекомендует пакет услуг на основе масштаба потерь."""

if total_lost_revenue >= 1_000_000:
return {
"name": "РОСТ",
"price": "150 000 ₽/мес",
"estimated_roi": total_lost_revenue / 150_000,
"description": (
"Полное обновление контента для 10+ SKU: "
"профессиональная съёмка, видео, инфографика, SEO"
),
}
elif total_lost_revenue >= 300_000:
return {
"name": "ОПТИМИЗАЦИЯ",
"price": "75 000 ₽/мес",
"estimated_roi": total_lost_revenue / 75_000,
"description": (
"Обновление контента для 5 SKU: "
"съёмка, видео, базовая инфографика"
),
}
else:
return {
"name": "АУДИТ",
"price": "25 000 ₽ (разовый)",
"estimated_roi": total_lost_revenue / 25_000,
"description": (
"Детальный аудит + рекомендации + "
"базовая оптимизация 3 карточек"
),
}

async def _get_category_id(self, sku: int, marketplace: str) -> int:
"""Получает ID категории по SKU."""
info = await self.sf.get_product_info(sku, marketplace)
return info.get("category_id", 0)

Расчёт потенциала роста

Методика расчёта

Потенциальная выручка = Текущие просмотры × Целевая конверсия × Цена

Целевая конверсия = Среднее(ТОП-3 конкурентов по выручке)
— Это консервативная оценка (ТОП-3, не ТОП-1)
— Корректируется коэффициентом 0.85 (не все дотянут до среднего ТОП-3)

Упущенная выручка = Потенциальная выручка - Текущая выручка
Рост в % = (Потенциальная / Текущая - 1) × 100

Пример расчёта

SKU: Набор кухонных ножей KnifeKing
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Текущие метрики:
Просмотры: 32 000/мес
Заказы: 352/мес
Конверсия: 1.1%
Цена: 2 890 ₽
Выручка: 1 017 280 ₽/мес

ТОП-3 конкурента:
SteelPro: конверсия 5.2%
ChefBlade: конверсия 4.8%
ProKnife: конверсия 3.9%
Среднее: 4.63%

Расчёт потенциала:
Целевая конверсия: 4.63% × 0.85 = 3.94%
Потенциальные заказы: 32 000 × 3.94% = 1 261/мес
Потенциальная выручка: 1 261 × 2 890 = 3 644 290 ₽/мес
Упущенная выручка: 3 644 290 - 1 017 280 = 2 627 010 ₽/мес
Рост: +258%

┌────────────────────────────────────────────┐
│ 💰 УПУЩЕНО: 2 627 010 ₽/мес │
│ 📈 ПОТЕНЦИАЛ РОСТА: +258% │
│ 🎯 ROI контента: 17.5x (при стоим. 150К) │
└────────────────────────────────────────────┘
Консервативность оценок

Мы намеренно используем консервативные оценки (× 0.85 от среднего ТОП-3). В аудите указываем «потенциал роста» и «расчётный диапазон». Перебор с обещаниями убивает доверие.


Психология аудита

4 принципа конвертирующего аудита

1. Якорение на потерях (Loss Aversion)

❌ НЕ ТАК: «Вы можете увеличить продажи»
✅ ТАК: «Вы теряете 2.6 млн ₽ каждый месяц»

Люди в 2 раза сильнее реагируют на потери, чем на эквивалентный выигрыш (Kahneman & Tversky, 1979). Аудит начинается с суммы потерь — это якорь, который определяет восприятие всего отчёта.

Executive Summary открывается так:

«По результатам анализа 3 ваших ключевых SKU на {marketplace}, суммарная упущенная выручка составляет {total_lost} в месяц. Это {percent_of_current}% от текущего оборота.»

2. Контраст с конкурентами (Social Proof + Contrast)

Ваша карточка           vs.    ТОП-3 конкурента
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
3 фото 12 фото
Нет видео Видео 45 сек
Нет инфографики 5 слайдов rich-content
1.1% конверсия 4.6% конверсия
Позиция 47 Позиция 3

Показываем таблицу сравнения «Вы vs. Конкуренты» — визуальный контраст вызывает немедленную реакцию.

3. Конкретность (Specificity Builds Trust)

❌ НЕ ТАК: «Нужно улучшить контент карточки»
✅ ТАК: «Добавьте 8 фото (4 ракурса + 2 в использовании + 2 детали),
видео 40 сек (распаковка → демонстрация → УТП),
инфографику (размеры + сравнение + преимущества).
Ожидаемый эффект: конверсия 1.1% → 3.5%, +680К ₽/мес.»

Чем конкретнее рекомендации, тем выше доверие. Каждая рекомендация содержит: что сделать, как сделать, сколько это стоит, какой эффект.

4. Срочность (Urgency)

📅 Окно возможности:
— Сезонный пик начинается через 6 недель
— Конкурент «SteelPro» обновил карточку 2 недели назад (+35% продажи)
— Каждый день без изменений = ~87 000 ₽ упущенной выручки

Показываем, почему действовать нужно сейчас: сезонность, активность конкурентов, ежедневные потери.


Шаблон PDF-отчёта

Структура по секциям

Секция 1: Executive Summary

def generate_executive_summary(report: AuditReport) -> dict:
"""Генерирует Executive Summary."""
return {
"title": f"Аудит карточек товаров — {report.seller_name}",
"subtitle": f"{report.marketplace.upper()} | {report.created_at.strftime('%d.%m.%Y')}",
"key_findings": [
{
"metric": "Упущенная выручка",
"value": f"{report.total_lost_revenue:,.0f} ₽/мес",
"icon": "money_loss",
"color": "#f44336",
},
{
"metric": "Потенциал роста",
"value": f"+{report.avg_growth_percent:.0f}%",
"icon": "trending_up",
"color": "#4caf50",
},
{
"metric": "SKU проанализировано",
"value": str(len(report.sku_analyses)),
"icon": "search",
"color": "#2196f3",
},
{
"metric": "Рекомендуемый пакет",
"value": report.package_recommendation,
"icon": "star",
"color": "#ff9800",
},
],
"summary_text": (
f"По результатам анализа {len(report.sku_analyses)} ключевых SKU "
f"на {report.marketplace.upper()}, суммарная упущенная выручка составляет "
f"{report.total_lost_revenue:,.0f} ₽ в месяц. Основные причины: "
f"недостаточное количество фотографий, отсутствие видео-контента "
f"и неоптимизированные описания. При устранении этих проблем "
f"ожидаемый рост составит +{report.avg_growth_percent:.0f}%."
),
}

Секция 2: Анализ SKU

def generate_sku_section(analysis: SKUAnalysis) -> dict:
"""Генерирует секцию анализа одного SKU."""
return {
"title": f"SKU {analysis.sku}: {analysis.name}",
"current_metrics": {
"Просмотры": f"{analysis.views:,}/мес",
"Заказы": f"{analysis.orders:,}/мес",
"Конверсия": f"{analysis.conversion_rate:.1f}%",
"Выручка": f"{analysis.revenue:,.0f} ₽/мес",
"Позиция": f"#{analysis.position}",
"Рейтинг": f"{analysis.rating:.1f} ({analysis.reviews_count} отзывов)",
},
"content_audit": {
"Фотографии": {
"current": analysis.photos_count,
"target": 10,
"status": "ok" if analysis.photos_count >= 7 else "problem",
},
"Видео": {
"current": "Есть" if analysis.has_video else "Нет",
"target": "30–60 сек",
"status": "ok" if analysis.has_video else "problem",
},
"Rich-content": {
"current": "Есть" if analysis.has_rich_content else "Нет",
"target": "3–5 слайдов",
"status": "ok" if analysis.has_rich_content else "problem",
},
"Описание": {
"current": f"{analysis.description_length} симв.",
"target": "1000+ символов",
"status": "ok" if analysis.description_length >= 500 else "problem",
},
},
"problems": analysis.problems,
"potential": {
"Целевая конверсия": f"{analysis.target_conversion:.1f}%",
"Потенциальные заказы": f"{analysis.potential_orders:,}/мес",
"Потенциальная выручка": f"{analysis.potential_revenue:,.0f} ₽/мес",
"Упущенная выручка": f"{analysis.lost_revenue:,.0f} ₽/мес",
"Рост": f"+{analysis.growth_percent:.0f}%",
},
"chart_data": {
"type": "bar",
"labels": ["Текущее", "Потенциал"],
"datasets": [
{
"label": "Выручка, ₽/мес",
"data": [analysis.revenue, analysis.potential_revenue],
"colors": ["#ff9800", "#4caf50"],
},
],
},
}

Секция 3: Конкурентный бенчмарк

def generate_benchmark_section(
analyses: list[SKUAnalysis],
competitors: list[CompetitorData],
) -> dict:
"""Генерирует секцию конкурентного бенчмарка."""

# Средние метрики клиента
client_avg = {
"photos": sum(a.photos_count for a in analyses) / len(analyses),
"video_pct": sum(1 for a in analyses if a.has_video) / len(analyses) * 100,
"rich_pct": sum(1 for a in analyses if a.has_rich_content) / len(analyses) * 100,
"conversion": sum(a.conversion_rate for a in analyses) / len(analyses),
"position": sum(a.position for a in analyses) / len(analyses),
}

# Средние метрики конкурентов
comp_avg = {
"photos": sum(c.photos_count for c in competitors) / max(len(competitors), 1),
"video_pct": sum(1 for c in competitors if c.has_video) / max(len(competitors), 1) * 100,
"rich_pct": sum(1 for c in competitors if c.has_rich_content) / max(len(competitors), 1) * 100,
"conversion": sum(c.conversion_rate for c in competitors) / max(len(competitors), 1),
"position": sum(c.position for c in competitors) / max(len(competitors), 1),
}

return {
"title": "Конкурентный бенчмарк: Вы vs. ТОП-3",
"comparison_table": [
{
"metric": "Фотографий",
"client": f"{client_avg['photos']:.0f}",
"competitors": f"{comp_avg['photos']:.0f}",
"gap": f"{comp_avg['photos'] - client_avg['photos']:+.0f}",
},
{
"metric": "Видео",
"client": f"{client_avg['video_pct']:.0f}%",
"competitors": f"{comp_avg['video_pct']:.0f}%",
"gap": f"{comp_avg['video_pct'] - client_avg['video_pct']:+.0f}%",
},
{
"metric": "Rich-content",
"client": f"{client_avg['rich_pct']:.0f}%",
"competitors": f"{comp_avg['rich_pct']:.0f}%",
"gap": f"{comp_avg['rich_pct'] - client_avg['rich_pct']:+.0f}%",
},
{
"metric": "Конверсия",
"client": f"{client_avg['conversion']:.1f}%",
"competitors": f"{comp_avg['conversion']:.1f}%",
"gap": f"{comp_avg['conversion'] - client_avg['conversion']:+.1f}%",
},
{
"metric": "Позиция",
"client": f"#{client_avg['position']:.0f}",
"competitors": f"#{comp_avg['position']:.0f}",
"gap": f"{client_avg['position'] - comp_avg['position']:+.0f}",
},
],
"radar_chart": {
"categories": ["Фото", "Видео", "Rich", "SEO", "Конверсия"],
"client_scores": [
min(client_avg["photos"] / 12 * 100, 100),
client_avg["video_pct"],
client_avg["rich_pct"],
max(0, (100 - client_avg["position"])),
min(client_avg["conversion"] / 6 * 100, 100),
],
"competitor_scores": [
min(comp_avg["photos"] / 12 * 100, 100),
comp_avg["video_pct"],
comp_avg["rich_pct"],
max(0, (100 - comp_avg["position"])),
min(comp_avg["conversion"] / 6 * 100, 100),
],
},
}

PDF рендеринг

Генерация PDF через WeasyPrint / ReportLab

from pathlib import Path
from jinja2 import Environment, FileSystemLoader


class AuditPDFRenderer:
"""Рендерит аудит-отчёт в PDF."""

TEMPLATE_DIR = Path("templates/audit")

def __init__(self):
self.env = Environment(
loader=FileSystemLoader(str(self.TEMPLATE_DIR)),
autoescape=True,
)

def render_pdf(self, report: AuditReport, output_path: str) -> str:
"""
Рендерит AuditReport в PDF-файл.

Args:
report: полный аудит-отчёт
output_path: путь для сохранения PDF

Returns:
путь к созданному PDF-файлу
"""
# 1. Подготавливаем данные для шаблона
context = {
"report": report,
"executive_summary": generate_executive_summary(report),
"sku_sections": [
generate_sku_section(a) for a in report.sku_analyses
],
"benchmark": generate_benchmark_section(
report.sku_analyses, report.competitors
),
"recommendations": report.priority_actions,
"package": {
"name": report.package_recommendation,
"roi": report.estimated_roi,
},
"generated_at": report.created_at.strftime("%d.%m.%Y %H:%M"),
}

# 2. Рендерим HTML
template = self.env.get_template("audit_report.html")
html_content = template.render(**context)

# 3. Конвертируем в PDF
try:
from weasyprint import HTML # type: ignore
HTML(string=html_content).write_pdf(output_path)
except ImportError:
# Fallback: сохраняем как HTML
html_path = output_path.replace(".pdf", ".html")
Path(html_path).write_text(html_content, encoding="utf-8")
return html_path

return output_path

Конверсия аудита

Что делает аудит конвертирующим на 30%+

ФакторКак реализованоВлияние на конверсию
ПерсонализацияКонкретные SKU клиента, его цифры+15% (vs generic audit)
Якорь на потеряхПервая страница = сумма упущенной выручки+10% (loss aversion)
Конкурентный контрастТаблица «Вы vs. ТОП-3»+8% (social proof)
Конкретные шагиКаждая рекомендация = что + как + сколько + эффект+7% (actionability)
ВизуализацияГрафики, radar chart, цветовые индикаторы+5% (comprehension)
Лёгкий следующий шаг«Ответьте OK — и мы начнём»+5% (low friction)

Upsell путь

graph LR
A["🆓 АУДИТ\nБесплатно\n(3 SKU)"] --> B["💰 ОПТИМИЗАЦИЯ\n75K/мес\n(5 SKU)"]
B --> C["🚀 РОСТ\n150K/мес\n(10+ SKU)"]
C --> D["🏆 МАСШТАБ\n300K+/мес\n(весь каталог)"]

style A fill:#e3f2fd
style B fill:#fff3e0
style C fill:#e8f5e9
style D fill:#c8e6c9
ЭтапЧто получает клиентСредний срокКонверсия в след. этап
АУДИТ (бесплатно)Отчёт с диагнозом + 3 SKU2–3 дня25–35% → ОПТИМИЗАЦИЯ
ОПТИМИЗАЦИЯ (75K/мес)Контент для 5 SKU + SEO1–2 мес40–50% → РОСТ
РОСТ (150K/мес)10+ SKU + аналитика + A/B тесты3–6 мес30–40% → МАСШТАБ
МАСШТАБ (300K+/мес)Весь каталог + стратегия + менеджмент6+ месRetention 80%+
Ключевой инсайт

Бесплатный аудит — не затрата, а инвестиция в клиента. Стоимость генерации аудита ~3 000 ₽ (1.5 часа аналитика + SF API). При конверсии 30% и среднем чеке 75 000 ₽/мес — ROI аудита составляет 7.5x в первый же месяц.


Реальный пример: полный аудит для KnifeKing

Executive Summary

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
АУДИТ КАРТОЧЕК ТОВАРОВ

Бренд: KnifeKing
Площадка: Wildberries
Дата: 17 февраля 2026
Аналитик: Fotofactor Analytics Team

┌────────────────────────────────────────────┐
│ 💰 УПУЩЕННАЯ ВЫРУЧКА: 4 127 000 ₽/мес │
│ 📈 ПОТЕНЦИАЛ РОСТА: +215% │
│ 📊 SKU ПРОАНАЛИЗИРОВАНО: 3 │
│ 🎯 РЕКОМЕНДУЕМЫЙ ПАКЕТ: РОСТ (150K/мес) │
└────────────────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

SKU #1: Набор кухонных ножей (198345672)

ТЕКУЩИЕ МЕТРИКИ:
Просмотры: 32 000/мес
Заказы: 352/мес
Конверсия: 1.1%
Цена: 2 890 ₽
Выручка: 1 017 280 ₽/мес
Позиция: #47
Рейтинг: 4.3 (127 отзывов)

АУДИТ КОНТЕНТА:
📸 Фото: 3 шт ❌ (нужно 10+)
🎬 Видео: Нет ❌
📊 Инфографика: Нет ❌
📝 Описание: 234 сим. ❌ (нужно 500+)

ПОТЕНЦИАЛ:
Целевая конверсия: 3.94% (среднее ТОП-3 × 0.85)
Потенциальные заказы: 1 261/мес (+258%)
Потенциальная выручка: 3 644 290 ₽/мес
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
УПУЩЕНО: 2 627 010 ₽/мес

Конкурентный бенчмарк

                KnifeKing   ТОП-3 среднее   Разрыв
─────────────────────────────────────────────────
Фото: 3 11 -8
Видео: Нет 100% ❌
Rich-content: Нет 100% ❌
Конверсия: 1.1% 4.63% -3.53%
Позиция: #47 #5 -42
─────────────────────────────────────────────────

Рекомендации (приоритизированные)

#1 ПРИОРИТЕТ: Профессиональная фотосъёмка
SKU: 198345672, 198345673, 198345674
Что: +8 фото на каждый SKU (ракурсы, детали, в использовании)
Стоимость: ~45 000 ₽ (3 SKU)
Эффект: +20% к конверсии → +800K ₽/мес выручки
Срок: 3–5 рабочих дней

#2 ПРИОРИТЕТ: Видео-обзор
SKU: все 3
Что: видео 40–60 сек (распаковка, демонстрация, УТП)
Стоимость: ~30 000 ₽ (3 видео)
Эффект: +15–25% к конверсии → +600K ₽/мес
Срок: 5–7 рабочих дней

#3 ПРИОРИТЕТ: Rich-content и инфографика
SKU: все 3
Что: инфографика с размерами, материалами, преимуществами
Стоимость: ~24 000 ₽
Эффект: +10–15% к конверсии → +400K ₽/мес
Срок: 3–5 рабочих дней

ИТОГО: ~99 000 ₽ → ОЖИДАЕМЫЙ ЭФФЕКТ: +1.8M ₽/мес → ROI: 18x

CLI команды

# Генерация аудита для лида
python spider.py leadgen audit-generate \
--lead-id 42 \
--skus "198345672,198345673,198345674" \
--marketplace wb \
--format pdf \
--output "audits/knifeking_audit.pdf"

# Предпросмотр аудита (JSON)
python spider.py leadgen audit-preview \
--lead-id 42 \
--json

# Массовая генерация аудитов
python spider.py leadgen audit-batch \
--temperature warm \
--limit 10 \
--output-dir "audits/batch_2026_03/"

# Статистика аудитов
python spider.py leadgen audit-stats \
--period "2026-03" \
--json

Метрики аудита

МетрикаФормулаЦель
Audit generation timeavg(generation_end - generation_start)≤ 60 сек
Audit delivery ratedelivered / generated≥ 95%
Audit open rateopened / delivered≥ 70%
Audit-to-call ratecalls / opened≥ 40%
Audit-to-client rateclients / delivered≥ 25%
Average audit costtotal_cost / generated≤ 3 000 ₽
Audit ROIclient_revenue / audit_cost≥ 25x