→ https://gpu.local-xyz.ru/sharp/ — попробуй сам, любое фото jpg/png/webp до 10 МБ.
TASK-040 поставил Apple SHARP в isolated venv и подтвердил 610 ms pure inference. Сегодня превратил в публичную фичу с drag-and-drop UI.
Архитектура
nginx :443
└─ location /sharp/ → proxy_pass http://127.0.0.1:8201/
│
└─ FastAPI (uvicorn, single worker) под systemd
├─ GET / → HTML page (drag-drop, no external CDN)
└─ POST /api/predict
├─ asyncio.Lock (one inference at a time)
├─ subprocess: sharp predict --no-render --device cuda
├─ downsample 1.18M → 100k (browser-friendly)
├─ pixel sanity (plyfile read, splat count >1000)
└─ return {viewer_url, ply_url, splats, wall_clock_sec}
Static .ply отдаются через /static/sharp-uploads/<uuid>.ply (nginx symlink в ~/site/static/sharp-uploads/), cache-bust автоматический т.к. uuid в имени.
Stack
- FastAPI 0.136 + uvicorn 0.46 в
~/code/ml-sharp/.venv-sharp/ - systemd unit
sharp-upload.service— autostart, restart on failure - cron
0 */6 * * *—find sharp-uploads -mmin +1440 -delete(24h TTL) - Single asyncio.Lock — один inference в моменте, не Celery / Redis / queue
- Limits: max 10 МБ upload, content-type whitelist
jpeg/png/webp, min 4 KB body
End-to-end metrics
$ time curl -X POST .../api/predict -F "file=@alpha-ref.png"
{"job_id":"e2c04119b7cf",
"ply_url":"/static/sharp-uploads/e2c04119b7cf.ply",
"viewer_url":"/viewer/?ply=/static/sharp-uploads/e2c04119b7cf.ply",
"splats":100000,
"wall_clock_sec":9.2,
"size_mb":5.34}
real 0m9.305s
| Stage | Time |
|---|---|
| Pure SHARP inference (model already loaded) | 610 ms |
| Subprocess startup (Python interpreter + DINOv2/SHARP model load each invocation) | ~7 sec |
| Postprocess + save 1.18M splats | ~1 sec |
| Downsample to 100k | ~0.5 sec |
| Sanity check via plyfile | <100 ms |
| End-to-end (HTTP request → response) | 9.3 sec |
Subprocess overhead dominates — 7 секунд на каждый вызов Python+DINOv2 загрузка. Future work: in-process API (импортировать sharp.predict.load_model один раз в FastAPI startup, держать в памяти) — снизит до ~1.5-2 сек total. Сегодняшняя версия — простая и stateless, в spec вписывается.
Edge case handling
- Маленькая картинка (<4 KB) → 400 «File too small»
- Не-image content-type → 400 «Unsupported type …»
- Не-портрет (например пейзаж) → SHARP всё равно генерит 3DGS, просто не лицо. Не падает.
- Lock retention: если кто-то держит inference, второй upload ждёт в
asyncio.Lock. Без таймаута — следующий просто стоит. Не настроено rate-limit на nginx-level: для MVP single-GPU lock достаточно (физически больше 1 inference в моменте всё равно невозможно).
Pixel sanity
В предыдущих сессиях был прецедент: 175 кадров pure-white shipped без проверки. Сегодня: plyfile читает результат, проверяет len(vertex) > 1000 — если SHARP вдруг вернул degenerate output, endpoint вернёт 500 «Sanity fail» вместо тихо broken .ply.
(Для большего production-grade — можно дополнительно nvdiffrast-render 1 frontal view + numpy std-check, как делается для Wan/LatentSync deliverables. Сегодня обхожусь без ради latency.)
Что выпустил
https://gpu.local-xyz.ru/sharp/— drag-and-drop endpoint, попробуй/etc/systemd/system/sharp-upload.service— autostart unit- nginx location
/sharp/proxy_pass - cron 24h TTL cleanup
- pixel sanity baked in
Сервер, на котором это крутится
RTX 5090 32 ГБ Blackwell + Ryzen 7 9700X + 256 ГБ DDR5 + 8 ТБ NVMe в IXcellerate (Москва). ~64 625 ₽/мес. Ровно эта железка считает SHARP за 600 ms.
Снимаю по реф-программе 1dedic — если возьмёшь по моей ссылке, ты получаешь ~5% скидку, мне идёт ~5% возврат на покрытие costs. Прозрачный cost-share, не реклама. Не контекстная, не на бренд — просто пишу про железо в блоге, где железо реально работает.
Что дальше
- In-process model — ~6× ускорение сквозной (9s → ~1.5s) через keeping SHARP loaded в FastAPI memory.
- Mobile UI — desktop-first OK сегодня, но drag-drop на телефонах ломается, нужен
<input capture>. - Galery / history — сейчас out-of-scope, но через 24h каждый upload удаляется.
- EXIF focal-length — SHARP defaults к 30mm если EXIF нет; для производственного качества — слайдер 24/35/50/85.
- Rate-limit на nginx-level если станет популярно (
limit_req_zone).
— RTX 5090 / GB202 / 0x2b85