Files
2026-11-02 01:41:24 -05:00

146 lines
5.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import math
import re
from collections import Counter
class KAIGapekaRAG:
"""Sistem RAG Sederhana berbasis Pure Python untuk topik GAPEKA 2026 PT KAI."""
def __init__(self, knowledge_base):
print("[INFO] Menginisialisasi Basis Pengetahuan KAI Gapeka 2026...")
self.documents = knowledge_base
self.vocab = self._build_vocab(self.documents)
# Pra-penghitungan vektor TF-IDF untuk dokumen lokal
self.doc_vectors = [
self._compute_tfidf(doc, self.vocab, self.documents)
for doc in self.documents
]
def _tokenize(self, text):
"""Membersihkan teks dan memecahnya menjadi kata-kata (token)."""
return re.findall(r"\b\w+\b", text.lower())
def _build_vocab(self, docs):
"""Membangun kamus kata unik dari seluruh dokumen."""
vocab = set()
for doc in docs:
vocab.update(self._tokenize(doc))
return sorted(list(vocab))
def _compute_tfidf(self, text, vocab, all_docs):
"""Menghitung bobot TF-IDF secara manual tanpa library eksternal."""
tokens = self._tokenize(text)
tf = Counter(tokens)
total_tokens = len(tokens) if tokens else 1
vector = {}
for word in vocab:
# Term Frequency (TF)
term_freq = tf[word] / total_tokens
# Inverse Document Frequency (IDF)
doc_count = sum(1 for d in all_docs if word in self._tokenize(d))
idf = (
math.log(len(all_docs) / (doc_count + 1)) + 1 if doc_count > 0 else 0
)
vector[word] = term_freq * idf
return vector
def _cosine_similarity(self, vec1, vec2):
"""Menghitung kemiripan kosinus antara dua vektor TF-IDF."""
intersection = set(vec1.keys()).intersection(set(vec2.keys()))
numerator = sum(vec1[x] * vec2[x] for x in intersection)
sum1 = sum(val ** 2 for val in vec1.values())
sum2 = sum(val ** 2 for val in vec2.values())
denominator = math.sqrt(sum1) * math.sqrt(sum2)
if denominator == 0:
return 0.0
return numerator / denominator
def retrieve(self, query, top_k=1):
"""Mencari dokumen paling relevan menggunakan Cosine Similarity."""
query_vector = self._compute_tfidf(query, self.vocab, self.documents)
scores = []
for i, doc_vec in enumerate(self.doc_vectors):
score = self._cosine_similarity(query_vector, doc_vec)
scores.append((score, self.documents[i]))
# Urutkan berdasarkan skor tertinggi
scores.sort(key=lambda x: x[0], reverse=True)
return [doc for score, doc in scores[:top_k]]
def generate_answer(self, query):
"""Tahap Generation: Menggabungkan hasil retrieval dengan format jawaban RAG."""
retrieved_docs = self.retrieve(query, top_k=1)
context = (
retrieved_docs[0]
if retrieved_docs
else "Maaf, informasi tidak ditemukan."
)
# Template Generator Extractive RAG
answer = (
f"==================================================\n"
f"HASIL GENERASI RAG - PT KERETA API INDONESIA (GAPEKA 2026)\n"
f"==================================================\n"
f"Pertanyaan : {query}\n\n"
f"Konteks Relevan (Retrieved):\n-> {context}\n\n"
f"Jawaban Sistem:\n"
f"Berdasarkan informasi resmi kebijakan GAPEKA 2026 PT KAI, "
f"berikut adalah detail informasinya:\n"
f'"{context}"\n'
f"=================================================="
)
return answer, retrieved_docs
# ==========================================
# EKSEKUSI PROGRAM UTAMA
# ==========================================
if __name__ == "__main__":
# 1. Dataset / Basis Pengetahuan Lokal KAI GAPEKA 2026
kai_kb = [
(
"PT Kereta Api Indonesia (KAI) resmi memberlakukan Grafik Perjalanan "
"Kereta Api (GAPEKA) 2026 mulai tanggal 1 Desember 2026."
),
(
"Tiket perjalanan kereta api untuk jadwal GAPEKA 2026 sudah dapat "
"dipesan secara online melalui aplikasi Access by KAI."
),
(
"Terdapat penyesuaian serta penyederhanaan nama pada beberapa "
"perjalanan kereta api agar lebih simpel dan mudah diingat oleh "
"penumpang."
),
(
"KAI menambah titik pemberhentian di sejumlah stasiun untuk "
"mendukung mobilitas antarkota dan kawasan aglomerasi."
),
(
"KAI menghadirkan layanan rute baru seperti KA Borobudur "
"(Lempuyangan–Gambir PP, fakultatif) dan KA Pandawa "
"(Yogyakarta–Semarang Tawang PP) yang mulai beroperasi pada 1 "
"Desember 2026."
),
]
# 2. Inisialisasi Sistem RAG
rag = KAIGapekaRAG(kai_kb)
# 3. Contoh Daftar Pengujian Pertanyaan Tugas RAG
daftar_pertanyaan = [
"Kapan GAPEKA 2026 mulai diberlakukan dan di mana bisa pesan tiketnya?",
"Apa saja rute kereta api baru yang dihadirkan KAI dalam GAPEKA 2026?",
"Bagaimana kebijakan terkait nama kereta api dalam GAPEKA 2026?"
]
# 4. Menjalankan Pipeline Pengujian
for idx, sample_query in enumerate(daftar_pertanyaan, 1):
print(f"\n[PENGUJIAN {idx}]")
final_answer, sources = rag.generate_answer(sample_query)
print(final_answer)