tugas
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,99 @@
|
|||||||
|
%PDF-1.4
|
||||||
|
%“Œ‹ž ReportLab Generated PDF document (opensource)
|
||||||
|
1 0 obj
|
||||||
|
<<
|
||||||
|
/F1 2 0 R /F2 3 0 R /F3 4 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
2 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
3 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
4 0 obj
|
||||||
|
<<
|
||||||
|
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
5 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 10 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 9 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
6 0 obj
|
||||||
|
<<
|
||||||
|
/Contents 11 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 9 0 R /Resources <<
|
||||||
|
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
|
||||||
|
>> /Rotate 0 /Trans <<
|
||||||
|
|
||||||
|
>>
|
||||||
|
/Type /Page
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
7 0 obj
|
||||||
|
<<
|
||||||
|
/PageMode /UseNone /Pages 9 0 R /Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
8 0 obj
|
||||||
|
<<
|
||||||
|
/Author (\(anonymous\)) /CreationDate (D:20261102034842+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20261102034842+00'00') /Producer (ReportLab PDF Library - \(opensource\))
|
||||||
|
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
9 0 obj
|
||||||
|
<<
|
||||||
|
/Count 2 /Kids [ 5 0 R 6 0 R ] /Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
10 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1516
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gatm;gMZ%0&:Ml+%/cp.%Th.c"^3%,1qO:1Bptt($M]=\BSV^<\WhaiJ);Cq>OjAnU4E?uiaq8rR574!JrLjeT$%c)ErqtO.8U84'i9s9OF2]<PDaoD8EANF"=/j+-hMu.1^q#.*kklMn,j<A:/&KF8aM0iKbAbl,(AU+_cQr#(VTc<Ru^.f>:4=T:d5*Bq-Il!5^^m;;es'tp)&![>Y8Zt.3p3Ahc[j^J<Ul:R40PPb_-UqO?>o$PI<V0i5IE:oAQ9lYH2-A$g;9MT,@$?;rI:S6f6H7Gf\@%"cfonJ:-%T:#c3Z53ri;F7h%HLrkB:U\JrsJ7CQ_,0`[nOXL^7#j7B[XS_=qS%l,pi;TA0lQ:=iF8^@^Y_@G3^Xf&B#qq,50g$6i%q:4B_t-4@5=Xg[kYMl";1rl7Kd6r`*P)J!f/]mo_i8,N,ALn'e)jKtP!-'J5[MR$Dd^IU<NVNp4(FX7=VX:<HT'c;!`a2kA5BOj;><oQTm.*cn?sV.!&0@6LLF$]hmm!5aU5P-D4W5fVh*=rm;V.D2UdH<>_hZjMb3*Z'[i7@CsPU[-SLidit5CJ!doS6WN+Vm7ucK81#HaIY=u)B'=i[`1PO^_$e_bsQEL]2<^7m1:pq71b='L=N#[L^)ojDFof4X-\!#k:W(Y`3;c2Q8)M_XD3es`78lgj10Q\aY9Ph]e2M[eU\]RUcdhYI7*%.Q%hS!g_=_q"B</)OaoBM)QQWJsXhl&2_9u-gF`.f5p'4?',"CoaoNOl37W>t#C.fupZY6WjK>eZ)9KC;\P9G%!C;m+c-%G3oZWjZq%89J=R&$'SI5IU0!_89r3?8!qoa6QS>Vq.d0hBY't;(fA"9?DGIWi4S)]/*cOOql]W-MYZ/>4n_??m&;u#7S%p>?97$EB-<&?5T5+M&5NV`'$kP`);1o@<Tg.<liLp1YQZg<oF1@LEWqEEQ#gc1lU[R[_bn$Hid>%r%Jkt=M7rk=]^_!Hoo/IT&*K8aHID*1Q#"Dq$MtqC\(`%YbpKH*lWl*@6Yn(V-!Jtr)Q>P59Wp2S6U89;B5@M[!%%K>VA92945Lf+'l%:rl>u!ACX[7r+<r"S@*haVE=">^GZGbEad5,[7-#0P]rtF6p=g[%Mj/b5A1W"=1#SD:r1^lC[l7^B_5_Zoo*53@\R+uaSd3OG4;<2)(=:;4g3T[:Tl;I+NLck<@@Y.Z<C<)d(24aX2Xs.X4kSK?1]:BF-J,Fcb!#o<aVFdENE3#`?<+DqU2pV,<am4.`Fb\9b=_mSaD8hjIHi>`XE&5dKBo,nV'Ep&1fG`9Qe@p'U^uRj4^5'i3np:>.j<i7aAVi[4PZSG;ZGm@cW6XEidkY<,@OoQJqYqN/ma>$W2h`hq?7ir?scZ@DhS<a78&EmVf]f;VBs=oL2=Qh>p&"+odduD/'a0`/Lmm7W8`V3_mu3i_?I!bjZ]Q22<(I%!qegYM%e`UU*.r&X$QERNdm8#hk8&66ZG]8"D&]gKgqc<k3On>O2A#\G-RE[Dr(~>endstream
|
||||||
|
endobj
|
||||||
|
11 0 obj
|
||||||
|
<<
|
||||||
|
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1002
|
||||||
|
>>
|
||||||
|
stream
|
||||||
|
Gau0B95iQ=%)1n+&34;hTN[@_.^2Rn[6&JcXgr:1d#%$9[Ui7#2[%%tq^CQ'[nG*?:]qO:8UPpH7ku%cqJj8&C4N?F>hj;V+j;$Y7kB8f*IOB<IZ@MG#9j89AP&9/^][Gs.#"k6,7SY0&ePH\d>Wob)K;VuSn0Iu_Y!B"K)<qjJ*,5gQL(ubR0\).!fQ&/"<k!/o#=A^"Sg9_K9[<e4Q@FD2,$3/Pt"%l.pSj#)YHuGoa^,"R(mjV#7;Xu(o^<'./8H1Oq`QOR4j5;09h,OX!u`JP(Zc(kW84b:E?6l0KZBHUMsER6jIaQV`G3ne/MDsA1a.Y1tX!c<M>#@ErnD04o@XAOPnKRVQWDr9@`48@W8Fb<](f?AtZ-B%Wt(,ZIb!:n;3A&]%Ia%a,u('JF"\W/W,IUfcJ]c5>:Vh=7?7)NNnc!GR@r<Al55UXek:*nIP)>pSu4JG,kG!,k,HJ.Ic@j(gef\T6IT,*MntF_S7b9SVU\32@Dpg77%ug2'AX5TnnNFcVkNpo+M2_VFUFRU^ZCcmIiY'_g!@8`_R>oEK5^DG2IS6SmYe=*3jL@ER?5PII=S_U>fi\;]+Lq.2T"Q6A8DM<p?>H><:b#F^)tn;\hI._(u@\7+p=I+4tfqpa\d5iNUk<c>eE^8u`Mc`\b[O(=gaJKdN^oUKbEo3TatK&(A!X5HsZmoXDO-i*Caop6,rN-*2s\SW?%hBW=HNof7h\jR!Na0=TPsM!r]j'i[o$8qa&5rQqCTVs[\s<DkF$`_6^6K;C#*qZ=AYTZ%tVX[oBhi"cEc>Y;=hI1?kK/:R2p$uNX</GIm2;)V)3(gdt=@b`F@=AU,DC="e@#*YpYC+7KFSj#'iit%l'fUZY3i"H,Jl'!6dmMr'#bl=<-d2n,DLYtYo5.`GBgYmSf="^]RY3("(a]@-TQL]gak6fsrSl5$Xqk^"pMfl)#6[<e%O;N+,=Z"V=[UM(_Qde8/]fHR$$Io3!5AHgG#=e^n]I6P]~>endstream
|
||||||
|
endobj
|
||||||
|
xref
|
||||||
|
0 12
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000061 00000 n
|
||||||
|
0000000112 00000 n
|
||||||
|
0000000219 00000 n
|
||||||
|
0000000331 00000 n
|
||||||
|
0000000436 00000 n
|
||||||
|
0000000640 00000 n
|
||||||
|
0000000844 00000 n
|
||||||
|
0000000912 00000 n
|
||||||
|
0000001192 00000 n
|
||||||
|
0000001257 00000 n
|
||||||
|
0000002865 00000 n
|
||||||
|
trailer
|
||||||
|
<<
|
||||||
|
/ID
|
||||||
|
[<8f92dc9b38dcbce41e380e8ab68ab56d><8f92dc9b38dcbce41e380e8ab68ab56d>]
|
||||||
|
% ReportLab generated PDF document -- digest (opensource)
|
||||||
|
|
||||||
|
/Info 8 0 R
|
||||||
|
/Root 7 0 R
|
||||||
|
/Size 12
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
3959
|
||||||
|
%%EOF
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
INSERT INTO "embedding_metadata" ("id", "key", "string_value", "int_value", "float_value", "bool_value") VALUES (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?) ON CONFLICT ("id", "key") DO UPDATE SET "string_value" = "excluded"."string_value", "int_value" = "excluded"."int_value", "float_value" = "excluded"."float_value", "bool_value" = "excluded"."bool_value"ÿÿÿÿÿÿÿ
|
||||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
invalid type: string "1. Histogram Data Berat Air Mineral Vit \n \n \nGambar 22. Tabel Data Kelompok Berat Air Mineral Aqua \n \n \nGambar 23. Histogram Data Berat Air Mineral Aqua \n \n\n \nGambar 24. Pengolahan Data Hasil Kuisioner \n \nGambar 25. Tabel Urutan Data Hasil Kuisioner \n \n \n \n \n \n\nLAMPIRAN 2 \n \n \n \n \n\n", expected i64mart \n \n \nadan Mahasiswa UKWMS Angkatan 2025 \n \n
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
INSERT INTO "embedding_metadata" ("id", "key", "string_value", "int_value", "float_value", "bool_value") VALUES (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?) ON CONFLICT ("id", "key") DO UPDATE SET "string_value" = "excluded"."string_value", "int_value" = "excluded"."int_value", "float_value" = "excluded"."float_value", "bool_value" = "excluded"."bool_value"ÿÿÿÿÿÿÿ
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
INSERT INTO "embedding_metadata" ("id", "key", "string_value", "int_value", "float_value", "bool_value") VALUES (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?), (?, ?, ?, ?, ?, ?) ON CONFLICT ("id", "key") DO UPDATE SET "string_value" = "excluded"."string_value", "int_value" = "excluded"."int_value", "float_value" = "excluded"."float_value", "bool_value" = "excluded"."bool_value"ÿÿÿÿÿÿÿ
|
||||||
+548
@@ -0,0 +1,548 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import chromadb
|
||||||
|
from chromadb.utils import embedding_functions
|
||||||
|
from pypdf import PdfReader
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# KONFIGURASI PROGRAM
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent
|
||||||
|
DB_PATH = str(BASE_DIR / "chroma_db")
|
||||||
|
|
||||||
|
UKURAN_CHUNK = [500, 1000, 1500]
|
||||||
|
OVERLAP_PERSEN = 0.10
|
||||||
|
|
||||||
|
MODEL_EMBEDDING = "paraphrase-multilingual-MiniLM-L12-v2"
|
||||||
|
|
||||||
|
print("Memuat model embedding...")
|
||||||
|
embedding = embedding_functions.SentenceTransformerEmbeddingFunction(
|
||||||
|
model_name=MODEL_EMBEDDING
|
||||||
|
)
|
||||||
|
|
||||||
|
client = chromadb.PersistentClient(path=DB_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# FUNGSI MEMBACA PDF
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def ambil_file_pdf():
|
||||||
|
return list(BASE_DIR.glob("*.pdf"))
|
||||||
|
|
||||||
|
|
||||||
|
def baca_pdf(path):
|
||||||
|
reader = PdfReader(str(path))
|
||||||
|
teks = ""
|
||||||
|
|
||||||
|
for halaman in reader.pages:
|
||||||
|
teks += (halaman.extract_text() or "") + "\n"
|
||||||
|
|
||||||
|
return teks
|
||||||
|
|
||||||
|
|
||||||
|
def pilih_pdf(files):
|
||||||
|
"""Memilih satu PDF agar eksperimen konsisten."""
|
||||||
|
if not files:
|
||||||
|
print("Belum ada file PDF!")
|
||||||
|
print("Letakkan PDF di folder yang sama dengan file Python ini.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if len(files) == 1:
|
||||||
|
return files[0]
|
||||||
|
|
||||||
|
print("\nDaftar dokumen PDF:")
|
||||||
|
for i, file in enumerate(files, 1):
|
||||||
|
print(f"{i}. {file.name}")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
pilihan = input("Pilih nomor PDF: ").strip()
|
||||||
|
if pilihan.isdigit() and 1 <= int(pilihan) <= len(files):
|
||||||
|
return files[int(pilihan) - 1]
|
||||||
|
print("Pilihan tidak valid.")
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# FUNGSI CHUNKING
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def chunking(teks, ukuran=1000, overlap=100):
|
||||||
|
if ukuran <= 0 or overlap < 0 or overlap >= ukuran:
|
||||||
|
raise ValueError("Ukuran atau overlap tidak valid.")
|
||||||
|
|
||||||
|
chunks = []
|
||||||
|
start = 0
|
||||||
|
|
||||||
|
while start < len(teks):
|
||||||
|
akhir = min(start + ukuran, len(teks))
|
||||||
|
potongan = teks[start:akhir]
|
||||||
|
|
||||||
|
if potongan.strip():
|
||||||
|
chunks.append(potongan)
|
||||||
|
|
||||||
|
start += ukuran - overlap
|
||||||
|
|
||||||
|
return chunks
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# LAB 1 - EKSPERIMEN CHUNKING
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def lab_chunking():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("LAB 1 - EKSPERIMEN CHUNKING")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
file = pilih_pdf(ambil_file_pdf())
|
||||||
|
if file is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
teks = baca_pdf(file)
|
||||||
|
print(f"\nDokumen : {file.name}")
|
||||||
|
print(f"Panjang teks : {len(teks)} karakter")
|
||||||
|
|
||||||
|
if not teks.strip():
|
||||||
|
print("Dokumen tidak memiliki teks yang dapat dibaca.")
|
||||||
|
return
|
||||||
|
|
||||||
|
for ukuran in UKURAN_CHUNK:
|
||||||
|
for persentase in [0.10, 0.20]:
|
||||||
|
overlap = int(ukuran * persentase)
|
||||||
|
chunks = chunking(teks, ukuran, overlap)
|
||||||
|
|
||||||
|
print("\n" + "-" * 55)
|
||||||
|
print(f"Ukuran chunk : {ukuran}")
|
||||||
|
print(f"Overlap : {overlap} ({persentase:.0%})")
|
||||||
|
print(f"Jumlah chunk : {len(chunks)}")
|
||||||
|
print("Tiga contoh chunk:")
|
||||||
|
|
||||||
|
# Tampilkan maksimal tiga contoh chunk.
|
||||||
|
# Pemilihan posisi dibuat tersebar agar tidak selalu awal dokumen.
|
||||||
|
if len(chunks) <= 3:
|
||||||
|
indeks = list(range(len(chunks)))
|
||||||
|
else:
|
||||||
|
indeks = [0, len(chunks) // 2, len(chunks) - 1]
|
||||||
|
|
||||||
|
for nomor, idx in enumerate(indeks, 1):
|
||||||
|
print(f"\nContoh {nomor} (Chunk {idx + 1}):")
|
||||||
|
print(chunks[idx][:350])
|
||||||
|
|
||||||
|
print("\nEksperimen chunking selesai!")
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# FUNGSI MEMBANGUN KOLEKSI
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def bangun_koleksi(nama_koleksi, ukuran_chunk, file_pdf, reset=True):
|
||||||
|
"""Membangun koleksi ChromaDB dari satu dokumen PDF."""
|
||||||
|
teks = baca_pdf(file_pdf)
|
||||||
|
|
||||||
|
if not teks.strip():
|
||||||
|
print("PDF kosong atau tidak dapat dibaca.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
overlap = int(ukuran_chunk * OVERLAP_PERSEN)
|
||||||
|
chunks = chunking(teks, ukuran_chunk, overlap)
|
||||||
|
|
||||||
|
if reset:
|
||||||
|
try:
|
||||||
|
client.delete_collection(nama_koleksi)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
collection = client.create_collection(
|
||||||
|
name=nama_koleksi,
|
||||||
|
embedding_function=embedding,
|
||||||
|
metadata={"hnsw:space": "cosine"}
|
||||||
|
)
|
||||||
|
|
||||||
|
ids = [f"chunk_{i}" for i in range(len(chunks))]
|
||||||
|
metadatas = [
|
||||||
|
{
|
||||||
|
"sumber": file_pdf.name,
|
||||||
|
"nomor_chunk": i,
|
||||||
|
"ukuran_chunk": ukuran_chunk
|
||||||
|
}
|
||||||
|
for i in range(len(chunks))
|
||||||
|
]
|
||||||
|
|
||||||
|
batch_size = 100
|
||||||
|
for start in range(0, len(chunks), batch_size):
|
||||||
|
end = start + batch_size
|
||||||
|
collection.upsert(
|
||||||
|
ids=ids[start:end],
|
||||||
|
documents=chunks[start:end],
|
||||||
|
metadatas=metadatas[start:end]
|
||||||
|
)
|
||||||
|
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# LAB 2 - MEMBANGUN INDEKS CHROMADB
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def lab_indexing():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("LAB 2 - INDEXING CHROMADB")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
file = pilih_pdf(ambil_file_pdf())
|
||||||
|
if file is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"\nMembaca: {file.name}")
|
||||||
|
collection = bangun_koleksi(
|
||||||
|
nama_koleksi="rag_part1",
|
||||||
|
ukuran_chunk=1000,
|
||||||
|
file_pdf=file,
|
||||||
|
reset=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if collection is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\nIndexing berhasil!")
|
||||||
|
print("Ukuran chunk :", 1000)
|
||||||
|
print("Total chunk :", collection.count())
|
||||||
|
print("Database :", DB_PATH)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MENGAMBIL KOLEKSI CHROMADB
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def ambil_koleksi():
|
||||||
|
try:
|
||||||
|
return client.get_collection(
|
||||||
|
name="rag_part1",
|
||||||
|
embedding_function=embedding
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
print("\nDatabase belum tersedia!")
|
||||||
|
print("Silakan jalankan Lab 2 terlebih dahulu.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# FUNGSI PENCARIAN DOKUMEN
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def cari_dokumen(pertanyaan, k=3, tampilkan=True, collection=None):
|
||||||
|
if collection is None:
|
||||||
|
collection = ambil_koleksi()
|
||||||
|
|
||||||
|
if collection is None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
total = collection.count()
|
||||||
|
if total == 0:
|
||||||
|
print("Database masih kosong!")
|
||||||
|
return []
|
||||||
|
|
||||||
|
k = min(k, total)
|
||||||
|
|
||||||
|
hasil = collection.query(
|
||||||
|
query_texts=[pertanyaan],
|
||||||
|
n_results=k
|
||||||
|
)
|
||||||
|
|
||||||
|
dokumen = hasil["documents"][0]
|
||||||
|
metadata = hasil["metadatas"][0]
|
||||||
|
jarak = hasil["distances"][0]
|
||||||
|
|
||||||
|
if tampilkan:
|
||||||
|
print("\nPertanyaan:", pertanyaan)
|
||||||
|
print("\nHasil pencarian:")
|
||||||
|
|
||||||
|
for i, doc in enumerate(dokumen):
|
||||||
|
print("\n" + "-" * 45)
|
||||||
|
print(f"HASIL KE-{i + 1}")
|
||||||
|
print("-" * 45)
|
||||||
|
print("Sumber:", metadata[i].get("sumber", "-"))
|
||||||
|
print("Chunk:", metadata[i].get("nomor_chunk", "-"))
|
||||||
|
print("Jarak:", round(jarak[i], 4))
|
||||||
|
print("Isi:")
|
||||||
|
print(doc[:500])
|
||||||
|
|
||||||
|
return dokumen
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# LAB 2 - PENCARIAN DOKUMEN
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def lab_pencarian():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("LAB 2 - PENCARIAN DOKUMEN")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
collection = ambil_koleksi()
|
||||||
|
if collection is None or collection.count() == 0:
|
||||||
|
print("Silakan lakukan indexing terlebih dahulu.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\nMasukkan pertanyaan untuk mencari informasi.")
|
||||||
|
print("Ketik '0' untuk kembali ke menu.")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
pertanyaan = input("\nPertanyaan: ").strip()
|
||||||
|
|
||||||
|
if pertanyaan == "0":
|
||||||
|
break
|
||||||
|
|
||||||
|
if not pertanyaan:
|
||||||
|
print("Pertanyaan tidak boleh kosong.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
cari_dokumen(pertanyaan, k=3, collection=collection)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# LAB 2 - PENGUJIAN PARAFRASE
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def lab_parafrase():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("LAB 2 - PENGUJIAN PARAFRASE")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
collection = ambil_koleksi()
|
||||||
|
if collection is None or collection.count() == 0:
|
||||||
|
print("Silakan lakukan indexing terlebih dahulu.")
|
||||||
|
return
|
||||||
|
|
||||||
|
pertanyaan_asli = input("\nPertanyaan asli: ").strip()
|
||||||
|
if not pertanyaan_asli:
|
||||||
|
print("Pertanyaan tidak boleh kosong.")
|
||||||
|
return
|
||||||
|
|
||||||
|
pertanyaan_parafrase = input("Pertanyaan parafrase: ").strip()
|
||||||
|
if not pertanyaan_parafrase:
|
||||||
|
print("Parafrase tidak boleh kosong.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("\n--- HASIL PERTANYAAN ASLI ---")
|
||||||
|
cari_dokumen(pertanyaan_asli, k=3, collection=collection)
|
||||||
|
|
||||||
|
print("\n--- HASIL PERTANYAAN PARAFRASE ---")
|
||||||
|
cari_dokumen(pertanyaan_parafrase, k=3, collection=collection)
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# LAB 3 - EVALUASI HIT@K
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def buat_koleksi_evaluasi(ukuran_chunk, file_pdf):
|
||||||
|
nama_koleksi = f"rag_eval_{ukuran_chunk}"
|
||||||
|
|
||||||
|
print(f"\nMembangun koleksi {nama_koleksi}...")
|
||||||
|
|
||||||
|
collection = bangun_koleksi(
|
||||||
|
nama_koleksi=nama_koleksi,
|
||||||
|
ukuran_chunk=ukuran_chunk,
|
||||||
|
file_pdf=file_pdf,
|
||||||
|
reset=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if collection is not None:
|
||||||
|
print("Indexing selesai.")
|
||||||
|
print("Jumlah chunk:", collection.count())
|
||||||
|
|
||||||
|
return collection
|
||||||
|
|
||||||
|
|
||||||
|
def hitung_hit_at_k(collection, data_uji, k):
|
||||||
|
jumlah_hit = 0
|
||||||
|
total = len(data_uji)
|
||||||
|
|
||||||
|
for nomor, (pertanyaan, keyword) in enumerate(data_uji, 1):
|
||||||
|
jumlah_dokumen = min(k, collection.count())
|
||||||
|
|
||||||
|
hasil = collection.query(
|
||||||
|
query_texts=[pertanyaan],
|
||||||
|
n_results=jumlah_dokumen
|
||||||
|
)
|
||||||
|
|
||||||
|
dokumen = hasil["documents"][0]
|
||||||
|
|
||||||
|
# Hit jika minimal satu dari K dokumen teratas
|
||||||
|
# memuat kata/frasa kunci jawaban.
|
||||||
|
ditemukan = any(
|
||||||
|
keyword.casefold() in teks.casefold()
|
||||||
|
for teks in dokumen
|
||||||
|
)
|
||||||
|
|
||||||
|
if ditemukan:
|
||||||
|
jumlah_hit += 1
|
||||||
|
|
||||||
|
status = "HIT" if ditemukan else "MISS"
|
||||||
|
print(f"{nomor:02d}. {status} | {pertanyaan}")
|
||||||
|
|
||||||
|
skor = jumlah_hit / total if total else 0
|
||||||
|
return jumlah_hit, total, skor
|
||||||
|
|
||||||
|
|
||||||
|
def lab_evaluasi():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print("LAB 3 - EVALUASI HIT@K")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
print("""
|
||||||
|
Evaluasi menggunakan:
|
||||||
|
- 15 pertanyaan uji
|
||||||
|
- Dua koleksi: chunk 500 dan 1000 karakter
|
||||||
|
- Overlap 10%
|
||||||
|
- Hit@1, Hit@3, dan Hit@5
|
||||||
|
|
||||||
|
Masukkan kata/frasa yang benar-benar terdapat
|
||||||
|
pada bagian dokumen yang menjawab pertanyaan.
|
||||||
|
""")
|
||||||
|
|
||||||
|
file_pdf = pilih_pdf(ambil_file_pdf())
|
||||||
|
if file_pdf is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
data_uji = []
|
||||||
|
|
||||||
|
for i in range(15):
|
||||||
|
print("\n" + "-" * 50)
|
||||||
|
print(f"PERTANYAAN KE-{i + 1}")
|
||||||
|
pertanyaan = input("Pertanyaan: ").strip()
|
||||||
|
keyword = input("Kata kunci jawaban: ").strip()
|
||||||
|
|
||||||
|
if not pertanyaan or not keyword:
|
||||||
|
print("Pertanyaan dan kata kunci wajib diisi.")
|
||||||
|
print("Evaluasi dibatalkan. Jalankan kembali menu 5.")
|
||||||
|
return
|
||||||
|
|
||||||
|
data_uji.append((pertanyaan, keyword))
|
||||||
|
|
||||||
|
# Bangun dua koleksi dari PDF yang sama.
|
||||||
|
koleksi_500 = buat_koleksi_evaluasi(500, file_pdf)
|
||||||
|
if koleksi_500 is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
koleksi_1000 = buat_koleksi_evaluasi(1000, file_pdf)
|
||||||
|
if koleksi_1000 is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
koleksi = {
|
||||||
|
"Chunk 500": koleksi_500,
|
||||||
|
"Chunk 1000": koleksi_1000
|
||||||
|
}
|
||||||
|
|
||||||
|
hasil_evaluasi = {}
|
||||||
|
|
||||||
|
for nama, collection in koleksi.items():
|
||||||
|
print("\n" + "=" * 60)
|
||||||
|
print(f"EVALUASI {nama}")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
hasil_evaluasi[nama] = {}
|
||||||
|
|
||||||
|
for k in [1, 3, 5]:
|
||||||
|
print(f"\n--- PENGUJIAN HIT@{k} ---")
|
||||||
|
|
||||||
|
hit, total, skor = hitung_hit_at_k(
|
||||||
|
collection,
|
||||||
|
data_uji,
|
||||||
|
k
|
||||||
|
)
|
||||||
|
|
||||||
|
hasil_evaluasi[nama][k] = {
|
||||||
|
"hit": hit,
|
||||||
|
"total": total,
|
||||||
|
"skor": skor
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"\nHit@{k} = {hit}/{total} = {skor:.2%}")
|
||||||
|
|
||||||
|
# Tampilkan perbandingan.
|
||||||
|
print("\n" + "=" * 68)
|
||||||
|
print("TABEL PERBANDINGAN HASIL HIT@K")
|
||||||
|
print("=" * 68)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"{'Ukuran Chunk':<18}"
|
||||||
|
f"{'Hit@1':<16}"
|
||||||
|
f"{'Hit@3':<16}"
|
||||||
|
f"{'Hit@5':<16}"
|
||||||
|
)
|
||||||
|
print("-" * 68)
|
||||||
|
|
||||||
|
for nama in koleksi:
|
||||||
|
h1 = hasil_evaluasi[nama][1]["skor"]
|
||||||
|
h3 = hasil_evaluasi[nama][3]["skor"]
|
||||||
|
h5 = hasil_evaluasi[nama][5]["skor"]
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"{nama:<18}"
|
||||||
|
f"{h1:<16.2%}"
|
||||||
|
f"{h3:<16.2%}"
|
||||||
|
f"{h5:<16.2%}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print("-" * 68)
|
||||||
|
print("""
|
||||||
|
Catatan:
|
||||||
|
Hit@K adalah proporsi pertanyaan yang memiliki
|
||||||
|
minimal satu dokumen relevan pada K hasil teratas.
|
||||||
|
|
||||||
|
Evaluasi ini menggunakan pencocokan kata/frasa
|
||||||
|
kunci sederhana, bukan penilaian relevansi manual.
|
||||||
|
Periksa kembali hasil MISS dan kecocokan keyword
|
||||||
|
agar kesimpulan praktikum lebih akurat.
|
||||||
|
""")
|
||||||
|
|
||||||
|
print("Evaluasi Hit@K selesai!")
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MENU UTAMA
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
def main():
|
||||||
|
while True:
|
||||||
|
print("\n")
|
||||||
|
print("=" * 60)
|
||||||
|
print(" RAG PART 1 SYSTEM")
|
||||||
|
print("=" * 60)
|
||||||
|
print("1. Lab 1 - Eksperimen Chunking")
|
||||||
|
print("2. Lab 2 - Indexing ChromaDB")
|
||||||
|
print("3. Lab 2 - Pencarian Dokumen")
|
||||||
|
print("4. Lab 2 - Pengujian Parafrase")
|
||||||
|
print("5. Lab 3 - Evaluasi Hit@K")
|
||||||
|
print("6. Keluar")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
pilihan = input("Pilih menu (1-6): ").strip()
|
||||||
|
|
||||||
|
if pilihan == "1":
|
||||||
|
lab_chunking()
|
||||||
|
elif pilihan == "2":
|
||||||
|
lab_indexing()
|
||||||
|
elif pilihan == "3":
|
||||||
|
lab_pencarian()
|
||||||
|
elif pilihan == "4":
|
||||||
|
lab_parafrase()
|
||||||
|
elif pilihan == "5":
|
||||||
|
lab_evaluasi()
|
||||||
|
elif pilihan == "6":
|
||||||
|
print("\nProgram selesai. Terima kasih!")
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("\nPilihan tidak valid!")
|
||||||
|
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# MENJALANKAN PROGRAM
|
||||||
|
# =====================================================
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user