Spaces:
Sleeping
Sleeping
File size: 5,964 Bytes
d6edb46 9b39287 d6edb46 4f4d6f1 d6edb46 446c80c 4f4d6f1 d6edb46 446c80c d6edb46 446c80c 4f4d6f1 446c80c 4f4d6f1 d6edb46 4f4d6f1 d6edb46 4f4d6f1 446c80c 4f4d6f1 d6edb46 446c80c d6edb46 446c80c d6edb46 446c80c d6edb46 9b39287 d6edb46 9b39287 4f4d6f1 446c80c 720a543 4f4d6f1 d6edb46 446c80c d6edb46 446c80c d6edb46 720a543 d6edb46 720a543 446c80c d6edb46 9b39287 d6edb46 9b39287 d6edb46 9b39287 720a543 d6edb46 720a543 d6edb46 720a543 d6edb46 446c80c d6edb46 446c80c 4f4d6f1 d6edb46 4f4d6f1 9b39287 d6edb46 9b39287 d6edb46 9b39287 d6edb46 720a543 d6edb46 720a543 d6edb46 4f4d6f1 d6edb46 |
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 |
# ============================================================
# πΌ CETHA - AI CV REVIEW (FINAL JSON VERSION with SCORE)
# ============================================================
# !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
# ============================================================
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 PENDUKUNG
# ============================================================
def ekstrak_teks_dari_pdf(path_file_pdf):
"""Membaca seluruh teks dari 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):
"""Membersihkan teks dari output model dan mem-parsing JSON valid."""
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)
# ============================================================
# π― FUNGSI UTAMA: PENILAIAN CV DENGAN SKOR DAN DETAIL
# ============================================================
def score_cv_json(cv_file):
"""Menilai CV dan mengembalikan hasil dalam format JSON dengan skor dan penjelasan detail."""
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 ---")
# 1οΈβ£ Ekstraksi 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 dari PDF.")
# 2οΈβ£ Prompt ke Gemini untuk analisis
prompt_penilaian = f"""
Anda adalah seorang career coach dan perekrut profesional.
Analisislah CV berikut dan berikan hasil dalam format JSON **valid**.
CV Kandidat:
---
{teks_cv}
---
Tugas Anda:
1. Nilai CV berdasarkan 3 kategori (0β100):
- "kelengkapan_informasi": Apakah CV mencakup nama, kontak, pengalaman, pendidikan, dan keterampilan?
- "keterbacaan_dan_format": Apakah struktur, urutan, dan tampilan CV rapi dan mudah dibaca?
- "dampak_pengalaman_kerja": Apakah deskripsi pengalaman menonjolkan hasil terukur (angka, pencapaian)?
2. Hitung "skor_keseluruhan" sebagai rata-rata dari ketiga kategori.
3. Temukan 3 KELEBIHAN utama dan 3 HAL YANG DAPAT DITINGKATKAN.
Setiap poin memiliki:
- "point": kalimat ringkas yang mewakili kelebihan/perbaikan.
- "explanation": penjelasan singkat (1β3 kalimat) tentang konteks atau alasannya.
Format output JSON yang harus dikembalikan:
{{
"skor_keseluruhan": <angka>,
"penilaian_per_kategori": {{
"kelengkapan_informasi": <angka>,
"keterbacaan_dan_format": <angka>,
"dampak_pengalaman_kerja": <angka>
}},
"highlights": [
{{
"point": "judul kelebihan singkat",
"explanation": "penjelasan detail"
}},
...
],
"improvements": [
{{
"point": "judul perbaikan singkat",
"explanation": "penjelasan detail"
}},
...
]
}}
Pastikan output hanya berupa JSON valid tanpa tambahan teks lain.
"""
print("π€ Mengirim prompt ke Gemini...")
response = model.generate_content(prompt_penilaian)
hasil_penilaian = clean_and_parse_json(response.text)
print("β
Analisis berhasil diterima dan dikonversi ke JSON.")
# 3οΈβ£ Mengembalikan hasil JSON rapi
return json.dumps(hasil_penilaian, indent=2, ensure_ascii=False)
except Exception as e:
print(f"π ERROR: {e}")
raise gr.Error(f"Terjadi kesalahan: {e}")
# ============================================================
# π» GRADIO INTERFACE
# ============================================================
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# π€ CETHA - AI CV Review (JSON Output with Score)")
gr.Markdown(
"""
Upload CV Anda dalam format **PDF** untuk mendapatkan hasil analisis otomatis berbasis AI.
Sistem akan memberikan **skor keseluruhan**, **penilaian per kategori**,
serta **3 poin kelebihan dan 3 poin perbaikan lengkap dengan penjelasan.**
"""
)
cv_pdf = gr.File(label="π Upload CV Anda (PDF)", file_types=[".pdf"])
score_button = gr.Button("π Analisis CV Sekarang", variant="primary")
output_json = gr.JSON(label="π Hasil Analisis (JSON Lengkap)")
score_button.click(
fn=score_cv_json,
inputs=[cv_pdf],
outputs=[output_json],
show_progress="full",
)
if __name__ == "__main__":
demo.launch()
|