Skip to content

SCRUMUX/RateMeAI

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

487 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RateMeAI (AI Look Studio)

ВСЕГДА ОТВЕЧАТЬ НА РУССКОМ ЯЗЫКЕ!

AI-стилист, который анализирует фото и показывает, как человек воспринимается в разных контекстах (знакомства, карьера, соцсети), с генерацией улучшенных образов.

Стек: Python 3.12 (FastAPI + ARQ + aiogram) + React SPA (Vite + Tailwind) + PostgreSQL + Redis

Платформы: Telegram bot, Web app (Vercel), OK/VK Mini Apps, RU edge

Архитектура (двухрегиональная)

Проект развёрнут в двух независимых регионах с одним codebase:

  • Global (Railway, MARKET_ID=global) — домен ailookstudio.vercel.app, Telegram-бот @AI_Look_Studio_bot (единственный, webhook, Telegram Stars), платежи Xsolla для веба.
  • RU edge (VPS, MARKET_ID=ru) — домен ailookstudio.ru, только веб-приложение, платежи YooKassa. Бота на VPS нет начиная с 1.62.0 — РКН блокирует исходящий трафик к api.telegram.org, поэтому polling из РФ невозможен; webhook-бот живёт на Railway и принимает обновления одинаково для всех языков.

Ключевые инварианты, которые надо знать перед любым изменением кода:

  1. PII RU-юзеров никогда не покидает VPS для веб-флоу. Edge → primary вызовы используют синтетический internal_user_id и extra="forbid" на Pydantic-схеме (см. RemoteAnalysisRequest в src/api/v1/internal.py).
  2. Один Telegram-бот на Railway. Лендинг-ссылки внутри бота выбираются по language_code через settings.resolve_landing_url (src/config.py). Кросс-регион нужен только при link-token redeem: RU edge тянет image_credits бота с Railway через подписанный internal endpoint (src/api/v1/internal_bot.py).
  3. Каждое фото сначала проходит через PrivacyLayer.sanitize_and_normalize (EXIF/ICC strip), потом — в модель. Оригиналы хранятся в Redis-stash 15 мин и удаляются.
  4. Логи маскируют PII через PIIFilter.
  5. Админки две и независимые — у каждого региона свой /admin. AdminStatusBanner (web/src/components/admin/AdminStatusBanner.tsx) делает разделение явным.

Полный документ: docs/ARCHITECTURE.md — содержит диаграммы, описание DNS-rollout'а, CMS-репликацию, бот-маршрутизацию и список ограничений.

Документация

Документ Содержание
docs/ARCHITECTURE.md Двухрегиональная архитектура: домены, PII-инварианты, edge→primary delegation, бот-маршрутизация по языку, DNS rollout
docs/DEPLOYMENT.md CI/CD, Railway, Vercel, RU edge, переменные окружения, чеклисты, troubleshooting
docs/DEVELOPMENT.md Локальный запуск, структура проекта, тесты, гайды по добавлению режимов/стилей/auth
docs/master_product_constitution.md Продуктовая конституция: концепция AI-стилиста, принципы, UX, scoring, pipeline requirements
docs/architecture/reserved.md Карта reserved-кода (orchestrator/advanced/, запасные провайдеры): что там лежит, зачем сохранено, как включать и дорожная карта Phase 2 (Scenario Engine) и Phase 3 (FLUX через FAL.ai)

Runtime сегодня работает по одному single-pass пути (AnalysisPipelineImageGenerationExecutor.single_pass → Reve). Multi-pass планнер, capability-router и fallback-цепочки провайдеров намеренно изолированы в src/orchestrator/advanced/ и под флагами MULTI_PASS_ENABLED / SEGMENTATION_ENABLED / IMAGE_GEN_PROVIDER. Подробности — в docs/architecture/reserved.md.

Деплой на сервер (обязательно читать)

Любое изменение в коде бессмысленно, пока все процессы с очередью не обновлены одной и той же сборкой:

Сервис Зачем
API (app) Принимает фото, пишет задачу и кладёт вход в Redis (ratemeai:task_input:…)
Worker Берёт задачу из ARQ и должен та же логика, что и API (чтение из Redis → пайплайн)
Bot Ходит в API; при изменении контрактов API стоит обновлять и его

