diff --git a/API Документация: Генерация стратегии продвижения (Frontend/Документация для фронтенда: Генерация изображений для постов.md b/API Документация: Генерация стратегии продвижения (Frontend/Документация для фронтенда: Генерация изображений для постов.md deleted file mode 100644 index e201db1..0000000 --- a/API Документация: Генерация стратегии продвижения (Frontend/Документация для фронтенда: Генерация изображений для постов.md +++ /dev/null @@ -1,548 +0,0 @@ -# Документация для фронтенда: Генерация изображений для постов - -## Обзор изменений - -В систему добавлена автоматическая генерация изображений для постов в социальных сетях. Теперь при создании маркетинговой стратегии для каждого поста автоматически генерируется уникальное изображение с помощью OpenAI DALL-E API. Изображения сохраняются в MinIO и прикрепляются к постам при публикации в Facebook. - ---- - -## Новые поля в API - -### 1. PostCalendarItem (Календарь постов) - -В объекте `PostCalendarItem` добавлены два новых поля для работы с изображениями: - -| Поле | Тип | Описание | Обязательное | -| --------------- | ------ | ------------------------------------------------------------ | ------------ | -| `imageUrl` | string | Имя файла изображения (используется для получения через API) | Нет | -| `imageFilename` | string | Имя файла изображения | Нет | - -**Важно:** - -- Поля могут быть `null`, если генерация изображения не удалась -- В этом случае пост публикуется без изображения -- Оба поля содержат одинаковое значение (имя файла) -- Для получения изображения используйте API эндпоинт `/api/marketing/analysis/images/{imageFilename}` - -### 2. PostingTask (Задачи публикации) - -В объекте `PostingTask` также добавлены поля для изображений: - -| Поле | Тип | Описание | Обязательное | -| --------------- | ------ | ------------------------------------------------------------ | ------------ | -| `imageUrl` | string | Имя файла изображения (используется для получения через API) | Нет | -| `imageFilename` | string | Имя файла изображения | Нет | - ---- - -## Изменения в API эндпоинтах - -### GET `/api/marketing/strategy/{strategyId}` - -Ответ теперь включает поля изображений в каждом элементе календаря постов. - -#### Пример ответа - -```json -{ - "success": true, - "data": { - "strategyId": "507f1f77bcf86cd799439011", - "analysisId": "507f1f77bcf86cd799439012", - "status": "completed", - "strategy": { - "postCalendar": [ - { - "publishDate": "2024-01-15T10:00:00", - "platform": "Facebook", - "contentType": "пост", - "theme": "Презентация нового продукта", - "postText": "Мы рады представить наш новый продукт...", - "hashtags": ["#новинка", "#продукт", "#маркетинг"], - "publishTime": "10:00", - "imageUrl": "post_image_1705312800000_1234567890.png", - "imageFilename": "post_image_1705312800000_1234567890.png" - } - ] - } - } -} -``` - -### GET `/api/marketing/analysis/{analysisId}/strategy` - -Аналогично, ответ включает поля изображений в календаре постов. - ---- - -## Получение изображений - -### Через бэкенд API - -Все изображения должны получаться через бэкенд API. Прямой доступ к MinIO с фронтенда не предусмотрен. - -#### Эндпоинт для получения изображения - -**GET** `/api/marketing/analysis/images/{imageFilename}` - -Возвращает изображение поста в формате PNG. - -#### Параметры пути - -| Параметр | Тип | Описание | -| --------------- | ------ | --------------------- | -| `imageFilename` | string | Имя файла изображения | - -#### Заголовки запроса - -| Заголовок | Тип | Обязательный | Описание | -| --------------- | ------ | ------------ | ------------------------------------ | -| `Authorization` | string | Да | JWT токен в формате `Bearer {token}` | - -#### Пример запроса - -```javascript -const imageUrl = `/api/marketing/analysis/images/${post.imageFilename}`; - -fetch(imageUrl, { - headers: { - Authorization: `Bearer ${token}` - } -}) - .then((response) => { - if (response.ok) { - return response.blob(); - } - throw new Error('Failed to load image'); - }) - .then((blob) => { - const imageObjectUrl = URL.createObjectURL(blob); - // Используйте imageObjectUrl для отображения - }); -``` - -#### Пример ответа - -- **Успешный ответ (200 OK):** - - - Content-Type: `image/png` - - Body: бинарные данные изображения PNG - -- **Ошибка 401 Unauthorized:** - - - Токен отсутствует или невалиден - -- **Ошибка 404 Not Found:** - - - Изображение не найдено на сервере - -- **Ошибка 500 Internal Server Error:** - - Внутренняя ошибка сервера при загрузке изображения - -#### Кэширование - -Сервер возвращает заголовок `Cache-Control: public, max-age=3600`, что позволяет браузеру кэшировать изображения на 1 час. - ---- - -## Рекомендации по отображению - -### 1. Проверка наличия изображения - -Всегда проверяйте наличие изображения перед отображением: - -```javascript -// Пример на JavaScript/TypeScript -const PostCard = ({ post, apiBaseUrl, authToken }) => { - const hasImage = post.imageUrl && post.imageFilename; - const imageUrl = hasImage ? `${apiBaseUrl}/api/marketing/analysis/images/${post.imageFilename}` : null; - - return ( -
-

{post.theme}

-

{post.postText}

- - {imageUrl ? ( - {post.theme} { - // Fallback если изображение не загрузилось - e.target.style.display = 'none'; - }} - // Если требуется авторизация, используйте fetch с заголовками - /> - ) : ( -
Изображение не сгенерировано
- )} - -
- {post.hashtags.map((tag) => ( - #{tag} - ))} -
-
- ); -}; -``` - -### 2. Обработка ошибок загрузки - -Всегда предусматривайте fallback для случаев, когда: - -- Изображение не сгенерировано (`imageUrl` = `null`) -- Изображение не найдено на сервере -- Ошибка при загрузке изображения - -```javascript -const [imageError, setImageError] = useState(false); - -const getImageUrl = (imageFilename) => { - if (!imageFilename) return null; - return `${API_BASE_URL}/api/marketing/analysis/images/${imageFilename}`; -}; - -const handleImageError = () => { - setImageError(true); -}; - -return ( - <> - {post.imageUrl && !imageError ? ( - {post.theme} - ) : ( -
- - Изображение недоступно -
- )} - -); -``` - -### 3. Оптимизация загрузки - -Рекомендуется использовать lazy loading для изображений: - -```javascript -{post.theme} -``` - -### 4. Размеры изображений - -Изображения генерируются в размере **1024x1024 пикселей** (квадратные). При отображении учитывайте это при настройке CSS: - -```css -.post-image { - width: 100%; - max-width: 512px; - height: auto; - border-radius: 8px; - object-fit: cover; -} -``` - ---- - -## Примеры использования - -### React компонент для отображения поста - -```typescript -import React, { useState } from 'react'; - -interface PostCalendarItem { - publishDate: string; - platform: string; - contentType: string; - theme: string; - postText: string; - hashtags: string[]; - publishTime: string; - imageUrl?: string | null; - imageFilename?: string | null; -} - -interface PostCardProps { - post: PostCalendarItem; - apiBaseUrl: string; -} - -const PostCard: React.FC = ({ post, apiBaseUrl }) => { - const [imageError, setImageError] = useState(false); - - const getImageUrl = (): string | null => { - if (!post.imageFilename) return null; - return `${apiBaseUrl}/api/marketing/analysis/images/${post.imageFilename}`; - }; - - const imageUrl = getImageUrl(); - - return ( -
-
- {post.platform} - {post.contentType} - {post.publishTime} -
- -

{post.theme}

- - {imageUrl && !imageError ? ( -
- {post.theme} setImageError(true)} - /> -
- ) : ( -
- - - -

Изображение не сгенерировано

-
- )} - -

{post.postText}

- -
- {post.hashtags.map((tag, index) => ( - - {tag.startsWith('#') ? tag : `#${tag}`} - - ))} -
- -
- - {new Date(post.publishDate).toLocaleDateString('ru-RU')} - -
-
- ); -}; - -export default PostCard; -``` - -### Vue компонент - -```vue - - - -``` - ---- - -## Важные замечания - -### 1. Генерация изображений - -- Изображения генерируются **автоматически** при создании стратегии -- Процесс генерации может занять время (обычно 10-30 секунд на изображение) -- Если генерация не удалась, пост все равно будет создан, но без изображения - -### 2. Хранение изображений - -- Все изображения хранятся на бэкенде -- Формат изображений: **PNG** -- Размер изображений: **1024x1024 пикселей** -- Имя файла уникально для каждого поста -- Доступ к изображениям только через API эндпоинт - -### 3. Публикация постов - -- При публикации поста в Facebook изображение автоматически прикрепляется -- Если изображение отсутствует, пост публикуется только с текстом -- Это не влияет на успешность публикации - -### 4. Обратная совместимость - -- Старые стратегии, созданные до добавления этой функции, не будут иметь изображений -- Поля `imageUrl` и `imageFilename` будут `null` для таких постов -- Фронтенд должен корректно обрабатывать `null` значения - ---- - -## Конфигурация - -Для работы с изображениями вам понадобится базовый URL вашего API: - -```typescript -// config.ts -export const API_CONFIG = { - baseUrl: 'http://your-backend-url' // URL вашего бэкенда - // Например: 'http://localhost:8080' или 'https://api.example.com' -}; -``` - ---- - -## Миграция существующего кода - -Если у вас уже есть компоненты для отображения постов, обновите их следующим образом: - -1. **Добавьте проверку наличия изображения:** - - ```typescript - const hasImage = post.imageUrl && post.imageFilename; - ``` - -2. **Добавьте отображение изображения:** - - ```jsx - { - hasImage && {post.theme}; - } - ``` - -3. **Обновите типы/интерфейсы:** - ```typescript - interface PostCalendarItem { - // ... существующие поля - imageUrl?: string | null; - imageFilename?: string | null; - } - ``` - ---- - -## Поддержка - -При возникновении проблем: - -1. Проверьте, что `imageUrl` и `imageFilename` не `null` -2. Убедитесь, что используете правильный API эндпоинт: `/api/marketing/analysis/images/{imageFilename}` -3. Проверьте, что JWT токен валиден и передается в заголовке `Authorization` -4. Проверьте консоль браузера на наличие ошибок сети или авторизации -5. Убедитесь, что используете правильный базовый URL API - ---- - -## Пример полного ответа API - -```json -{ - "success": true, - "data": { - "strategyId": "507f1f77bcf86cd799439011", - "analysisId": "507f1f77bcf86cd799439012", - "status": "completed", - "createdAt": "2024-01-15T10:00:00", - "completedAt": "2024-01-15T10:05:00", - "durationWeeks": 4, - "priorityPlatforms": ["Facebook", "Instagram"], - "strategy": { - "weeklyPlans": [ - { - "weekNumber": 1, - "mainThemes": ["Презентация продукта", "Преимущества"], - "contentRecommendations": "Создавайте контент...", - "priorityPlatforms": ["Facebook"] - } - ], - "postCalendar": [ - { - "publishDate": "2024-01-16T10:00:00", - "platform": "Facebook", - "contentType": "пост", - "theme": "Презентация нового продукта", - "postText": "Мы рады представить наш новый продукт, который поможет вам...", - "hashtags": ["#новинка", "#продукт", "#маркетинг"], - "publishTime": "10:00", - "imageUrl": "post_image_1705312800000_1234567890.png", - "imageFilename": "post_image_1705312800000_1234567890.png" - }, - { - "publishDate": "2024-01-18T14:00:00", - "platform": "Instagram", - "contentType": "сторис", - "theme": "Преимущества продукта", - "postText": "Узнайте о главных преимуществах нашего продукта...", - "hashtags": ["#преимущества", "#качество"], - "publishTime": "14:00", - "imageUrl": null, - "imageFilename": null - } - ] - } - } -} -``` - -Обратите внимание, что второй пост не имеет изображения (`imageUrl` и `imageFilename` равны `null`). Это нормальная ситуация, если генерация изображения не удалась. - ---- - -**Дата обновления:** 2024-01-15 -**Версия API:** 1.0 diff --git a/src/components/marketing/PptKpiCard.vue b/src/components/marketing/PptKpiCard.vue index eaba672..6063a5b 100644 --- a/src/components/marketing/PptKpiCard.vue +++ b/src/components/marketing/PptKpiCard.vue @@ -28,7 +28,7 @@
-
+
{{ value }}
@@ -59,9 +59,9 @@ function hexToRgba(hex, alpha) { const full = h.length === 3 ? h - .split('') - .map((c) => c + c) - .join('') + .split('') + .map((c) => c + c) + .join('') : h; if (full.length !== 6) return `rgba(91, 137, 255, ${alpha})`; const r = parseInt(full.slice(0, 2), 16); diff --git a/src/service/MarketingService.js b/src/service/MarketingService.js index c122870..892fa09 100644 --- a/src/service/MarketingService.js +++ b/src/service/MarketingService.js @@ -140,7 +140,18 @@ class MarketingService { // v2: извлекаем data из обёртки {success, message, data}, если она есть // для обратной совместимости поддерживаем оба формата - return result.data || result; + let extracted = result.data || result; + + // Убеждаемся, что sources сохраняются, если они есть в исходных данных + if (extracted && !extracted.sources) { + if (result.data?.sources) { + extracted.sources = result.data.sources; + } else if (result.sources) { + extracted.sources = result.sources; + } + } + + return extracted; } catch (error) { console.error('Ошибка при запуске маркетингового анализа v2:', error); throw error; diff --git a/src/views/pages/MarketingAnalysis.vue b/src/views/pages/MarketingAnalysis.vue index a586411..28b2be2 100644 --- a/src/views/pages/MarketingAnalysis.vue +++ b/src/views/pages/MarketingAnalysis.vue @@ -120,7 +120,7 @@ {{ marketYoYGrowthValue }}
- +
@@ -523,20 +475,6 @@
-
-
-
-
Тип запроса
-
Доля
-
-
-
-
{{ row.label }}
-
{{ row.value }}%
-
-
-
-
@@ -551,21 +489,7 @@ >
- -
-
-
-
-
Фактор
-
Доля
-
-
-
-
{{ row.label }}
-
{{ row.value }}%
-
-
-
+
@@ -579,21 +503,7 @@ >
- -
-
-
-
-
Причина
-
Доля
-
-
-
-
{{ row.label }}
-
{{ row.value }}%
-
-
-
+
@@ -642,35 +552,39 @@ /> -
- -
-
+
-
-
Основные проблемы на воронке
+
+
Воронка продаж
+
+
+ +
+
+
+ +
+
+
+
Узкие места воронки
+
-
Этап
-
Проблема
+
Этап
+
Причина
-
-
Лид → Запись
-
{{ report?.sections?.customer_journey?.funnel_bottlenecks?.lead_to_booking }}
-
-
-
Запись → Оплата
-
{{ report?.sections?.customer_journey?.funnel_bottlenecks?.booking_to_payment }}
+
+
{{ row.stage }}
+
{{ row.reason }}
@@ -719,55 +633,19 @@ />
-
+
Доли каналов
-
- -
-
-
-
-
Канал
-
Доля
-
-
-
-
{{ row.label }}
-
{{ row.value }}%
-
-
-
-
-
-
-
-
-
-
Стоимость привлечения
- -
-
-
-
Канал
-
Стоимость
-
Эффективность
-
-
-
-
{{ row.label }}
-
{{ row.cost }}
-
{{ row.status }}
-
+
+ +
+ Нет данных по долям каналов
@@ -1090,12 +968,69 @@
+ + +
+
+
Маркетинг Источники
+
+
ИСТОЧНИКИ
+ +
+
список источников данных для анализа
+ + + +
+ +
+ + Источники не найдены +
+
+
+
+ + +
+
+
+
+
+