fix(): adaptix is a common dependency due to it being used in domain

This commit is contained in:
gitgernit
2025-11-22 14:26:39 +03:00
parent 00af067f4d
commit 71389d5d82
8 changed files with 181 additions and 4 deletions
+1 -1
View File
@@ -10,12 +10,12 @@ dependencies = [
"dishka==1.7.2", "dishka==1.7.2",
"pydantic[email]>=2.12.4", "pydantic[email]>=2.12.4",
"levenshtein>=0.27.3", "levenshtein>=0.27.3",
"adaptix==3.0.0b11",
"markupsafe", "markupsafe",
] ]
[dependency-groups] [dependency-groups]
backend = [ backend = [
"adaptix==3.0.0b11",
"sqlalchemy==2.0.44", "sqlalchemy==2.0.44",
"argon2_cffi==23.1.0", "argon2_cffi==23.1.0",
"cryptography==46.0.3", "cryptography==46.0.3",
+2 -1
View File
@@ -14,7 +14,7 @@ from fastapi.middleware.cors import CORSMiddleware
from template_project.ml.configuration import load_configuration from template_project.ml.configuration import load_configuration
from template_project.ml.ioc.make import make_ioc from template_project.ml.ioc.make import make_ioc
from template_project.ml.routes import embedding, healthcheck from template_project.ml.routes import embedding, healthcheck, predict
LOG_CONFIG: Final = { LOG_CONFIG: Final = {
"version": 1, "version": 1,
@@ -56,6 +56,7 @@ def make_asgi_application(
) )
app.include_router(healthcheck.router) app.include_router(healthcheck.router)
app.include_router(embedding.router) app.include_router(embedding.router)
app.include_router(predict.router)
setup_dishka(container=ioc, app=app) setup_dishka(container=ioc, app=app)
@@ -0,0 +1,39 @@
from decimal import Decimal
from template_project.application.common.data_structure import to_data_structure
from template_project.application.common.interactor import to_interactor
from template_project.application.resume.entity import ResumeId
@to_data_structure
class VacancyInput:
vacancy_id: str
from_salary: Decimal
to_salary: Decimal
key_skills: list[str]
resume_similarity: float
@to_data_structure
class PredictSalaryRequest:
resume_id: ResumeId
key_skills: list[str]
vacancies: list[VacancyInput]
@to_data_structure
class PredictSalaryResponse:
salary_from: Decimal
salary_to: Decimal
recommended_skills: list[str]
@to_interactor
class PredictSalaryInteractor:
async def execute(self, request: PredictSalaryRequest) -> PredictSalaryResponse:
return PredictSalaryResponse(
salary_from=Decimal("50000"),
salary_to=Decimal("80000"),
recommended_skills=["python", "django", "postgresql"],
)
+12
View File
@@ -0,0 +1,12 @@
from dishka import BaseScope, Provider, Scope, provide_all
from template_project.ml.interactors.predict_salary import PredictSalaryInteractor
class InteractorProvider(Provider):
scope: BaseScope | None = Scope.REQUEST
interactors = provide_all(
PredictSalaryInteractor,
)
+2
View File
@@ -3,6 +3,7 @@ from dishka.integrations.fastapi import FastapiProvider
from template_project.ml.configuration import Configuration, ServerConfiguration from template_project.ml.configuration import Configuration, ServerConfiguration
from template_project.ml.ioc.embedding import EmbeddingProvider from template_project.ml.ioc.embedding import EmbeddingProvider
from template_project.ml.ioc.interactor import InteractorProvider
from template_project.ml.ioc.model import ModelProvider from template_project.ml.ioc.model import ModelProvider
@@ -10,6 +11,7 @@ def make_ioc(configuration: Configuration) -> AsyncContainer:
return make_async_container( return make_async_container(
ModelProvider(), ModelProvider(),
EmbeddingProvider(), EmbeddingProvider(),
InteractorProvider(),
FastapiProvider(), FastapiProvider(),
validation_settings=STRICT_VALIDATION, validation_settings=STRICT_VALIDATION,
context={ context={
+123
View File
@@ -0,0 +1,123 @@
from decimal import Decimal
from dishka import FromDishka
from dishka.integrations.fastapi import DishkaRoute
from fastapi import APIRouter, status
from pydantic import BaseModel, Field
from template_project.application.resume.entity import ResumeId
from template_project.ml.interactors.predict_salary import (
PredictSalaryInteractor,
PredictSalaryRequest,
PredictSalaryResponse,
VacancyInput,
)
router = APIRouter(route_class=DishkaRoute, tags=["Prediction"])
class VacancyInputModel(BaseModel):
vacancy_id: str = Field(description="Vacancy ID", examples=["vacancy_123"])
from_salary: Decimal = Field(description="Minimum salary", examples=[Decimal(100000)])
to_salary: Decimal = Field(description="Maximum salary", examples=[Decimal(150000)])
key_skills: list[str] = Field(description="List of key skills", examples=[["Python", "FastAPI", "PostgreSQL"]])
resume_similarity: float = Field(
ge=0.0, le=1.0, description="Resume similarity score (0.0 to 1.0)", examples=[0.85]
)
model_config = {
"json_schema_extra": {
"example": {
"vacancy_id": "vacancy_123",
"from_salary": "100000",
"to_salary": "150000",
"key_skills": ["Python", "FastAPI", "PostgreSQL"],
"resume_similarity": 0.85,
}
}
}
class PredictSalaryRequestModel(BaseModel):
resume_id: ResumeId = Field(description="Resume ID", examples=["01234567-89ab-cdef-0123-456789abcdef"])
key_skills: list[str] = Field(
min_length=1, description="List of key skills from resume", examples=[["Python", "FastAPI", "PostgreSQL"]]
)
vacancies: list[VacancyInputModel] = Field(
min_length=1, description="List of relevant vacancies", examples=[[]]
)
model_config = {
"json_schema_extra": {
"example": {
"resume_id": "01234567-89ab-cdef-0123-456789abcdef",
"key_skills": ["Python", "FastAPI", "PostgreSQL"],
"vacancies": [
{
"vacancy_id": "vacancy_123",
"from_salary": "100000",
"to_salary": "150000",
"key_skills": ["Python", "FastAPI", "PostgreSQL", "Docker"],
"resume_similarity": 0.85,
}
],
}
}
}
class PredictSalaryResponseModel(BaseModel):
salary_from: Decimal = Field(description="Minimum predicted salary", examples=[Decimal(100000)])
salary_to: Decimal = Field(description="Maximum predicted salary", examples=[Decimal(150000)])
recommended_skills: list[str] = Field(
description="Top 3 recommended skills", examples=[["Kubernetes", "Redis", "Docker"]]
)
model_config = {
"json_schema_extra": {
"example": {
"salary_from": "100000",
"salary_to": "150000",
"recommended_skills": ["Kubernetes", "Redis", "Docker"],
}
}
}
@router.post(
"/predict_salary",
summary="Predict salary",
description="Predict salary range and recommend skills based on resume and relevant vacancies",
responses={
200: {"description": "Salary prediction generated successfully", "model": PredictSalaryResponseModel},
},
)
async def predict_salary(
request: PredictSalaryRequestModel,
interactor: FromDishka[PredictSalaryInteractor],
) -> PredictSalaryResponseModel:
vacancy_inputs = [
VacancyInput(
vacancy_id=vacancy.vacancy_id,
from_salary=vacancy.from_salary,
to_salary=vacancy.to_salary,
key_skills=vacancy.key_skills,
resume_similarity=vacancy.resume_similarity,
)
for vacancy in request.vacancies
]
predict_request = PredictSalaryRequest(
resume_id=request.resume_id,
key_skills=request.key_skills,
vacancies=vacancy_inputs,
)
response = await interactor.execute(predict_request)
return PredictSalaryResponseModel(
salary_from=response.salary_from,
salary_to=response.salary_to,
recommended_skills=response.recommended_skills,
)
Generated
+2 -2
View File
@@ -2416,6 +2416,7 @@ name = "template-project"
version = "1.0.0" version = "1.0.0"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "adaptix" },
{ name = "dishka" }, { name = "dishka" },
{ name = "fastapi" }, { name = "fastapi" },
{ name = "levenshtein" }, { name = "levenshtein" },
@@ -2427,7 +2428,6 @@ dependencies = [
[package.dev-dependencies] [package.dev-dependencies]
backend = [ backend = [
{ name = "adaptix" },
{ name = "aioboto3" }, { name = "aioboto3" },
{ name = "argon2-cffi" }, { name = "argon2-cffi" },
{ name = "cryptography" }, { name = "cryptography" },
@@ -2478,6 +2478,7 @@ types = [
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "adaptix", specifier = "==3.0.0b11" },
{ name = "dishka", specifier = "==1.7.2" }, { name = "dishka", specifier = "==1.7.2" },
{ name = "fastapi", specifier = "==0.119.0" }, { name = "fastapi", specifier = "==0.119.0" },
{ name = "levenshtein", specifier = ">=0.27.3" }, { name = "levenshtein", specifier = ">=0.27.3" },
@@ -2489,7 +2490,6 @@ requires-dist = [
[package.metadata.requires-dev] [package.metadata.requires-dev]
backend = [ backend = [
{ name = "adaptix", specifier = "==3.0.0b11" },
{ name = "aioboto3", specifier = "==15.5.0" }, { name = "aioboto3", specifier = "==15.5.0" },
{ name = "argon2-cffi", specifier = "==23.1.0" }, { name = "argon2-cffi", specifier = "==23.1.0" },
{ name = "cryptography", specifier = "==46.0.3" }, { name = "cryptography", specifier = "==46.0.3" },