firmanaziz commited on
Commit
4f4d6f1
·
verified ·
1 Parent(s): 299310a

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +124 -0
app.py ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Install dependensi yang dibutuhkan oleh Hugging Face Spaces
2
+ #!pip install -q gradio google-generativeai pymupdf
3
+
4
+ import gradio as gr
5
+ import google.generativeai as genai
6
+ import fitz # PyMuPDF
7
+ import json
8
+ import os
9
+
10
+ # --- KONFIGURASI API KEY DARI HUGGING FACE SECRETS ---
11
+ # Pastikan Anda sudah mengatur Secret bernama 'GEMINI_API_KEY' di repository Space Anda
12
+ try:
13
+ api_key = os.environ.get('GEMINI_API_KEY')
14
+ genai.configure(api_key=api_key)
15
+ print("✅ Konfigurasi API berhasil!")
16
+ model = genai.GenerativeModel('gemini-1.5-flash-latest')
17
+ print(f"✅ Model '{model.model_name}' berhasil diinisialisasi.")
18
+ API_CONFIGURED = True
19
+ except (TypeError, ValueError) as e:
20
+ print(f"🛑 Error Konfigurasi API: Pastikan GEMINI_API_KEY sudah di-set di Secrets. Detail: {e}")
21
+ API_CONFIGURED = False
22
+ except Exception as e:
23
+ print(f"🛑 Terjadi error tak terduga saat inisialisasi: {e}")
24
+ API_CONFIGURED = False
25
+
26
+ # --- FUNGSI-FUNGSI UTAMA ---
27
+
28
+ def ekstrak_teks_dari_pdf(path_file_pdf):
29
+ """Membuka file PDF dari path temporer dan mengekstrak teksnya."""
30
+ try:
31
+ dokumen = fitz.open(path_file_pdf)
32
+ teks_lengkap = "".join(halaman.get_text() for halaman in dokumen)
33
+ dokumen.close()
34
+ return teks_lengkap
35
+ except Exception as e:
36
+ raise gr.Error(f"Gagal membaca file PDF: {e}")
37
+
38
+ def format_output_markdown(parsed_json, hasil_analisis):
39
+ """Menyusun hasil akhir menjadi string Markdown yang rapi."""
40
+ nama = parsed_json.get('nama_lengkap', 'N/A')
41
+ skor = hasil_analisis.get('skor_kecocokan', 'N/A')
42
+ ringkasan = hasil_analisis.get('ringkasan_analisis', 'N/A')
43
+ kekuatan = "\n".join([f"- {poin}" for poin in hasil_analisis.get('poin_kekuatan', [])])
44
+ kelemahan = "\n".join([f"- {poin}" for poin in hasil_analisis.get('potensi_kelemahan', [])])
45
+
46
+ markdown_output = f"""
47
+ ### HASIL ANALISIS KECOCOKAN KANDIDAT
48
+ **👤 Nama Kandidat:** {nama}
49
+ ***
50
+ **⭐ Skor Kecocokan:** {skor} / 10
51
+
52
+ **📝 Ringkasan Analisis:**
53
+ {ringkasan}
54
+
55
+ **✅ Poin Kekuatan Utama:**
56
+ {kekuatan}
57
+
58
+ **⚠️ Potensi Kelemahan / Pertanyaan Lanjutan:**
59
+ {kelemahan}
60
+ """
61
+ return markdown_output
62
+
63
+ def analyze_cv(cv_file, deskripsi_pekerjaan):
64
+ """Fungsi utama yang dijalankan oleh Gradio saat tombol ditekan."""
65
+ if not API_CONFIGURED:
66
+ raise gr.Error("API Key Gemini belum terkonfigurasi. Hubungi pemilik aplikasi.")
67
+ if cv_file is None or not deskripsi_pekerjaan.strip():
68
+ raise gr.Error("Mohon upload file CV (PDF) dan isi deskripsi pekerjaan.")
69
+
70
+ print("1. Memulai ekstraksi teks dari PDF...")
71
+ teks_cv = ekstrak_teks_dari_pdf(cv_file.name) # cv_file.name adalah path temporer
72
+ if not teks_cv:
73
+ raise gr.Error("PDF kosong atau tidak dapat dibaca.")
74
+
75
+ print("2. Memulai ekstraksi CV menjadi JSON...")
76
+ prompt_ekstraksi = f"Ekstrak informasi dari teks CV berikut dan sajikan dalam format JSON. Pastikan JSON memiliki struktur: nama_lengkap, kontak, ringkasan, keterampilan, pengalaman_kerja, dan pendidikan. Teks CV:\n---\n{teks_cv}\n---\nOutput harus berupa JSON saja."
77
+ response_ekstraksi = model.generate_content(prompt_ekstraksi)
78
+ try:
79
+ parsed_json = json.loads(response_ekstraksi.text.strip().replace('```json', '').replace('```', ''))
80
+ except (json.JSONDecodeError, AttributeError) as e:
81
+ raise gr.Error(f"Gagal mem-parsing CV menjadi JSON. Error: {e}\n\nRespons Mentah:\n{response_ekstraksi.text}")
82
+
83
+ print("3. Memulai analisis kecocokan...")
84
+ prompt_analisis = f"""
85
+ Anda adalah seorang Manajer Perekrutan senior. Analisis data kandidat (JSON) dan bandingkan dengan deskripsi pekerjaan.
86
+ Deskripsi Pekerjaan: {deskripsi_pekerjaan}
87
+ Data Kandidat (JSON): {json.dumps(parsed_json, indent=2)}
88
+ Instruksi: Berikan output JSON dengan struktur: skor_kecocokan, ringkasan_analisis, poin_kekuatan, potensi_kelemahan. Output harus JSON saja.
89
+ """
90
+ response_analisis = model.generate_content(prompt_analisis)
91
+ try:
92
+ hasil_analisis = json.loads(response_analisis.text.strip().replace('```json', '').replace('```', ''))
93
+ except (json.JSONDecodeError, AttributeError) as e:
94
+ raise gr.Error(f"Gagal menganalisis kecocokan. Error: {e}\n\nRespons Mentah:\n{response_analisis.text}")
95
+
96
+ print("4. Menyusun output...")
97
+ return format_output_markdown(parsed_json, hasil_analisis)
98
+
99
+ # --- MEMBUAT INTERFACE GRADIO ---
100
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
101
+ gr.Markdown("# 🤖 Aplikasi Analisis CV Otomatis")
102
+ gr.Markdown("Upload CV dalam format PDF dan masukkan deskripsi pekerjaan untuk mendapatkan analisis kecocokan secara instan.")
103
+
104
+ with gr.Row():
105
+ with gr.Column(scale=1):
106
+ cv_pdf = gr.File(label="1. Upload CV Anda (PDF)", file_types=[".pdf"])
107
+ job_desc = gr.Textbox(
108
+ lines=10,
109
+ label="2. Masukkan Deskripsi Pekerjaan",
110
+ placeholder="Contoh:\nPosisi: Senior Backend Engineer\n\nKami mencari seorang Senior Backend Engineer dengan pengalaman minimal 4 tahun..."
111
+ )
112
+ analyze_button = gr.Button("✨ Analisis Sekarang", variant="primary")
113
+
114
+ with gr.Column(scale=2):
115
+ output_analysis = gr.Markdown(label="Hasil Analisis")
116
+
117
+ analyze_button.click(
118
+ fn=analyze_cv,
119
+ inputs=[cv_pdf, job_desc],
120
+ outputs=[output_analysis]
121
+ )
122
+
123
+ if __name__ == "__main__":
124
+ demo.launch()