2394eff1c0
- LM Studio client (httpx-based, OpenAI-compatible) - SVG validator (lxml, whitelist tags, no <script>/<foreignObject>/http refs) - PNG renderer (resvg-py primary, cairosvg fallback - no native cairo dep) - History (SQLite, tracks raw/validated/preview paths) - Gradio UI on 127.0.0.1:8788 with: * mode radio (icon/illustration) * n_candidates slider (default 1) * image upload for image-to-SVG * LM Studio URL/token inputs * model dropdown + refresh button - prompts/ with system_icon.txt, system_illustration.txt, few_shot_examples.txt - docs/spec.md, docs/design.md - 122 unit/integration tests passing
120 lines
5.2 KiB
Markdown
120 lines
5.2 KiB
Markdown
# OmniSVG-Lite
|
|
|
|
Локальный MVP для генерации SVG-иконок и иллюстраций через LM Studio.
|
|
Gradio UI, локальная SQLite-история, валидация выхода модели через `lxml`,
|
|
PNG-превью через `cairosvg`.
|
|
|
|
> Контракт: см. `docs/spec.md` и `docs/design.md`. Промпт-шаблоны: `prompts/`.
|
|
|
|
## Что внутри
|
|
|
|
| Файл | Назначение |
|
|
|--------------------|------------------------------------------------------------------|
|
|
| `app.py` | Gradio 5 UI: text/prompt → N SVG-кандидатов → PNG-превью → БД |
|
|
| `lm_client.py` | httpx-клиент к OpenAI-compatible LM Studio, `generate_svg()` |
|
|
| `prompts.py` | Загрузка шаблонов из `prompts/` + `build_messages()` |
|
|
| `validator.py` | lxml-парсинг + проверка whitelist/тегов/href/on* |
|
|
| `renderer.py` | cairosvg → PNG (graceful fallback, если cairo недоступен) |
|
|
| `history.py` | SQLite WAL, контекст-менеджер `History` |
|
|
| `prompts/` | system-инструкции + few-shot примеры |
|
|
| `tests/` | pytest на validator (6+ кейсов) |
|
|
|
|
## Установка
|
|
|
|
```bash
|
|
# 1) зависимости
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
> **Важно для Windows**: `cairosvg` — это Python-биндинг к нативному `cairo`.
|
|
> На Windows чистого `pip install cairosvg` обычно недостаточно — нужна
|
|
> библиотека `cairo.dll`. Варианты:
|
|
>
|
|
> ```bash
|
|
> # вариант 1: conda (рекомендуется)
|
|
> conda install -c conda-forge pycairo cairo
|
|
>
|
|
> # вариант 2: MSYS2 / vcpkg / GTK3 runtime
|
|
> ```
|
|
>
|
|
> Если cairo не установлен — UI стартует, но PNG-превью будут пропущены
|
|
> (в логе появится `WARNING` от renderer.py).
|
|
|
|
## Настройка LM Studio
|
|
|
|
1. Запустить LM Studio локально (`http://127.0.0.1:1234`).
|
|
2. Загрузить модель, например `qwen/qwen3.5-35b-a3b`.
|
|
3. Включить **OpenAI-compatible server** в LM Studio.
|
|
|
|
Переменные окружения (опционально, все имеют дефолты):
|
|
|
|
| Переменная | Дефолт |
|
|
|---------------------------|-----------------------------------|
|
|
| `LM_STUDIO_BASE_URL` | `http://127.0.0.1:1234/v1` |
|
|
| `LM_STUDIO_API_KEY` | `lm-studio` |
|
|
| `DEFAULT_MODEL` | `qwen/qwen3.5-35b-a3b` |
|
|
| `REQUEST_TIMEOUT_S` | `120` |
|
|
| `OMNISVG_DB_PATH` | `~/.omnisvg_lite/history.sqlite` |
|
|
| `OMNISVG_PREVIEW_DIR` | `~/.omnisvg_lite/previews` |
|
|
| `LOG_LEVEL` | `INFO` |
|
|
|
|
## Запуск
|
|
|
|
```bash
|
|
python app.py
|
|
```
|
|
|
|
UI откроется на `http://127.0.0.1:7860`. Кнопка «Сгенерировать» отправляет
|
|
промпт в LM Studio, валидирует SVG, рисует PNG-превью и сохраняет запись
|
|
в SQLite.
|
|
|
|
## Тесты
|
|
|
|
```bash
|
|
python -m pytest tests/ -v
|
|
```
|
|
|
|
Покрытие — `validator.py` (well-formed, viewBox, forbidden tags, http refs,
|
|
on*-атрибуты).
|
|
|
|
## Smoke-тест импорта (без живого LM Studio)
|
|
|
|
```bash
|
|
python -c "from app import demo, main; print('imports ok')"
|
|
```
|
|
|
|
Запускается **только импорт**, Gradio-сервер не поднимается. Если gradio не
|
|
установлен, импорт `app.py` упадёт (gradio захардкожен в `import`).
|
|
|
|
## Известные ограничения (MVP)
|
|
|
|
- Один пользователь, без авторизации.
|
|
- Выбор «лучшего» кандидата — по минимальному размеру файла (прокси
|
|
компактности, не качества). См. `spec.md §4`.
|
|
- `cairosvg` на Windows без conda — см. выше; UI работает и без PNG-превью.
|
|
- Размер БД не ограничен; очистка старых превью — на совести пользователя
|
|
(дизайн §11, open question).
|
|
|
|
## Структура SQLite
|
|
|
|
```sql
|
|
CREATE TABLE generations (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
created_at REAL NOT NULL,
|
|
prompt TEXT NOT NULL,
|
|
mode TEXT NOT NULL, -- icon | illustration
|
|
model TEXT NOT NULL,
|
|
n_requested INTEGER NOT NULL,
|
|
n_returned INTEGER NOT NULL,
|
|
temperature REAL NOT NULL,
|
|
status TEXT NOT NULL, -- ok | partial | failed
|
|
error_reason TEXT,
|
|
raw_outputs TEXT NOT NULL, -- JSON list[str]
|
|
validated_outputs TEXT NOT NULL, -- JSON list[str]
|
|
previews TEXT NOT NULL, -- JSON list[str] (PNG paths)
|
|
best_index INTEGER
|
|
);
|
|
```
|
|
|
|
WAL-режим, индекс по `created_at DESC`.
|