Spaces:
Sleeping
Sleeping
| import time | |
| import gradio as gr | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification | |
| import torch | |
| MODEL_ID = "abnetsisaynew/joblink-match-scorer" | |
| # ββ Model loading βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _startup_time = time.time() | |
| print(f"β³ Loading model: {MODEL_ID} ...") | |
| _tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) | |
| _model = AutoModelForSequenceClassification.from_pretrained( | |
| MODEL_ID, | |
| num_labels=1, | |
| problem_type="regression", | |
| ignore_mismatched_sizes=True, | |
| ) | |
| _model.eval().float() | |
| _load_time = time.time() - _startup_time | |
| print(f"β Model loaded in {_load_time:.1f}s!") | |
| # ββ Prediction function βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def compute_score(text: str): | |
| if not text or not text.strip(): | |
| return {"score": 0.0} | |
| text = text.strip()[:4096] | |
| tokens = _tokenizer( | |
| text, truncation=True, padding="max_length", | |
| max_length=512, return_tensors="pt" | |
| ) | |
| with torch.no_grad(): | |
| score = _model(**tokens).logits.squeeze().item() | |
| return {"score": round(float(max(0.0, min(1.0, score))), 4)} | |
| custom_css = ''' | |
| .gradio-container { | |
| font-family: 'Inter', sans-serif !important; | |
| } | |
| .header-text { | |
| text-align: center; | |
| color: var(--color-accent) !important; | |
| font-weight: 800; | |
| margin-bottom: 0.5rem; | |
| font-size: 2.8rem !important; | |
| letter-spacing: -0.025em; | |
| } | |
| .sub-text { | |
| text-align: center; | |
| color: var(--body-text-color-subdued) !important; | |
| margin-bottom: 2rem; | |
| font-size: 1.2rem !important; | |
| } | |
| .score-box { | |
| border-radius: 12px; | |
| padding: 1.5rem; | |
| box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); | |
| } | |
| ''' | |
| with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo", neutral_hue="slate"), css=custom_css, title="JobLink Matcher") as demo: | |
| gr.Markdown("<h1 class='header-text'>π JobLink AI Match Scorer</h1>") | |
| gr.Markdown("<p class='sub-text'>State-of-the-art semantic matching powered by fine-tuned DeBERTa-v3.</p>") | |
| with gr.Row(): | |
| with gr.Column(scale=2): | |
| gr.Markdown("### π Job Description & Candidate CV") | |
| input_text = gr.Textbox( | |
| show_label=False, | |
| placeholder="JOB: Senior Software Engineer... [SEP] CANDIDATE: BSc Computer Science...", | |
| lines=12, | |
| container=False | |
| ) | |
| submit_btn = gr.Button("π Compute Match Score", variant="primary", size="lg") | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π― Match Score Result") | |
| with gr.Group(elem_classes="score-box"): | |
| output_json = gr.JSON(label="Result JSON") | |
| gr.Markdown( | |
| """ | |
| <br> | |
| ### π Score Guide | |
| - π’ **β₯ 0.85** : Excellent Match | |
| - π‘ **0.65 - 0.84** : Good Match | |
| - π **0.40 - 0.64** : Moderate Match | |
| - π΄ **< 0.40** : Poor Match | |
| """ | |
| ) | |
| # api_name="predict" creates the /call/predict endpoints natively! | |
| submit_btn.click(fn=compute_score, inputs=input_text, outputs=output_json, api_name="predict") | |
| gr.Markdown("---") | |
| gr.Markdown("### π§ͺ Quick Tests") | |
| gr.Examples( | |
| examples=[ | |
| # 1. Perfect Match | |
| ["JOB: Full Stack Developer. Experience: 4+ years. Required Skills: React, Node.js, MongoDB, TypeScript. [SEP] CANDIDATE: Full Stack Engineer. Experience: 5 years. Skills: React, Node.js, MongoDB, TypeScript, AWS."], | |
| # 2. Good Match (Transferable Skills) | |
| ["JOB: Machine Learning Engineer. Required Skills: Python, PyTorch, SQL, Data Modeling. [SEP] CANDIDATE: Data Scientist. Experience: 3 years. Skills: Python, TensorFlow, SQL, Pandas."], | |
| # 3. Junior applying for Senior (Experience Gap) | |
| ["JOB: Senior DevOps Engineer. Experience: 7+ years. Required Skills: Kubernetes, Terraform, AWS, CI/CD. [SEP] CANDIDATE: Junior Cloud Developer. Experience: 1 year. Skills: AWS, Docker, Git."], | |
| # 4. Partial Skill Match (Skills Gap) | |
| ["JOB: UI/UX Designer. Required Skills: Figma, Adobe XD, Prototyping, User Research. [SEP] CANDIDATE: Graphic Designer. Skills: Adobe Illustrator, Photoshop, Branding."], | |
| # 5. Missing Core Requirement | |
| ["JOB: Bilingual Customer Support (Spanish/English). Required Skills: Fluent Spanish, CRM, Communication. [SEP] CANDIDATE: Customer Service Rep. Skills: English, Zendesk, Communication."], | |
| # 6. Completely Unrelated Match (Hard Knockout) | |
| ["JOB: Heart Surgeon. Field: Health Sciences. Experience: 10+ years. Required Skills: Surgery, Diagnostics. [SEP] CANDIDATE: Truck Driver. Field: Logistics. Experience: 10 years. Skills: Driving, Navigation."] | |
| ], | |
| inputs=input_text | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |