import streamlit as st
import joblib
from textblob import TextBlob
import mammoth
import pdfplumber
import io
import re
import os
# --- 1. MODEL FUNCTION ---
def ekkok(text):
try:
words = TextBlob(str(text)).words
return [word.lemmatize() for word in words]
except:
return str(text).split()
# --- PAGE CONFIG ---
st.set_page_config(page_title="AI Resume Analyzer", layout="centered", page_icon="🎯")
# --- SECTOR KEYWORDS ---
SECTOR_KEYWORDS = {
"Hospitality & Management": ["hospitality", "restaurant", "hotel", "waiter", "bartender", "bar manager", "chef", "tourism"],
"Marketing / Advertising": ["marketing", "advertising", "social media", "branding", "seo", "store manager", "salesman"],
"Information Technology": ["software", "developer", "java", "python", "javascript", "cloud", "data science"],
"Finance & Accounting": ["finance", "accounting", "audit", "banking", "tax", "budget"],
"Human Resources": ["recruitment", "hr", "payroll", "onboarding", "talent acquisition"]
}
# --- FILE EXTRACTOR ---
def extract_text(uploaded_file):
try:
if uploaded_file.name.lower().endswith('.docx'):
return mammoth.extract_raw_text(io.BytesIO(uploaded_file.getvalue())).value
elif uploaded_file.name.lower().endswith('.pdf'):
full_text = ""
with pdfplumber.open(io.BytesIO(uploaded_file.getvalue())) as pdf:
for page in pdf.pages:
page_text = page.extract_text()
if page_text: full_text += page_text + "\n"
return full_text if full_text.strip() else "ERR_SCAN"
except: return None
# --- LOAD ASSETS ---
@st.cache_resource
def load_assets():
m_p, v_p = "best_model.pkl", "tfidf_vectorizer.pkl"
if os.path.exists(m_p) and os.path.exists(v_p):
try: return joblib.load(m_p), joblib.load(v_p)
except: return None, None
return None, None
model, vectorizer = load_assets()
# --- BILINGUAL TITLE (İNGİLİZCE & TÜRKÇE BAŞLIK) ---
st.markdown("""
🎯 AI Resume Classifier / Akıllı CV Sınıflandırıcı
Automated Department Prediction System / Otomatik Bölüm Tahmin Sistemi
""", unsafe_allow_html=True)
st.divider()
# --- INPUT SECTION ---
# 1. Metin Girişi
manual_input = st.text_area("✍️ Paste CV Text / CV Metnini Yapıştırın:", height=150, key="m_input")
# 2. Dosya Yükleme
uploaded_file = st.file_uploader("📂 Upload CV (PDF/DOCX) / Dosya Yükleyin:", type=['pdf', 'docx'], key="f_input")
# --- VALIDATION ---
final_cv_text = ""
if manual_input.strip() and uploaded_file:
st.error("⚠️ Please use ONLY ONE method! Delete text OR remove file. / Lütfen SADECE BİR yöntem kullanın! Metni silin VEYA dosyayı kaldırın.")
elif manual_input.strip():
final_cv_text = manual_input
elif uploaded_file:
with st.spinner('Reading...'):
res = extract_text(uploaded_file)
if res == "ERR_SCAN":
st.error("❌ This PDF is an image. Please paste text instead. / Bu PDF resimden oluşuyor, lütfen metni kopyalayıp kutuya yapıştırın.")
elif res:
final_cv_text = res
st.success(f"✅ {uploaded_file.name} ready!")
st.divider()
# --- ANALYSIS BUTTON ---
if st.button("🚀 START ANALYSIS / ANALİZİ BAŞLAT", use_container_width=True):
if not final_cv_text or len(final_cv_text.strip()) < 10:
st.warning("⚠️ Please provide CV content! / Lütfen CV içeriği sağlayın!")
else:
with st.spinner('Processing...'):
# Email Identity
email_id = "NOT FOUND"
match = re.search(r'([a-zA-Z0-9_.+-]+)@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+', final_cv_text)
if match: email_id = match.group(1).upper()
# Prediction
low_txt = final_cv_text.lower()
scores = {s: sum(1 for k in kw if k in low_txt) for s, kw in SECTOR_KEYWORDS.items()}
prediction = max(scores, key=scores.get)
if scores[prediction] == 0 and model:
try: prediction = model.predict(vectorizer.transform([final_cv_text]))[0]
except: prediction = "Unclassified"
st.balloons()
st.success("### Results / Sonuçlar")
c1, c2 = st.columns(2)
c1.metric("Email Identity / E-posta", email_id)
c2.metric("Department / Bölüm", prediction)
# --- FOOTER ---
st.markdown("
", unsafe_allow_html=True)
footer_html = """
Developed by Data Science Dept.
Advanced HR Analytics Solutions
Veri Bilimi Departmanı
Gelişmiş İK Analitik Çözümleri
Developer / Geliştirici: EsmaTuğba MERGEN | v37.0
"""
st.markdown(footer_html, unsafe_allow_html=True)