не помнб

This commit is contained in:
ivankirpichnikov
2025-11-22 18:15:29 +03:00
parent 995141a200
commit effbcfbc2d
17 changed files with 210 additions and 54 deletions
@@ -4,7 +4,6 @@ from typing import Protocol
from template_project.application.resume.entity import (
Resume,
ResumeEmbeddingId,
ResumeId,
ResumePrediction,
)
@@ -12,10 +11,6 @@ from template_project.application.user.entity import UserId
class ResumeDataGateway(Protocol):
@abstractmethod
async def get_suitable_resumes(self, embedding_id: ResumeEmbeddingId) -> Sequence[Resume]:
raise NotImplementedError
@abstractmethod
async def load(self, resume_id: ResumeId) -> Resume:
raise NotImplementedError
@@ -3,19 +3,20 @@ from collections.abc import Callable
from Levenshtein import ratio
from template_project.application.common.unit_of_work import UnitOfWork
from template_project.application.resume.data_gateway import ResumeDataGateway
from template_project.application.resume.entity import Resume, ResumeEmbedding, ResumePrediction
from template_project.application.resume.vector_generator import ResumeEmbeddingVectorGenerator
from template_project.application.vacancy.data_gateway import VacancyDataGateway
from template_project.application.vacancy.entity import Vacancy
def suitable_resumes_key(
def suitable_vacancies_key(
resume: Resume,
) -> Callable[[Resume], bool]:
def wrapper(suitable_resume: Resume) -> bool:
) -> Callable[[Vacancy], bool]:
def wrapper(vacancy: Vacancy) -> bool:
count_skills = 0
ratio_skill_sum = 0.0
for resum_key_skill in resume.key_skills:
for suitable_resume_key_skill in suitable_resume.key_skills:
for suitable_resume_key_skill in vacancy.key_skills:
ratio_skill = ratio(resum_key_skill, suitable_resume_key_skill)
if ratio_skill != 0:
count_skills += 1
@@ -26,7 +27,7 @@ def suitable_resumes_key(
except ZeroDivisionError:
matching_skills = 0
return resume.experience_type == suitable_resume.experience_type and matching_skills >= 50
return resume.experience_type == vacancy.experience_type and matching_skills >= 50
return wrapper
@@ -35,11 +36,11 @@ class ResumeEmbeddingPipeline:
def __init__(
self,
unit_of_work: UnitOfWork,
resume_data_gateway: ResumeDataGateway,
vacancy_data_gateway: VacancyDataGateway,
vector_generator: ResumeEmbeddingVectorGenerator,
) -> None:
self.unit_of_work = unit_of_work
self.resume_data_gateway = resume_data_gateway
self.vacancy_data_gateway = vacancy_data_gateway
self.vector_generator = vector_generator
async def run(
@@ -50,18 +51,20 @@ class ResumeEmbeddingPipeline:
position=resume.position,
about_me=resume.about_me,
key_skills=resume.key_skills,
experience_type=resume.experience_type,
)
resume_embedding = ResumeEmbedding.factory(
resume_id=resume.id,
vector=vector,
)
suitable_resumes = await self.resume_data_gateway.get_suitable_resumes(resume_embedding.id)
suitable_resumes_filtered = sorted(
suitable_resumes,
key=suitable_resumes_key(resume),
suitable_vacancies = await self.vacancy_data_gateway.get_suitable(resume_embedding.vector)
suitable_vacancies_filtered = sorted(
suitable_vacancies,
key=suitable_vacancies_key(resume),
)
suitable_resumes = suitable_resumes_filtered[:50]
suitable_vacancies = suitable_vacancies_filtered[:50]
# TODO: тут надо сделать отправку в ИИ
@@ -0,0 +1 @@
# class ResumePredicition
@@ -1,13 +1,15 @@
from abc import abstractmethod
from typing import Protocol
from template_project.application.common.enums import ExperienceType
class ResumeEmbeddingVectorGenerator(Protocol):
class ResumeEmbeddingVectorGenerator:
@abstractmethod
async def generate(
self,
position: str,
about_me: str,
experience_type: ExperienceType,
key_skills: list[str],
) -> list[float]:
raise NotImplementedError
@@ -0,0 +1,11 @@
from abc import abstractmethod
from collections.abc import Sequence
from typing import Protocol
from template_project.application.vacancy.entity import Vacancy
class VacancyDataGateway(Protocol):
@abstractmethod
async def get_suitable(self, vector: list[float]) -> Sequence[Vacancy]:
raise NotImplementedError