File size: 3,367 Bytes
5888c6a
 
 
 
 
 
 
a47415e
 
 
 
 
 
 
 
 
 
 
5888c6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a47415e
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
81
82
83
84
85
86
87
88
89
90
import os, requests, tqdm, torch, numpy as np
from torch import nn
from transformers import XLNetModel, XLNetTokenizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

# ------------------------------------------------------------------
from huggingface_hub import hf_hub_download
import torch

# Downloads the file automatically from your model repo
MODEL_PATH = hf_hub_download(
    repo_id="yeswanthvarma/xlnet-evaluator-model",
    filename="xlnet_answer_assessment_model.pt"
)

# Load the model
model.load_state_dict(torch.load(MODEL_PATH, map_location=torch.device("cpu")))

def download_model_if_needed():
    if os.path.exists(MODEL_PATH):
        return
    print("▶️  Downloading XLNet weights from Hugging Face …")
    with requests.get(HF_URL, stream=True) as r:
        r.raise_for_status()
        total = int(r.headers.get("content-length", 0))
        with open(MODEL_PATH, "wb") as f, tqdm.tqdm(total=total, unit="B", unit_scale=True) as bar:
            for chunk in r.iter_content(chunk_size=8192):
                f.write(chunk)
                bar.update(len(chunk))
    print("✅  Download complete.")

download_model_if_needed()
# ------------------------------------------------------------------

xlnet_available = False   # will flip to True if load succeeds

class XLNetAnswerAssessmentModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.xlnet = XLNetModel.from_pretrained("xlnet-base-cased")
        hidden = 768
        self.fc1 = nn.Linear(hidden, 256)
        self.fc2 = nn.Linear(256, 64)
        self.out = nn.Linear(64, 1)

    def forward(self, input_ids, attention_mask=None):
        pooled = self.xlnet(input_ids, attention_mask).last_hidden_state.mean(1)
        x = torch.relu(self.fc1(pooled))
        x = torch.relu(self.fc2(x))
        return torch.sigmoid(self.out(x))

try:
    tokenizer = XLNetTokenizer.from_pretrained("xlnet-base-cased")
    model = XLNetAnswerAssessmentModel()
    model.load_state_dict(torch.load(MODEL_PATH, map_location="cpu"))
    model.eval()
    xlnet_available = True
    print("✅ Custom XLNet model loaded.")
except Exception as e:
    print("⚠️  Could not load XLNet model → fallback to TF‑IDF\n", e)

# ------------------------------------------------------------------
# scoring helpers (unchanged)
# ------------------------------------------------------------------
embedding_cache = {}

def get_model_prediction(q, s, r):
    if not xlnet_available:
        raise ValueError("XLNet unavailable")
    combined = f"{q} [SEP] {s} [SEP] {r}"
    inputs = tokenizer(combined, return_tensors="pt", truncation=True, max_length=512, padding=True)
    with torch.no_grad():
        score = float(model(**inputs).squeeze()) * 100
    return round(score)

def tfidf_similarity(t1, t2):
    vec = TfidfVectorizer()
    mat = vec.fit_transform([t1, t2])
    return round(cosine_similarity(mat[0], mat[1])[0][0] * 100)

def fallback_similarity(t1, t2):
    w1, w2 = set(t1.lower().split()), set(t2.lower().split())
    return round(len(w1 & w2) / len(w1 | w2) * 100) if w1 and w2 else 0

def get_similarity_score(q, s, r):
    try:
        return get_model_prediction(q, s, r) if xlnet_available else tfidf_similarity(s, r)
    except Exception:
        return fallback_similarity(s, r)