Spaces:
Running
Running
Commit
·
979bdd1
1
Parent(s):
ee816fa
projects
Browse files- Process/utils.py +69 -3
- ResumeATS/urls.py +2 -1
Process/utils.py
CHANGED
|
@@ -24,8 +24,9 @@ class ATSResumeParser:
|
|
| 24 |
def __init__(self):
|
| 25 |
logger.info("Initializing ATSResumeParser")
|
| 26 |
self.score_weights = {
|
| 27 |
-
"skills_match":
|
| 28 |
-
"experience_relevance":
|
|
|
|
| 29 |
"education_relevance": 10,
|
| 30 |
"overall_formatting": 15,
|
| 31 |
"keyword_optimization": 10,
|
|
@@ -92,6 +93,67 @@ class ATSResumeParser:
|
|
| 92 |
"explanation": response["explanation"],
|
| 93 |
}
|
| 94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
def _score_experience(
|
| 96 |
self, experience: List[Dict], job_description: Optional[str]
|
| 97 |
) -> Dict:
|
|
@@ -252,7 +314,6 @@ class ATSResumeParser:
|
|
| 252 |
detailed_feedback = {}
|
| 253 |
|
| 254 |
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 255 |
-
# Define tasks to run in parallel
|
| 256 |
tasks = {
|
| 257 |
"skills_match": executor.submit(
|
| 258 |
self._score_skills,
|
|
@@ -264,6 +325,11 @@ class ATSResumeParser:
|
|
| 264 |
structured_data.get("experience", []),
|
| 265 |
job_description,
|
| 266 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
"education_relevance": executor.submit(
|
| 268 |
self._score_education, structured_data.get("education", [])
|
| 269 |
),
|
|
|
|
| 24 |
def __init__(self):
|
| 25 |
logger.info("Initializing ATSResumeParser")
|
| 26 |
self.score_weights = {
|
| 27 |
+
"skills_match": 20,
|
| 28 |
+
"experience_relevance": 20,
|
| 29 |
+
"project_relevance": 15,
|
| 30 |
"education_relevance": 10,
|
| 31 |
"overall_formatting": 15,
|
| 32 |
"keyword_optimization": 10,
|
|
|
|
| 93 |
"explanation": response["explanation"],
|
| 94 |
}
|
| 95 |
|
| 96 |
+
def _score_projects(
|
| 97 |
+
self, projects: List[Dict], job_description: Optional[str]
|
| 98 |
+
) -> Dict:
|
| 99 |
+
"""Score projects with optimized processing"""
|
| 100 |
+
print("567898765", projects)
|
| 101 |
+
if not projects:
|
| 102 |
+
return {
|
| 103 |
+
"score": 0,
|
| 104 |
+
"matching": [],
|
| 105 |
+
"missing": [],
|
| 106 |
+
"explanation": "No projects provided",
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
# Basic score based only on project count
|
| 110 |
+
base_score = 70
|
| 111 |
+
|
| 112 |
+
if not job_description:
|
| 113 |
+
return {
|
| 114 |
+
"score": base_score,
|
| 115 |
+
"matching": [p.get("title", "Untitled Project") for p in projects[:3]],
|
| 116 |
+
"missing": [],
|
| 117 |
+
"explanation": "No job description provided",
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
# Fix: Use 'name' instead of 'title' to match your data structure
|
| 121 |
+
simplified_projects = [
|
| 122 |
+
{"title": p.get("title", ""), "description": p.get("description", "")}
|
| 123 |
+
for p in projects[:3]
|
| 124 |
+
]
|
| 125 |
+
try:
|
| 126 |
+
prompt = f"""Projects: {json.dumps(simplified_projects)}. Job description: {job_description[:500]}.
|
| 127 |
+
Analyze how well these projects match the job requirements. In your response:
|
| 128 |
+
- Give specific matching elements from projects relevant to the job
|
| 129 |
+
- List missing project types or skills that would improve the match
|
| 130 |
+
- Keep lists concise with specific items, not paragraphs
|
| 131 |
+
- Provide a numerical score between 0-10 reflecting the overall match quality"""
|
| 132 |
+
|
| 133 |
+
response = self._parse_gemini_response(
|
| 134 |
+
get_response(prompt, SYSTEM_INSTRUCTION)
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
score = response.get("score", 5.0)
|
| 138 |
+
|
| 139 |
+
return {
|
| 140 |
+
"score": (base_score + (score * 10)) / 2,
|
| 141 |
+
"matching": response.get("matching", []),
|
| 142 |
+
"missing": response.get("missing", []),
|
| 143 |
+
"explanation": response.get(
|
| 144 |
+
"explanation", "Project assessment completed"
|
| 145 |
+
),
|
| 146 |
+
}
|
| 147 |
+
except Exception as e:
|
| 148 |
+
logger.error(f"Error in _score_projects: {e}")
|
| 149 |
+
logger.debug(traceback.format_exc())
|
| 150 |
+
return {
|
| 151 |
+
"score": base_score,
|
| 152 |
+
"matching": [p.get("name", "Untitled Project") for p in projects[:3]],
|
| 153 |
+
"missing": [],
|
| 154 |
+
"explanation": "Error analyzing project relevance",
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
def _score_experience(
|
| 158 |
self, experience: List[Dict], job_description: Optional[str]
|
| 159 |
) -> Dict:
|
|
|
|
| 314 |
detailed_feedback = {}
|
| 315 |
|
| 316 |
with concurrent.futures.ThreadPoolExecutor() as executor:
|
|
|
|
| 317 |
tasks = {
|
| 318 |
"skills_match": executor.submit(
|
| 319 |
self._score_skills,
|
|
|
|
| 325 |
structured_data.get("experience", []),
|
| 326 |
job_description,
|
| 327 |
),
|
| 328 |
+
"project_relevance": executor.submit(
|
| 329 |
+
self._score_projects,
|
| 330 |
+
structured_data.get("projects", []),
|
| 331 |
+
job_description,
|
| 332 |
+
),
|
| 333 |
"education_relevance": executor.submit(
|
| 334 |
self._score_education, structured_data.get("education", [])
|
| 335 |
),
|
ResumeATS/urls.py
CHANGED
|
@@ -14,9 +14,10 @@ Including another URLconf
|
|
| 14 |
1. Import the include() function: from django.urls import include, path
|
| 15 |
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
| 16 |
"""
|
|
|
|
| 17 |
from django.contrib import admin
|
| 18 |
from django.urls import path, include
|
| 19 |
|
| 20 |
urlpatterns = [
|
| 21 |
-
path(
|
| 22 |
]
|
|
|
|
| 14 |
1. Import the include() function: from django.urls import include, path
|
| 15 |
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
| 16 |
"""
|
| 17 |
+
|
| 18 |
from django.contrib import admin
|
| 19 |
from django.urls import path, include
|
| 20 |
|
| 21 |
urlpatterns = [
|
| 22 |
+
path("", include("Process.urls")),
|
| 23 |
]
|