Если обновить только API, а воркер оставить старый образ, снова возможны ошибки вроде File not found: inputs/... — воркер не умеет новый протокол.

Что делать после мерджа / смены ветки:

  1. Пересобрать образ(ы) и задеплоить app + worker + bot с одного commit (на Railway — redeploy каждого сервиса или общий pipeline).
  2. Проверка: GET https://<ваш-api>/health — в ответе должны быть version (см. src/version.py) и при необходимости git, если задали DEPLOY_GIT_SHA в env.
  3. В логах воркера при старте должна быть строка Worker started RateMeAI version=… с той же version, что и у API.

Версию приложения поднимайте в src/version.py при каждой выкладке, чтобы по логам и /health было видно расхождение сервер ↔ репозиторий. Описание изменений добавляйте в CHANGELOG.md (newest-first) — src/version.py теперь содержит только литерал APP_VERSION, чтобы не раздувать импорт на старте app/worker/bot.

Переменная API_BASE_URL: кому какой адрес

Компонент Что должен видеть Зачем
app, worker Публичный HTTPS URL API (или туннель типа ngrok в разработке) LocalStorageProvider.get_url строит ссылки на файлы в /storage/.... Эти URL попадают в результат задачи и в share-карточку.
bot (Docker Compose) Внутренний URL сервиса app, например http://app:8000 В docker-compose.yml для сервиса bot задано API_BASE_URL: http://app:8000, чтобы запросы шли по Docker-сети, а не наружу.
Telegram Только публичный HTTPS send_photo по URL заставляет серверы Telegram скачать файл по указанному адресу. http://localhost и приватные IP не подходят.

Итог: в .env для локальной разработки с ботом в Docker оставьте публичный API_BASE_URL для app/worker (туннель или боевой домен), а переопределение для бота задавайте только через Compose, как в репозитории.

Хранилище в проде (несколько инстансов / без общего диска)

При STORAGE_PROVIDER=local файлы лежат на диске; в Compose для app, worker, bot смонтирован один каталог ./storage. Входное фото дублируется в Redis (ratemeai:task_input:<task_id>) до обработки воркером — так анализ не зависит от общего тома между API и worker.

В облаке без общего тома (несколько реплик API или воркера) используйте S3-совместимое хранилище:

  1. Задайте STORAGE_PROVIDER=s3.
  2. Заполните S3_ENDPOINT, S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET, S3_REGION.
  3. Либо настройте публичный доступ к объектам и укажите S3_PUBLIC_BASE_URL (CDN или публичный endpoint бакета), либо полагайтесь на presigned URL из S3StorageProvider.
  4. Установите S3_PRESIGN_TTL_SECONDS с запасом (например 3600), чтобы ссылка не истекла до того, как пользователь откроет результат в боте.

Для Replicate провайдер передаёт в модель публичный URL референса — объекты должны быть доступны по URL извне.

Локальный запуск (Docker)

cp .env.example .env
# Заполните секреты. API_BASE_URL — публичный, если тестируете Telegram с медиа по URL.
docker compose up --build
  • API: http://localhost:8000
  • Проверка: GET http://localhost:8000/health

Тесты

Интеграционные API-тесты (tests/test_api/) требуют PostgreSQL и Redis на 127.0.0.1 (порты по умолчанию как в Compose). Если сервисы не запущены, эти тесты пропускаются (skipped), остальные всё равно выполняются.

python -m pytest
# или: docker compose up -d postgres redis && python -m pytest

В CI см. .github/workflows/ci.yml.

Ручной смок (чеклист)

  1. Поднять стек, GET /healthstatus, поле version совпадает с src/version.py.
  2. В боте: /start, отправить портретное фото (с лицом).
  3. Режим rating (через /rating): дождаться результата, проверить текст и карточку.
  4. Режим dating: выбор стиля (На прогулке / Студия / Кафе) → сгенерированное фото + скор.
  5. Режим cv: выбор стиля (Корпоративный / Креативный / Нейтральный) → профессиональный образ.
  6. Режим social: выбор стиля (Influencer / Luxury / Casual / Artistic) → образ для соцсетей.
  7. Режим emoji (через /emoji): стикер-аватар из фото.
  8. При ошибке пайплайна: в боте отображается сообщение из error_message задачи.

About

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors