194 lines
6.8 KiB
Markdown
194 lines
6.8 KiB
Markdown
# ТЗ: Веб-интерфейс для 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`
|
||
|
||
---
|
||
|
||
## Стилизация
|
||
|
||
### Тема: тёмная
|
||
```css
|
||
--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)
|
||
|
||
```html
|
||
<!-- 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
|
||
|
||
Добавить:
|
||
```python
|
||
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)
|