Spaces:
Sleeping
Sleeping
File size: 5,575 Bytes
773f31c d89f106 773f31c ace3652 773f31c 1e76509 d89f106 573e1e6 d89f106 773f31c d89f106 773f31c d89f106 773f31c 1e76509 773f31c d89f106 773f31c d89f106 773f31c 573e1e6 d89f106 773f31c d89f106 773f31c d89f106 773f31c d89f106 573e1e6 773f31c d89f106 573e1e6 773f31c 01828f7 773f31c d89f106 773f31c d89f106 773f31c d89f106 773f31c d89f106 773f31c d89f106 773f31c d89f106 773f31c |
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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
import subprocess
import sys
import os
# --- 1. AWARYJNA INSTALACJA XGBOOST ---
# Ten fragment musi być na samej górze, zaraz po importach sys i subprocess
try:
import xgboost
except ImportError:
print("--- ⚠️ BRAK XGBOOST. Rozpoczynam awaryjną instalację... ---")
subprocess.check_call([sys.executable, "-m", "pip", "install", "xgboost"])
print("--- ✅ XGBoost zainstalowany pomyślnie! ---")
import xgboost
# --------------------------------------
import joblib
import pandas as pd
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
from typing import List
from huggingface_hub import hf_hub_download
from contextlib import asynccontextmanager
# --- Sekcja Konfiguracji Modelu ---
# Upewnij się, że nazwa pliku jest zgodna z tym co masz w Files!
# Wcześniej w logach miałeś 'model_raport.pkl', teraz w kodzie masz 'model.pkl'.
# Zostawiam 'model.pkl', ale sprawdź to!
MODEL_FILE_NAME = 'model.pkl'
MODEL_REPO_ID = 'zotthytt12/model_hr'
MODEL_FEATURES_ORDER = [
'Experience (Years)', 'Education', 'Certifications', 'Job Role',
'Salary Expectation ($)', 'Projects Count', 'C++', 'Cybersecurity',
'Deep Learning', 'Ethical Hacking', 'Java', 'Linux',
'Machine Learning', 'NLP', 'Networking', 'Python', 'Pytorch',
'React', 'SQL', 'TensorFlow'
]
# --- Globalna zmienna na model ---
model = None
# --- 2. Definicja cyklu życia aplikacji (Lifespan) ---
@asynccontextmanager
async def lifespan(app: FastAPI):
# Kod uruchamiany przy starcie
global model
print("--- Rozpoczynanie ładowania modelu z Huba... ---")
try:
model_path = hf_hub_download(
repo_id=MODEL_REPO_ID,
filename=MODEL_FILE_NAME
)
# Tutaj joblib użyje zainstalowanego wyżej xgboost
model = joblib.load(model_path)
print(f"--- Pomyślnie pobrano i wczytano model z Huba: {MODEL_REPO_ID} ---")
# 🧹 Naprawa nazw kolumn – usuwamy spacje z przodu i końca
if hasattr(model, "feature_names_in_"):
clean_names = [f.strip() for f in model.feature_names_in_]
model.feature_names_in_ = clean_names
print("🧹 Oczyszczone feature_names_in_:", model.feature_names_in_)
except Exception as e:
print(f"BŁĄD KRYTYCZNY: Nie można wczytać modelu z Huba ({MODEL_REPO_ID}). Błąd: {e}")
# Nie przerywamy yield, żeby aplikacja wstała i pokazała błąd w HTTP 503
yield
print("--- Zamykanie aplikacji ---")
# --- 3. Definicja API ---
app = FastAPI(
title="API Rankingu CV",
description="API oceniania kandydatów (XGBoost/RandomForest)",
lifespan=lifespan
)
# --- 4. Modele danych (Pydantic) ---
class CandidateFeatures(BaseModel):
identifier: str = Field(..., description="ID kandydata")
Experience_Years: float = Field(..., alias="Experience (Years)")
Education: float
Certifications: float
Job_Role: float = Field(..., alias="Job Role")
Salary_Expectation: float = Field(..., alias="Salary Expectation ($)")
Projects_Count: float = Field(..., alias="Projects Count")
Cpp: float = Field(..., alias="C++")
Cybersecurity: float
Deep_Learning: float = Field(..., alias="Deep Learning")
Ethical_Hacking: float = Field(..., alias="Ethical Hacking")
Java: float
Linux: float
Machine_Learning: float = Field(..., alias="Machine Learning")
NLP: float
Networking: float
Python: float
Pytorch: float
React: float
SQL: float
TensorFlow: float
class Config:
populate_by_name = True
class RankingRequest(BaseModel):
candidates: List[CandidateFeatures]
class RankedCandidate(BaseModel):
identifier: str
score: float
class RankingResponse(BaseModel):
ranked_candidates: List[RankedCandidate]
# --- 5. Punkty końcowe API ---
@app.get("/")
def read_root():
return {"status": "OK", "message": "API działa poprawnie"}
@app.post("/rank", response_model=RankingResponse)
def rank_candidates(request: RankingRequest):
global model
if model is None:
raise HTTPException(status_code=503, detail="Model nie jest gotowy. Sprawdź logi aplikacji.")
if not request.candidates:
return {"ranked_candidates": []}
try:
# Konwersja danych
candidate_data_list = [c.model_dump(by_alias=True) for c in request.candidates]
identifiers = [c['identifier'] for c in candidate_data_list]
# DataFrame
df = pd.DataFrame(candidate_data_list)
features_df = df.drop(columns=['identifier'])
# Dopasowanie kolumn do modelu
features_df_ordered = features_df.reindex(columns=model.feature_names_in_, fill_value=0)
# Predykcja
probabilities = model.predict_proba(features_df_ordered)[:, 1]
# Wynik
ranked_list = []
for i, identifier in enumerate(identifiers):
ranked_list.append(RankedCandidate(
identifier=identifier,
score=float(probabilities[i])
))
# Sortowanie
sorted_ranked_list = sorted(ranked_list, key=lambda x: x.score, reverse=True)
return {"ranked_candidates": sorted_ranked_list}
except Exception as e:
print(f"Błąd podczas predykcji: {e}")
raise HTTPException(status_code=500, detail=f"Błąd serwera: {str(e)}")
# Uruchomienie lokalne
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000) |