964 lines
37 KiB
Markdown
964 lines
37 KiB
Markdown
# 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\-,]+$`
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"businessNiche": "E-commerce платформы"
|
|
"businessNiche": "Образовательные технологии"
|
|
"businessNiche": "Финансовые услуги для малого бизнеса"
|
|
```
|
|
|
|
---
|
|
|
|
### 2. `product` (обязательное)
|
|
|
|
**Описание**: Конкретный продукт или услуга, которую предоставляет компания.
|
|
|
|
**Валидация**:
|
|
|
|
- Минимальная длина: 3 символа
|
|
- Максимальная длина: 200 символов
|
|
- Разрешены: буквы, цифры, пробелы, дефисы, запятые
|
|
- Паттерн: `^[\p{L}\p{N}\s\-,]+$`
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"product": "Разработка мобильных приложений"
|
|
"product": "Консультации по маркетингу"
|
|
"product": "Веб-разработка и дизайн"
|
|
```
|
|
|
|
---
|
|
|
|
### 3. `targetAudience` (обязательное)
|
|
|
|
**Описание**: Структурированное описание целевой аудитории в формате JSON. Позволяет выбрать гендер, возрастные диапазоны и типы аудитории. Можно выбрать несколько вариантов в каждой категории.
|
|
|
|
**Валидация**:
|
|
|
|
- Должно быть объектом JSON с полями `genders`, `ageRanges`, `types`
|
|
- Хотя бы одно поле должно быть заполнено и содержать непустой массив
|
|
- Каждое поле должно содержать только допустимые значения
|
|
|
|
**Структура**:
|
|
|
|
```json
|
|
{
|
|
"genders": ["Женщины", "Мужчины"],
|
|
"ageRanges": ["20-40", "25-45"],
|
|
"types": ["Семьи", "Молодёжь"]
|
|
}
|
|
```
|
|
|
|
**Допустимые значения**:
|
|
|
|
- `genders`: `["Женщины", "Мужчины"]` - можно выбрать один или оба
|
|
- `ageRanges`: `["20-40", "25-45", "18-25", "40-60", "60+"]` - можно выбрать один или несколько диапазонов
|
|
- `types`: `["Семьи", "Молодёжь", "Все подряд"]` - можно выбрать один или несколько типов
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"targetAudience": {
|
|
"genders": ["Женщины"],
|
|
"ageRanges": ["20-40"],
|
|
"types": ["Молодёжь"]
|
|
}
|
|
```
|
|
|
|
```json
|
|
"targetAudience": {
|
|
"genders": ["Женщины", "Мужчины"],
|
|
"ageRanges": ["25-45", "40-60"],
|
|
"types": ["Семьи"]
|
|
}
|
|
```
|
|
|
|
```json
|
|
"targetAudience": {
|
|
"genders": ["Мужчины"],
|
|
"ageRanges": ["18-25"],
|
|
"types": ["Молодёжь", "Все подряд"]
|
|
}
|
|
```
|
|
|
|
**Примечание**: Можно выбрать несколько вариантов в каждой категории. Все выбранные значения будут отражены в анализе.
|
|
|
|
---
|
|
|
|
### 4. `region` (обязательное)
|
|
|
|
**Описание**: Регионы (города Казахстана), в которых работает бизнес. Можно выбрать один или несколько регионов. Это поле заменяет старое поле `location`.
|
|
|
|
**Валидация**:
|
|
|
|
- Должно быть массивом строк
|
|
- Минимум один регион должен быть выбран
|
|
- Каждый регион должен быть одним из допустимых городов Казахстана
|
|
- Проверка выполняется через валидатор `@ValidRegion`
|
|
|
|
**Допустимые значения** (точное совпадение):
|
|
|
|
- `"Алматы"`
|
|
- `"Астана"`
|
|
- `"Шымкент"`
|
|
- `"Караганда"`
|
|
- `"Актобе"`
|
|
- `"Тараз"`
|
|
- `"Павлодар"`
|
|
- `"Усть-Каменогорск"`
|
|
- `"Семей"`
|
|
- `"Костанай"`
|
|
- `"Кызылорда"`
|
|
- `"Уральск"`
|
|
- `"Петропавловск"`
|
|
- `"Атырау"`
|
|
- `"Актау"`
|
|
- `"Туркестан"`
|
|
- `"Кокшетау"`
|
|
- `"Талдыкорган"`
|
|
- `"Экибастуз"`
|
|
- `"Рудный"`
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"region": ["Алматы"]
|
|
```
|
|
|
|
```json
|
|
"region": ["Алматы", "Астана", "Шымкент"]
|
|
```
|
|
|
|
```json
|
|
"region": ["Астана", "Караганда"]
|
|
```
|
|
|
|
**Важно**:
|
|
- Значения должны точно совпадать с допустимыми городами (регистр важен)
|
|
- Можно выбрать все регионы, перечислив их в массиве
|
|
- Все выбранные регионы будут отражены в анализе
|
|
|
|
---
|
|
|
|
### 5. `goal` (обязательное)
|
|
|
|
**Описание**: Цель бизнеса на период 6-12 месяцев. Это новое поле, которое помогает AI лучше понять приоритеты бизнеса.
|
|
|
|
**Валидация**:
|
|
|
|
- Минимальная длина: 10 символов
|
|
- Максимальная длина: 500 символов
|
|
- Разрешены любые символы
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"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 рекомендаций | Детальная с обоснованием |
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"detailLevel": "КРАТКО"
|
|
"detailLevel": "СТАНДАРТНО"
|
|
"detailLevel": "ПОДРОБНО"
|
|
```
|
|
|
|
---
|
|
|
|
### 7. `strongSide` (опциональное)
|
|
|
|
**Описание**: Сильная сторона бизнеса. Помогает AI лучше понять конкурентные преимущества.
|
|
|
|
**Валидация**:
|
|
|
|
- Максимальная длина: 500 символов
|
|
- Разрешены любые символы
|
|
- Может быть пустым или отсутствовать
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"strongSide": "Опытная команда разработчиков с 10+ летним опытом, быстрая доставка проектов"
|
|
"strongSide": "Уникальная технология, низкие цены, отличная поддержка клиентов"
|
|
```
|
|
|
|
**Примечание**: Если поле не указано, AI будет анализировать сильные стороны на основе других данных.
|
|
|
|
---
|
|
|
|
### 8. `weakSide` (опциональное)
|
|
|
|
**Описание**: Слабая сторона бизнеса. Помогает AI лучше понять области для улучшения.
|
|
|
|
**Валидация**:
|
|
|
|
- Максимальная длина: 500 символов
|
|
- Разрешены любые символы
|
|
- Может быть пустым или отсутствовать
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"weakSide": "Ограниченный маркетинговый бюджет, недостаточная узнаваемость бренда"
|
|
"weakSide": "Небольшая команда, ограниченные ресурсы для масштабирования"
|
|
```
|
|
|
|
**Примечание**: Если поле не указано, AI будет анализировать слабые стороны на основе других данных.
|
|
|
|
---
|
|
|
|
### 9. `analysisType` (обязательное)
|
|
|
|
**Описание**: Тип(ы) анализа, которые необходимо провести. Можно выбрать один или несколько типов анализа. При выборе нескольких типов будет создан отдельный анализ для каждого типа.
|
|
|
|
**Валидация**:
|
|
|
|
- Должно быть массивом строк
|
|
- Минимум один тип анализа должен быть выбран
|
|
- Каждый тип должен быть одним из допустимых значений
|
|
- Проверка выполняется через валидатор `@ValidAnalysisType`
|
|
|
|
**Допустимые значения**:
|
|
|
|
- `"РЫНОК"` - Анализ рынка (размер рынка, динамика роста, сегменты, тренды)
|
|
- `"КОНКУРЕНТЫ"` - Анализ конкурентов (основные конкуренты, их сильные/слабые стороны, позиционирование)
|
|
- `"ЦА"` - Анализ целевой аудитории (демография, психография, потребности, поведение)
|
|
- `"КАНАЛЫ"` - Анализ маркетинговых каналов (эффективность каналов, рекомендации по выбору)
|
|
- `"SWOT"` - SWOT-анализ (сильные стороны, слабые стороны, возможности, угрозы)
|
|
|
|
**Примеры**:
|
|
|
|
```json
|
|
"analysisType": ["РЫНОК"]
|
|
```
|
|
|
|
```json
|
|
"analysisType": ["РЫНОК", "КОНКУРЕНТЫ", "ЦА"]
|
|
```
|
|
|
|
```json
|
|
"analysisType": ["РЫНОК", "КОНКУРЕНТЫ", "ЦА", "КАНАЛЫ", "SWOT"]
|
|
```
|
|
|
|
**Важно**:
|
|
- При выборе нескольких типов анализа API создаст отдельные записи анализа для каждого типа
|
|
- В ответе будет возвращен массив с информацией о каждом созданном анализе
|
|
- Каждый анализ будет обрабатываться независимо и иметь свой статус
|
|
|
|
---
|
|
|
|
## Полный пример запроса
|
|
|
|
### POST `/api/marketing/analysis/start`
|
|
|
|
**Пример 1: Один тип анализа, один регион**
|
|
|
|
```json
|
|
{
|
|
"businessNiche": "E-commerce платформы",
|
|
"product": "Разработка мобильных приложений для интернет-магазинов",
|
|
"targetAudience": {
|
|
"genders": ["Женщины"],
|
|
"ageRanges": ["25-45"],
|
|
"types": ["Молодёжь"]
|
|
},
|
|
"region": ["Алматы"],
|
|
"goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев и выйти на рынок соседних регионов",
|
|
"detailLevel": "СТАНДАРТНО",
|
|
"strongSide": "Опытная команда разработчиков с 10+ летним опытом, быстрая доставка проектов, использование современных технологий",
|
|
"weakSide": "Ограниченный маркетинговый бюджет, недостаточная узнаваемость бренда в новых регионах",
|
|
"analysisType": ["РЫНОК"]
|
|
}
|
|
```
|
|
|
|
**Пример 2: Несколько типов анализа, несколько регионов**
|
|
|
|
```json
|
|
{
|
|
"businessNiche": "E-commerce платформы",
|
|
"product": "Разработка мобильных приложений для интернет-магазинов",
|
|
"targetAudience": {
|
|
"genders": ["Женщины", "Мужчины"],
|
|
"ageRanges": ["25-45", "40-60"],
|
|
"types": ["Семьи", "Молодёжь"]
|
|
},
|
|
"region": ["Алматы", "Астана", "Шымкент"],
|
|
"goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев и выйти на рынок соседних регионов",
|
|
"detailLevel": "СТАНДАРТНО",
|
|
"strongSide": "Опытная команда разработчиков с 10+ летним опытом, быстрая доставка проектов",
|
|
"weakSide": "Ограниченный маркетинговый бюджет",
|
|
"analysisType": ["РЫНОК", "КОНКУРЕНТЫ", "ЦА"]
|
|
}
|
|
```
|
|
|
|
**Пример 3: Все типы анализа**
|
|
|
|
```json
|
|
{
|
|
"businessNiche": "E-commerce платформы",
|
|
"product": "Разработка мобильных приложений для интернет-магазинов",
|
|
"targetAudience": {
|
|
"genders": ["Женщины", "Мужчины"],
|
|
"ageRanges": ["20-40", "25-45"],
|
|
"types": ["Семьи", "Молодёжь", "Все подряд"]
|
|
},
|
|
"region": ["Алматы", "Астана"],
|
|
"goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев",
|
|
"detailLevel": "ПОДРОБНО",
|
|
"analysisType": ["РЫНОК", "КОНКУРЕНТЫ", "ЦА", "КАНАЛЫ", "SWOT"]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Примеры использования на фронтенде
|
|
|
|
### JavaScript/TypeScript
|
|
|
|
```typescript
|
|
interface TargetAudience {
|
|
genders?: ('Женщины' | 'Мужчины')[];
|
|
ageRanges?: ('20-40' | '25-45' | '18-25' | '40-60' | '60+')[];
|
|
types?: ('Семьи' | 'Молодёжь' | 'Все подряд')[];
|
|
}
|
|
|
|
interface MarketingAnalysisRequest {
|
|
businessNiche: string;
|
|
product: string;
|
|
targetAudience: TargetAudience;
|
|
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<MarketingAnalysisResponse | MarketingAnalysisResponse[]> {
|
|
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');
|
|
}
|
|
|
|
// Если выбрано несколько типов анализа, result.data будет массивом
|
|
return result.data;
|
|
}
|
|
|
|
interface MarketingAnalysisResponse {
|
|
analysisId: string;
|
|
status: string;
|
|
estimatedCompletion: string;
|
|
message: string;
|
|
}
|
|
|
|
// Пример использования
|
|
const result = await startMarketingAnalysis({
|
|
businessNiche: 'E-commerce платформы',
|
|
product: 'Разработка мобильных приложений',
|
|
targetAudience: {
|
|
genders: ['Женщины', 'Мужчины'],
|
|
ageRanges: ['25-45'],
|
|
types: ['Молодёжь']
|
|
},
|
|
region: ['Алматы', 'Астана'],
|
|
goal: 'Увеличить количество клиентов на 50% за следующие 6 месяцев',
|
|
detailLevel: 'СТАНДАРТНО',
|
|
strongSide: 'Опытная команда, быстрая доставка',
|
|
weakSide: 'Ограниченный маркетинговый бюджет',
|
|
analysisType: ['РЫНОК', 'КОНКУРЕНТЫ'],
|
|
});
|
|
|
|
// Если выбрано несколько типов анализа, result будет массивом
|
|
if (Array.isArray(result)) {
|
|
console.log(`Создано ${result.length} анализов`);
|
|
result.forEach((analysis, index) => {
|
|
console.log(`Анализ ${index + 1}: ${analysis.analysisId}`);
|
|
});
|
|
} else {
|
|
console.log('Анализ создан:', result.analysisId);
|
|
}
|
|
```
|
|
|
|
### React компонент с формой
|
|
|
|
```tsx
|
|
import React, { useState } from 'react';
|
|
|
|
const MarketingAnalysisForm: React.FC = () => {
|
|
const [formData, setFormData] = useState<MarketingAnalysisRequest>({
|
|
businessNiche: '',
|
|
product: '',
|
|
targetAudience: {
|
|
genders: [],
|
|
ageRanges: [],
|
|
types: []
|
|
},
|
|
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>
|
|
<div>
|
|
<div>
|
|
<label>Гендер:</label>
|
|
{['Женщины', 'Мужчины'].map((gender) => (
|
|
<label key={gender}>
|
|
<input
|
|
type='checkbox'
|
|
checked={formData.targetAudience.genders?.includes(gender as any)}
|
|
onChange={(e) => {
|
|
const genders = formData.targetAudience.genders || [];
|
|
if (e.target.checked) {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
genders: [...genders, gender as any]
|
|
}
|
|
});
|
|
} else {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
genders: genders.filter((g) => g !== gender)
|
|
}
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
{gender}
|
|
</label>
|
|
))}
|
|
</div>
|
|
<div>
|
|
<label>Возраст:</label>
|
|
{['20-40', '25-45', '18-25', '40-60', '60+'].map((age) => (
|
|
<label key={age}>
|
|
<input
|
|
type='checkbox'
|
|
checked={formData.targetAudience.ageRanges?.includes(age as any)}
|
|
onChange={(e) => {
|
|
const ageRanges = formData.targetAudience.ageRanges || [];
|
|
if (e.target.checked) {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
ageRanges: [...ageRanges, age as any]
|
|
}
|
|
});
|
|
} else {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
ageRanges: ageRanges.filter((a) => a !== age)
|
|
}
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
{age}
|
|
</label>
|
|
))}
|
|
</div>
|
|
<div>
|
|
<label>Тип:</label>
|
|
{['Семьи', 'Молодёжь', 'Все подряд'].map((type) => (
|
|
<label key={type}>
|
|
<input
|
|
type='checkbox'
|
|
checked={formData.targetAudience.types?.includes(type as any)}
|
|
onChange={(e) => {
|
|
const types = formData.targetAudience.types || [];
|
|
if (e.target.checked) {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
types: [...types, type as any]
|
|
}
|
|
});
|
|
} else {
|
|
setFormData({
|
|
...formData,
|
|
targetAudience: {
|
|
...formData.targetAudience,
|
|
types: types.filter((t) => t !== type)
|
|
}
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
{type}
|
|
</label>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label>Регион *</label>
|
|
<div>
|
|
{VALID_REGIONS.map((region) => (
|
|
<label key={region}>
|
|
<input
|
|
type='checkbox'
|
|
checked={formData.region.includes(region)}
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
setFormData({
|
|
...formData,
|
|
region: [...formData.region, region]
|
|
});
|
|
} else {
|
|
setFormData({
|
|
...formData,
|
|
region: formData.region.filter((r) => r !== region)
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
{region}
|
|
</label>
|
|
))}
|
|
</div>
|
|
</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>
|
|
<div>
|
|
{['РЫНОК', 'КОНКУРЕНТЫ', 'ЦА', 'КАНАЛЫ', 'SWOT'].map((type) => (
|
|
<label key={type}>
|
|
<input
|
|
type='checkbox'
|
|
checked={formData.analysisType.includes(type as any)}
|
|
onChange={(e) => {
|
|
if (e.target.checked) {
|
|
setFormData({
|
|
...formData,
|
|
analysisType: [...formData.analysisType, type as any]
|
|
});
|
|
} else {
|
|
setFormData({
|
|
...formData,
|
|
analysisType: formData.analysisType.filter((t) => t !== type)
|
|
});
|
|
}
|
|
}}
|
|
/>
|
|
{type === 'РЫНОК' && ' Рынок'}
|
|
{type === 'КОНКУРЕНТЫ' && ' Конкуренты'}
|
|
{type === 'ЦА' && ' Целевая аудитория'}
|
|
{type === 'КАНАЛЫ' && ' Каналы'}
|
|
{type === 'SWOT' && ' SWOT'}
|
|
</label>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<button type='submit'>Сгенерировать анализ бизнеса</button>
|
|
</form>
|
|
);
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Валидация на клиенте
|
|
|
|
Рекомендуется выполнять валидацию на клиенте перед отправкой запроса:
|
|
|
|
```typescript
|
|
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
|
|
|
|
Если у вас есть код, использующий старые поля, необходимо обновить его следующим образом:
|
|
|
|
### Старый формат (больше не работает):
|
|
|
|
```json
|
|
{
|
|
"product": "Разработка мобильных приложений",
|
|
"location": "Алматы, Казахстан",
|
|
"client": "B2B клиенты",
|
|
"differentiator": "Быстрая разработка за 2 недели",
|
|
"analysisType": "РЫНОК"
|
|
}
|
|
```
|
|
|
|
### Новый формат:
|
|
|
|
```json
|
|
{
|
|
"businessNiche": "Разработка программного обеспечения",
|
|
"product": "Разработка мобильных приложений",
|
|
"targetAudience": "B2B клиенты, технологические компании, стартапы",
|
|
"region": "Алматы",
|
|
"goal": "Увеличить количество клиентов на 50% за следующие 6 месяцев",
|
|
"detailLevel": "СТАНДАРТНО",
|
|
"strongSide": "Быстрая разработка за 2 недели, опытная команда",
|
|
"weakSide": "",
|
|
"analysisType": "РЫНОК"
|
|
}
|
|
```
|
|
|
|
### Маппинг старых полей на новые:
|
|
|
|
| Старое поле | Новое поле(я) | Примечание |
|
|
| ---------------- | ----------------------------------------- | ------------------------------------------------ |
|
|
| `location` | `region` | Только название города из списка |
|
|
| `client` | `targetAudience` | Более детальное описание (свободный текст) |
|
|
| `differentiator` | `businessNiche`, `strongSide`, `weakSide` | Разделено на несколько полей для лучшего анализа |
|
|
|
|
---
|
|
|
|
## Обработка ошибок валидации
|
|
|
|
При ошибках валидации API возвращает следующий формат:
|
|
|
|
```json
|
|
{
|
|
"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` (если есть)
|
|
- Время запроса
|
|
- Описание проблемы
|
|
- Код ошибки (если есть)
|
|
- Пример запроса (без чувствительных данных)
|