# Install dependensi yang dibutuhkan oleh Hugging Face Spaces #!pip install -q gradio google-generativeai pymupdf import gradio as gr import google.generativeai as genai import fitz # PyMuPDF import json import os # --- KONFIGURASI API KEY DARI HUGGING FACE SECRETS --- API_CONFIGURED = False try: api_key = os.environ.get('GEMINI_API_KEY') if api_key: genai.configure(api_key=api_key) model = genai.GenerativeModel('gemini-flash-latest') API_CONFIGURED = True print("✅ Konfigurasi API dan model berhasil.") else: print("🛑 Secret 'GEMINI_API_KEY' tidak ditemukan.") except Exception as e: print(f"🛑 Terjadi error saat inisialisasi: {e}") # --- FUNGSI-FUNGSI UTAMA --- def ekstrak_teks_dari_pdf(path_file_pdf): try: with fitz.open(path_file_pdf) as dokumen: teks_lengkap = "".join(halaman.get_text() for halaman in dokumen) return teks_lengkap except Exception as e: raise gr.Error(f"Gagal membaca file PDF: {e}") def clean_and_parse_json(raw_text): """Fungsi andal untuk membersihkan dan mem-parsing JSON dari teks mentah.""" start_index = raw_text.find('{') end_index = raw_text.rfind('}') if start_index == -1 or end_index == -1: raise json.JSONDecodeError("Tidak ditemukan blok JSON valid dalam respons.", raw_text, 0) json_str = raw_text[start_index:end_index+1] return json.loads(json_str) def format_output_markdown(hasil_penilaian): """Menyusun hasil penilaian menjadi string Markdown yang rapi.""" skor = hasil_penilaian.get('skor_keseluruhan', 0) penilaian = hasil_penilaian.get('penilaian_per_kategori', {}) kelebihan = "\n".join([f"- {poin}" for poin in hasil_penilaian.get('poin_kelebihan', [])]) perbaikan = "\n".join([f"- {poin}" for poin in hasil_penilaian.get('poin_perbaikan', [])]) # Membuat progress bar untuk setiap kategori progress_bars = "" for kategori, nilai in penilaian.items(): # Mengganti underscore dengan spasi dan membuat judul nama_kategori = kategori.replace("_", " ").title() progress_bars += f"**{nama_kategori}**\n`{'█' * int(nilai/10)}{'░' * (10 - int(nilai/10))}` {nilai}/100\n" return f""" ### HASIL PENILAIAN CV ANDA **⭐ Skor Keseluruhan: {skor} / 100** *** {progress_bars} *** **✅ Hal yang Sudah Baik:** {kelebihan} **💡 Poin yang Perlu Diperbaiki:** {perbaikan} """ def score_cv(cv_file): """Fungsi utama yang dijalankan Gradio untuk menilai CV.""" if not API_CONFIGURED: raise gr.Error("API Key Gemini belum terkonfigurasi. Periksa Logs aplikasi di Hugging Face.") if cv_file is None: raise gr.Error("Mohon upload file CV (PDF) Anda.") try: print("--- Memulai Proses Penilaian CV ---") print("1. Mengekstrak teks dari PDF...") teks_cv = ekstrak_teks_dari_pdf(cv_file.name) if not teks_cv: raise gr.Error("PDF kosong atau tidak dapat dibaca.") print("✅ Teks berhasil diekstrak.") print("2. Mengirim permintaan penilaian ke Gemini...") prompt_penilaian = f""" Anda adalah seorang career coach dan perekrut profesional. Tugas Anda adalah menilai kualitas sebuah CV berdasarkan kriteria standar industri. Teks CV: --- {teks_cv} --- Lakukan penilaian berdasarkan kriteria berikut dan berikan output dalam format JSON yang ketat. Kriteria Penilaian: 1. Kelengkapan_Informasi (0-100): Apakah ada nama, kontak, ringkasan, pengalaman, pendidikan, dan skill? 2. Keterbacaan_dan_Format (0-100): Apakah formatnya rapi, mudah dibaca, dan menggunakan bullet points dengan baik? 3. Dampak_Pengalaman_Kerja (0-100): Apakah deskripsi pengalaman menggunakan kata kerja aktif dan hasil yang terukur (angka/metrik)? Semakin banyak metrik, semakin tinggi nilainya. Instruksi Output JSON: Berikan output dalam format JSON dengan struktur berikut: - "skor_keseluruhan": Rata-rata dari ketiga skor kategori (angka 0-100). - "penilaian_per_kategori": Objek berisi skor untuk "kelengkapan_informasi", "keterbacaan_dan_format", dan "dampak_pengalaman_kerja". - "poin_kelebihan": Sebuah array (list) berisi 2-3 poin positif dari CV ini. - "poin_perbaikan": Sebuah array (list) berisi 3-4 poin saran yang paling penting dan actionable untuk meningkatkan kualitas CV. Pastikan output hanya berupa JSON saja tanpa teks tambahan. """ response = model.generate_content(prompt_penilaian) hasil_penilaian = clean_and_parse_json(response.text) print("✅ Penilaian berhasil diterima.") print("3. Menyusun output akhir...") final_output = format_output_markdown(hasil_penilaian) print("--- Proses Selesai ---") return final_output except Exception as e: print(f"🛑 ERROR DALAM FUNGSI PENILAIAN: {e}") raise gr.Error(f"Terjadi kesalahan: {e}") # --- MEMBUAT INTERFACE GRADIO --- with gr.Blocks(theme=gr.themes.Soft()) as demo: gr.Markdown("# 💡 Aplikasi Penilai Kualitas CV (CV Scorer)") gr.Markdown("Upload CV Anda dalam format PDF untuk mendapatkan skor dan saran perbaikan instan berdasarkan standar industri.") with gr.Row(): with gr.Column(scale=1): cv_pdf = gr.File(label="Upload CV Anda (PDF)", file_types=[".pdf"]) score_button = gr.Button("✨ Nilai CV Saya", variant="primary") with gr.Column(scale=2): output_score = gr.Markdown(label="Hasil Penilaian") score_button.click( fn=score_cv, inputs=[cv_pdf], outputs=[output_score], show_progress='full' ) if __name__ == "__main__": demo.launch()