Spaces:
Sleeping
Sleeping
| 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 --- | |
| 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(""" | |
| <div style="text-align: center;"> | |
| <h1 style="color: #1E3A8A; margin-bottom: 0;">🎯 AI Resume Classifier / Akıllı CV Sınıflandırıcı</h1> | |
| <p style="color: #666; font-size: 1.1rem; margin-top: 5px;">Automated Department Prediction System / Otomatik Bölüm Tahmin Sistemi</p> | |
| </div> | |
| """, 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("<br><br><br><hr>", unsafe_allow_html=True) | |
| footer_html = """ | |
| <div style="display: flex; justify-content: space-between; align-items: center; font-family: sans-serif;"> | |
| <div style="text-align: left;"> | |
| <h4 style="margin:0; color: #1E3A8A;">Developed by Data Science Dept.</h4> | |
| <p style="margin:0; font-size: 0.8rem; color: #666;">Advanced HR Analytics Solutions</p> | |
| </div> | |
| <div style="text-align: right;"> | |
| <h4 style="margin:0; color: #1E3A8A;">Veri Bilimi Departmanı</h4> | |
| <p style="margin:0; font-size: 0.8rem; color: #666;">Gelişmiş İK Analitik Çözümleri</p> | |
| </div> | |
| </div> | |
| <div style="text-align: center; margin-top: 15px; border-top: 1px solid #eee; padding-top: 10px;"> | |
| <span style="color: #444; font-size: 0.9rem;">Developer / Geliştirici: <b>EsmaTuğba MERGEN</b> | <b>v37.0</b></span> | |
| </div> | |
| """ | |
| st.markdown(footer_html, unsafe_allow_html=True) |