From d16eabcfd830cd2174e0eaeaf5f87072af7a8a36 Mon Sep 17 00:00:00 2001 From: angelicatesvara07-crypto Date: Mon, 2 Nov 2026 10:50:42 +0700 Subject: [PATCH] Initial commit --- buat_pdf.py | 55 +++++++++++++ cari.py | 27 +++++++ cek_pdf.py | 12 +++ .../data_level0.bin | Bin 0 -> 167600 bytes .../header.bin | Bin 0 -> 100 bytes .../length.bin | Bin 0 -> 400 bytes .../link_lists.bin | 0 chroma_db/chroma.sqlite3 | Bin 0 -> 212992 bytes dokumen/akademik.pdf | 74 ++++++++++++++++++ dokumen/kemahasiswaan.pdf | 74 ++++++++++++++++++ dokumen/keuangan.pdf | 74 ++++++++++++++++++ evaluasi_retrieval.py | 36 +++++++++ indeks.py | 38 +++++++++ lab1_chunking.py | 31 ++++++++ 14 files changed, 421 insertions(+) create mode 100644 buat_pdf.py create mode 100644 cari.py create mode 100644 cek_pdf.py create mode 100644 chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/data_level0.bin create mode 100644 chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/header.bin create mode 100644 chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/length.bin create mode 100644 chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/link_lists.bin create mode 100644 chroma_db/chroma.sqlite3 create mode 100644 dokumen/akademik.pdf create mode 100644 dokumen/kemahasiswaan.pdf create mode 100644 dokumen/keuangan.pdf create mode 100644 evaluasi_retrieval.py create mode 100644 indeks.py create mode 100644 lab1_chunking.py diff --git a/buat_pdf.py b/buat_pdf.py new file mode 100644 index 0000000..0f54312 --- /dev/null +++ b/buat_pdf.py @@ -0,0 +1,55 @@ + +from reportlab.lib.pagesizes import A4 +from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer +from reportlab.lib.styles import getSampleStyleSheet + +dokumen = [ + { + "nama": "akademik.pdf", + "judul": "Panduan Akademik Mahasiswa", + "isi": [ + ("Cuti Akademik", "Mahasiswa dapat mengajukan cuti akademik paling lama dua semester berturut-turut dengan persetujuan dekan. Permohonan cuti diajukan sebelum masa registrasi semester berjalan dimulai."), + ("Kehadiran", "Mahasiswa wajib mengikuti minimal 75 persen dari total pertemuan perkuliahan agar dapat mengikuti ujian akhir semester."), + ("Nilai", "Nilai D pada mata kuliah wajib dapat diperbaiki dengan mengulang mata kuliah tersebut pada semester berikutnya."), + ] + }, + { + "nama": "keuangan.pdf", + "judul": "Panduan Administrasi Keuangan", + "isi": [ + ("Pembayaran Kuliah", "Pembayaran biaya kuliah dilakukan paling lambat dua minggu sebelum perkuliahan dimulai melalui bagian keuangan universitas."), + ("Keterlambatan", "Mahasiswa yang terlambat melakukan pembayaran wajib menghubungi bagian administrasi keuangan untuk memperoleh informasi penyelesaian administrasi."), + ("Bukti Pembayaran", "Mahasiswa harus menyimpan bukti pembayaran sebagai dokumen administrasi selama masa studi."), + ] + }, + { + "nama": "kemahasiswaan.pdf", + "judul": "Panduan Layanan Kemahasiswaan", + "isi": [ + ("Beasiswa", "Mahasiswa dapat mengajukan beasiswa dengan memenuhi persyaratan akademik dan administratif yang ditentukan universitas."), + ("Organisasi", "Mahasiswa diperbolehkan mengikuti organisasi kemahasiswaan selama tidak mengganggu kewajiban akademik."), + ("Konsultasi Akademik", "Mahasiswa dapat berkonsultasi dengan dosen wali mengenai kesulitan belajar dan perencanaan mata kuliah."), + ] + } +] + +styles = getSampleStyleSheet() + +for item in dokumen: + path = "dokumen/" + item["nama"] + pdf = SimpleDocTemplate(path, pagesize=A4) + + konten = [ + Paragraph(item["judul"], styles["Title"]), + Spacer(1, 20) + ] + + for judul, isi in item["isi"]: + konten.append(Paragraph(judul, styles["Heading2"])) + konten.append(Paragraph(isi, styles["BodyText"])) + konten.append(Spacer(1, 15)) + + pdf.build(konten) + print("Berhasil membuat:", path) + +print("\nSemua PDF berhasil dibuat!") diff --git a/cari.py b/cari.py new file mode 100644 index 0000000..72f9169 --- /dev/null +++ b/cari.py @@ -0,0 +1,27 @@ +import chromadb +from chromadb.utils import embedding_functions + +# Panggil model dan database yang sama +emb = embedding_functions.SentenceTransformerEmbeddingFunction( + model_name="paraphrase-multilingual-MiniLM-L12-v2") +client = chromadb.PersistentClient(path="./chroma_db") +koleksi = client.get_or_create_collection("pedoman", embedding_function=emb) + +# Daftar pertanyaan uji +daftar_pertanyaan = [ + "Apa syarat cuti akademik?", + "Berapa batas kehadiran untuk ujian?", + "Bolehkah berhenti kuliah sementara?", # Pertanyaan parafrase (tanpa kata 'cuti') + "Apa sanksi jika telat bayar kuliah?" # Pertanyaan parafrase (tanpa kata 'keuangan') +] + +for q in daftar_pertanyaan: + print("=" * 60) + print("PERTANYAAN:", q) + # Ambil 2 hasil terdekat + hasil = koleksi.query(query_texts=[q], n_results=2) + + for doc, meta, jarak in zip(hasil["documents"][0], hasil["metadatas"][0], hasil["distances"][0]): + # Jarak (distance) semakin kecil berarti semakin mirip + print(f" [Sumber: {meta['sumber']} | Jarak: {jarak:.3f}]") + print(" Teks:", doc[:120].replace("\n", " "), "...") \ No newline at end of file diff --git a/cek_pdf.py b/cek_pdf.py new file mode 100644 index 0000000..51ad6b4 --- /dev/null +++ b/cek_pdf.py @@ -0,0 +1,12 @@ +from pathlib import Path +from pypdf import PdfReader + +for pdf in Path("dokumen").glob("*.pdf"): + r = PdfReader(pdf) + teks = "\n".join((p.extract_text() or "") for p in r.pages) + print("=" * 50) + print("File :", pdf.name) + print("Halaman:", len(r.pages)) + print("Panjang teks:", len(teks)) + print("500 karakter pertama:") + print(teks[:500]) \ No newline at end of file diff --git a/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/data_level0.bin b/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/data_level0.bin new file mode 100644 index 0000000000000000000000000000000000000000..5efb1b9f398d64303b911a57992cc0b9721a21dc GIT binary patch literal 167600 zcmeIuF#!Mo0K%a4Pi+kkh(KY$fB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ z0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VK zfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5 zV8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM z7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b* z1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj ZFkrxd0RsjM7%*VKfB^#r3>Yx*JTQ*V00961 literal 0 HcmV?d00001 diff --git a/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/header.bin b/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/header.bin new file mode 100644 index 0000000000000000000000000000000000000000..bb54792626c8e16cb8f8a2b989bd1998268ad65c GIT binary patch literal 100 rcmZQ%K!6kk6U^#ig9x<1XsG;uC=h`16`(YX|F20q)m`+uJfl1n8)tk&9MMb zqQdt*eQ5FE)1jB06}WEauZau3c4!lDRcDQB=8lo18#=6(4Em_F6dhBXiEA1b=}1GtKPVNC6Dg^XtH;C?&O0z RPv=)IkM=(~F3GyF=?4c69y$O3 literal 0 HcmV?d00001 diff --git a/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/link_lists.bin b/chroma_db/6f7bc640-f0f3-49c9-bb37-3e55ae6d9dcb/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/chroma.sqlite3 b/chroma_db/chroma.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..8aabcf552b8c42cf91357d32ab56e26ad6fa4f6a GIT binary patch literal 212992 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 aLK^q!6adu@&>Nj-uwK9k|4>jsH2oK4NGE~- literal 0 HcmV?d00001 diff --git a/dokumen/akademik.pdf b/dokumen/akademik.pdf new file mode 100644 index 0000000..2eb0b1e --- /dev/null +++ b/dokumen/akademik.pdf @@ -0,0 +1,74 @@ +%PDF-1.4 +%東京 ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 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 +<< +/Contents 8 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 7 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/PageMode /UseNone /Pages 7 0 R /Type /Catalog +>> +endobj +6 0 obj +<< +/Author (\(anonymous\)) /CreationDate (D:20261102090414+07'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20261102090414+07'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False +>> +endobj +7 0 obj +<< +/Count 1 /Kids [ 4 0 R ] /Type /Pages +>> +endobj +8 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 566 +>> +stream +Gat=fbAQ&g&4Q?mMHRLkU5H*ae&sq<9cln,rP0gljcMsbTh#=bq[R=CZ%Kta%0;,IEpas>\H6gN6s:ZA^m>Blh?sl&W;_;qZ3%$JE*(;UAn&E`P-?E(-KSEO"Wugi^bmpN'pBUR)O=QWOATbtLdH-MQ0V]GEM[(BJ5ui\n@:o_%<_.R2`T1RN$"^-Tt5g0P6,X^2h.a-LiR7le^79\s3YD?*\:ffo<6!ZeCC7Z\(m>3AIC5=0[r41,SK_5Xe9Wg*fRN:[\71PO3o!Z:j1KTD4jD:=a0+WHR\WiHB095'1>H6.3W/HlK=YeXIWeAL/eOj0a`&q6(/hZ&Aj&d-\k7NT3G\ZkT]c)fcVMZTQFm]+H\\>oW<@`+(pqRU7*&U^c3@\I(>q*aqiV7(^dW+sp>8FYkF(+m3faerOToA6s>kUY:Cm311AZrJP;+(@1!S_X&AN=&G^~>endstream +endobj +xref +0 9 +0000000000 65535 f +0000000061 00000 n +0000000102 00000 n +0000000209 00000 n +0000000321 00000 n +0000000524 00000 n +0000000592 00000 n +0000000872 00000 n +0000000931 00000 n +trailer +<< +/ID +[<430fe01d3101a78d4a66e001f226174a><430fe01d3101a78d4a66e001f226174a>] +% ReportLab generated PDF document -- digest (opensource) + +/Info 6 0 R +/Root 5 0 R +/Size 9 +>> +startxref +1587 +%%EOF diff --git a/dokumen/kemahasiswaan.pdf b/dokumen/kemahasiswaan.pdf new file mode 100644 index 0000000..f7865d8 --- /dev/null +++ b/dokumen/kemahasiswaan.pdf @@ -0,0 +1,74 @@ +%PDF-1.4 +%東京 ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 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 +<< +/Contents 8 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 7 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/PageMode /UseNone /Pages 7 0 R /Type /Catalog +>> +endobj +6 0 obj +<< +/Author (\(anonymous\)) /CreationDate (D:20261102090414+07'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20261102090414+07'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False +>> +endobj +7 0 obj +<< +/Count 1 /Kids [ 4 0 R ] /Type /Pages +>> +endobj +8 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 516 +>> +stream +Gatn"d8%PD&4PLPMKqT'Z&:1bO-8]7(cCOg%!3rID7A0R9)O%6.o\3#+u)gGA7t&mSWd7Y!C+H9QNb/]L>,3!@L2K26oYGqT#3qNHg?Mok?,S\'E]d3OsdaNpd18>GZM1l4BSi;&;4kqL;QJo*"2ld8hS-joO#rj2&_kB#9*Te<.ShlA@IBW$K;KRCUcBn@4/8V*4le[lfL]O,bmR@%K4SX1"r8"0-bf_^KisZcDuko4DU:\C9SuuTRDM;X/'XL@&f9jk_+%Gu""SJ@L`-q,OQQ)!<$.[?cBj.uJ[G#(ZMZ`78r1_T\3(A+Y`c5#t>N`.DJ%meekooi2A1giX^G"JU1+B=\Yf3+p0P.J>b"^rEJof/?C9lNGendstream +endobj +xref +0 9 +0000000000 65535 f +0000000061 00000 n +0000000102 00000 n +0000000209 00000 n +0000000321 00000 n +0000000524 00000 n +0000000592 00000 n +0000000872 00000 n +0000000931 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 6 0 R +/Root 5 0 R +/Size 9 +>> +startxref +1537 +%%EOF diff --git a/dokumen/keuangan.pdf b/dokumen/keuangan.pdf new file mode 100644 index 0000000..bbb93d2 --- /dev/null +++ b/dokumen/keuangan.pdf @@ -0,0 +1,74 @@ +%PDF-1.4 +%東京 ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 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 +<< +/Contents 8 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 7 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +5 0 obj +<< +/PageMode /UseNone /Pages 7 0 R /Type /Catalog +>> +endobj +6 0 obj +<< +/Author (\(anonymous\)) /CreationDate (D:20261102090414+07'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20261102090414+07'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False +>> +endobj +7 0 obj +<< +/Count 1 /Kids [ 4 0 R ] /Type /Pages +>> +endobj +8 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 539 +>> +stream +Gat=fb>,r/&4Q?lMHL]?8fX#F/4"k^5lrK"0HmS\`-+cnKDP=9dPQBN/Y]Nb7@r,%j!u83,MMUA"aJ8Lp/up%+e+$R7LdrV9rR7p'KD0h!ERqP'9+eC.-dV3=(UUq@B8k]hrm(t@%@3Z7W`^=D:Hjf&*N#l5>\f;THJku./A1GL7AI#S6,jq"/_o;!3^ESJq^&$ejZ*6O:;C#X>4GjD+"nUeAU=OK+#NC\#MR@kXT8E9;7Vd7endstream +endobj +xref +0 9 +0000000000 65535 f +0000000061 00000 n +0000000102 00000 n +0000000209 00000 n +0000000321 00000 n +0000000524 00000 n +0000000592 00000 n +0000000872 00000 n +0000000931 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 6 0 R +/Root 5 0 R +/Size 9 +>> +startxref +1560 +%%EOF diff --git a/evaluasi_retrieval.py b/evaluasi_retrieval.py new file mode 100644 index 0000000..ac09f35 --- /dev/null +++ b/evaluasi_retrieval.py @@ -0,0 +1,36 @@ +import chromadb +from chromadb.utils import embedding_functions + +# Panggil DB dan Model +emb = embedding_functions.SentenceTransformerEmbeddingFunction( + model_name="paraphrase-multilingual-MiniLM-L12-v2") +client = chromadb.PersistentClient(path="./chroma_db") +koleksi = client.get_or_create_collection("pedoman", embedding_function=emb) + +# Daftar (Pertanyaan, Kata Kunci Jawaban yang HARUS ada di chunk) +UJI = [ + ("Apa syarat cuti akademik?", "cuti akademik"), + ("Berapa lama cuti akademik bisa diajukan?", "dua semester"), + ("Berapa batas kehadiran untuk ujian?", "75 persen"), + ("Bolehkah berhenti kuliah sementara?", "cuti akademik"), + ("Bagaimana cara mengajukan beasiswa?", "beasiswa"), + ("Apa sanksi jika telat bayar kuliah?", "terlambat melakukan pembayaran"), + ("Kapan batas pembayaran biaya kuliah?", "dua minggu sebelum"), + ("Apa yang harus disimpan setelah bayar?", "bukti pembayaran") +] + +def hit_at_k(uji, k=3): + benar = 0 + for pertanyaan, kunci in uji: + # Ambil k hasil teratas + hasil = koleksi.query(query_texts=[pertanyaan], n_results=k)["documents"][0] + # Cek apakah kunci ada di salah satu hasil + if any(kunci.lower() in d.lower() for d in hasil): + benar += 1 + return benar / len(uji) + +print(f"Total pertanyaan uji: {len(UJI)}\n") +print("Mengevaluasi Retrieval...") +for k in (1, 3, 5): + skor = hit_at_k(UJI, k) + print(f"Hit@{k} = {skor:.2f} (Benar {int(skor*len(UJI))} dari {len(UJI)} pertanyaan)") \ No newline at end of file diff --git a/indeks.py b/indeks.py new file mode 100644 index 0000000..f4153ee --- /dev/null +++ b/indeks.py @@ -0,0 +1,38 @@ +from pathlib import Path +from pypdf import PdfReader +import chromadb +from chromadb.utils import embedding_functions + +def baca_pdf(path): + r = PdfReader(path) + return "\n".join((p.extract_text() or "") for p in r.pages) + +def potong(teks, ukuran=500, tumpang=75): + hasil, mulai = [], 0 + while mulai < len(teks): + hasil.append(teks[mulai:mulai + ukuran]) + mulai += ukuran - tumpang + return [h for h in hasil if h.strip()] + +print("Menyiapkan model embedding (unduh jika belum ada)...") +# Model multilingual agar bisa bahasa Indonesia +emb = embedding_functions.SentenceTransformerEmbeddingFunction( + model_name="paraphrase-multilingual-MiniLM-L12-v2") + +client = chromadb.PersistentClient(path="./chroma_db") +koleksi = client.get_or_create_collection( + name="pedoman", embedding_function=emb, + metadata={"hnsw:space": "cosine"}) + +# Proses tiap PDF +for pdf in Path("dokumen").glob("*.pdf"): + teks = baca_pdf(pdf) + chunks = potong(teks, ukuran=500, tumpang=75) # Pakai ukuran 500 + koleksi.upsert( + ids=[f"{pdf.stem}-{i}" for i in range(len(chunks))], + documents=chunks, + metadatas=[{"sumber": pdf.name, "chunk": i} for i in range(len(chunks))], + ) + print(f"{pdf.name} 竊� {len(chunks)} chunk disimpan.") + +print("\nSelesai! Indeks tersimpan di folder 'chroma_db'.") \ No newline at end of file diff --git a/lab1_chunking.py b/lab1_chunking.py new file mode 100644 index 0000000..135875d --- /dev/null +++ b/lab1_chunking.py @@ -0,0 +1,31 @@ +from pathlib import Path +from pypdf import PdfReader + +def baca_pdf(path): + r = PdfReader(path) + return "\n".join((p.extract_text() or "") for p in r.pages) + +def potong(teks, ukuran=800, tumpang=100): + hasil, mulai = [], 0 + while mulai < len(teks): + hasil.append(teks[mulai:mulai + ukuran]) + mulai += ukuran - tumpang + return [h for h in hasil if h.strip()] + +# Gabungkan semua teks PDF untuk simulasi dokumen besar +semua_teks = "" +for pdf in Path("dokumen").glob("*.pdf"): + semua_teks += baca_pdf(pdf) + "\n\n" + +print("Total panjang teks semua PDF:", len(semua_teks), "karakter\n") + +for ukuran in (500, 1000, 1500): + tumpang = int(ukuran * 0.15) # Overlap 15% + chunks = potong(semua_teks, ukuran, tumpang) + print(f"=== Ukuran: {ukuran}, Overlap: {tumpang} ===") + print(f"Jumlah chunk yang dihasilkan: {len(chunks)}") + # Cetak 100 karakter pertama dari chunk ke-1 dan terakhir + print(f"Chunk 1: {repr(chunks[0][:100])}...") + if len(chunks) > 1: + print(f"Chunk akhir: {repr(chunks[-1][:100])}...") + print("-" * 40) \ No newline at end of file