6.8 KiB
ТЗ: Веб-интерфейс для Snowbike RAG
Общее описание
Одностраничное веб-приложение для семантического поиска по базе знаний сноубайков. Тёмная тема, адаптивный дизайн, минималистичный интерфейс.
URL: https://openclaw.mva154.duckdns.org/snowbike-rag/
Стек: Flask (порт 5557) + HTML/CSS/JS (без сборщиков)
Бизнес-требования: docs/BRD-UI.md
Архитектура
Браузер
↓
Flask server.py (порт 5557)
↓
GET /snowbike-rag/ → index.html
GET /snowbike-rag/api/search?q=... → JSON ответ
GET /snowbike-rag/api/stats → статистика
Nginx: location /snowbike-rag/ → proxy_pass http://172.19.0.2:5557/ (уже настроен)
Файлы
tasks/snowbike-rag/
├── templates/
│ └── index.html — единственная страница (HTML + CSS + JS)
├── static/
│ └── style.css — кастомные стили (если нужно, иначе inline)
├── server.py — обновить: добавить роуты / и /api/search, /api/stats
└── docs/
├── BRD.md — бизнес-требования (API)
├── BRD-UI.md — бизнес-требования (UI)
└── TZ-UI.md — это документ
Страница: index.html
1. Заголовок
• Иконка снежинки или снегохода (emoji: 🏔️) • Название: Snowbike Поиск • Подзаголовок: «База знаний по 155 000 сообщений»
2. Поле ввода
• <textarea> по центру экрана, ширина 80% (max 700px)
• Placeholder: «Спросите про сноубайки... Например: какое масло для Polaris 850?»
• Высота: 2 строки (auto-resize до 5 строк при вводе)
• Кнопка отправки: иконка 🔍 справа внизу поля
• Отправка по Ctrl+Enter
3. Результаты
• Появляются ниже поля ввода • Анимация: fadeIn 0.3s
Блок ответа: • Заголовок: «Ответ» • Текст: Markdown → HTML (через marked.js) • Максимальная ширина: 700px, выравнивание по левому краю
Блок источников: • Заголовок: «Источники (N)» • Список карточек (max 10, с прокруткой если больше) • Каждая карточка:
- Дата: DD.MM.YYYY
- Топик: цветная метка (badge)
- Превью: 2 строки текста
- Ссылка: «Открыть в Telegram» (если message_id доступен)
Мета-информация: • Время ответа: X.X секунд • Найдено источников: N
4. Состояние загрузки
• Спиннер (три пульсирующие точки) вместо кнопки • Skeleton-анимация для блока ответа (серые полосы)
5. Ошибки
• API недоступен: тост-уведомление «Сервис временно недоступен» • Пустой запрос: подсветка поля красным + текст «Введите запрос»
Страница: статистика (footer)
Внизу страницы, маленькая ссылка «О базе данных»: • Модальное окно при клике • Показывает:
- Всего сообщений в индексе
- Количество топиков
- Статус ChromaDB (генерация / готов)
- Последнее обновление
API (новые роуты в server.py)
GET /
Возвращает templates/index.html
GET /api/search?q={query}&topics={ids}&limit={N}
Аналогично текущему /search, но:
• Добавить CORS-заголовки
• Возвращать JSON с полями: answer, sources, count, time_ms
GET /api/stats
Аналогично текущему /stats
Стилизация
Тема: тёмная
--bg-primary: #0F172A; /* фон страницы */
--bg-card: #1E293B; /* карточки */
--bg-input: #334155; /* поле ввода */
--text-primary: #F1F5F9; /* основной текст */
--text-secondary: #94A3B8; /* вторичный текст */
--accent: #3B82F6; /* акцент (синий) */
--accent-hover: #2563EB; /* акцент при наведении */
--error: #EF4444; /* ошибки */
--border: #334155; /* границы */
Шрифты
• Основной: Inter (Google Fonts, через CDN) • Моноширинный (код): JetBrains Mono (CDN)
Адаптивность
• Мобильные (< 768px): поле ввода 95% ширины, источники в столбик • Планшеты (768–1024px): поле ввода 80% ширины • Десктоп (> 1024px): поле ввода max 700px, по центру
Зависимости (CDN)
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- Marked.js (Markdown → HTML) -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
Обновление server.py
Добавить:
from flask import render_template
@app.route('/')
def index():
return render_template('index.html')
Переименовать /search → /api/search (или оставить оба для обратной совместимости)
Критерии приёмки
https://openclaw.mva154.duckdns.org/snowbike-rag/— открывается страница поиска- Ввод «какое масло для Polaris» → ответ с источниками
- Тёмная тема, красивый интерфейс
- Хорошо выглядит на телефоне
- Markdown ответ рендерится в HTML
- Источники — карточки с датой и топиком
- Спиннер при загрузке
- Ошибка при недоступности API
Важно
• Всё в одном HTML-файле (inline CSS + JS) • Tailwind через CDN (без сборки) • Не ломать существующие API-роуты • Работает в контейнере (Flask :5557)