feat: implement core frontend dashboard, auth flow, and AI-driven case management system
This commit is contained in:
@@ -6,9 +6,11 @@
|
|||||||
|
|
||||||
## 💎 Ключевые возможности
|
## 💎 Ключевые возможности
|
||||||
|
|
||||||
### 1. 🤖 AI Assistant (Интеграция с Google Gemini)
|
### 1. 🤖 AI Assistant & Content Factory
|
||||||
* **Авто-претензии:** Генерация юридически грамотных жалоб на нарушителей на основе артикула и площадки.
|
* **Умный генератор карточек:** Создание полноценного контента (описание, ТТХ, SEO-теги) по одному лишь названию товара.
|
||||||
* **Умный ответчик:** Автоматическая генерация персонализированных ответов на отзывы покупателей (поддержка позитивного и отработка негативного сценария).
|
* **ИИ-Фото Промпты:** Генерация детальных заданий для нейросетей (Midjourney/DALL-E) для создания идеальных изображений товара.
|
||||||
|
* **Авто-претензии:** Генерация юридически грамотных жалоб на нарушителей.
|
||||||
|
* **Умный ответчик:** Автоматическая генерация ответов на отзывы покупателей.
|
||||||
|
|
||||||
### 2. 📊 Multi-account Dashboard
|
### 2. 📊 Multi-account Dashboard
|
||||||
* Единое окно управления для неограниченного количества магазинов и юридических лиц.
|
* Единое окно управления для неограниченного количества магазинов и юридических лиц.
|
||||||
|
|||||||
@@ -77,3 +77,19 @@ def ai_generate_reply(current_user_id):
|
|||||||
from ..utils.ai_utils import generate_review_reply
|
from ..utils.ai_utils import generate_review_reply
|
||||||
text = generate_review_reply(review_text, rating)
|
text = generate_review_reply(review_text, rating)
|
||||||
return jsonify({"text": text})
|
return jsonify({"text": text})
|
||||||
|
|
||||||
|
@ai_blueprint.route('/ai/generate-card', methods=['POST'])
|
||||||
|
@token_required
|
||||||
|
def ai_generate_card(current_user_id):
|
||||||
|
"""
|
||||||
|
Генерация полной карточки товара
|
||||||
|
"""
|
||||||
|
data = request.json
|
||||||
|
title = data.get('title')
|
||||||
|
|
||||||
|
if not title:
|
||||||
|
return jsonify({"error": "Название товара обязательно"}), 400
|
||||||
|
|
||||||
|
from ..utils.ai_utils import generate_product_card
|
||||||
|
card_data = generate_product_card(title)
|
||||||
|
return jsonify(card_data)
|
||||||
|
|||||||
@@ -63,3 +63,35 @@ def generate_review_reply(review_text, rating):
|
|||||||
return response.text.strip()
|
return response.text.strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return f"Ошибка ИИ: {str(e)}"
|
return f"Ошибка ИИ: {str(e)}"
|
||||||
|
|
||||||
|
def generate_product_card(title):
|
||||||
|
"""Генерирует описание и характеристики товара по его названию."""
|
||||||
|
api_key = os.getenv('GEMINI_API_KEY')
|
||||||
|
if not api_key:
|
||||||
|
return {"error": "API ключ не настроен."}
|
||||||
|
|
||||||
|
genai.configure(api_key=api_key)
|
||||||
|
model = genai.GenerativeModel('gemini-1.5-flash')
|
||||||
|
|
||||||
|
prompt = f"""
|
||||||
|
Ты - эксперт по листингу на маркетплейсах Ozon и Wildberries.
|
||||||
|
Тебе дано название товара: "{title}"
|
||||||
|
|
||||||
|
Твоя задача - сгенерировать контент для карточки товара в формате JSON.
|
||||||
|
JSON должен содержать:
|
||||||
|
1. "description": Продающее описание (3-4 абзаца), выделяющее преимущества.
|
||||||
|
2. "features": Список из 5-8 ключевых характеристик (ключ: значение).
|
||||||
|
3. "seo_tags": Список из 10 ключевых слов для поиска.
|
||||||
|
4. "image_prompts": 3 подробных промпта для нейросети (на английском), чтобы сгенерировать идеальные фото этого товара (главное фото, в интерьере, детали).
|
||||||
|
|
||||||
|
Ответ дай ТОЛЬКО в виде чистого JSON, без лишних слов.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = model.generate_content(prompt)
|
||||||
|
import json
|
||||||
|
# Очистка от markdown-обертки если есть
|
||||||
|
clean_json = response.text.replace('```json', '').replace('```', '').strip()
|
||||||
|
return json.loads(clean_json)
|
||||||
|
except Exception as e:
|
||||||
|
return {"error": f"Ошибка при генерации карточки: {str(e)}"}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
<button class="tab-btn" data-target="seo-section"><i data-lucide="trending-up" class="icon-sm"></i> SEO</button>
|
<button class="tab-btn" data-target="seo-section"><i data-lucide="trending-up" class="icon-sm"></i> SEO</button>
|
||||||
<button class="tab-btn" data-target="content-section"><i data-lucide="image" class="icon-sm"></i> Контент</button>
|
<button class="tab-btn" data-target="content-section"><i data-lucide="image" class="icon-sm"></i> Контент</button>
|
||||||
<button class="tab-btn" data-target="finance-section"><i data-lucide="wallet" class="icon-sm"></i> Финансы</button>
|
<button class="tab-btn" data-target="finance-section"><i data-lucide="wallet" class="icon-sm"></i> Финансы</button>
|
||||||
|
<button class="tab-btn" data-target="generator-section"><i data-lucide="wand-2" class="icon-sm"></i> Генератор</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<main class="container">
|
<main class="container">
|
||||||
@@ -313,6 +314,47 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Product Generator Section -->
|
||||||
|
<section id="generator-section" class="section hidden">
|
||||||
|
<h2>Умный генератор карточек товара</h2>
|
||||||
|
<div class="platforms-grid">
|
||||||
|
<div class="platform-card" style="grid-column: 1 / -1;">
|
||||||
|
<p style="margin-bottom: 1.5rem; color: var(--color-text-dim);">
|
||||||
|
Введите название товара, и ИИ подготовит описание, характеристики и промпты для генерации изображений.
|
||||||
|
</p>
|
||||||
|
<div style="display: flex; gap: 1rem; max-width: 800px;">
|
||||||
|
<input type="text" id="gen-title-input" placeholder="Например: Беспроводная кофемолка с керамическими жерновами" style="flex: 1;">
|
||||||
|
<button class="btn-primary" id="ai-gen-card-btn">
|
||||||
|
<i data-lucide="sparkles" class="icon-sm"></i> Создать карточку
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="gen-result-container" class="hidden" style="margin-top: 2rem; animation: fadeIn 0.4s;">
|
||||||
|
<div class="platforms-grid">
|
||||||
|
<!-- Description & SEO -->
|
||||||
|
<div class="platform-card" style="grid-column: 1 / 2;">
|
||||||
|
<h3>Продающее описание</h3>
|
||||||
|
<div id="gen-description" style="margin-top: 1rem; line-height: 1.6; color: var(--color-text-dim);"></div>
|
||||||
|
<h3 style="margin-top: 2rem;">SEO Теги</h3>
|
||||||
|
<div id="gen-tags" style="display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem;"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Features & Image Prompts -->
|
||||||
|
<div class="platform-card" style="grid-column: 2 / -1;">
|
||||||
|
<h3>Технические характеристики</h3>
|
||||||
|
<table id="gen-features-table" class="table" style="margin-top: 1rem;">
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3 style="margin-top: 2rem;">Промпты для ИИ-фото (DALL-E/Midjourney)</h3>
|
||||||
|
<div id="gen-image-prompts" style="margin-top: 1rem;"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<!-- Integrations List -->
|
<!-- Integrations List -->
|
||||||
<section id="integrations-section" class="section hidden">
|
<section id="integrations-section" class="section hidden">
|
||||||
<h2>Доступные маркетплейсы</h2>
|
<h2>Доступные маркетплейсы</h2>
|
||||||
|
|||||||
@@ -272,10 +272,86 @@ function initTabs() {
|
|||||||
if(target === 'seo-section') loadSEO();
|
if(target === 'seo-section') loadSEO();
|
||||||
if(target === 'content-section') loadReferences();
|
if(target === 'content-section') loadReferences();
|
||||||
if(target === 'finance-section') { /* No initial load */ }
|
if(target === 'finance-section') { /* No initial load */ }
|
||||||
|
if(target === 'generator-section') { /* No initial load */ }
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.getElementById('ai-gen-card-btn').addEventListener('click', async () => {
|
||||||
|
const title = document.getElementById('gen-title-input').value;
|
||||||
|
if (!title) {
|
||||||
|
alert('Введите название товара');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const btn = document.getElementById('ai-gen-card-btn');
|
||||||
|
const originalText = btn.innerHTML;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.innerHTML = '<i data-lucide="loader-2" class="icon-sm spin"></i> Магия ИИ в процессе...';
|
||||||
|
if (window.lucide) lucide.createIcons();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
const res = await fetch('http://localhost:5000/api/ai/generate-card', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ title })
|
||||||
|
});
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.error) throw new Error(data.error);
|
||||||
|
|
||||||
|
document.getElementById('gen-result-container').classList.remove('hidden');
|
||||||
|
document.getElementById('gen-description').innerText = data.description;
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
const tagsDiv = document.getElementById('gen-tags');
|
||||||
|
tagsDiv.innerHTML = '';
|
||||||
|
data.seo_tags.forEach(tag => {
|
||||||
|
const span = document.createElement('span');
|
||||||
|
span.className = 'status-pill';
|
||||||
|
span.style.background = 'rgba(255,255,255,0.1)';
|
||||||
|
span.innerText = `#${tag}`;
|
||||||
|
tagsDiv.appendChild(span);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Features
|
||||||
|
const featuresTbody = document.querySelector('#gen-features-table tbody');
|
||||||
|
featuresTbody.innerHTML = '';
|
||||||
|
for (const [key, val] of Object.entries(data.features)) {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
tr.innerHTML = `<td><strong>${key}</strong></td><td>${val}</td>`;
|
||||||
|
featuresTbody.appendChild(tr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Image Prompts
|
||||||
|
const promptsDiv = document.getElementById('gen-image-prompts');
|
||||||
|
promptsDiv.innerHTML = '';
|
||||||
|
data.image_prompts.forEach((p, i) => {
|
||||||
|
const pBox = document.createElement('div');
|
||||||
|
pBox.style.background = 'rgba(0,0,0,0.2)';
|
||||||
|
pBox.style.padding = '10px';
|
||||||
|
pBox.style.borderRadius = '8px';
|
||||||
|
pBox.style.marginBottom = '10px';
|
||||||
|
pBox.style.fontSize = '0.8rem';
|
||||||
|
pBox.innerHTML = `<strong>Вариант ${i+1}:</strong><br>${p}`;
|
||||||
|
promptsDiv.appendChild(pBox);
|
||||||
|
});
|
||||||
|
|
||||||
|
showToast('Карточка успешно сгенерирована!', 'success');
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert(err.message);
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerHTML = originalText;
|
||||||
|
if (window.lucide) lucide.createIcons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('pnl-form').addEventListener('submit', async (e) => {
|
document.getElementById('pnl-form').addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const fd = new FormData(e.target);
|
const fd = new FormData(e.target);
|
||||||
|
|||||||
Reference in New Issue
Block a user