JobSelect 0.11.2__tar.gz → 0.11.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/PKG-INFO +54 -15
  2. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/SOURCES.txt +0 -2
  3. {jobselect-0.11.2 → jobselect-0.11.3}/PKG-INFO +54 -15
  4. {jobselect-0.11.2 → jobselect-0.11.3}/README.md +53 -14
  5. {jobselect-0.11.2 → jobselect-0.11.3}/cli/api_val.py +4 -2
  6. {jobselect-0.11.2 → jobselect-0.11.3}/cli/jobselect.py +18 -16
  7. {jobselect-0.11.2 → jobselect-0.11.3}/cli/model_select.py +14 -15
  8. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/data_prep.py +0 -2
  9. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/test.py +1 -0
  10. {jobselect-0.11.2 → jobselect-0.11.3}/pyproject.toml +1 -1
  11. {jobselect-0.11.2 → jobselect-0.11.3}/test/test_model.py +1 -3
  12. jobselect-0.11.2/cli/test_cli.py +0 -60
  13. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/dependency_links.txt +0 -0
  14. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/entry_points.txt +0 -0
  15. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/requires.txt +0 -0
  16. {jobselect-0.11.2 → jobselect-0.11.3}/JobSelect.egg-info/top_level.txt +0 -0
  17. {jobselect-0.11.2 → jobselect-0.11.3}/LICENSE +0 -0
  18. {jobselect-0.11.2 → jobselect-0.11.3}/cli/utils.py +0 -0
  19. {jobselect-0.11.2 → jobselect-0.11.3}/model/Model.py +0 -0
  20. {jobselect-0.11.2 → jobselect-0.11.3}/model/__init__.py +0 -0
  21. {jobselect-0.11.2 → jobselect-0.11.3}/model/eval.py +0 -0
  22. {jobselect-0.11.2 → jobselect-0.11.3}/model/pred.py +0 -0
  23. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/__init__.py +0 -0
  24. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/label_vocab.json +0 -0
  25. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/prepared_data.npz +0 -0
  26. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/sym_map.py +0 -0
  27. {jobselect-0.11.2 → jobselect-0.11.3}/model/prep/vectorizer.pkl +0 -0
  28. {jobselect-0.11.2 → jobselect-0.11.3}/model_out/skill_classifier.pt +0 -0
  29. {jobselect-0.11.2 → jobselect-0.11.3}/model_out/training_history.json +0 -0
  30. {jobselect-0.11.2 → jobselect-0.11.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JobSelect
3
- Version: 0.11.2
3
+ Version: 0.11.3
4
4
  Summary: A CLI Based AI Skill Classifier for Job Descriptions Build by Akshay Babu
5
5
  Author-email: Akshay Babu <akshaysureshbabu100@gmail.com>
6
6
  License-Expression: MIT
@@ -19,7 +19,7 @@ Requires-Dist: requests==2.34.2
19
19
  Requires-Dist: torch==2.12.1
20
20
  Dynamic: license-file
21
21
 
22
- # Job Description Skill Classifier [JobSelect v0.10.5 & JobAnalyze 6k v1.0] (Multi-Label)
22
+ # Job Description Skill Classifier [JobSelect v0.11.2 & JobAnalyze 6k v1.0] (Multi-Label)
23
23
 
24
24
  [![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=flat&logo=python)](https://www.python.org/)
25
25
  [![PyTorch](https://img.shields.io/badge/PyTorch-2.12.1-%23EE4C2C?style=flat&logo=pytorch)](https://pytorch.org/)
@@ -29,6 +29,8 @@ Dynamic: license-file
29
29
 
30
30
  This project builds a lightweight text classification pipeline that predicts **multiple technical skills** from a job posting. Given a job description (optionally augmented with role and job type), the model outputs a ranked list of likely skills.
31
31
 
32
+ ![JobSelect CLI](./frontend/repo/title_page_jobselect.png)
33
+
32
34
  Installation:
33
35
 
34
36
  - `pip install jobselect`
@@ -64,7 +66,7 @@ It uses:
64
66
 
65
67
  3. **Evaluation** (`model/eval.py`)
66
68
  - Loads the trained model.
67
- - Applies a fixed sigmoid + threshold (**0.5**) to obtain binary skill predictions.
69
+ - Applies a fixed sigmoid + threshold (**0.3**) to obtain binary skill predictions.
68
70
  - Reports:
69
71
  - Per-skill precision/recall/F1
70
72
  - Micro-F1 and Macro-F1
@@ -118,7 +120,10 @@ It uses:
118
120
  │ └─ training_history.json # Training loss history (generated by model.py)
119
121
 
120
122
  ├─ cli/
121
- └─ jobselect.py # Rich terminal CLI for interactive prediction (uses model.pred.predict)
123
+ ├─ jobselect.py # Rich terminal CLI (prompts + prints top skills)
124
+ │ ├─ model_select.py # Inference routing: API-first, LOCAL fallback (key resolved lazily)
125
+ │ └─ api_val.py # API key prompt / mode selection for CLI
126
+
122
127
 
123
128
  ├─ test/
124
129
  │ └─ test_model.py # Pytest checks expected artifacts exist in model_out/ and model/prep/
@@ -127,10 +132,16 @@ It uses:
127
132
  │ ├─ 01_EDA.ipynb # Exploratory Data Analysis
128
133
  │ └─ 02_Data_Engineering.ipynb # Data engineering / cleaning notes
129
134
 
135
+ ├─ api/
136
+ │ ├─ JobAnalyze_API.py # FastAPI service + Pydantic validation + API-key verification
137
+ │ ├─ pred.py # API/server-side prediction wrapper (imports model.pred)
138
+ │ └─ supabase_client.py # Optional API key persistence (Supabase)
139
+
130
140
  ├─ pipeline.py # Executes notebooks + training/eval steps in order
131
- ├─ pyproject.toml # Installs as a cli tool
141
+ ├─ pyproject.toml # Installs as a cli tool (jobselect)
132
142
  ├─ requirements.txt
133
143
  └─ README.md
144
+
134
145
  ```
135
146
 
136
147
  ---
@@ -189,24 +200,48 @@ Outputs include:
189
200
 
190
201
  ### 5) Predict skills for a new job description
191
202
 
192
- #### Option A: Use Python function
203
+ #### Option A: Use Python function (LOCAL model)
193
204
 
194
- `from model.pred import predict`
205
+ `from api.pred import JobAnalyze_6k`
195
206
 
196
- `data/sample_data/test.txt` contains an example job description inside. You can also call the `predict(job_desc, role=..., job_type=..., top_k=...)` function from Python.
207
+ `data/sample_data/test.txt` contains an example job description inside. Use:
197
208
 
198
- #### Option B: Use the interactive CLI
209
+ ```python
210
+ JobAnalyze_6k(job_desc, role="AI Engineer", job_type="Junior", top_k=50)
211
+ ```
199
212
 
200
- ```bash
201
- python cli/jobselect.py
213
+ #### Option B: Use the interactive CLI (API-first with validation)
202
214
 
203
- or
215
+ ```bash
216
+ python -m cli.jobselect
204
217
 
218
+ # or after install
205
219
  pip install jobselect
206
220
  jobselect
207
221
  ```
208
222
 
209
- The CLI prompts for job description, role, and job type, then prints the top skills with probabilities.
223
+ The CLI:
224
+
225
+ - prompts for **Job Description**, **Role**, and **Type**
226
+ - validates them via the API schema when running in API mode
227
+ - prints the top skills ranked by probability
228
+
229
+ ---
230
+
231
+ #### Option C: Get Predictions through API (recommended)
232
+
233
+ Currently, the API service is under development, you could press `Enter` on first screen:
234
+
235
+ - The CLI will always prompt the user for an API Key, press `Enter` to skip to LOCAL Mode
236
+
237
+ ![JobSelect CLI](./frontend/repo/mode_selection_jobselect.png)
238
+
239
+ #### Option D: Call the FastAPI service (optional)
240
+
241
+ Run `api/JobAnalyze_API.py`. Requests must include:
242
+
243
+ - header `JobAnalyze_6k_Key` with a valid API key
244
+ - JSON body with `Job_Desc`, `Role`, and `Type` (validated via Pydantic)
210
245
 
211
246
  ---
212
247
 
@@ -224,14 +259,18 @@ The CLI prompts for job description, role, and job type, then prints the top ski
224
259
  ## Important implementation notes
225
260
 
226
261
  - **Multi-label learning:** Each skill is treated independently (binary relevance via sigmoid + `BCEWithLogitsLoss`).
227
- - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.5**. For production use, you may want per-label thresholds tuned on a validation set.
262
+ - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.3**. For production use, you may want per-label thresholds tuned on a validation set.
228
263
  - **Dataset size:** The included notebooks and evaluation code suggest the dataset may be small; results can be limited by label frequency and data coverage.
229
264
 
230
265
  ---
231
266
 
232
267
  ## New features / capabilities
233
268
 
234
- - **Rich terminal CLI** (`cli/jobauto.py`) using `rich` + `pyfiglet` for interactive top-skill display.
269
+ - **Rich terminal CLI** (`cli/jobselect.py`) using `rich` + `pyfiglet` for interactive top-skill display.
270
+ - **API validation + schema enforcement**
271
+ - Input validation via **Pydantic** model constraints in `api/JobAnalyze_API.py`.
272
+ - API key auth via header + secure verification, with optional Supabase-backed storage in `api/supabase_client.py`.
273
+ - CLI mode auto-detection (`cli/api_val.py` + `cli/model_select.py`): uses API when a key is available, otherwise falls back to local inference.
235
274
  - **Synonym/phrase normalization hook** (`model/prep/sym_map.py`) applied during data preparation.
236
275
  - **Pipeline runner** (`pipeline.py`) to execute notebooks and training steps in sequence.
237
276
 
@@ -4,7 +4,6 @@ pyproject.toml
4
4
  ./cli/api_val.py
5
5
  ./cli/jobselect.py
6
6
  ./cli/model_select.py
7
- ./cli/test_cli.py
8
7
  ./cli/utils.py
9
8
  ./model/Model.py
10
9
  ./model/__init__.py
@@ -28,7 +27,6 @@ JobSelect.egg-info/top_level.txt
28
27
  cli/api_val.py
29
28
  cli/jobselect.py
30
29
  cli/model_select.py
31
- cli/test_cli.py
32
30
  cli/utils.py
33
31
  model/Model.py
34
32
  model/__init__.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JobSelect
3
- Version: 0.11.2
3
+ Version: 0.11.3
4
4
  Summary: A CLI Based AI Skill Classifier for Job Descriptions Build by Akshay Babu
5
5
  Author-email: Akshay Babu <akshaysureshbabu100@gmail.com>
6
6
  License-Expression: MIT
@@ -19,7 +19,7 @@ Requires-Dist: requests==2.34.2
19
19
  Requires-Dist: torch==2.12.1
20
20
  Dynamic: license-file
21
21
 
22
- # Job Description Skill Classifier [JobSelect v0.10.5 & JobAnalyze 6k v1.0] (Multi-Label)
22
+ # Job Description Skill Classifier [JobSelect v0.11.2 & JobAnalyze 6k v1.0] (Multi-Label)
23
23
 
24
24
  [![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=flat&logo=python)](https://www.python.org/)
25
25
  [![PyTorch](https://img.shields.io/badge/PyTorch-2.12.1-%23EE4C2C?style=flat&logo=pytorch)](https://pytorch.org/)
@@ -29,6 +29,8 @@ Dynamic: license-file
29
29
 
30
30
  This project builds a lightweight text classification pipeline that predicts **multiple technical skills** from a job posting. Given a job description (optionally augmented with role and job type), the model outputs a ranked list of likely skills.
31
31
 
32
+ ![JobSelect CLI](./frontend/repo/title_page_jobselect.png)
33
+
32
34
  Installation:
33
35
 
34
36
  - `pip install jobselect`
@@ -64,7 +66,7 @@ It uses:
64
66
 
65
67
  3. **Evaluation** (`model/eval.py`)
66
68
  - Loads the trained model.
67
- - Applies a fixed sigmoid + threshold (**0.5**) to obtain binary skill predictions.
69
+ - Applies a fixed sigmoid + threshold (**0.3**) to obtain binary skill predictions.
68
70
  - Reports:
69
71
  - Per-skill precision/recall/F1
70
72
  - Micro-F1 and Macro-F1
@@ -118,7 +120,10 @@ It uses:
118
120
  │ └─ training_history.json # Training loss history (generated by model.py)
119
121
 
120
122
  ├─ cli/
121
- └─ jobselect.py # Rich terminal CLI for interactive prediction (uses model.pred.predict)
123
+ ├─ jobselect.py # Rich terminal CLI (prompts + prints top skills)
124
+ │ ├─ model_select.py # Inference routing: API-first, LOCAL fallback (key resolved lazily)
125
+ │ └─ api_val.py # API key prompt / mode selection for CLI
126
+
122
127
 
123
128
  ├─ test/
124
129
  │ └─ test_model.py # Pytest checks expected artifacts exist in model_out/ and model/prep/
@@ -127,10 +132,16 @@ It uses:
127
132
  │ ├─ 01_EDA.ipynb # Exploratory Data Analysis
128
133
  │ └─ 02_Data_Engineering.ipynb # Data engineering / cleaning notes
129
134
 
135
+ ├─ api/
136
+ │ ├─ JobAnalyze_API.py # FastAPI service + Pydantic validation + API-key verification
137
+ │ ├─ pred.py # API/server-side prediction wrapper (imports model.pred)
138
+ │ └─ supabase_client.py # Optional API key persistence (Supabase)
139
+
130
140
  ├─ pipeline.py # Executes notebooks + training/eval steps in order
131
- ├─ pyproject.toml # Installs as a cli tool
141
+ ├─ pyproject.toml # Installs as a cli tool (jobselect)
132
142
  ├─ requirements.txt
133
143
  └─ README.md
144
+
134
145
  ```
135
146
 
136
147
  ---
@@ -189,24 +200,48 @@ Outputs include:
189
200
 
190
201
  ### 5) Predict skills for a new job description
191
202
 
192
- #### Option A: Use Python function
203
+ #### Option A: Use Python function (LOCAL model)
193
204
 
194
- `from model.pred import predict`
205
+ `from api.pred import JobAnalyze_6k`
195
206
 
196
- `data/sample_data/test.txt` contains an example job description inside. You can also call the `predict(job_desc, role=..., job_type=..., top_k=...)` function from Python.
207
+ `data/sample_data/test.txt` contains an example job description inside. Use:
197
208
 
198
- #### Option B: Use the interactive CLI
209
+ ```python
210
+ JobAnalyze_6k(job_desc, role="AI Engineer", job_type="Junior", top_k=50)
211
+ ```
199
212
 
200
- ```bash
201
- python cli/jobselect.py
213
+ #### Option B: Use the interactive CLI (API-first with validation)
202
214
 
203
- or
215
+ ```bash
216
+ python -m cli.jobselect
204
217
 
218
+ # or after install
205
219
  pip install jobselect
206
220
  jobselect
207
221
  ```
208
222
 
209
- The CLI prompts for job description, role, and job type, then prints the top skills with probabilities.
223
+ The CLI:
224
+
225
+ - prompts for **Job Description**, **Role**, and **Type**
226
+ - validates them via the API schema when running in API mode
227
+ - prints the top skills ranked by probability
228
+
229
+ ---
230
+
231
+ #### Option C: Get Predictions through API (recommended)
232
+
233
+ Currently, the API service is under development, you could press `Enter` on first screen:
234
+
235
+ - The CLI will always prompt the user for an API Key, press `Enter` to skip to LOCAL Mode
236
+
237
+ ![JobSelect CLI](./frontend/repo/mode_selection_jobselect.png)
238
+
239
+ #### Option D: Call the FastAPI service (optional)
240
+
241
+ Run `api/JobAnalyze_API.py`. Requests must include:
242
+
243
+ - header `JobAnalyze_6k_Key` with a valid API key
244
+ - JSON body with `Job_Desc`, `Role`, and `Type` (validated via Pydantic)
210
245
 
211
246
  ---
212
247
 
@@ -224,14 +259,18 @@ The CLI prompts for job description, role, and job type, then prints the top ski
224
259
  ## Important implementation notes
225
260
 
226
261
  - **Multi-label learning:** Each skill is treated independently (binary relevance via sigmoid + `BCEWithLogitsLoss`).
227
- - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.5**. For production use, you may want per-label thresholds tuned on a validation set.
262
+ - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.3**. For production use, you may want per-label thresholds tuned on a validation set.
228
263
  - **Dataset size:** The included notebooks and evaluation code suggest the dataset may be small; results can be limited by label frequency and data coverage.
229
264
 
230
265
  ---
231
266
 
232
267
  ## New features / capabilities
233
268
 
234
- - **Rich terminal CLI** (`cli/jobauto.py`) using `rich` + `pyfiglet` for interactive top-skill display.
269
+ - **Rich terminal CLI** (`cli/jobselect.py`) using `rich` + `pyfiglet` for interactive top-skill display.
270
+ - **API validation + schema enforcement**
271
+ - Input validation via **Pydantic** model constraints in `api/JobAnalyze_API.py`.
272
+ - API key auth via header + secure verification, with optional Supabase-backed storage in `api/supabase_client.py`.
273
+ - CLI mode auto-detection (`cli/api_val.py` + `cli/model_select.py`): uses API when a key is available, otherwise falls back to local inference.
235
274
  - **Synonym/phrase normalization hook** (`model/prep/sym_map.py`) applied during data preparation.
236
275
  - **Pipeline runner** (`pipeline.py`) to execute notebooks and training steps in sequence.
237
276
 
@@ -1,4 +1,4 @@
1
- # Job Description Skill Classifier [JobSelect v0.10.5 & JobAnalyze 6k v1.0] (Multi-Label)
1
+ # Job Description Skill Classifier [JobSelect v0.11.2 & JobAnalyze 6k v1.0] (Multi-Label)
2
2
 
3
3
  [![Python](https://img.shields.io/badge/Python-3.8+-3776AB?style=flat&logo=python)](https://www.python.org/)
4
4
  [![PyTorch](https://img.shields.io/badge/PyTorch-2.12.1-%23EE4C2C?style=flat&logo=pytorch)](https://pytorch.org/)
@@ -8,6 +8,8 @@
8
8
 
9
9
  This project builds a lightweight text classification pipeline that predicts **multiple technical skills** from a job posting. Given a job description (optionally augmented with role and job type), the model outputs a ranked list of likely skills.
10
10
 
11
+ ![JobSelect CLI](./frontend/repo/title_page_jobselect.png)
12
+
11
13
  Installation:
12
14
 
13
15
  - `pip install jobselect`
@@ -43,7 +45,7 @@ It uses:
43
45
 
44
46
  3. **Evaluation** (`model/eval.py`)
45
47
  - Loads the trained model.
46
- - Applies a fixed sigmoid + threshold (**0.5**) to obtain binary skill predictions.
48
+ - Applies a fixed sigmoid + threshold (**0.3**) to obtain binary skill predictions.
47
49
  - Reports:
48
50
  - Per-skill precision/recall/F1
49
51
  - Micro-F1 and Macro-F1
@@ -97,7 +99,10 @@ It uses:
97
99
  │ └─ training_history.json # Training loss history (generated by model.py)
98
100
 
99
101
  ├─ cli/
100
- └─ jobselect.py # Rich terminal CLI for interactive prediction (uses model.pred.predict)
102
+ ├─ jobselect.py # Rich terminal CLI (prompts + prints top skills)
103
+ │ ├─ model_select.py # Inference routing: API-first, LOCAL fallback (key resolved lazily)
104
+ │ └─ api_val.py # API key prompt / mode selection for CLI
105
+
101
106
 
102
107
  ├─ test/
103
108
  │ └─ test_model.py # Pytest checks expected artifacts exist in model_out/ and model/prep/
@@ -106,10 +111,16 @@ It uses:
106
111
  │ ├─ 01_EDA.ipynb # Exploratory Data Analysis
107
112
  │ └─ 02_Data_Engineering.ipynb # Data engineering / cleaning notes
108
113
 
114
+ ├─ api/
115
+ │ ├─ JobAnalyze_API.py # FastAPI service + Pydantic validation + API-key verification
116
+ │ ├─ pred.py # API/server-side prediction wrapper (imports model.pred)
117
+ │ └─ supabase_client.py # Optional API key persistence (Supabase)
118
+
109
119
  ├─ pipeline.py # Executes notebooks + training/eval steps in order
110
- ├─ pyproject.toml # Installs as a cli tool
120
+ ├─ pyproject.toml # Installs as a cli tool (jobselect)
111
121
  ├─ requirements.txt
112
122
  └─ README.md
123
+
113
124
  ```
114
125
 
115
126
  ---
@@ -168,24 +179,48 @@ Outputs include:
168
179
 
169
180
  ### 5) Predict skills for a new job description
170
181
 
171
- #### Option A: Use Python function
182
+ #### Option A: Use Python function (LOCAL model)
172
183
 
173
- `from model.pred import predict`
184
+ `from api.pred import JobAnalyze_6k`
174
185
 
175
- `data/sample_data/test.txt` contains an example job description inside. You can also call the `predict(job_desc, role=..., job_type=..., top_k=...)` function from Python.
186
+ `data/sample_data/test.txt` contains an example job description inside. Use:
176
187
 
177
- #### Option B: Use the interactive CLI
188
+ ```python
189
+ JobAnalyze_6k(job_desc, role="AI Engineer", job_type="Junior", top_k=50)
190
+ ```
178
191
 
179
- ```bash
180
- python cli/jobselect.py
192
+ #### Option B: Use the interactive CLI (API-first with validation)
181
193
 
182
- or
194
+ ```bash
195
+ python -m cli.jobselect
183
196
 
197
+ # or after install
184
198
  pip install jobselect
185
199
  jobselect
186
200
  ```
187
201
 
188
- The CLI prompts for job description, role, and job type, then prints the top skills with probabilities.
202
+ The CLI:
203
+
204
+ - prompts for **Job Description**, **Role**, and **Type**
205
+ - validates them via the API schema when running in API mode
206
+ - prints the top skills ranked by probability
207
+
208
+ ---
209
+
210
+ #### Option C: Get Predictions through API (recommended)
211
+
212
+ Currently, the API service is under development, you could press `Enter` on first screen:
213
+
214
+ - The CLI will always prompt the user for an API Key, press `Enter` to skip to LOCAL Mode
215
+
216
+ ![JobSelect CLI](./frontend/repo/mode_selection_jobselect.png)
217
+
218
+ #### Option D: Call the FastAPI service (optional)
219
+
220
+ Run `api/JobAnalyze_API.py`. Requests must include:
221
+
222
+ - header `JobAnalyze_6k_Key` with a valid API key
223
+ - JSON body with `Job_Desc`, `Role`, and `Type` (validated via Pydantic)
189
224
 
190
225
  ---
191
226
 
@@ -203,14 +238,18 @@ The CLI prompts for job description, role, and job type, then prints the top ski
203
238
  ## Important implementation notes
204
239
 
205
240
  - **Multi-label learning:** Each skill is treated independently (binary relevance via sigmoid + `BCEWithLogitsLoss`).
206
- - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.5**. For production use, you may want per-label thresholds tuned on a validation set.
241
+ - **Evaluation threshold:** `model/eval.py` uses a fixed threshold of **0.3**. For production use, you may want per-label thresholds tuned on a validation set.
207
242
  - **Dataset size:** The included notebooks and evaluation code suggest the dataset may be small; results can be limited by label frequency and data coverage.
208
243
 
209
244
  ---
210
245
 
211
246
  ## New features / capabilities
212
247
 
213
- - **Rich terminal CLI** (`cli/jobauto.py`) using `rich` + `pyfiglet` for interactive top-skill display.
248
+ - **Rich terminal CLI** (`cli/jobselect.py`) using `rich` + `pyfiglet` for interactive top-skill display.
249
+ - **API validation + schema enforcement**
250
+ - Input validation via **Pydantic** model constraints in `api/JobAnalyze_API.py`.
251
+ - API key auth via header + secure verification, with optional Supabase-backed storage in `api/supabase_client.py`.
252
+ - CLI mode auto-detection (`cli/api_val.py` + `cli/model_select.py`): uses API when a key is available, otherwise falls back to local inference.
214
253
  - **Synonym/phrase normalization hook** (`model/prep/sym_map.py`) applied during data preparation.
215
254
  - **Pipeline runner** (`pipeline.py`) to execute notebooks and training steps in sequence.
216
255
 
@@ -7,12 +7,14 @@ Handles the API key prompt. Stores the user-entered key in module-level
7
7
  No imports from model_select or api_logic — circular import is gone.
8
8
  """
9
9
 
10
- from .utils import clear_console, API_title, query
10
+
11
11
  import os
12
+
13
+ from .utils import clear_console, API_title, query
12
14
 
13
15
 
14
16
  key: str = ""
15
-
17
+
16
18
 
17
19
  def val_api() -> str:
18
20
  clear_console()
@@ -4,54 +4,56 @@ Uses relative imports so it works both as an installed pip package
4
4
  (jobselect command) and during local development (python -m cli.jobselect).
5
5
  """
6
6
 
7
+
8
+ from rich import print
9
+ from rich.console import Console
10
+
7
11
  from .api_val import val_api, infer_mode
8
12
  from .utils import clear_console, title, query
9
13
  from .model_select import predict
10
- from rich import print
11
- from rich.console import Console
12
-
13
-
14
+
15
+
14
16
  def cli() -> None:
15
17
  try:
16
18
  console = Console()
17
-
19
+
18
20
  val_api()
19
21
  infer = infer_mode()
20
-
22
+
21
23
  clear_console()
22
24
  title()
23
-
25
+
24
26
  print(f"[yellow][JobAnalyze : {infer}]")
25
27
  print("[yellow]>> Welcome to JobSelect!")
26
-
28
+
27
29
  query("Enter Job Description")
28
30
  jd = input(" >> ")
29
-
31
+
30
32
  query("Enter Role (AI Engineer / AI Developer)")
31
33
  role = input(" >> ")
32
-
34
+
33
35
  query("Enter Type (Internship / Junior / Senior)")
34
36
  job_type = input(" >> ")
35
-
37
+
36
38
  with console.status("[bold green]Loading...", spinner="dots2"):
37
39
  results, mode = predict(jd, role=role, job_type=job_type)
38
-
40
+
39
41
  clear_console()
40
42
  title()
41
-
43
+
42
44
  mode_colour = "green" if mode == "API" else "cyan"
43
45
  print(f"\n [{mode_colour}][Mode: {mode}][/{mode_colour}]")
44
-
46
+
45
47
  print("\n [yellow]Job Description Provided : \n", jd.strip())
46
48
  print("\n [yellow]Job Role : \n", role)
47
49
  print("\n [yellow]Type : \n", job_type)
48
50
  print()
49
-
51
+
50
52
  print("\n [yellow]TOP Skills \n")
51
53
  for label, prob in results:
52
54
  bar = "█" * int(prob * 30)
53
55
  print(f" {label:25s} {prob:.2f} {bar}\n")
54
-
56
+
55
57
  except KeyboardInterrupt:
56
58
  print("\n[yellow]Exiting JobSelect")
57
59
 
@@ -8,20 +8,19 @@ from dotenv import load_dotenv
8
8
  import os
9
9
  import requests
10
10
  import sys
11
-
11
+
12
12
  PROJECT_ROOT = Path(__file__).resolve().parent.parent
13
13
  if str(PROJECT_ROOT) not in sys.path:
14
14
  sys.path.insert(0, str(PROJECT_ROOT))
15
-
15
+
16
16
  _env_path = Path(__file__).resolve().parent / ".env"
17
17
  if not _env_path.exists():
18
18
  _env_path = PROJECT_ROOT / ".env"
19
19
  load_dotenv(dotenv_path=_env_path)
20
-
21
- API_URL = 'https://job-description-analysis.onrender.com'
20
+
21
+ API_URL = os.getenv("JOBSELECT_API_URL", "")
22
22
  _ENV_KEY = os.getenv("JOBSELECT_API_KEY", "").strip()
23
-
24
-
23
+
25
24
  def _resolve_key() -> str:
26
25
  """
27
26
  Lazy key resolution at inference time (not import time).
@@ -40,27 +39,27 @@ def _resolve_key() -> str:
40
39
  pass
41
40
  return _ENV_KEY
42
41
 
43
-
42
+
44
43
  def _local_predict(jd: str, role: str, job_type: str):
45
44
  from model.pred import JobAnalyze_6k as _job_analyze
46
45
  return _job_analyze(jd, role=role, job_type=job_type)
47
-
48
-
46
+
47
+
49
48
  def _call_api(jd: str, role: str, job_type: str, api_key: str) -> list[tuple[str, float]]:
50
49
  endpoint = f"{API_URL}/JobAnalyze_6k"
51
50
  headers = {"JobAnalyze_6k_Key": api_key}
52
51
  payload = {"Job_Desc": jd, "Role": role, "Type": job_type}
53
-
52
+
54
53
  response = requests.post(endpoint, json=payload, headers=headers, timeout=(10, 120))
55
54
  response.raise_for_status()
56
-
55
+
57
56
  data = response.json()
58
57
  return [(skill, float(score)) for skill, score in data["answer"]]
59
-
60
-
58
+
59
+
61
60
  def predict(jd: str, role: str, job_type: str) -> tuple[list[tuple[str, float]], str]:
62
61
  api_key = _resolve_key()
63
-
62
+
64
63
  if API_URL and api_key:
65
64
  try:
66
65
  results = _call_api(jd, role, job_type, api_key)
@@ -74,6 +73,6 @@ def predict(jd: str, role: str, job_type: str) -> tuple[list[tuple[str, float]],
74
73
  print(f"[JobSelect] API error {code} — falling back to LOCAL")
75
74
  except Exception as e:
76
75
  print(f"[JobSelect] Unexpected error: {e} — falling back to LOCAL")
77
-
76
+
78
77
  results = _local_predict(jd, role=role, job_type=job_type)
79
78
  return results, "LOCAL"
@@ -6,7 +6,6 @@ Run this script, model/model.py and the notebooks through pipeline.py
6
6
 
7
7
  import json
8
8
  from pathlib import Path
9
-
10
9
  import numpy as np
11
10
  import pandas as pd
12
11
  import pickle
@@ -16,7 +15,6 @@ from sklearn.model_selection import train_test_split
16
15
 
17
16
  from sym_map import SYNONYM_MAP
18
17
 
19
-
20
18
  df = pd.read_csv(r'C:\Portfolio-Projects\Job-Description-Analysis\data\clean\cleaned_job_descriptions.csv')
21
19
 
22
20
  SKILLS_FIX = {
@@ -1,4 +1,5 @@
1
1
  import pickle
2
+
2
3
  with open('vectorizer.pkl', 'rb') as f:
3
4
  v = pickle.load(f)
4
5
  print('ci/cd' in v.get_feature_names_out())
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "JobSelect"
3
- version = "0.11.2"
3
+ version = "0.11.3"
4
4
  dependencies = [
5
5
  "rich==15.0.0",
6
6
  "pyfiglet==1.0.4",
@@ -1,9 +1,7 @@
1
1
  from __future__ import annotations
2
-
3
- import json
2
+ import sys
4
3
  from pathlib import Path
5
4
 
6
- import sys
7
5
 
8
6
  REPO_ROOT = Path(__file__).resolve().parents[1]
9
7
 
@@ -1,60 +0,0 @@
1
- """
2
- test_cli.py — dev/test entry point.
3
- Run as: python -m cli.test_cli
4
- """
5
-
6
- from rich import print
7
- from rich.console import Console
8
- from .utils import clear_console, title, query
9
- from .model_select import predict
10
- from .api_val import val_api, infer_mode
11
-
12
-
13
- def cli() -> None:
14
- try:
15
- console = Console()
16
-
17
- val_api()
18
- infer = infer_mode()
19
-
20
- clear_console()
21
- title()
22
-
23
- print(f"[yellow][JobAnalyze : {infer}]")
24
- print("[yellow]>> Welcome to JobSelect!")
25
-
26
- query("Enter Job Description")
27
- jd = input(" >> ")
28
-
29
- query("Enter Role (AI Engineer / AI Developer)")
30
- role = input(" >> ")
31
-
32
- query("Enter Type (Internship / Junior / Senior)")
33
- job_type = input(" >> ")
34
-
35
- with console.status("[bold green]Loading...", spinner="dots2"):
36
- results, mode = predict(jd, role=role, job_type=job_type)
37
-
38
- clear_console()
39
- title()
40
-
41
- mode_colour = "green" if mode == "API" else "cyan"
42
- print(f"\n [{mode_colour}][Mode: {mode}][/{mode_colour}]")
43
-
44
- print("\n [yellow]Job Description Provided : \n", jd.strip())
45
- print("\n [yellow]Job Role : \n", role)
46
- print("\n [yellow]Type : \n", job_type)
47
- print()
48
-
49
- print("\n [yellow]TOP Skills \n")
50
- for label, prob in results:
51
- bar = "█" * int(prob * 30)
52
- print(f" {label:25s} {prob:.2f} {bar}\n")
53
-
54
- except KeyboardInterrupt:
55
- print("\n[yellow]Exiting JobSelect")
56
-
57
-
58
- if __name__ == "__main__":
59
- cli()
60
-
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes