File size: 2,424 Bytes
ab331fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
"""

pred.py - predictor for evaluation

"""

import json
import pickle
from typing import List, Tuple
import numpy as np
import torch
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent

from torch import nn

class SkillClassifier(nn.Module):
    def __init__(self, input_dim, num_labels, hidden_dim=32, dropout=0.3):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Dropout(dropout),
            nn.Linear(hidden_dim, num_labels),
        )

    def forward(self, x):
        return self.net(x)

def JobAnalyze_6k(job_desc: str = "", role: str = "", job_type: str = "", top_k: int = 50) -> List[Tuple[str, float]]:
    """

    Predict top-k skills.

    

    Current top-k = 48

    """
    prep_dir = ROOT / "model" / "prep"
    if not prep_dir.exists():
        alt = ROOT / "prep"
        if alt.exists():
            prep_dir = alt

    label_path = prep_dir / "label_vocab.json"
    vector_path = prep_dir / "vectorizer.pkl"
    weights_path = ROOT / "model_out" / "skill_classifier.pt"

    if not label_path.exists():
        raise FileNotFoundError(
            f"Missing {label_path}. Make sure you ran data_prep and model training."
        )
    if not vector_path.exists():
        raise FileNotFoundError(
            f"Missing {vector_path}. Make sure you ran data_prep."
        )
    if not weights_path.exists():
        raise FileNotFoundError(
            f"Missing {weights_path}. Make sure you ran model/model.py."
        )

    with open(label_path, encoding="utf-8") as f:
        label_vocab = json.load(f)
    with open(vector_path, "rb") as f:
        vectorizer = pickle.load(f)

    input_dim = int(getattr(vectorizer, "vocabulary_", {}).__len__()) or vectorizer.transform([""]).shape[1]

    model = SkillClassifier(input_dim, len(label_vocab))
    model.load_state_dict(torch.load(weights_path, map_location="cpu"))

    model.eval()
    
    combined_text = f"{job_desc} {role} {job_type}"
    X = vectorizer.transform([combined_text]).toarray().astype(np.float32)
    
    with torch.no_grad():
        logits = model(torch.tensor(X))
        probs = torch.sigmoid(logits).numpy()[0]
        
    ranked = sorted(zip(label_vocab, probs), key=lambda x: -x[1])
    return ranked[:top_k]