Files
marketing/docs/marketing-analysis-api-updated-fields.md
2025-12-03 09:05:00 +05:00

27 KiB

API Документация: Обновленные поля для генерации бизнес-анализа (Frontend/AI Agent)

Обзор изменений

API для генерации маркетингового анализа был обновлен с новыми полями, которые более точно отражают требования бизнес-анализа. Все старые поля были заменены новыми для улучшения качества анализа.


Изменения в структуре запроса

Удаленные поля (больше не используются)

Следующие поля были удалены из API и больше не принимаются:

  • location - заменено на region
  • client - заменено на targetAudience
  • differentiator - заменено на комбинацию businessNiche, strongSide, weakSide

Новые обязательные поля

Поле Тип Обязательный Описание Пример значения
businessNiche string Ниша бизнеса "E-commerce платформы"
product string Продукт или услуга "Разработка мобильных приложений"
targetAudience string Целевая аудитория (детальное описание) "Малый и средний бизнес, владельцы интернет-магазинов"
region string Регион (город Казахстана) "Алматы"
goal string Цель на 6-12 месяцев "Увеличить количество клиентов на 50%"
detailLevel string Уровень детализации анализа "СТАНДАРТНО"
analysisType string Тип анализа "РЫНОК"

Новые опциональные поля

Поле Тип Обязательный Описание Пример значения
strongSide string Сильная сторона бизнеса "Опытная команда разработчиков, быстрая доставка"
weakSide string Слабая сторона бизнеса "Ограниченный маркетинговый бюджет"

Детальное описание полей

1. businessNiche (обязательное)

Описание: Ниша бизнеса, в которой работает компания.

Валидация:

  • Минимальная длина: 3 символа
  • Максимальная длина: 200 символов
  • Разрешены: буквы, цифры, пробелы, дефисы, запятые
  • Паттерн: ^[\p{L}\p{N}\s\-,]+$

Примеры:

"businessNiche": "E-commerce платформы"
"businessNiche": "Образовательные технологии"
"businessNiche": "Финансовые услуги для малого бизнеса"

2. product (обязательное)

Описание: Конкретный продукт или услуга, которую предоставляет компания.

Валидация:

  • Минимальная длина: 3 символа
  • Максимальная длина: 200 символов
  • Разрешены: буквы, цифры, пробелы, дефисы, запятые
  • Паттерн: ^[\p{L}\p{N}\s\-,]+$

Примеры:

"product": "Разработка мобильных приложений"
"product": "Консультации по маркетингу"
"product": "Веб-разработка и дизайн"

3. targetAudience (обязательное)

Описание: Детальное описание целевой аудитории. Это поле заменяет старое поле client и должно содержать более подробную информацию.

Валидация:

  • Минимальная длина: 3 символа
  • Максимальная длина: 300 символов
  • Разрешены любые символы

Примеры:

"targetAudience": "Малый и средний бизнес, владельцы интернет-магазинов в возрасте 30-50 лет"
"targetAudience": "Стартапы и технологические компании, нуждающиеся в быстрой разработке MVP"
"targetAudience": "Частные лица, желающие создать личный бренд в социальных сетях"

Примечание: В отличие от старого поля client, которое принимало только фиксированные значения, targetAudience принимает свободный текст для более гибкого описания.


4. region (обязательное)

Описание: Регион (город Казахстана), в котором работает бизнес. Это поле заменяет старое поле location.

Валидация:

  • Должно быть одним из допустимых городов Казахстана
  • Проверка выполняется через валидатор @ValidRegion

Допустимые значения (точное совпадение):

  • "Алматы"
  • "Астана"
  • "Шымкент"
  • "Караганда"
  • "Актобе"
  • "Тараз"
  • "Павлодар"
  • "Усть-Каменогорск"
  • "Семей"
  • "Костанай"
  • "Кызылорда"
  • "Уральск"
  • "Петропавловск"
  • "Атырау"
  • "Актау"
  • "Туркестан"
  • "Кокшетау"
  • "Талдыкорган"
  • "Экибастуз"
  • "Рудный"

Примеры:

"region": "Алматы"
"region": "Астана"
"region": "Шымкент"

Важно: Значение должно точно совпадать с одним из допустимых городов (регистр важен).


5. goal (обязательное)

Описание: Цель бизнеса на период 6-12 месяцев. Это новое поле, которое помогает AI лучше понять приоритеты бизнеса.

Валидация:

  • Минимальная длина: 10 символов
  • Максимальная длина: 500 символов
  • Разрешены любые символы

Примеры:

"goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев"
"goal": "Выйти на рынок соседних регионов и открыть 3 новых филиала"
"goal": "Повысить узнаваемость бренда и увеличить продажи через онлайн-каналы на 30%"

6. detailLevel (обязательное)

Описание: Уровень детализации анализа. Влияет на объем и глубину генерируемого анализа.

Валидация:

  • Должно быть одним из допустимых значений
  • Проверка выполняется через валидатор @ValidDetailLevel

Допустимые значения (точное совпадение, регистр важен):

  • "КРАТКО" - Краткий анализ (1-2 абзаца)
  • "СТАНДАРТНО" - Стандартный анализ (3-5 абзацев) - рекомендуется по умолчанию
  • "ПОДРОБНО" - Подробный анализ (5-8 абзацев)

Влияние на анализ:

Уровень Длина ответов Количество рекомендаций Детализация стратегии
КРАТКО 1-2 абзаца 3-4 рекомендации Краткая
СТАНДАРТНО 3-5 абзацев 4-6 рекомендаций Стандартная
ПОДРОБНО 5-8 абзацев 6-8 рекомендаций Детальная с обоснованием

Примеры:

"detailLevel": "КРАТКО"
"detailLevel": "СТАНДАРТНО"
"detailLevel": "ПОДРОБНО"

7. strongSide (опциональное)

Описание: Сильная сторона бизнеса. Помогает AI лучше понять конкурентные преимущества.

Валидация:

  • Максимальная длина: 500 символов
  • Разрешены любые символы
  • Может быть пустым или отсутствовать

Примеры:

"strongSide": "Опытная команда разработчиков с 10+ летним опытом, быстрая доставка проектов"
"strongSide": "Уникальная технология, низкие цены, отличная поддержка клиентов"

Примечание: Если поле не указано, AI будет анализировать сильные стороны на основе других данных.


8. weakSide (опциональное)

Описание: Слабая сторона бизнеса. Помогает AI лучше понять области для улучшения.

Валидация:

  • Максимальная длина: 500 символов
  • Разрешены любые символы
  • Может быть пустым или отсутствовать

Примеры:

"weakSide": "Ограниченный маркетинговый бюджет, недостаточная узнаваемость бренда"
"weakSide": "Небольшая команда, ограниченные ресурсы для масштабирования"

Примечание: Если поле не указано, AI будет анализировать слабые стороны на основе других данных.


9. analysisType (обязательное)

Описание: Тип анализа, который необходимо провести. Поле осталось без изменений.

Допустимые значения:

  • "РЫНОК" - Анализ рынка
  • "КОНКУРЕНТЫ" - Анализ конкурентов
  • "ЦА" - Анализ целевой аудитории
  • "КАНАЛЫ" - Анализ маркетинговых каналов
  • "SWOT" - SWOT-анализ

Полный пример запроса

POST /api/marketing/analysis/start

{
  "businessNiche": "E-commerce платформы",
  "product": "Разработка мобильных приложений для интернет-магазинов",
  "targetAudience": "Малый и средний бизнес, владельцы интернет-магазинов в возрасте 30-50 лет, нуждающиеся в мобильных решениях",
  "region": "Алматы",
  "goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев и выйти на рынок соседних регионов",
  "detailLevel": "СТАНДАРТНО",
  "strongSide": "Опытная команда разработчиков с 10+ летним опытом, быстрая доставка проектов, использование современных технологий",
  "weakSide": "Ограниченный маркетинговый бюджет, недостаточная узнаваемость бренда в новых регионах",
  "analysisType": "РЫНОК"
}

Примеры использования на фронтенде

JavaScript/TypeScript

interface MarketingAnalysisRequest {
  businessNiche: string;
  product: string;
  targetAudience: string;
  region: string;
  goal: string;
  detailLevel: 'КРАТКО' | 'СТАНДАРТНО' | 'ПОДРОБНО';
  strongSide?: string;
  weakSide?: string;
  analysisType: 'РЫНОК' | 'КОНКУРЕНТЫ' | 'ЦА' | 'КАНАЛЫ' | 'SWOT';
}

// Список допустимых регионов
const VALID_REGIONS = [
  'Алматы',
  'Астана',
  'Шымкент',
  'Караганда',
  'Актобе',
  'Тараз',
  'Павлодар',
  'Усть-Каменогорск',
  'Семей',
  'Костанай',
  'Кызылорда',
  'Уральск',
  'Петропавловск',
  'Атырау',
  'Актау',
  'Туркестан',
  'Кокшетау',
  'Талдыкорган',
  'Экибастуз',
  'Рудный',
];

// Список уровней детализации
const DETAIL_LEVELS = ['КРАТКО', 'СТАНДАРТНО', 'ПОДРОБНО'] as const;

// Функция для отправки запроса
async function startMarketingAnalysis(
  data: MarketingAnalysisRequest
): Promise<string> {
  const response = await fetch(
    'https://api.konturai.kz/api/marketing/analysis/start',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: 'Bearer YOUR_JWT_TOKEN', // Если требуется
      },
      body: JSON.stringify(data),
    }
  );

  const result = await response.json();

  if (!result.success) {
    throw new Error(result.error?.message || 'Failed to start analysis');
  }

  return result.data.analysisId;
}

// Пример использования
const analysisId = await startMarketingAnalysis({
  businessNiche: 'E-commerce платформы',
  product: 'Разработка мобильных приложений',
  targetAudience: 'Малый и средний бизнес, владельцы интернет-магазинов',
  region: 'Алматы',
  goal: 'Увеличить количество клиентов на 50% за следующие 6 месяцев',
  detailLevel: 'СТАНДАРТНО',
  strongSide: 'Опытная команда, быстрая доставка',
  weakSide: 'Ограниченный маркетинговый бюджет',
  analysisType: 'РЫНОК',
});

React компонент с формой

import React, { useState } from 'react';

