Files
marketing-parser/IMAGE_GENERATION_FRONTEND.md
T
2025-12-05 01:03:01 +05:00

525 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Документация для фронтенда: Генерация изображений для постов
## Обзор изменений
В систему добавлена автоматическая генерация изображений для постов в социальных сетях. Теперь при создании маркетинговой стратегии для каждого поста автоматически генерируется уникальное изображение с помощью OpenAI DALL-E API. Изображения сохраняются в MinIO и прикрепляются к постам при публикации в Facebook.
---
## Новые поля в API
### 1. PostCalendarItem (Календарь постов)
В объекте `PostCalendarItem` добавлены два новых поля для работы с изображениями:
| Поле | Тип | Описание | Обязательное |
| --------------- | ------ | ------------------------------------------------------------------- | ------------ |
| `imageUrl` | string | Путь к изображению в MinIO (используется для получения изображения) | Нет |
| `imageFilename` | string | Имя файла изображения в MinIO | Нет |
**Важно:**
- Поля могут быть `null`, если генерация изображения не удалась
- В этом случае пост публикуется без изображения
- Оба поля содержат одинаковое значение (имя файла в MinIO)
### 2. PostingTask (Задачи публикации)
В объекте `PostingTask` также добавлены поля для изображений:
| Поле | Тип | Описание | Обязательное |
| --------------- | ------ | ----------------------------- | ------------ |
| `imageUrl` | string | Путь к изображению в MinIO | Нет |
| `imageFilename` | string | Имя файла изображения в MinIO | Нет |
---
## Изменения в 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`
Аналогично, ответ включает поля изображений в календаре постов.
---
## Получение изображений
### Способ 1: Через MinIO API (рекомендуется)
Если у вас есть доступ к MinIO API, используйте `imageUrl` или `imageFilename` для получения изображения:
```
GET {minio-endpoint}/{bucket-name}/{imageFilename}
```
Где:
- `minio-endpoint` - адрес вашего MinIO сервера (например, `http://92.38.48.166:9000`)
- `bucket-name` - имя bucket (обычно `konturai`)
- `imageFilename` - значение из поля `imageFilename` или `imageUrl`
### Способ 2: Через бэкенд API (если реализован)
Если бэкенд предоставляет эндпоинт для получения изображений, используйте его:
```
GET /api/marketing/images/{imageFilename}
```
**Примечание:** На данный момент такой эндпоинт не реализован. При необходимости его можно добавить.
---
## Рекомендации по отображению
### 1. Проверка наличия изображения
Всегда проверяйте наличие изображения перед отображением:
```javascript
// Пример на JavaScript/TypeScript
const PostCard = ({ post }) => {
const hasImage = post.imageUrl && post.imageFilename;
return (
<div className='post-card'>
<h3>{post.theme}</h3>
<p>{post.postText}</p>
{hasImage ? (
<img
src={`${MINIO_ENDPOINT}/${BUCKET_NAME}/${post.imageFilename}`}
alt={post.theme}
onError={(e) => {
// Fallback если изображение не загрузилось
e.target.style.display = 'none';
}}
/>
) : (
<div className='no-image-placeholder'>Изображение не сгенерировано</div>
)}
<div className='hashtags'>
{post.hashtags.map((tag) => (
<span key={tag}>#{tag}</span>
))}
</div>
</div>
);
};
```
### 2. Обработка ошибок загрузки
Всегда предусматривайте fallback для случаев, когда:
- Изображение не сгенерировано (`imageUrl` = `null`)
- Изображение не найдено в MinIO
- Ошибка при загрузке изображения
```javascript
const [imageError, setImageError] = useState(false);
const handleImageError = () => {
setImageError(true);
};
return (
<>
{post.imageUrl && !imageError ? (
<img
src={getImageUrl(post.imageFilename)}
alt={post.theme}
onError={handleImageError}
/>
) : (
<div className='image-placeholder'>
<Icon name='image' />
<span>Изображение недоступно</span>
</div>
)}
</>
);
```
### 3. Оптимизация загрузки
Рекомендуется использовать lazy loading для изображений:
```javascript
<img
src={
post.imageUrl
? `${MINIO_ENDPOINT}/${BUCKET_NAME}/${post.imageFilename}`
: null
}
alt={post.theme}
loading='lazy'
className='post-image'
/>
```
### 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;
minioEndpoint: string;
bucketName: string;
}
const PostCard: React.FC<PostCardProps> = ({
post,
minioEndpoint,
bucketName,
}) => {
const [imageError, setImageError] = useState(false);
const getImageUrl = (): string | null => {
if (!post.imageFilename) return null;
return `${minioEndpoint}/${bucketName}/${post.imageFilename}`;
};
const imageUrl = getImageUrl();
return (
<div className='post-card'>
<div className='post-header'>
<span className='platform-badge'>{post.platform}</span>
<span className='content-type'>{post.contentType}</span>
<span className='publish-time'>{post.publishTime}</span>
</div>
<h3 className='post-theme'>{post.theme}</h3>
{imageUrl && !imageError ? (
<div className='post-image-container'>
<img
src={imageUrl}
alt={post.theme}
className='post-image'
loading='lazy'
onError={() => setImageError(true)}
/>
</div>
) : (
<div className='no-image-placeholder'>
<svg width='64' height='64' viewBox='0 0 24 24' fill='none'>
<path
d='M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z'
fill='currentColor'
/>
</svg>
<p>Изображение не сгенерировано</p>
</div>
)}
<p className='post-text'>{post.postText}</p>
<div className='post-hashtags'>
{post.hashtags.map((tag, index) => (
<span key={index} className='hashtag'>
{tag.startsWith('#') ? tag : `#${tag}`}
</span>
))}
</div>
<div className='post-footer'>
<span className='publish-date'>
{new Date(post.publishDate).toLocaleDateString('ru-RU')}
</span>
</div>
</div>
);
};
export default PostCard;
```
### Vue компонент
```vue
<template>
<div class="post-card">
<div class="post-header">
<span class="platform-badge">{{ post.platform }}</span>
<span class="content-type">{{ post.contentType }}</span>
<span class="publish-time">{{ post.publishTime }}</span>
</div>
<h3 class="post-theme">{{ post.theme }}</h3>
<div v-if="imageUrl && !imageError" class="post-image-container">
<img
:src="imageUrl"
:alt="post.theme"
class="post-image"
loading="lazy"
@error="imageError = true"
/>
</div>
<div v-else class="no-image-placeholder">
<Icon name="image" />
<p>Изображение не сгенерировано</p>
</div>
<p class="post-text">{{ post.postText }}</p>
<div class="post-hashtags">
<span v-for="(tag, index) in post.hashtags" :key="index" class="hashtag">
{{ tag.startsWith('#') ? tag : `#${tag}` }}
</span>
</div>
<div class="post-footer">
<span class="publish-date">
{{ formatDate(post.publishDate) }}
</span>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
interface PostCalendarItem {
publishDate: string;
platform: string;
contentType: string;
theme: string;
postText: string;
hashtags: string[];
publishTime: string;
imageUrl?: string | null;
imageFilename?: string | null;
}
const props = defineProps<{
post: PostCalendarItem;
minioEndpoint: string;
bucketName: string;
}>();
const imageError = ref(false);
const imageUrl = computed(() => {
if (!props.post.imageFilename) return null;
return `${props.minioEndpoint}/${props.bucketName}/${props.post.imageFilename}`;
});
const formatDate = (dateString: string) => {
return new Date(dateString).toLocaleDateString('ru-RU');
};
</script>
```
---
## Важные замечания
### 1. Генерация изображений
- Изображения генерируются **автоматически** при создании стратегии
- Процесс генерации может занять время (обычно 10-30 секунд на изображение)
- Если генерация не удалась, пост все равно будет создан, но без изображения
### 2. Хранение изображений
- Все изображения хранятся в MinIO
- Формат изображений: **PNG**
- Размер изображений: **1024x1024 пикселей**
- Имя файла уникально для каждого поста
### 3. Публикация постов
- При публикации поста в Facebook изображение автоматически прикрепляется
- Если изображение отсутствует, пост публикуется только с текстом
- Это не влияет на успешность публикации
### 4. Обратная совместимость
- Старые стратегии, созданные до добавления этой функции, не будут иметь изображений
- Поля `imageUrl` и `imageFilename` будут `null` для таких постов
- Фронтенд должен корректно обрабатывать `null` значения
---
## Конфигурация
Для работы с изображениями вам понадобятся следующие настройки:
```typescript
// config.ts
export const MINIO_CONFIG = {
endpoint: 'http://92.38.48.166:9000', // или ваш MinIO endpoint
bucketName: 'konturai',
// Если требуется авторизация:
// accessKey: 'your-access-key',
// secretKey: 'your-secret-key',
};
```
---
## Миграция существующего кода
Если у вас уже есть компоненты для отображения постов, обновите их следующим образом:
1. **Добавьте проверку наличия изображения:**
```typescript
const hasImage = post.imageUrl && post.imageFilename;
```
2. **Добавьте отображение изображения:**
```jsx
{
hasImage && <img src={getImageUrl(post)} alt={post.theme} />;
}
```
3. **Обновите типы/интерфейсы:**
```typescript
interface PostCalendarItem {
// ... существующие поля
imageUrl?: string | null;
imageFilename?: string | null;
}
```
---
## Поддержка
При возникновении проблем:
1. Проверьте, что `imageUrl` и `imageFilename` не `null`
2. Убедитесь, что MinIO доступен и изображение существует
3. Проверьте консоль браузера на наличие ошибок CORS (если обращаетесь к MinIO напрямую)
4. Убедитесь, что используете правильный endpoint и bucket name
---
## Пример полного ответа 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