Студия — экран генерации
Главный экран AI Студии. Пользователь загружает фото блюда, выбирает один из 4 режимов и параметров — задание уходит в фон, форма освобождается, результат появляется в Истории.
Файл
ai-photo-studio-frontend/src/pages/PhotoStudioPage.tsx
Роут
GET /photo — default route после успешного логина.
GET /photo?job=<job_id> — открывает существующий job в режиме «прогресс» (используется при retry с экрана Истории).
Доступ
Permission gensvc.access. Без него фронт редиректит на /no-access.
Режимы
ModeSelector в шапке экрана, четыре варианта:
| Режим | Ключ API | Что нужно |
|---|---|---|
| Стиль | style | image + системный или личный preset (опц. extra_prompt ≤500 симв.) |
| Композиция | composition | image + plate + background (опц. extra_prompt ≤500 симв.) |
| Преобразить | enhance | image + обязательный extra_prompt (≤1000 симв.) |
| Постер | poster | image + poster_template + обязательный extra_prompt (≤1000 симв.) — это headline |
Смена режима сбрасывает выбранный preset/template/asset, фото и extra_prompt остаются.
Layout
┌──────────────────────────────────────────────────────────┐
│ [✓ Генерация запущена] (banner — после успешного submit) │ ← см. § Submit & banner
├──────────────────────────────────────────────────────────┤
│ Заголовок «Студия фото» │
│ Подсказка под режим (RU) │
│ ModeSelector: [Стиль] [Композиция] [Преобразить] [Постер]│
├──────────────────────────────────────────────────────────┤
│ ┌─ Dropzone ─┐ ┌─ Галерея пресетов / форма ─┐ │
│ │ фото │ │ (зависит от режима) │ height │
│ │ (drag/ │ │ │ 540px │
│ │ drop) │ │ │ │
│ └────────────┘ └─────────────────────────────┘ │
├──────────────────────────────────────────────────────────┤
│ ▸ Дополнительные пожелания (collapsible, default closed) │
├──────────────────────────────────────────────────────────┤
│ [Размер ▾] [Кол-во ▾] [Сгенерировать] │
└──────────────────────────────────────────────────────────┘
В режиме Композиции — три колонки в основной области (Dropzone + Plate gallery + Background gallery), в остальных — две.
Поля и валидация
| Поле | Источник | Валидация |
|---|---|---|
image | Dropzone (jpg/png/webp ≤10 МБ) | min: обязательно |
preset_id (style) или user_preset_id (style) | PresetGallery | one-of: ровно один из двух обязателен |
template_id (poster) | PosterTemplateGallery | required в poster |
plate_id, background_id (composition) | AssetGallery × 2 | оба required в composition |
extra_prompt | Textarea, ≤500/≤1000 (по режиму) | required в enhance и poster, опц. в style/composition |
size | SizeSelector | one-of: delivery-1x1 / story-9x16 / banner-16x9 / menu-4x3 |
count | CountSelector | 1..4 |
canSubmit зависит от режима: для style — нужны image + (preset_id\|user_preset_id); для enhance — image + extra_prompt.trim() ≠ ""; для poster — image + template_id + extra_prompt; для composition — image + plate + background.
Submit & banner
После клика «Сгенерировать»:
-
pageState = "submitting"— кнопка показывает loader. -
POST /v1/jobs/{photo|enhance|poster|composition}(multipart) → ответ 202 за миллисекунды (см. ADR-022). -
Не переключаться в
phase: "progress"— иначе форма заблокирована. -
Поставить
submittedNotice = { jobId },image = null,pageState = "idle". -
Сверху страницы появляется зелёный banner:
✓ Генерация запущена. Обычно занимает 3-6 минут. Можно закрыть вкладку — фото появится в Истории, придёт уведомление. [Открыть Историю →] [✕]
-
Banner авто-исчезает через 12 секунд или по клику ✕. Кнопка «Открыть Историю» —
<Link to="/history">. -
Форма доступна для нового submit (фото нужно выбрать заново).
Состояния pageState
stateDiagram-v2 [*] --> idle idle --> submitting: click Submit submitting --> idle: 202 OK (новый flow — non-blocking) submitting --> idle: error (показать submitError) idle --> progress: ?job=<id> в URL (retry-flow из Истории) progress --> result: SSE done succeeded progress --> failed: SSE done failed failed --> progress: click "Повторить" result --> idle: click "Новая генерация"
Legacy
progressphase
phase: "progress"остался только для retry-flow (/photo?job=<id>с Истории). На обычном submit мы туда не переходим — сразу освобождаем форму.
Отображаемые ошибки
submitError— alert красным баннером под ModeSelector (выше Dropzone). Сообщение изe.messageили fallback «Ошибка создания задачи».extraPromptOver— inline error под Textarea, кнопка Submit заблокирована.enhanceCommentEmpty— после первого клика на Submit без текста, под Textarea: «Расскажите, какой результат хотите получить».
Связанные API
POST /v1/jobs/photo(style mode)POST /v1/jobs/enhancePOST /v1/jobs/posterPOST /v1/jobs/compositionPOST /v1/jobs/{id}/retry(retry-flow)GET /v1/presets,GET /v1/poster-templates,GET /v1/composition-assets— для галерейGET /v1/user-presets— личная библиотека стилей