const MarketingAnalysisForm: React.FC = () => {
  const [formData, setFormData] = useState<MarketingAnalysisRequest>({
    businessNiche: '',
    product: '',
    targetAudience: '',
    region: '',
    goal: '',
    detailLevel: 'СТАНДАРТНО',
    strongSide: '',
    weakSide: '',
    analysisType: 'РЫНОК',
  });

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();

    try {
      const analysisId = await startMarketingAnalysis(formData);
      console.log('Analysis started:', analysisId);
      // Перенаправление на страницу с результатами
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Ниша бизнеса *</label>
        <input
          type='text'
          value={formData.businessNiche}
          onChange={(e) =>
            setFormData({ ...formData, businessNiche: e.target.value })
          }
          required
          minLength={3}
          maxLength={200}
        />
      </div>

      <div>
        <label>Продукт / услуга *</label>
        <input
          type='text'
          value={formData.product}
          onChange={(e) =>
            setFormData({ ...formData, product: e.target.value })
          }
          required
          minLength={3}
          maxLength={200}
        />
      </div>

      <div>
        <label>Целевая аудитория *</label>
        <textarea
          value={formData.targetAudience}
          onChange={(e) =>
            setFormData({ ...formData, targetAudience: e.target.value })
          }
          required
          minLength={3}
          maxLength={300}
        />
      </div>

      <div>
        <label>Регион *</label>
        <select
          value={formData.region}
          onChange={(e) => setFormData({ ...formData, region: e.target.value })}
          required
        >
          <option value=''>Выберите регион</option>
          {VALID_REGIONS.map((region) => (
            <option key={region} value={region}>
              {region}
            </option>
          ))}
        </select>
      </div>

      <div>
        <label>Цель на 6-12 месяцев *</label>
        <textarea
          value={formData.goal}
          onChange={(e) => setFormData({ ...formData, goal: e.target.value })}
          required
          minLength={10}
          maxLength={500}
        />
      </div>

      <div>
        <label>Уровень детализации анализа *</label>
        <div>
          {DETAIL_LEVELS.map((level) => (
            <label key={level}>
              <input
                type='radio'
                name='detailLevel'
                value={level}
                checked={formData.detailLevel === level}
                onChange={(e) =>
                  setFormData({
                    ...formData,
                    detailLevel: e.target.value as any,
                  })
                }
              />
              {level === 'КРАТКО' && ' Кратко'}
              {level === 'СТАНДАРТНО' && ' Стандартно'}
              {level === 'ПОДРОБНО' && ' Подробно'}
            </label>
          ))}
        </div>
      </div>

      <div>
        <label>Сильная сторона</label>
        <textarea
          value={formData.strongSide}
          onChange={(e) =>
            setFormData({ ...formData, strongSide: e.target.value })
          }
          maxLength={500}
        />
      </div>

      <div>
        <label>Слабая сторона</label>
        <textarea
          value={formData.weakSide}
          onChange={(e) =>
            setFormData({ ...formData, weakSide: e.target.value })
          }
          maxLength={500}
        />
      </div>

      <div>
        <label>Тип анализа *</label>
        <select
          value={formData.analysisType}
          onChange={(e) =>
            setFormData({ ...formData, analysisType: e.target.value as any })
          }
          required
        >
          <option value='РЫНОК'>Рынок</option>
          <option value='КОНКУРЕНТЫ'>Конкуренты</option>
          <option value='ЦА'>Целевая аудитория</option>
          <option value='КАНАЛЫ'>Каналы</option>
          <option value='SWOT'>SWOT</option>
        </select>
      </div>

      <button type='submit'>Сгенерировать анализ бизнеса</button>
    </form>
  );
};

Валидация на клиенте

Рекомендуется выполнять валидацию на клиенте перед отправкой запроса:

