This commit is contained in:
Cliff Julyano S
2026-11-02 11:24:52 +07:00
parent 5cfa138cf4
commit db453afcf9
23 changed files with 46 additions and 160 deletions
@@ -0,0 +1 @@
invalid type: string "vention\n \nis\n \nnot\n \nused\n \nin\n \nevery\n \ncase\n \nbecause\n \nsometimes\n \nthe\n \nargument\n \nname\n \nand\n \nthe\n \nvariable\n \nname\n \nare\n \ndifferent.\n \nFor\n \nexample:\n \ntext\n \ncontext:\n \nshortUrlBase\n \nHere,\n \n`context`\n \nis\n \nthe\n \nargument\n \nname\n \nand\n \n`shortUrlBase`\n \nis\n \nthe\n \nvariable\n \nbeing\n \npassed\n \nto
Binary file not shown.
Binary file not shown.
+30 -145
View File
@@ -1,86 +1,53 @@
from pathlib import Path from pathlib import Path
from pypdf import PdfReader from pypdf import PdfReader
import chromadb import chromadb
from chromadb.utils import embedding_functions from chromadb.utils import embedding_functions
# ========================================== # ==========================================
# 1. MEMBACA DOKUMEN PDF # FUNGSI BANTU
# ========================================== # ==========================================
def baca_pdf(path): def baca_pdf(path):
reader = PdfReader(path) reader = PdfReader(path)
return "\n".join((p.extract_text() or "") for p in reader.pages) return "\n".join((p.extract_text() or "") for p in reader.pages)
# ==========================================
# 2. MEMBAGI DOKUMEN MENJADI CHUNK
# ==========================================
def potong(teks, ukuran=800, tumpang=100): def potong(teks, ukuran=800, tumpang=100):
hasil = [] hasil, mulai = [], 0
mulai = 0
while mulai < len(teks): while mulai < len(teks):
hasil.append(teks[mulai:mulai + ukuran]) hasil.append(teks[mulai:mulai + ukuran])
mulai += ukuran - tumpang mulai += ukuran - tumpang
return [h for h in hasil if h.strip()] return [h for h in hasil if h.strip()]
# ========================================== # ==========================================
# 3. PENGATURAN EMBEDDING DAN DATABASE # SETUP EMBEDDING & CLIENT
# ========================================== # ==========================================
emb = embedding_functions.SentenceTransformerEmbeddingFunction( emb = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="paraphrase-multilingual-MiniLM-L12-v2" model_name="paraphrase-multilingual-MiniLM-L12-v2")
)
client = chromadb.PersistentClient(path="./chroma_db") client = chromadb.PersistentClient(path="./chroma_db")
# ==========================================
# 4. MEMBUAT KOLEKSI
# ==========================================
def buat_koleksi(nama, ukuran, tumpang): def buat_koleksi(nama, ukuran, tumpang):
try: try:
client.delete_collection(nama) client.delete_collection(nama)
except Exception: except Exception:
pass pass
kol = client.get_or_create_collection( kol = client.get_or_create_collection(
name=nama, name=nama, embedding_function=emb,
embedding_function=emb, metadata={"hnsw:space": "cosine"})
metadata={"hnsw:space": "cosine"}
)
for pdf in Path("dokumen").glob("*.pdf"): for pdf in Path("dokumen").glob("*.pdf"):
chunks = potong(baca_pdf(pdf), ukuran, tumpang)
teks = baca_pdf(pdf)
chunks = potong(teks, ukuran, tumpang)
if not chunks:
continue
kol.upsert( kol.upsert(
ids=[ ids=[f"{nama}-{pdf.stem}-{i}" for i in range(len(chunks))],
f"{nama}-{pdf.stem}-{i}"
for i in range(len(chunks))
],
documents=chunks, documents=chunks,
metadatas=[ metadatas=[{"sumber": pdf.name, "chunk": i} for i in range(len(chunks))],
{"sumber": pdf.name, "chunk": i}
for i in range(len(chunks))
]
) )
print(f" {nama}: {pdf.name} -> {len(chunks)} chunk")
return kol return kol
# ========================================== # ==========================================
# 5. 15 PERTANYAAN DAN KATA KUNCI # 15 PERTANYAAN + KATA KUNCI
# (disesuaikan dengan isi PDF probabilitas)
# ========================================== # ==========================================
UJI = [ UJI = [
@@ -101,124 +68,42 @@ UJI = [
("What is a random variable?", "random variable"), ("What is a random variable?", "random variable"),
] ]
# ==========================================
# 6. FUNGSI HIT@K
# ==========================================
def hit_at_k(koleksi, uji, k): def hit_at_k(koleksi, uji, k):
benar = 0 benar = 0
jumlah = min(k, koleksi.count())
if jumlah == 0:
return 0
for pertanyaan, kunci in uji: for pertanyaan, kunci in uji:
docs = koleksi.query(query_texts=[pertanyaan], n_results=k)["documents"][0]
docs = koleksi.query(
query_texts=[pertanyaan],
n_results=jumlah
)["documents"][0]
if any(kunci.lower() in d.lower() for d in docs): if any(kunci.lower() in d.lower() for d in docs):
benar += 1 benar += 1
return benar / len(uji) return benar / len(uji)
# ========================================== # ==========================================
# 7. MEMBUAT DUA KOLEKSI BERBEDA # JALANKAN: BUAT 2 KOLEKSI
# ========================================== # ==========================================
print("=== MEMBUAT KOLEKSI ===")
kol_500 = buat_koleksi("chunk_500", 500, 75) kol_500 = buat_koleksi("chunk_500", 500, 75)
kol_1500 = buat_koleksi("chunk_1500", 1500, 225) kol_1500 = buat_koleksi("chunk_1500", 1500, 225)
print("\n=== CEK ISI KOLEKSI ===")
print(f" chunk_500 : {kol_500.count()} dokumen")
print(f" chunk_1500 : {kol_1500.count()} dokumen")
# ========================================== # ==========================================
# 8. MENAMPILKAN TABEL HASIL HIT@K # HITUNG HIT@K
# ========================================== # ==========================================
print("\n========== TABEL HIT@K ==========") print("\n=== TABEL HIT@K ===")
print(f"{'k':<4}{'Chunk 500':<14}{'Chunk 1500':<14}")
print(f"{'k':<5}{'Chunk 500':<15}{'Chunk 1500':<15}")
hasil = {}
for k in (1, 3, 5): for k in (1, 3, 5):
print(f"{k:<4}{hit_at_k(kol_500, UJI, k):<14.2f}{hit_at_k(kol_1500, UJI, k):<14.2f}")
h500 = hit_at_k(kol_500, UJI, k) print("\n=== PERTANYAAN GAGAL di k=3 ===")
h1500 = hit_at_k(kol_1500, UJI, k)
hasil[k] = (h500, h1500)
print(f"{k:<5}{h500:<15.2f}{h1500:<15.2f}")
# ==========================================
# 9. MENAMPILKAN PERTANYAAN YANG GAGAL
# ==========================================
print("\n========== PERTANYAAN GAGAL DI k=3 ==========")
gagal = []
for pertanyaan, kunci in UJI: for pertanyaan, kunci in UJI:
ok_500 = any(kunci.lower() in d.lower()
for d in kol_500.query(query_texts=[pertanyaan], n_results=3)["documents"][0])
ok_1500 = any(kunci.lower() in d.lower()
for d in kol_1500.query(query_texts=[pertanyaan], n_results=3)["documents"][0])
if not ok_500 and not ok_1500:
print(f"X {pertanyaan} (kunci: '{kunci}')")
docs_500 = kol_500.query( print("\n=== SELESAI ===")
query_texts=[pertanyaan],
n_results=min(3, kol_500.count())
)["documents"][0]
docs_1500 = kol_1500.query(
query_texts=[pertanyaan],
n_results=min(3, kol_1500.count())
)["documents"][0]
ok_500 = any(kunci.lower() in d.lower() for d in docs_500)
ok_1500 = any(kunci.lower() in d.lower() for d in docs_1500)
if not ok_500 or not ok_1500:
gagal.append(pertanyaan)
print(f"\nPertanyaan: {pertanyaan}")
print(f"Kata kunci: {kunci}")
print(f"Chunk 500 : {'Berhasil' if ok_500 else 'Gagal'}")
print(f"Chunk 1500: {'Berhasil' if ok_1500 else 'Gagal'}")
if not gagal:
print("Semua pertanyaan berhasil ditemukan pada kedua koleksi.")
# ==========================================
# 10. KESIMPULAN OTOMATIS
# ==========================================
print("\n========== KESIMPULAN ==========")
rata_500 = sum(v[0] for v in hasil.values()) / len(hasil)
rata_1500 = sum(v[1] for v in hasil.values()) / len(hasil)
print(f"Rata-rata Hit@K Chunk 500 : {rata_500:.2f}")
print(f"Rata-rata Hit@K Chunk 1500 : {rata_1500:.2f}")
if rata_500 > rata_1500:
print("Chunk 500 memiliki hasil pencarian lebih baik.")
elif rata_1500 > rata_500:
print("Chunk 1500 memiliki hasil pencarian lebih baik.")
else:
print("Kedua ukuran chunk memiliki hasil rata-rata yang sama.")
print(
f"Jumlah pertanyaan yang gagal pada minimal satu koleksi "
f"di k=3: {len(gagal)} dari {len(UJI)}."
)
print(
"Kegagalan pencarian dapat disebabkan oleh perbedaan istilah, "
"informasi yang tersebar di beberapa chunk, atau hasil embedding "
"yang kurang relevan."
)
print("\n========== PENGUJIAN SELESAI ==========")