File size: 7,718 Bytes
5dd6b73
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13a2c93
 
5dd6b73
13a2c93
5dd6b73
 
 
651b93a
5dd6b73
 
 
 
 
 
13a2c93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5dd6b73
 
 
13a2c93
5dd6b73
13a2c93
 
 
 
5dd6b73
13a2c93
 
 
 
 
 
 
 
 
 
 
 
 
5dd6b73
13a2c93
5dd6b73
 
 
13a2c93
 
5dd6b73
 
 
 
 
 
13a2c93
5dd6b73
 
 
 
 
 
 
13a2c93
 
 
 
5dd6b73
 
 
 
 
13a2c93
 
 
 
 
 
 
 
b1695a3
5dd6b73
 
b1695a3
13a2c93
b1695a3
 
13a2c93
 
 
 
 
 
 
 
5dd6b73
 
13a2c93
5dd6b73
 
 
 
13a2c93
5dd6b73
 
 
 
13a2c93
 
5dd6b73
 
 
 
13a2c93
5dd6b73
 
13a2c93
5dd6b73
13a2c93
 
5dd6b73
13a2c93
5dd6b73
 
 
 
 
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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# 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()