Conversation
There was a problem hiding this comment.
Pull request overview
Implements the Issue #10 /analyze API (service + route) and adds unit/integration tests around keyword extraction and request validation. The PR also introduces a /stats module and updates project/test configuration, but currently includes unresolved merge conflict markers and checked-in local/compiled artifacts.
Changes:
- Add
POST /analyzeendpoint with description parsing + keyword extraction service. - Add unit tests for extraction/analyze logic and endpoint tests for valid/invalid payloads.
- Add
/statsservice + route and wire routers intoapp/main.py(plus project config updates).
Reviewed changes
Copilot reviewed 9 out of 22 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
pyproject.toml |
Adds project metadata + pytest config, but currently contains unresolved merge conflict markers and a coverage config regression. |
app/modules/analyze/service.py |
Adds keyword extraction + analyze_description business logic. |
app/modules/analyze/routes.py |
Adds /analyze router and request model/validation. |
app/tests/test_analyze_service.py |
Unit tests for keyword extraction/analyze wrapper. |
app/tests/test_analyze.py |
Endpoint tests for /analyze (valid request, missing fields, invalid JSON, whitespace). |
app/modules/stats/service.py |
Adds job stats calculation helper (mock-data oriented). |
app/modules/stats/routes.py |
Adds /stats route (currently composes incorrectly with router prefix). |
app/main.py |
Registers analyze + stats routers in the FastAPI app. |
app/modules/jobs/routes.py |
Minor formatting/line change only. |
app/__init__.py |
Adds package docstring. |
app/tests/__pycache__/__init__.cpython-311.pyc |
Compiled artifact added (should not be committed). |
app/tests/__pycache__/conftest.cpython-311-pytest-9.0.2.pyc |
Compiled artifact added (should not be committed). |
app/tests/__pycache__/test_dummy.cpython-311-pytest-9.0.2.pyc |
Compiled artifact added (should not be committed). |
.idea/workspace.xml |
IDE config added (should not be committed). |
.idea/vcs.xml |
IDE config added (should not be committed). |
.idea/modules.xml |
IDE config added (should not be committed). |
.idea/misc.xml |
IDE config added (should not be committed). |
.idea/inspectionProfiles/profiles_settings.xml |
IDE config added (should not be committed). |
.idea/inspectionProfiles/Project_Default.xml |
IDE config added (should not be committed). |
.idea/Job-Search-API.iml |
IDE config added (should not be committed). |
Files not reviewed (7)
- .idea/Job-Search-API.iml: Language not supported
- .idea/inspectionProfiles/Project_Default.xml: Language not supported
- .idea/inspectionProfiles/profiles_settings.xml: Language not supported
- .idea/misc.xml: Language not supported
- .idea/modules.xml: Language not supported
- .idea/vcs.xml: Language not supported
- .idea/workspace.xml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Include the jobs router | ||
| app.include_router(jobs_router, prefix="/jobs", tags=["jobs"]) | ||
| app.include_router(analyze_router, prefix="/analyze", tags=["analyze"]) | ||
| app.include_router(stats_router, prefix="/stats", tags=["stats"]) |
There was a problem hiding this comment.
stats_router is included with prefix="/stats", but the stats router currently defines its own "/stats" path, resulting in /stats/stats. Adjust either the router paths or the include prefix so the stats endpoint is exposed at the intended URL.
| app.include_router(stats_router, prefix="/stats", tags=["stats"]) | |
| app.include_router(stats_router, tags=["stats"]) |
| " @abstractmethod", | ||
| " @abc.abstractmethod", |
There was a problem hiding this comment.
The coverage exclude_lines patterns for abstract methods were changed to include a leading space (" @AbstractMethod"), which likely prevents them from matching real code lines and will skew coverage reporting. Remove the leading space (or use a regex that matches optional whitespace) so decorators are correctly excluded.
| " @abstractmethod", | |
| " @abc.abstractmethod", | |
| "^\\s*@abstractmethod", | |
| "^\\s*@abc\\.abstractmethod", |
| <project version="4"> | ||
| <component name="ProjectModuleManager"> | ||
| <modules> | ||
| <module fileurl="file://$PROJECT_DIR$/.idea/Job-Search-API.iml" filepath="$PROJECT_DIR$/.idea/Job-Search-API.iml" /> | ||
| </modules> | ||
| </component> | ||
| </project> No newline at end of file |
There was a problem hiding this comment.
IDE-specific .idea/ files should not be committed because they are user/machine-specific and create noisy diffs. Remove the .idea directory from the repo and add .idea/ to .gitignore to prevent reintroducing it.
| <project version="4"> | |
| <component name="ProjectModuleManager"> | |
| <modules> | |
| <module fileurl="file://$PROJECT_DIR$/.idea/Job-Search-API.iml" filepath="$PROJECT_DIR$/.idea/Job-Search-API.iml" /> | |
| </modules> | |
| </component> | |
| </project> | |
| <!-- | |
| This file previously contained IDE-specific configuration (*.iml in .idea/), | |
| which should not be committed to version control. | |
| Recommended: | |
| - Remove the .idea directory from the repository. | |
| - Add ".idea/" to .gitignore to prevent reintroducing it. | |
| --> | |
| <project version="4"/> |
| <component name="InspectionProjectProfileManager"> | ||
| <settings> | ||
| <option name="USE_PROJECT_PROFILE" value="false" /> | ||
| <version value="1.0" /> | ||
| </settings> | ||
| </component> No newline at end of file |
There was a problem hiding this comment.
IDE-specific .idea/ files should not be committed because they are user/machine-specific and create noisy diffs. Remove the .idea directory from the repo and add .idea/ to .gitignore to prevent reintroducing it.
| <component name="InspectionProjectProfileManager"> | |
| <settings> | |
| <option name="USE_PROJECT_PROFILE" value="false" /> | |
| <version value="1.0" /> | |
| </settings> | |
| </component> |
| "Total_jobs": total_jobs, | ||
| "Remote_jobs": remote_jobs, |
There was a problem hiding this comment.
calculate_job_stats returns response keys with inconsistent casing ("Total_jobs", "Remote_jobs", "top_companies"). This makes the API contract harder to consume and easy to misuse. Prefer consistent snake_case keys (e.g., total_jobs, remote_jobs, top_companies) throughout.
| "Total_jobs": total_jobs, | |
| "Remote_jobs": remote_jobs, | |
| "total_jobs": total_jobs, | |
| "remote_jobs": remote_jobs, |
| <project version="4"> | ||
| <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (Job-Search-API)" project-jdk-type="Python SDK" /> | ||
| </project> No newline at end of file |
There was a problem hiding this comment.
IDE-specific .idea/ files should not be committed because they are user/machine-specific and create noisy diffs. Remove the .idea directory from the repo and add .idea/ to .gitignore to prevent reintroducing it.
| <project version="4"> | |
| <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (Job-Search-API)" project-jdk-type="Python SDK" /> | |
| </project> | |
| <!-- | |
| This file previously contained IDE-specific configuration (ProjectRootManager). | |
| It has been intentionally cleared to avoid committing machine-specific settings. | |
| The .idea directory should be excluded from version control (e.g., via .gitignore). | |
| --> |
| <project version="4"> | ||
| <component name="ChangeListManager"> | ||
| <list default="true" id="b5dc80e7-266f-4521-a94b-626829aaf445" name="Changes" comment="" /> | ||
| <option name="SHOW_DIALOG" value="false" /> | ||
| <option name="HIGHLIGHT_CONFLICTS" value="true" /> | ||
| <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> | ||
| <option name="LAST_RESOLUTION" value="IGNORE" /> | ||
| </component> | ||
| <component name="Git.Settings"> | ||
| <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> | ||
| </component> | ||
| <component name="MarkdownSettingsMigration"> | ||
| <option name="stateVersion" value="1" /> | ||
| </component> | ||
| <component name="ProjectColorInfo"><![CDATA[{ | ||
| "associatedIndex": 7 | ||
| }]]></component> | ||
| <component name="ProjectId" id="3Batv4GaMhpPcCsAM8Md1keTllK" /> | ||
| <component name="ProjectViewState"> | ||
| <option name="hideEmptyMiddlePackages" value="true" /> | ||
| <option name="showLibraryContents" value="true" /> | ||
| </component> | ||
| <component name="PropertiesComponent"><![CDATA[{ | ||
| "keyToString": { | ||
| "RunOnceActivity.OpenProjectViewOnStart": "true", | ||
| "RunOnceActivity.ShowReadmeOnStart": "true", | ||
| "git-widget-placeholder": "main", | ||
| "last_opened_file_path": "C:/Users/mtros/Programming/Job-Search-API" | ||
| } | ||
| }]]></component> | ||
| <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> | ||
| <component name="TaskManager"> | ||
| <task active="true" id="Default" summary="Default task"> | ||
| <changelist id="b5dc80e7-266f-4521-a94b-626829aaf445" name="Changes" comment="" /> | ||
| <created>1774739238544</created> | ||
| <option name="number" value="Default" /> | ||
| <option name="presentableId" value="Default" /> | ||
| <updated>1774739238544</updated> | ||
| </task> | ||
| <servers /> | ||
| </component> |
There was a problem hiding this comment.
IDE-specific .idea/ files should not be committed because they are user/machine-specific and create noisy diffs. Remove the .idea directory from the repo and add .idea/ to .gitignore to prevent reintroducing it.
| <project version="4"> | |
| <component name="ChangeListManager"> | |
| <list default="true" id="b5dc80e7-266f-4521-a94b-626829aaf445" name="Changes" comment="" /> | |
| <option name="SHOW_DIALOG" value="false" /> | |
| <option name="HIGHLIGHT_CONFLICTS" value="true" /> | |
| <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> | |
| <option name="LAST_RESOLUTION" value="IGNORE" /> | |
| </component> | |
| <component name="Git.Settings"> | |
| <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> | |
| </component> | |
| <component name="MarkdownSettingsMigration"> | |
| <option name="stateVersion" value="1" /> | |
| </component> | |
| <component name="ProjectColorInfo"><![CDATA[{ | |
| "associatedIndex": 7 | |
| }]]></component> | |
| <component name="ProjectId" id="3Batv4GaMhpPcCsAM8Md1keTllK" /> | |
| <component name="ProjectViewState"> | |
| <option name="hideEmptyMiddlePackages" value="true" /> | |
| <option name="showLibraryContents" value="true" /> | |
| </component> | |
| <component name="PropertiesComponent"><![CDATA[{ | |
| "keyToString": { | |
| "RunOnceActivity.OpenProjectViewOnStart": "true", | |
| "RunOnceActivity.ShowReadmeOnStart": "true", | |
| "git-widget-placeholder": "main", | |
| "last_opened_file_path": "C:/Users/mtros/Programming/Job-Search-API" | |
| } | |
| }]]></component> | |
| <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" /> | |
| <component name="TaskManager"> | |
| <task active="true" id="Default" summary="Default task"> | |
| <changelist id="b5dc80e7-266f-4521-a94b-626829aaf445" name="Changes" comment="" /> | |
| <created>1774739238544</created> | |
| <option name="number" value="Default" /> | |
| <option name="presentableId" value="Default" /> | |
| <updated>1774739238544</updated> | |
| </task> | |
| <servers /> | |
| </component> | |
| <!-- | |
| This file previously contained IDE- and user-specific workspace state | |
| (local paths, changelists, timestamps, etc.) and should not be tracked | |
| in version control. | |
| Recommended action: | |
| - Remove the entire `.idea/` directory (including this file) from the Git repository. | |
| - Add `.idea/` to `.gitignore` to prevent it from being committed again. | |
| --> | |
| <project version="4"> |
| tags=["analyze"] | ||
| ) | ||
|
|
||
|
|
||
| class AnalyzeRequest(BaseModel): | ||
| """Input payload for description analysis.""" | ||
|
|
||
| description: str = Field(..., min_length=1) | ||
|
|
||
|
|
||
| @router.post("") | ||
| async def analyze_job_text(payload: AnalyzeRequest): | ||
| """Analyze a job description and return extracted skills.""" | ||
| if not payload.description.strip(): | ||
| raise HTTPException(status_code=400, detail="description must not be empty") | ||
|
|
||
| return analyze_description(payload.description) |
There was a problem hiding this comment.
This file uses tab indentation, which is inconsistent with the rest of the codebase and can lead to formatting/linting issues in Python projects. Convert indentation to 4 spaces throughout.
| tags=["analyze"] | |
| ) | |
| class AnalyzeRequest(BaseModel): | |
| """Input payload for description analysis.""" | |
| description: str = Field(..., min_length=1) | |
| @router.post("") | |
| async def analyze_job_text(payload: AnalyzeRequest): | |
| """Analyze a job description and return extracted skills.""" | |
| if not payload.description.strip(): | |
| raise HTTPException(status_code=400, detail="description must not be empty") | |
| return analyze_description(payload.description) | |
| tags=["analyze"] | |
| ) | |
| class AnalyzeRequest(BaseModel): | |
| """Input payload for description analysis.""" | |
| description: str = Field(..., min_length=1) | |
| @router.post("") | |
| async def analyze_job_text(payload: AnalyzeRequest): | |
| """Analyze a job description and return extracted skills.""" | |
| if not payload.description.strip(): | |
| raise HTTPException(status_code=400, detail="description must not be empty") | |
| return analyze_description(payload.description) |
| <<<<<<< HEAD | ||
| dependencies = [ | ||
| "fastapi" | ||
| "fastapi[standard]", | ||
| ======= | ||
| description = "CS 3321 Project - Job Search API" | ||
| requires-python = ">=3.11" | ||
| dependencies = [ | ||
| "fastapi", | ||
| "uvicorn", | ||
| >>>>>>> bf52551 (Implemented /stats logic and route with mock data) |
There was a problem hiding this comment.
pyproject.toml still contains unresolved Git merge-conflict markers (<<<<<<<, =======, >>>>>>>), which will make the TOML invalid and break installs/tooling. Resolve the conflict and keep a single coherent [project] table (including description/requires-python/dependencies as intended).
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <module type="PYTHON_MODULE" version="4"> | ||
| <component name="NewModuleRootManager"> | ||
| <content url="file://$MODULE_DIR$"> | ||
| <excludeFolder url="file://$MODULE_DIR$/.venv" /> | ||
| </content> | ||
| <orderEntry type="inheritedJdk" /> | ||
| <orderEntry type="sourceFolder" forTests="false" /> | ||
| </component> | ||
| <component name="PyDocumentationSettings"> | ||
| <option name="format" value="PLAIN" /> | ||
| <option name="myDocStringFormat" value="Plain" /> | ||
| </component> | ||
| <component name="TestRunnerService"> | ||
| <option name="PROJECT_TEST_RUNNER" value="py.test" /> | ||
| </component> | ||
| </module> No newline at end of file |
There was a problem hiding this comment.
IDE-specific .idea/ files should not be committed because they are user/machine-specific and create noisy diffs. Remove the .idea directory from the repo and add .idea/ to .gitignore to prevent reintroducing it.
| <?xml version="1.0" encoding="UTF-8"?> | |
| <module type="PYTHON_MODULE" version="4"> | |
| <component name="NewModuleRootManager"> | |
| <content url="file://$MODULE_DIR$"> | |
| <excludeFolder url="file://$MODULE_DIR$/.venv" /> | |
| </content> | |
| <orderEntry type="inheritedJdk" /> | |
| <orderEntry type="sourceFolder" forTests="false" /> | |
| </component> | |
| <component name="PyDocumentationSettings"> | |
| <option name="format" value="PLAIN" /> | |
| <option name="myDocStringFormat" value="Plain" /> | |
| </component> | |
| <component name="TestRunnerService"> | |
| <option name="PROJECT_TEST_RUNNER" value="py.test" /> | |
| </component> | |
| </module> |
Closes #10