File size: 6,497 Bytes
59ac0fe
 
0485056
83d8c54
0485056
83d8c54
 
 
d5d4e8c
83d8c54
 
 
 
0485056
83d8c54
 
d5d4e8c
83d8c54
 
59ac0fe
83d8c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5d4e8c
 
83d8c54
 
 
 
d5d4e8c
 
 
 
83d8c54
 
 
d5d4e8c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83d8c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5d4e8c
83d8c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d5d4e8c
83d8c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59ac0fe
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
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
import gradio as gr
import numpy as np # Import numpy jika belum ada

# --- 1. Inisialisasi Model dan Tokenizer (Dilakukan Sekali Saat Aplikasi Dimulai) ---
# Pastikan 'model_name' ini adalah model yang sudah kamu unggah ke Hugging Face Hub
# atau model publik lain yang ingin kamu gunakan.
model_name = "atsnetwork/my-custom-tinyllama-chatbot"
model = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
tokenizer.pad_token = tokenizer.eos_token # Pastikan token padding diatur
tokenizer.padding_side = "right" # Penting untuk efisiensi saat memproses sequence

# --- 2. Fungsi Pemroses Utama untuk Chatbot (Dipanggil Oleh Gradio) ---
# Fungsi ini mengintegrasikan logika inferensi dan analisis developer info
def generate_response_with_dev_info(prompt, max_new_tokens=100, temperature=0.6, top_k=30):
    formatted_prompt = f"<s>[INST] {prompt} [/INST]"
    inputs = tokenizer(formatted_prompt, return_tensors="pt").to(model.device)

    # Generate dengan output_scores=True untuk analisis probabilitas
    outputs = model.generate(
        **inputs,
        max_new_tokens=max_new_tokens,
        do_sample=True,
        temperature=temperature,
        top_k=top_k,
        eos_token_id=tokenizer.eos_token_id,
        pad_token_id=tokenizer.pad_token_id,
        return_dict_in_generate=True,
        output_scores=True
    )

    generated_ids = outputs.sequences[0]
    generated_text = tokenizer.decode(generated_ids, skip_special_tokens=True)

    # Ekstrak jawaban bersih
    answer = ""
    start_answer = generated_text.find("[/INST]")
    if start_answer != -1:
        answer = generated_text[start_answer + len("[/INST]"):].strip()
        if answer.endswith("</s>"):
            answer = answer[:-len("</s>")].strip()
    else:
        answer = generated_text.strip() # Fallback jika format tidak ditemukan

    # --- Analisis Konfidensi Berbasis ENTROPY (PENGGANTI avg_max_prob) ---
    avg_entropy = 0
    total_generated_tokens = 0
    if outputs.scores:
        for score_tensor in outputs.scores:
            probabilities = torch.softmax(score_tensor, dim=-1)
            # Menghitung entropy untuk setiap distribusi probabilitas
            epsilon = 1e-9 # Tambahkan sedikit epsilon untuk menghindari log(0)
            entropy = -torch.sum(probabilities * torch.log(probabilities + epsilon), dim=-1).item()
            avg_entropy += entropy
            total_generated_tokens += 1
        
        if total_generated_tokens > 0:
            avg_entropy /= total_generated_tokens
        else:
            # Jika tidak ada token yang dihasilkan setelah prompt (kasus jarang)
            avg_entropy = float('inf') 

    # Batas ambang keyakinan (contoh) untuk ENTROPY
    # Penting: Nilai ini HARUS ditentukan setelah analisis empiris pada modelmu.
    # Nilai entropy yang lebih RENDAH berarti model lebih YAKIN.
    # Nilai entropy yang lebih TINGGI berarti model lebih TIDAK YAKIN.
    # Sebagai titik awal, kamu bisa coba sekitar 1.0 atau lebih,
    # tetapi validasi empiris sangat dianjurkan.
    entropy_threshold = 1.0 # <--- SESUAIKAN NILAI INI BERDASARKAN ANALISISMU!

    if avg_entropy > entropy_threshold: # <--- Perhatikan operatornya berubah (lebih besar = LOW_CONFIDENCE)
        confidence_status = "LOW_CONFIDENCE: Model mungkin tidak memiliki pola yang jelas (Entropy Tinggi)."
    else:
        confidence_status = "HIGH_CONFIDENCE"

    # --- Analisis Frasa "Tidak Tahu" yang Dilatih ---
    is_explicitly_unknown = False
    explicit_unknown_reason = ""
    unknown_phrases = [
        "maaf, saya tidak memiliki informasi",
        "saya tidak familiar dengan",
        "di luar cakupan data pelatihan saya",
        "saya tidak tahu",
        "tidak dapat menemukan informasi"
    ]
    answer_lower = answer.lower()
    for phrase in unknown_phrases:
        if phrase in answer_lower:
            is_explicitly_unknown = True
            explicit_unknown_reason = f"Model menggunakan frasa 'tidak tahu': '{phrase}'"
            break # Hentikan setelah menemukan frasa pertama

    # --- Gabungkan Informasi untuk Developer ---
    developer_info = {
        "confidence_score": f"{avg_entropy:.4f}", # Sekarang ini adalah entropy
        "confidence_status": confidence_status,
        "explicit_unknown_phrase_detected": is_explicitly_unknown,
        "explicit_unknown_reason": explicit_unknown_reason if is_explicitly_unknown else "Tidak ada frasa 'tidak tahu' eksplisit.",
        # "raw_generated_text": generated_text # Bisa diaktifkan untuk debug, tapi akan terlihat di UI
    }

    # Untuk tampilan user, hanya tampilkan jawabannya.
    # Informasi developer bisa ditampilkan di antarmuka terpisah atau log.
    return answer, developer_info

# --- 3. Fungsi Adaptor untuk Gradio Interface (Mengonversi Dictionary info menjadi String) ---
# Gradio Interface mengharapkan output string/angka, bukan dictionary.
# Fungsi ini akan mengubah dictionary developer_info menjadi string yang mudah dibaca.
def gradio_interface_fn(prompt):
    answer, dev_info = generate_response_with_dev_info(prompt)
    
    # Format developer info untuk ditampilkan di Gradio
    dev_info_str = "--- Developer Info ---\n"
    dev_info_str += f"Confidence Score (Entropy): {dev_info['confidence_score']} ({dev_info['confidence_status']})\n"
    dev_info_str += f"Explicit Unknown Phrase Detected: {dev_info['explicit_unknown_phrase_detected']}\n"
    dev_info_str += f"Reason: {dev_info['explicit_unknown_reason']}\n"
    # dev_info_str += f"Raw Generated Text: {dev_info['raw_generated_text']}\n" 

    return answer, dev_info_str

# --- 4. Inisialisasi Antarmuka Gradio ---
# Ini yang akan membangun UI di Hugging Face Space.
iface = gr.Interface(
    fn=gradio_interface_fn, # Fungsi yang akan dipanggil saat ada input
    inputs=gr.Textbox(lines=2, label="Your Question"), # Input berupa kotak teks untuk pertanyaan
    outputs=[
        gr.Textbox(label="Chatbot Response", lines=5), # Output pertama untuk jawaban chatbot
        gr.Textbox(label="Developer Information", lines=5) # Output kedua untuk informasi developer
    ],
    title="TinyLlama Custom Chatbot with Developer Insights πŸš€",
    description="Ask anything and get a response from the chatbot. Additional information for developers will be displayed below."
)

# --- 5. Jalankan Aplikasi Gradio ---
iface.launch()