You've already forked RekomenciBackend
Merge branch 'main' of gitlab.prodcontest.com:team-39/backend
* 'main' of gitlab.prodcontest.com:team-39/backend: fix(): reset vectors similarity threshold chore(): update rfc
This commit is contained in:
@@ -37,30 +37,48 @@ RFC определяет интерфейсы для API, операционны
|
|||||||
## 4. Цели и критерии приёмки
|
## 4. Цели и критерии приёмки
|
||||||
Цели:
|
Цели:
|
||||||
- Стабильный REST/HTTP API для вакансий и предсказаний
|
- Стабильный REST/HTTP API для вакансий и предсказаний
|
||||||
- Горизонтально масштабируемый ML embedding-сервис
|
- Стабильный и масштабируемый REST/HTTP API, утилизирующий ML алгоритмы
|
||||||
- Повторяемый pipeline подготовки данных и обучения
|
|
||||||
|
|
||||||
|
|
||||||
## 5. Высокоуровневая архитектура
|
## 5. Высокоуровневая архитектура
|
||||||
- Web API (web_api): HTTP-сервис, инкапсулирующий бизнес логику. Проксируются запросы к ML
|
- Web API (web_api): HTTP-сервис, инкапсулирующий бизнес логику. Интегрируется с ML-сервисом
|
||||||
- ML сервис (ml): HTTP-сервис для генерации embenddings и предсказания
|
- ML сервис (ml): HTTP-сервис, инкапсулирующий ML бизнес логику
|
||||||
- PostgreSQL — является хранилищем данных
|
- PostgreSQL + pgvector - основное хранилище данных
|
||||||
- Инфра: Docker Compose для локальной разработки; Coolify для CI/CD
|
- Инфра: Docker Compose для локальной разработки; Coolify для CI/CD
|
||||||
|
|
||||||
Коммуникация:
|
Коммуникация:
|
||||||
- HTTP rest-ful между web_api и ml; опционально gRPC в будущем
|
- HTTP REST между web_api и ml; опционально gRPC / WebSocket в будущем
|
||||||
- Обмен артефактами через object storage и метаданные в PostgreSQL
|
- Хранение данных в PostgreSQL + pgvector, хранение файловых данных в S3
|
||||||
|
|
||||||
## 6. Контракты API (предварительно)
|
Входные/выходные схемы должны быть описаны в формате OpenAPI
|
||||||
- Web API:
|
|
||||||
- POST /v1/predict — payload: vacancy/resume; returns: salary_prediction {value, confidence, model_version}.
|
|
||||||
- POST /v1/vacancies — сохраняет вакансию для последующей обработки.
|
|
||||||
- GET /v1/models — список доступных моделей и версий.
|
|
||||||
- ML service:
|
|
||||||
- POST /infer — принимает фичи/сырой текст, возвращает предсказание и мета.
|
|
||||||
- GET /health, GET /metrics.
|
|
||||||
|
|
||||||
Входные/выходные схемы должны быть описаны в OpenAPI (yaml) и поддерживаться CI-валидатором
|
### 5.1. Домены приложения
|
||||||
|
- **Resume**: управление резюме пользователей, история версий, эмбеддинги, предикты зарплаты
|
||||||
|
- **Vacancy**: каталог вакансий с эмбеддингами для поиска похожих
|
||||||
|
- **User**: пользователи, профили, аутентификация
|
||||||
|
- **Auth Identity**: методы аутентификации (email/password)
|
||||||
|
- **Notification Device**: регистрация устройств для уведомлений
|
||||||
|
|
||||||
|
### 5.2. Флоу создания резюме и предикта
|
||||||
|
1. Пользователь создает резюме через Gateway (AddResumeInteractor)
|
||||||
|
2. Gateway сохраняет резюме в хранилище и возвращает ответ
|
||||||
|
3. В фоне запускается ResumePredictionInteractor:
|
||||||
|
- Генерирует эмбеддинг резюме через ML Service (модель эмбеддинга)
|
||||||
|
- Сохраняет эмбеддинг в хранилище
|
||||||
|
- Ищет подходящие вакансии по векторному сходству (HNSW индекс, cosine similarity >= 0.5)
|
||||||
|
- Фильтрует и сортирует до 50 наиболее релевантных вакансий
|
||||||
|
- Запрашивает предикт зарплаты и рекомендуемые навыки через ML Service (алгоритм предикта)
|
||||||
|
- Сохраняет предикт в хранилище
|
||||||
|
|
||||||
|
### 5.3. Структура хранилища
|
||||||
|
- **Users**: пользователи, профили
|
||||||
|
- **Resumes**: резюме с версионированием (up_resume_id, down_resume_id)
|
||||||
|
- **Resume Embeddings**: векторные представления резюме (384 измерения)
|
||||||
|
- **Resume Predictions**: предикты зарплаты и рекомендуемые навыки
|
||||||
|
- **Resume Experience/Education/Projects**: опыт, образование, проекты
|
||||||
|
- **Vacancies**: вакансии с зарплатами и требованиями
|
||||||
|
- **Vacancy Embeddings**: векторные представления вакансий (384 измерения)
|
||||||
|
- **Key Skills**: словарь навыков для автокомплита (GIN индекс с pg_trgm для ILIKE поиска)
|
||||||
|
|
||||||
## 7. Деплой и CI/CD
|
## 7. Деплой и CI/CD
|
||||||
- Локально: Docker Compose (just up/build)
|
- Локально: Docker Compose (just up/build)
|
||||||
@@ -70,17 +88,22 @@ RFC определяет интерфейсы для API, операционны
|
|||||||
|
|
||||||
## 8. Миграции данных и схем
|
## 8. Миграции данных и схем
|
||||||
- Использовать alembic для миграций схем PostgreSQL.
|
- Использовать alembic для миграций схем PostgreSQL.
|
||||||
- Версионировать фичи и контракт входных данных (jsonschema).
|
- Использовать вспомогательные скрипты для выгрузки датасета в хранилище
|
||||||
- При изменениях схем: обеспечить миграционные скрипты + миграционный план с откатом.
|
|
||||||
|
|
||||||
## 9. Безопасность и секреты
|
## 9. Безопасность и секреты
|
||||||
- Секреты в ENV (environment secrets в CI).
|
- Секреты в ENV (environment secrets в CI).
|
||||||
- Валидация входящих данных и rate-limiting (Redis).
|
- Валидация входящих данных, шифрование конфиденциальных данных
|
||||||
|
|
||||||
## 10. Мониторинг и логирование
|
## 10. Мониторинг и логирование
|
||||||
|
- Prometheus метрики через prometheus-fastapi-instrumentator
|
||||||
|
- Логирование через стандартный Python logging
|
||||||
|
- Базовый healthcheck endpoint
|
||||||
- Логи можно посмотреть в Coolify (см. креды в Readme.md)
|
- Логи можно посмотреть в Coolify (см. креды в Readme.md)
|
||||||
- Доступны дашборды в графане с метриками контейнеров, бека, мль
|
- Доступны дашборды в графане с метриками контейнеров, бека, мль
|
||||||
|
|
||||||
## 11. Тестирование
|
## 11. Тестирование
|
||||||
|
- Unit tests - тестируют бизнес логику (entities, factories, invariants)
|
||||||
|
- E2E - тестируют весь user flow через TestApiGateway
|
||||||
|
- Интеграционные тесты для взаимодействия с хранилищем
|
||||||
- Unit tests - тестируют бизнес логику
|
- Unit tests - тестируют бизнес логику
|
||||||
- E2E - тестируют весь user flow, а также интеграцию с ml
|
- E2E - тестируют весь user flow, а также интеграцию с ml
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
DB_URL="${DATABASE_URL:-postgresql://user:password@localhost:5432/dbname}"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
DUMP_FILE="${1:-dump_data.sql}"
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
DUMP_FILE="${1:-$PROJECT_ROOT/dumps/data_dump.sql}"
|
||||||
|
|
||||||
if [ ! -f "$DUMP_FILE" ]; then
|
if [ ! -f "$DUMP_FILE" ]; then
|
||||||
echo "Ошибка: файл $DUMP_FILE не найден"
|
echo "Ошибка: файл $DUMP_FILE не найден"
|
||||||
|
echo "Использование: $0 [путь_к_дампу]"
|
||||||
|
echo "По умолчанию: $PROJECT_ROOT/dumps/data_dump.sql"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Импорт дампа из $DUMP_FILE в БД..."
|
DB_URL="${DATABASE_URL:-postgresql://postgres:postgres@localhost:5432/app}"
|
||||||
|
|
||||||
|
echo "Импорт дампа из $DUMP_FILE в БД $DB_URL..."
|
||||||
|
|
||||||
psql "$DB_URL" -f "$DUMP_FILE"
|
psql "$DB_URL" -f "$DUMP_FILE"
|
||||||
|
|
||||||
echo "Импорт завершен!"
|
echo "Импорт завершен!"
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class DefaultVacancyDataGateway(VacancyDataGateway):
|
|||||||
statement = (
|
statement = (
|
||||||
select(Vacancy, label("resume_similarity", similarity_expr))
|
select(Vacancy, label("resume_similarity", similarity_expr))
|
||||||
.join(VacancyEmbedding, vacancy_embedding_table.c.vacancy_id == vacancy_table.c.id)
|
.join(VacancyEmbedding, vacancy_embedding_table.c.vacancy_id == vacancy_table.c.id)
|
||||||
.where(similarity_expr >= 0.5)
|
.where(similarity_expr >= 0.0)
|
||||||
.order_by(distance_expr.asc())
|
.order_by(distance_expr.asc())
|
||||||
.limit(100)
|
.limit(100)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2406,7 +2406,6 @@ dependencies = [
|
|||||||
{ name = "fastapi" },
|
{ name = "fastapi" },
|
||||||
{ name = "levenshtein" },
|
{ name = "levenshtein" },
|
||||||
{ name = "markupsafe" },
|
{ name = "markupsafe" },
|
||||||
{ name = "prometheus-fastapi-instrumentator" },
|
|
||||||
{ name = "pydantic", extra = ["email"] },
|
{ name = "pydantic", extra = ["email"] },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
@@ -2420,6 +2419,7 @@ backend = [
|
|||||||
{ name = "firebase-admin" },
|
{ name = "firebase-admin" },
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
{ name = "pgvector" },
|
{ name = "pgvector" },
|
||||||
|
{ name = "prometheus-fastapi-instrumentator" },
|
||||||
{ name = "psycopg", extra = ["binary"] },
|
{ name = "psycopg", extra = ["binary"] },
|
||||||
{ name = "python-multipart" },
|
{ name = "python-multipart" },
|
||||||
{ name = "sqlalchemy" },
|
{ name = "sqlalchemy" },
|
||||||
@@ -2482,7 +2482,6 @@ requires-dist = [
|
|||||||
{ name = "fastapi", specifier = "==0.119.0" },
|
{ name = "fastapi", specifier = "==0.119.0" },
|
||||||
{ name = "levenshtein", specifier = ">=0.27.3" },
|
{ name = "levenshtein", specifier = ">=0.27.3" },
|
||||||
{ name = "markupsafe", git = "https://github.com/pallets/markupsafe?rev=3.0.2" },
|
{ name = "markupsafe", git = "https://github.com/pallets/markupsafe?rev=3.0.2" },
|
||||||
{ name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" },
|
|
||||||
{ name = "pydantic", extras = ["email"], specifier = ">=2.12.4" },
|
{ name = "pydantic", extras = ["email"], specifier = ">=2.12.4" },
|
||||||
{ name = "uuid-utils", specifier = "==0.11.1" },
|
{ name = "uuid-utils", specifier = "==0.11.1" },
|
||||||
{ name = "uvicorn", specifier = "==0.37.0" },
|
{ name = "uvicorn", specifier = "==0.37.0" },
|
||||||
@@ -2496,6 +2495,7 @@ backend = [
|
|||||||
{ name = "firebase-admin", specifier = ">=7.1.0" },
|
{ name = "firebase-admin", specifier = ">=7.1.0" },
|
||||||
{ name = "httpx", specifier = "==0.28.1" },
|
{ name = "httpx", specifier = "==0.28.1" },
|
||||||
{ name = "pgvector", specifier = ">=0.4.1" },
|
{ name = "pgvector", specifier = ">=0.4.1" },
|
||||||
|
{ name = "prometheus-fastapi-instrumentator", specifier = ">=7.1.0" },
|
||||||
{ name = "psycopg", extras = ["binary"], specifier = ">=3.2.12" },
|
{ name = "psycopg", extras = ["binary"], specifier = ">=3.2.12" },
|
||||||
{ name = "python-multipart", specifier = ">=0.0.20" },
|
{ name = "python-multipart", specifier = ">=0.0.20" },
|
||||||
{ name = "sqlalchemy", specifier = "==2.0.44" },
|
{ name = "sqlalchemy", specifier = "==2.0.44" },
|
||||||
|
|||||||
Reference in New Issue
Block a user