firmanaziz's picture
Update app.py
651b93a verified
# 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
import urllib.parse
# --- 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-pro-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 generate_search_links(keywords):
"""Membuat tautan pencarian dari kata kunci untuk berbagai platform."""
if not keywords:
return {}
keywords_encoded = urllib.parse.quote_plus(keywords)
keywords_hyphenated = keywords.lower().replace(" ", "-").replace("(", "").replace(")", "")
links = {
"LinkedIn": f"https://www.linkedin.com/jobs/search/?keywords={keywords_encoded}&location=Indonesia",
"JobStreet": f"https://id.jobstreet.com/id/{keywords_hyphenated}-jobs/",
"Glints": f"https://glints.com/id/opportunities/jobs/explore?keyword={keywords_encoded}",
"Indeed": f"https://id.indeed.com/jobs?q={keywords_encoded}",
"Google Jobs": f"https://www.google.com/search?q={keywords_encoded}+jobs+in+Indonesia&ibp=htl;jobs"
}
return links
def format_output_markdown(analysis_json, links):
"""Menyusun laporan komprehensif DAN tautan pencarian menjadi satu output."""
jabatan = analysis_json.get("jabatan_ideal", "N/A")
alasan_list = analysis_json.get("alasan_kecocokan", [])
deskripsi_list = analysis_json.get("deskripsi_pekerjaan", [])
potensi_list = analysis_json.get("potensi_karir", [])
gaji = analysis_json.get("kisaran_gaji", {})
kelebihan_list = analysis_json.get("kelebihan_tambahan", [])
alasan_md = "\n".join([f"- {item}" for item in alasan_list])
deskripsi_md = "\n".join([f"- {item}" for item in deskripsi_list])
potensi_md = "\n".join([f"- {item}" for item in potensi_list])
kelebihan_md = "\n".join([f"- {item}" for item in kelebihan_list])
gaji_md = f"""
| Level | Estimasi Gaji / Bulan |
| :--- | :--- |
| **Junior** | {gaji.get("junior", "N/A")} |
| **Mid-Level** | {gaji.get("mid_level", "N/A")} |
| **Senior / Lead** | {gaji.get("senior", "N/A")} |
> (Estimasi berdasarkan data pasar kerja di Indonesia)
"""
# ==================================================================
# BAGIAN BARU: Membuat daftar tautan pencarian
# ==================================================================
markdown_links = ""
for site, url in links.items():
markdown_links += f"- **[{site}]({url})**\n"
return f"""
### 🎯 {jabatan}
***
#### 🧩 Alasan Kecocokan
{alasan_md}
#### πŸ’Ό Deskripsi Pekerjaan Umum
Seorang **{jabatan.split('(')[0].strip()}** bertanggung jawab untuk:
{deskripsi_md}
#### πŸš€ Potensi Jenjang Karir
Dari posisi ini, Anda dapat berkembang menjadi:
{potensi_md}
#### πŸ’° Kisaran Gaji (Indonesia)
{gaji_md}
#### πŸ“ˆ Kelebihan Tambahan untuk Karirmu
{kelebihan_md}
***
### πŸš€ Klik untuk Mencari Lowongan Terbaru
{markdown_links}
"""
def analyze_career_path(cv_file):
"""Fungsi utama pipeline: Analisis CV -> Buat Laporan -> Buat Link."""
if not API_CONFIGURED:
raise gr.Error("API Key Gemini belum terkonfigurasi. Periksa Logs aplikasi.")
if cv_file is None:
raise gr.Error("Mohon upload file CV (PDF) Anda.")
try:
print("--- Memulai Proses Analisis Karir ---")
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 analisis karir ke Gemini...")
prompt_analisis_karir = f"""
Anda adalah seorang "Career Analyst AI" yang sangat berpengalaman. Tugas Anda adalah membaca teks CV, menganalisisnya secara mendalam, dan membuat laporan peluang karir yang komprehensif.
Teks CV:
---
{teks_cv}
---
Lakukan analisis dan berikan output dalam format JSON yang ketat dengan struktur berikut:
- "jabatan_ideal": Tentukan satu jabatan paling ideal untuk kandidat ini, termasuk spesialisasi jika ada (Contoh: "Frontend Developer (Web & Mobile)").
- "alasan_kecocokan": Buat sebuah array (list) berisi 3-4 poin utama MENGAPA kandidat ini sangat cocok untuk jabatan tersebut, hubungkan langsung dengan data dari CV.
- "deskripsi_pekerjaan": Buat sebuah array (list) berisi 5 poin deskripsi pekerjaan umum untuk jabatan ideal tersebut.
- "potensi_karir": Buat sebuah array (list) berisi 3-4 jalur pengembangan karir dari posisi ini.
- "kisaran_gaji": Buat sebuah objek JSON berisi estimasi gaji bulanan di Indonesia untuk level "junior", "mid_level", dan "senior". Gunakan format string seperti "Rp 6 - 9 juta".
- "kelebihan_tambahan": Buat sebuah array (list) berisi 1-2 poin saran atau kelebihan unik yang dimiliki kandidat dari CV-nya.
Pastikan output hanya berupa JSON saja.
"""
generation_config = genai.types.GenerationConfig(response_mime_type="application/json")
response = model.generate_content(prompt_analisis_karir, generation_config=generation_config)
response_json = json.loads(response.text)
print("βœ… Laporan karir komprehensif berhasil diterima.")
# ==================================================================
# LANGKAH TAMBAHAN: Gunakan hasil analisis untuk membuat link
# ==================================================================
print("3. Membuat tautan pencarian dari hasil analisis...")
keywords_from_analysis = response_json.get("jabatan_ideal", "")
search_links = generate_search_links(keywords_from_analysis)
print("4. Menyusun output akhir...")
final_output = format_output_markdown(response_json, search_links)
print("--- Proses Selesai ---")
return final_output
except Exception as e:
print(f"πŸ›‘ ERROR DALAM FUNGSI ANALISIS: {e}")
raise gr.Error(f"Terjadi kesalahan: {e}")
# --- MEMBUAT INTERFACE GRADIO ---
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# πŸš€ Aplikasi Analis Peluang Karir Personal")
gr.Markdown("Upload CV Anda, dan biarkan AI membuat laporan komprehensif tentang jalur karir terbaik Anda, lengkap dengan tautan pencarian kerja!")
with gr.Row():
with gr.Column(scale=1):
cv_pdf = gr.File(label="Upload CV Anda (PDF)", file_types=[".pdf"])
analyze_button = gr.Button("πŸ” Analisis Karir Saya", variant="primary")
with gr.Column(scale=2):
output_analysis = gr.Markdown(label="Laporan Peluang Karir Anda")
analyze_button.click(
fn=analyze_career_path,
inputs=[cv_pdf],
outputs=[output_analysis],
show_progress='full'
)
if __name__ == "__main__":
demo.launch()