function validateMarketingAnalysisRequest(data: MarketingAnalysisRequest): {
  valid: boolean;
  errors: Record<string, string>;
} {
  const errors: Record<string, string> = {};

  // Валидация businessNiche
  if (!data.businessNiche || data.businessNiche.trim().length < 3) {
    errors.businessNiche = 'Ниша бизнеса должна содержать минимум 3 символа';
  }
  if (data.businessNiche && data.businessNiche.length > 200) {
    errors.businessNiche = 'Ниша бизнеса не должна превышать 200 символов';
  }

  // Валидация product
  if (!data.product || data.product.trim().length < 3) {
    errors.product = 'Продукт должен содержать минимум 3 символа';
  }
  if (data.product && data.product.length > 200) {
    errors.product = 'Продукт не должен превышать 200 символов';
  }

  // Валидация targetAudience
  if (!data.targetAudience || data.targetAudience.trim().length < 3) {
    errors.targetAudience =
      'Целевая аудитория должна содержать минимум 3 символа';
  }
  if (data.targetAudience && data.targetAudience.length > 300) {
    errors.targetAudience =
      'Целевая аудитория не должна превышать 300 символов';
  }

  // Валидация region
  if (!data.region || !VALID_REGIONS.includes(data.region)) {
    errors.region = 'Выберите допустимый регион из списка';
  }

  // Валидация goal
  if (!data.goal || data.goal.trim().length < 10) {
    errors.goal = 'Цель должна содержать минимум 10 символов';
  }
  if (data.goal && data.goal.length > 500) {
    errors.goal = 'Цель не должна превышать 500 символов';
  }

  // Валидация detailLevel
  if (!data.detailLevel || !DETAIL_LEVELS.includes(data.detailLevel)) {
    errors.detailLevel = 'Выберите допустимый уровень детализации';
  }

  // Валидация strongSide (опциональное)
  if (data.strongSide && data.strongSide.length > 500) {
    errors.strongSide = 'Сильная сторона не должна превышать 500 символов';
  }

  // Валидация weakSide (опциональное)
  if (data.weakSide && data.weakSide.length > 500) {
    errors.weakSide = 'Слабая сторона не должна превышать 500 символов';
  }

  // Валидация analysisType
  const validAnalysisTypes = ['РЫНОК', 'КОНКУРЕНТЫ', 'ЦА', 'КАНАЛЫ', 'SWOT'];
  if (!data.analysisType || !validAnalysisTypes.includes(data.analysisType)) {
    errors.analysisType = 'Выберите допустимый тип анализа';
  }

  return {
    valid: Object.keys(errors).length === 0,
    errors,
  };
}

Миграция со старого API

Если у вас есть код, использующий старые поля, необходимо обновить его следующим образом:

Старый формат (больше не работает):

{
  "product": "Разработка мобильных приложений",
  "location": "Алматы, Казахстан",
  "client": "B2B клиенты",
  "differentiator": "Быстрая разработка за 2 недели",
  "analysisType": "РЫНОК"
}

Новый формат:

{
  "businessNiche": "Разработка программного обеспечения",
  "product": "Разработка мобильных приложений",
  "targetAudience": "B2B клиенты, технологические компании, стартапы",
  "region": "Алматы",
  "goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев",
  "detailLevel": "СТАНДАРТНО",
  "strongSide": "Быстрая разработка за 2 недели, опытная команда",
  "weakSide": "",
  "analysisType": "РЫНОК"
}

Маппинг старых полей на новые:

Старое поле Новое поле(я) Примечание
location region Только название города из списка
client targetAudience Более детальное описание (свободный текст)
differentiator businessNiche, strongSide, weakSide Разделено на несколько полей для лучшего анализа

Обработка ошибок валидации

При ошибках валидации API возвращает следующий формат:

{
  "success": false,
  "message": "Ошибка валидации",
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Ошибка валидации входных данных",
    "details": {
      "businessNiche": "Поле 'businessNiche' должно содержать от 3 до 200 символов",
      "region": "Поле 'region' должно быть одним из допустимых городов Казахстана",
      "detailLevel": "Поле 'detailLevel' должно быть одним из: КРАТКО, СТАНДАРТНО, ПОДРОБНО"
    }
  }
}

Важные замечания

  1. Регистр важен: Значения region, detailLevel и analysisType чувствительны к регистру. Используйте точные значения из списка допустимых.

  2. Все новые поля передаются в OpenAI: Все указанные поля включаются в контекст для генерации анализа, что улучшает качество и релевантность результатов.

  3. Уровень детализации влияет на результат: Выбор detailLevel напрямую влияет на объем и глубину генерируемого анализа.

  4. Опциональные поля улучшают анализ: Хотя strongSide и weakSide опциональны, их указание помогает AI лучше понять бизнес и дать более точные рекомендации.

  5. Обратная совместимость: Старые поля больше не поддерживаются. Необходимо обновить все клиентские приложения.


Поддержка

При возникновении проблем с API обращайтесь в техническую поддержку с указанием:

  • analysisId (если есть)
  • Время запроса
  • Описание проблемы
  • Код ошибки (если есть)
  • Пример запроса (без чувствительных данных)