File size: 5,833 Bytes
a325830
40ca111
8e728f2
40ca111
8e728f2
233e3ae
40ca111
a325830
 
40ca111
 
ecb0859
40ca111
233e3ae
 
 
171075d
d60f2e2
 
 
 
171075d
fb29745
009ed68
171075d
 
e96d1ec
fb29745
171075d
 
 
 
 
 
 
 
 
 
 
 
 
 
8834b7b
d60f2e2
8834b7b
40ca111
233e3ae
8e728f2
233e3ae
f7ef9f6
3d4ae06
8e728f2
 
 
 
 
f7ef9f6
8e728f2
54188da
233e3ae
171075d
233e3ae
8e728f2
 
9657a0d
233e3ae
171075d
233e3ae
f7ef9f6
171075d
b571d20
171075d
233e3ae
8834b7b
 
 
 
 
 
a325830
f7ef9f6
60d5f12
233e3ae
 
171075d
233e3ae
473d8c1
f7ef9f6
233e3ae
171075d
233e3ae
 
 
 
171075d
233e3ae
 
 
171075d
233e3ae
8e728f2
40ca111
98032d3
dc383bb
b571d20
4f4b5b9
 
 
8834b7b
4962d1c
8834b7b
4f4b5b9
8834b7b
4962d1c
 
4f4b5b9
b571d20
4f4b5b9
a325830
8e728f2
 
 
 
 
 
dc383bb
8e728f2
 
 
dc383bb
233e3ae
171075d
233e3ae
a325830
8e728f2
 
171075d
f7ef9f6
dc383bb
171075d
245a76d
8e728f2
171075d
233e3ae
 
89c2257
 
70b0d98
98032d3
a325830
f7ef9f6
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
import gradio as gr
import gspread
import torch
from oauth2client.service_account import ServiceAccountCredentials
from transformers import AutoModelForCausalLM, AutoTokenizer
from llama_index.core import VectorStoreIndex, Settings
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
from huggingface_hub import hf_hub_download
from llama_index.core.llms import ChatMessage
from llama_index.core.chat_engine.condense_plus_context import CondensePlusContextChatEngine
from llama_index.core.schema import Document

# ===================================
# 1️⃣ Fungsi Membaca Data Google Spreadsheet
# ===================================
def read_google_sheets():
    try:
        scope = ["https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/drive"]
        creds = ServiceAccountCredentials.from_json_keyfile_name("credentials.json", scope)
        client = gspread.authorize(creds)
        
        SPREADSHEET_ID = "1e_cNMhwF-QYpyYUpqQh-XCw-OdhWS6EuYsoBUsVtdNg"
        sheet_names = ["datatarget", "datacuti", "dataabsen", "datalembur"]

        all_data = []
        spreadsheet = client.open_by_key(SPREADSHEET_ID)
        
        for sheet_name in sheet_names:
            try:
                sheet = spreadsheet.worksheet(sheet_name)
                data = sheet.get_all_values()
                all_data.append(f"=== Data dari {sheet_name.upper()} ===")
                all_data.extend([" | ".join(row) for row in data])
                all_data.append("\n")
            except gspread.exceptions.WorksheetNotFound:
                all_data.append(f"❌ ERROR: Worksheet {sheet_name} tidak ditemukan.")

        return "\n".join(all_data).strip()
    
    except gspread.exceptions.SpreadsheetNotFound:
        return "❌ ERROR: Spreadsheet tidak ditemukan!"
    
    except Exception as e:
        return f"❌ ERROR: {str(e)}"

# ===================================
# 2️⃣ Inisialisasi Model Llama di GPU
# ===================================
def initialize_llama_model():
    model_name = "HuggingFaceH4/zephyr-7b-beta"  # Pastikan model ini kompatibel dengan transformers
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForCausalLM.from_pretrained(
        model_name,
        torch_dtype=torch.float16,  # Gunakan float16 agar lebih hemat memori
        device_map="auto"  # Memastikan model berjalan di GPU jika tersedia
    )
    return tokenizer, model

# ===================================
# 3️⃣ Inisialisasi Pengaturan Model
# ===================================
def initialize_settings(tokenizer, model):
    Settings.llm = model  # Tidak lagi menggunakan LlamaCPP

# ===================================
# 4️⃣ Inisialisasi Index & Chat Engine
# ===================================
def initialize_index():
    text_data = read_google_sheets()
    document = Document(text=text_data)
    parser = SentenceSplitter(chunk_size=100, chunk_overlap=30)
    nodes = parser.get_nodes_from_documents([document])
    
    embedding = HuggingFaceEmbedding("sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2")
    Settings.embed_model = embedding
    
    index = VectorStoreIndex(nodes)
    return index

def initialize_chat_engine(index):
    retriever = index.as_retriever(similarity_top_k=3)
    chat_engine = CondensePlusContextChatEngine.from_defaults(
        retriever=retriever,
        verbose=False  # ❌ Hapus verbose agar tidak ada referensi dokumen
    )
    return chat_engine

# ===================================
# 5️⃣ Fungsi untuk Merapikan Jawaban Chatbot
# ===================================
def clean_response(response):
    text = "".join(response.response_gen)  # Gabungkan teks yang dihasilkan
    text = text.replace("\n\n", "\n").strip()  # Hilangkan newline berlebihan
    text = text.replace("user:", "").replace("jawaban:", "").replace("assistant:", "").strip()
    return text

# ===================================
# 6️⃣ Fungsi untuk Menghasilkan Respons Chatbot
# ===================================
def generate_response(message, history, tokenizer, model):
    if history is None:
        history = []

    chat_messages = [
        ChatMessage(
            role="system",
            content=(
                "Anda adalah chatbot HRD yang membantu karyawan memahami administrasi perusahaan. "
                "Jangan menjawab menggunakan Bahasa Inggris. "
                "Gunakan Bahasa Indonesia dengan gaya profesional dan ramah. "
                "Jika informasi tidak tersedia dalam dokumen, katakan dengan sopan bahwa Anda tidak tahu. "
                "Jawaban harus singkat, jelas, dan sesuai konteks."
                "Jangan memberikan jawaban untuk pertanyaan yang tidak diajukan oleh pengguna. "
                "Jangan menyertakan rekomendasi pertanyaan lain."
            ),
        ),
    ]

    # Tokenisasi input
    inputs = tokenizer(message, return_tensors="pt").to("cuda")
    
    # Hasilkan respons
    with torch.no_grad():
        outputs = model.generate(**inputs, max_length=512)

    response = tokenizer.decode(outputs[0], skip_special_tokens=True)
    history.append((message, response))  
    return response

# ===================================
# 7️⃣ Fungsi Utama untuk Menjalankan Aplikasi
# ===================================
def main():
    tokenizer, model = initialize_llama_model()
    initialize_settings(tokenizer, model)

    index = initialize_index()
    chat_engine = initialize_chat_engine(index)

    def chatbot_response(message, history=None):
        return generate_response(message, history, tokenizer, model)

    gr.Interface(
        fn=chatbot_response,
        inputs=["text"],
        outputs=["text"],
    ).launch()

if __name__ == "__main__":
    main()