Delete cli
Browse files- cli/__init__.py +0 -0
- cli/api_val.py +0 -89
- cli/jobselect.py +0 -38
- cli/main_screen.py +0 -38
- cli/model_select.py +0 -93
- cli/utils.py +0 -41
cli/__init__.py
DELETED
|
File without changes
|
cli/api_val.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
api_val.py - Handles the API key prompt. Stores the user-entered key in module-level
|
| 3 |
-
`key` so model_select can read it lazily at inference time.
|
| 4 |
-
"""
|
| 5 |
-
|
| 6 |
-
from rich import print
|
| 7 |
-
from dotenv import load_dotenv
|
| 8 |
-
from pathlib import Path
|
| 9 |
-
import os
|
| 10 |
-
|
| 11 |
-
from .utils import clear_console, API_title, query
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
_API_URL = "https://job-description-analysis.onrender.com"
|
| 15 |
-
|
| 16 |
-
_ENV_DIR = Path.home() / ".jobselect"
|
| 17 |
-
_ENV_FILE = _ENV_DIR / ".env"
|
| 18 |
-
|
| 19 |
-
key: str = ""
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
def _load_env() -> None:
|
| 23 |
-
if _ENV_FILE.exists():
|
| 24 |
-
load_dotenv(dotenv_path=_ENV_FILE, override=False)
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def _save_key(api_key: str) -> None:
|
| 28 |
-
try:
|
| 29 |
-
_ENV_DIR.mkdir(parents=True, exist_ok=True)
|
| 30 |
-
_ENV_FILE.write_text(
|
| 31 |
-
f'JOBSELECT_API_URL="{_API_URL}"\n'
|
| 32 |
-
f'JOBSELECT_API_KEY="{api_key}"\n',
|
| 33 |
-
encoding="utf-8",
|
| 34 |
-
)
|
| 35 |
-
except OSError as e:
|
| 36 |
-
print(f"[JobSelect] Warning: could not save key ({e})")
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
def _load_saved_key() -> str:
|
| 40 |
-
_load_env()
|
| 41 |
-
return os.getenv("JOBSELECT_API_KEY", "").strip()
|
| 42 |
-
|
| 43 |
-
def query_api() -> str:
|
| 44 |
-
clear_console()
|
| 45 |
-
API_title()
|
| 46 |
-
query("Which Mode? \n[yellow]- API : A\n[yellow]- LOCAL : L")
|
| 47 |
-
mode = input(" >> ").upper()
|
| 48 |
-
|
| 49 |
-
return mode
|
| 50 |
-
|
| 51 |
-
def val_api() -> str:
|
| 52 |
-
global key
|
| 53 |
-
|
| 54 |
-
mode = query_api()
|
| 55 |
-
|
| 56 |
-
saved = _load_saved_key()
|
| 57 |
-
if saved and mode == "A":
|
| 58 |
-
key = saved
|
| 59 |
-
return key
|
| 60 |
-
elif mode == "L":
|
| 61 |
-
key = ""
|
| 62 |
-
return key
|
| 63 |
-
|
| 64 |
-
modes = ('A','L')
|
| 65 |
-
|
| 66 |
-
if mode not in modes:
|
| 67 |
-
mode = query_api()
|
| 68 |
-
|
| 69 |
-
clear_console()
|
| 70 |
-
API_title()
|
| 71 |
-
query("Enter API Key (Press Enter to run locally)")
|
| 72 |
-
typed = input(" >> ").strip()
|
| 73 |
-
|
| 74 |
-
if typed:
|
| 75 |
-
_save_key(typed)
|
| 76 |
-
os.environ["JOBSELECT_API_URL"] = _API_URL
|
| 77 |
-
os.environ["JOBSELECT_API_KEY"] = typed
|
| 78 |
-
key = typed
|
| 79 |
-
else:
|
| 80 |
-
key = ""
|
| 81 |
-
|
| 82 |
-
return key
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
def infer_mode() -> str:
|
| 86 |
-
"""Return 'API' or 'LOCAL'. Call after val_api() has run."""
|
| 87 |
-
if key:
|
| 88 |
-
return "API"
|
| 89 |
-
return "LOCAL"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cli/jobselect.py
DELETED
|
@@ -1,38 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
jobselect.py β CLI entry point.
|
| 3 |
-
Uses relative imports so it works both as an installed pip package
|
| 4 |
-
(jobselect command) and during local development (python -m cli.jobselect).
|
| 5 |
-
"""
|
| 6 |
-
|
| 7 |
-
from rich import print
|
| 8 |
-
|
| 9 |
-
from .utils import clear_console, title, query
|
| 10 |
-
from .main_screen import main_screen
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
def cli() -> None:
|
| 14 |
-
try:
|
| 15 |
-
jd, role, job_type, results, mode = main_screen()
|
| 16 |
-
|
| 17 |
-
clear_console()
|
| 18 |
-
title()
|
| 19 |
-
|
| 20 |
-
mode_colour = "green" if mode == "API" else "cyan"
|
| 21 |
-
print(f"\n [{mode_colour}][Mode: {mode}][/{mode_colour}]")
|
| 22 |
-
|
| 23 |
-
print("\n [yellow]Job Description Provided : \n", jd.strip())
|
| 24 |
-
print("\n [yellow]Job Role : \n", role)
|
| 25 |
-
print("\n [yellow]Type : \n", job_type)
|
| 26 |
-
print()
|
| 27 |
-
|
| 28 |
-
print("\n [yellow]TOP Skills \n")
|
| 29 |
-
for label, prob in results:
|
| 30 |
-
bar = "β" * int(prob * 30)
|
| 31 |
-
print(f" {label:25s} {prob:.2f} {bar}\n")
|
| 32 |
-
|
| 33 |
-
except KeyboardInterrupt:
|
| 34 |
-
print("\n[yellow]Exiting JobSelect")
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
if __name__ == "__main__":
|
| 38 |
-
cli()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cli/main_screen.py
DELETED
|
@@ -1,38 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
main_screen.py - Main screen utils for jobslect CLI tool
|
| 3 |
-
"""
|
| 4 |
-
|
| 5 |
-
from rich.console import Console
|
| 6 |
-
from rich import print
|
| 7 |
-
|
| 8 |
-
from .utils import clear_console, title, query
|
| 9 |
-
|
| 10 |
-
console = Console()
|
| 11 |
-
|
| 12 |
-
def main_screen():
|
| 13 |
-
from .api_val import val_api, infer_mode
|
| 14 |
-
|
| 15 |
-
val_api()
|
| 16 |
-
infer = infer_mode()
|
| 17 |
-
|
| 18 |
-
clear_console()
|
| 19 |
-
title()
|
| 20 |
-
|
| 21 |
-
print(f"[yellow][JobAnalyze : {infer}]")
|
| 22 |
-
print("[yellow]>> Welcome to JobSelect!")
|
| 23 |
-
|
| 24 |
-
query("Enter Job Description")
|
| 25 |
-
jd = input(" >> ")
|
| 26 |
-
|
| 27 |
-
query("Enter Role (AI Engineer / AI Developer)")
|
| 28 |
-
role = input(" >> ")
|
| 29 |
-
|
| 30 |
-
query("Enter Type (Internship / Junior / Senior)")
|
| 31 |
-
job_type = input(" >> ")
|
| 32 |
-
|
| 33 |
-
from .model_select import predict
|
| 34 |
-
|
| 35 |
-
with console.status("[bold green]Loading...", spinner="dots2"):
|
| 36 |
-
results, mode = predict(jd, role=role, job_type=job_type, force_local=(infer == "LOCAL"))
|
| 37 |
-
|
| 38 |
-
return jd, role, job_type, results, mode
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cli/model_select.py
DELETED
|
@@ -1,93 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
model_select.py β inference routing (API first, local fallback).
|
| 3 |
-
Never prompts the user. Key is resolved lazily at predict() call time.
|
| 4 |
-
"""
|
| 5 |
-
|
| 6 |
-
from pathlib import Path
|
| 7 |
-
from dotenv import load_dotenv
|
| 8 |
-
from rich import print
|
| 9 |
-
import os
|
| 10 |
-
import requests
|
| 11 |
-
import sys
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
def _load_env() -> None:
|
| 15 |
-
candidates = [
|
| 16 |
-
Path.cwd() / ".env",
|
| 17 |
-
Path.home() / ".jobselect" / ".env",
|
| 18 |
-
Path(__file__).resolve().parent.parent / ".env",
|
| 19 |
-
]
|
| 20 |
-
for path in candidates:
|
| 21 |
-
if path.exists():
|
| 22 |
-
load_dotenv(dotenv_path=path, override=False)
|
| 23 |
-
return
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
def _resolve_config() -> tuple[str, str]:
|
| 27 |
-
_load_env()
|
| 28 |
-
url = os.getenv("JOBSELECT_API_URL", "").strip().rstrip("/")
|
| 29 |
-
key = os.getenv("JOBSELECT_API_KEY", "").strip()
|
| 30 |
-
return url, key
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
def _resolve_key(env_key: str) -> str:
|
| 34 |
-
try:
|
| 35 |
-
from . import api_val
|
| 36 |
-
if api_val.key:
|
| 37 |
-
return api_val.key
|
| 38 |
-
except ImportError:
|
| 39 |
-
try:
|
| 40 |
-
import api_val
|
| 41 |
-
if api_val.key:
|
| 42 |
-
return api_val.key
|
| 43 |
-
except ImportError:
|
| 44 |
-
pass
|
| 45 |
-
return env_key
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
def _local_predict(jd: str, role: str, job_type: str):
|
| 49 |
-
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
| 50 |
-
if str(PROJECT_ROOT) not in sys.path:
|
| 51 |
-
sys.path.insert(0, str(PROJECT_ROOT))
|
| 52 |
-
from model.pred import JobAnalyze_6k as _job_analyze
|
| 53 |
-
return _job_analyze(jd, role=role, job_type=job_type)
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
def _call_api(
|
| 57 |
-
jd: str, role: str, job_type: str, api_key: str, api_url: str
|
| 58 |
-
) -> list[tuple[str, float]]:
|
| 59 |
-
endpoint = f"{api_url}/JobAnalyze_6k"
|
| 60 |
-
headers = {"JobAnalyze_6k_Key": api_key}
|
| 61 |
-
payload = {"Job_Desc": jd, "Role": role, "Type": job_type}
|
| 62 |
-
|
| 63 |
-
response = requests.post(endpoint, json=payload, headers=headers, timeout=(10, 120))
|
| 64 |
-
response.raise_for_status()
|
| 65 |
-
|
| 66 |
-
data = response.json()
|
| 67 |
-
return [(skill, float(score)) for skill, score in data["answer"]]
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
def predict(jd: str, role: str, job_type: str, force_local: bool = False) -> tuple[list[tuple[str, float]], str]:
|
| 71 |
-
if force_local:
|
| 72 |
-
results = _local_predict(jd, role=role, job_type=job_type)
|
| 73 |
-
return results, "LOCAL"
|
| 74 |
-
|
| 75 |
-
api_url, env_key = _resolve_config()
|
| 76 |
-
api_key = _resolve_key(env_key)
|
| 77 |
-
|
| 78 |
-
if api_url and api_key:
|
| 79 |
-
try:
|
| 80 |
-
results = _call_api(jd, role, job_type, api_key, api_url)
|
| 81 |
-
return results, "API"
|
| 82 |
-
except requests.exceptions.ConnectionError as e:
|
| 83 |
-
print(f"[red][JobSelect] Connection error: {e} β falling back to LOCAL")
|
| 84 |
-
except requests.exceptions.Timeout:
|
| 85 |
-
print("[red][JobSelect] Request timed out/Under Maintainance β falling back to LOCAL")
|
| 86 |
-
except requests.exceptions.HTTPError as e:
|
| 87 |
-
code = e.response.status_code if e.response is not None else "?"
|
| 88 |
-
print(f"[red][JobSelect] API error {code} β falling back to LOCAL")
|
| 89 |
-
except Exception as e:
|
| 90 |
-
print(f"[red][JobSelect] Unexpected error: {e} β falling back to LOCAL")
|
| 91 |
-
|
| 92 |
-
results = _local_predict(jd, role=role, job_type=job_type)
|
| 93 |
-
return results, "LOCAL"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cli/utils.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
utils.py - Main Utilities for the CLI Interface
|
| 3 |
-
"""
|
| 4 |
-
|
| 5 |
-
import os
|
| 6 |
-
import subprocess
|
| 7 |
-
from pyfiglet import Figlet
|
| 8 |
-
from rich import print
|
| 9 |
-
from rich.console import Console
|
| 10 |
-
|
| 11 |
-
console = Console()
|
| 12 |
-
|
| 13 |
-
def clear_console() -> None:
|
| 14 |
-
if os.name == "nt":
|
| 15 |
-
subprocess.run("cls", shell=True)
|
| 16 |
-
else:
|
| 17 |
-
subprocess.run(["clear"])
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
def API_title() -> None:
|
| 21 |
-
f = Figlet(font="slant")
|
| 22 |
-
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
|
| 23 |
-
print(f.renderText("JobSelect CLI"))
|
| 24 |
-
print(" Copyright Akshay Babu, All rights reserved")
|
| 25 |
-
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
def title() -> None:
|
| 29 |
-
f = Figlet(font="slant")
|
| 30 |
-
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
|
| 31 |
-
print(f.renderText("JobSelect CLI"))
|
| 32 |
-
print("[blue] Running Model : JobAnalyze 6k v1.0")
|
| 33 |
-
print(" Copyright Akshay Babu, All rights reserved")
|
| 34 |
-
print("ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ")
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
def query(message: str) -> None:
|
| 38 |
-
print("\n[yellow][JobSelect]")
|
| 39 |
-
print(f"[yellow] >> {message} : ")
|
| 40 |
-
print("[You]")
|
| 41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|