Files
omnisvg-lite/README.md
Mavis 2394eff1c0 Initial commit: OmniSVG-Lite MVP before live-streaming work
- 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
2026-06-13 15:32:54 +03:00

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`.