<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://onnocenter.or.id/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Onnowpurbo</id>
	<title>OnnoWiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://onnocenter.or.id/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Onnowpurbo"/>
	<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php/Special:Contributions/Onnowpurbo"/>
	<updated>2026-07-27T05:49:17Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.35.4</generator>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Reset_dari_nol,_embed_semua_doc,_isi_vector_database&amp;diff=73727</id>
		<title>MCP: Reset dari nol, embed semua doc, isi vector database</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Reset_dari_nol,_embed_semua_doc,_isi_vector_database&amp;diff=73727"/>
		<updated>2026-07-26T02:54:55Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;# Rekomendasi  **Tidak perlu install ulang AnythingLLM.** Gunakan reset melalui API lalu lakukan **restart normal**, bukan `docker kill` atau force restart.  Menghapus dan mem...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Rekomendasi&lt;br /&gt;
&lt;br /&gt;
**Tidak perlu install ulang AnythingLLM.** Gunakan reset melalui API lalu lakukan **restart normal**, bukan `docker kill` atau force restart.&lt;br /&gt;
&lt;br /&gt;
Menghapus dan membuat ulang container dengan storage volume yang sama tidak menghapus workspace, dokumen, atau vector database karena data AnythingLLM disimpan di `/app/server/storage` dan memang dirancang tetap ada setelah rebuild atau pull image baru. ([AnythingLLM][1])&lt;br /&gt;
&lt;br /&gt;
Script berikut menggunakan API resmi untuk:&lt;br /&gt;
&lt;br /&gt;
1. Backup seluruh storage AnythingLLM.&lt;br /&gt;
2. Menghapus semua workspace.&lt;br /&gt;
3. Menghapus semua dokumen internal dan cached embedding.&lt;br /&gt;
4. Restart container secara graceful.&lt;br /&gt;
5. Membuat satu workspace baru.&lt;br /&gt;
6. Upload dan embed ulang seluruh file dari `/opt/ai-stack/documents`.&lt;br /&gt;
7. Membuat manifest berisi nama file, hash SHA-256, dan lokasi dokumen internal.&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menyediakan endpoint resmi untuk mendaftar dan menghapus workspace, menghapus dokumen permanen, membuat workspace, serta upload dokumen langsung ke workspace. &lt;br /&gt;
&lt;br /&gt;
[Download reset-rebuild-anythingllm.sh](sandbox:/mnt/data/reset-rebuild-anythingllm.sh)&lt;br /&gt;
&lt;br /&gt;
Script sudah diperiksa dengan `bash -n`.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 1. Copy script ke server&lt;br /&gt;
&lt;br /&gt;
Misalnya file sudah berada di folder Downloads:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mkdir -p /opt/ai-stack/batch&lt;br /&gt;
&lt;br /&gt;
sudo cp ~/Downloads/reset-rebuild-anythingllm.sh \&lt;br /&gt;
  /opt/ai-stack/batch/&lt;br /&gt;
&lt;br /&gt;
sudo chmod 750 \&lt;br /&gt;
  /opt/ai-stack/batch/reset-rebuild-anythingllm.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lh /opt/ai-stack/batch/reset-rebuild-anythingllm.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. Periksa nama dan port container&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}' \&lt;br /&gt;
  | grep -i anything&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atau:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker port anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
3001/tcp -&amp;gt; 0.0.0.0:3001&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Berarti:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_URL=&amp;quot;http://127.0.0.1:3001&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Apabila AnythingLLM memakai port host `3002`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_URL=&amp;quot;http://127.0.0.1:3002&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hal ini penting bila port `3001` sudah digunakan WAHA.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. Buat API key AnythingLLM&lt;br /&gt;
&lt;br /&gt;
Masuk ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
AnythingLLM&lt;br /&gt;
→ Settings&lt;br /&gt;
→ Developer API&lt;br /&gt;
→ API Keys&lt;br /&gt;
→ New API Key&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dokumentasi API pada instance tersedia di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:PORT/api/docs&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
API key harus disimpan sebagai rahasia karena siapa pun yang memilikinya dapat mengoperasikan API AnythingLLM. ([AnythingLLM][2])&lt;br /&gt;
&lt;br /&gt;
Set API key:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_API_KEY='MASUKKAN_API_KEY_ANDA'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan menyimpan API key langsung di dalam script.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. Tentukan konfigurasi&lt;br /&gt;
&lt;br /&gt;
Untuk hanya meng-embed Markdown:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export DOCUMENT_ROOT=&amp;quot;/opt/ai-stack/documents&amp;quot;&lt;br /&gt;
export WORKSPACE_NAME=&amp;quot;Perpustakaan&amp;quot;&lt;br /&gt;
export CONTAINER_NAME=&amp;quot;anythingllm&amp;quot;&lt;br /&gt;
export EMBED_EXTENSIONS=&amp;quot;md&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk Markdown, PDF, DOCX, dan TXT:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export EMBED_EXTENSIONS=&amp;quot;md,pdf,docx,txt&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Saya menyarankan memakai:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export EMBED_EXTENSIONS=&amp;quot;md&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
bila semua PDF sudah dikonversi dan dibersihkan menjadi Markdown untuk RAG. Ini mencegah isi yang sama ter-embed dua kali dari versi PDF dan Markdown.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. Pastikan API key bekerja&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/auth&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;authenticated&amp;quot;: true&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Jalankan dry-run dahulu&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
/opt/ai-stack/batch/reset-rebuild-anythingllm.sh \&lt;br /&gt;
  --dry-run&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dry-run hanya menghitung:&lt;br /&gt;
&lt;br /&gt;
* Jumlah workspace lama.&lt;br /&gt;
* Jumlah dokumen internal lama.&lt;br /&gt;
* Jumlah file sumber yang akan di-embed.&lt;br /&gt;
* Ekstensi yang diproses.&lt;br /&gt;
* Nama workspace baru.&lt;br /&gt;
&lt;br /&gt;
Tidak ada data yang dihapus.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Jalankan reset dan rebuild&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
/opt/ai-stack/batch/reset-rebuild-anythingllm.sh \&lt;br /&gt;
  --yes-reset&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika user belum mendapat akses Docker dan direktori backup:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo -E /opt/ai-stack/batch/reset-rebuild-anythingllm.sh \&lt;br /&gt;
  --yes-reset&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Opsi `-E` mempertahankan variabel lingkungan seperti API key dan URL.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Hasil backup&lt;br /&gt;
&lt;br /&gt;
Sebelum menghapus data, script menghentikan container sementara dan membuat backup konsisten:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/backups/anythingllm-storage-YYYYMMDD-HHMMSS.tar.gz&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lh /opt/ai-stack/backups/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
anythingllm-storage-20260726-103000.tar.gz&lt;br /&gt;
anythingllm-rebuild-manifest-20260726-103215.tsv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Manifest berisi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
relative_path    sha256    anythingllm_location&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
AI/RAG/Pengenalan RAG.md    a421...    custom-documents/Pengenalan-RAG.md-uuid.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. Pantau proses&lt;br /&gt;
&lt;br /&gt;
Terminal lain:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker logs -f anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pantau resource:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker stats anythingllm ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pantau GPU ketika embedding memakai Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
watch -n 1 nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 10. Verifikasi setelah selesai&lt;br /&gt;
&lt;br /&gt;
Periksa workspace:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/workspaces&amp;quot; \&lt;br /&gt;
  | python3 -m json.tool&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Seharusnya hanya terdapat satu workspace baru.&lt;br /&gt;
&lt;br /&gt;
Periksa dokumen:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/documents&amp;quot; \&lt;br /&gt;
  | python3 -m json.tool&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menjelaskan bahwa menghapus dokumen secara permanen dari sistem akan menghapus parsed source, cached embedding, serta mengeluarkannya dari setiap workspace. ([AnythingLLM][3])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Apakah perlu force restart?&lt;br /&gt;
&lt;br /&gt;
## Pilihan terbaik: reset API + restart normal&lt;br /&gt;
&lt;br /&gt;
Script menggunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker restart -t 30 anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini memberikan waktu sampai 30 detik agar proses berhenti secara normal sebelum Docker mengambil tindakan lanjutan.&lt;br /&gt;
&lt;br /&gt;
**Jangan menggunakan ini kecuali container macet:**&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker kill anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Force restart tidak membersihkan vector database. Ia hanya menghentikan dan menyalakan proses.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Kapan perlu install ulang?&lt;br /&gt;
&lt;br /&gt;
Install ulang atau factory reset hanya diperlukan apabila:&lt;br /&gt;
&lt;br /&gt;
* SQLite AnythingLLM rusak.&lt;br /&gt;
* LanceDB rusak dan API tidak dapat membersihkannya.&lt;br /&gt;
* Container terus crash akibat storage internal.&lt;br /&gt;
* Konfigurasi sistem sudah sangat kacau.&lt;br /&gt;
* Anda benar-benar ingin menghapus user, API key, model settings, MCP, agent skills, chat history, dan seluruh konfigurasi.&lt;br /&gt;
&lt;br /&gt;
Menarik image atau membuat ulang container **tanpa menghapus storage** bukan factory reset karena data tetap persisten. ([AnythingLLM][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Factory reset penuh&lt;br /&gt;
&lt;br /&gt;
Ini **bukan pilihan utama**. Perintah berikut menghilangkan seluruh konfigurasi aplikasi, bukan hanya RAG.&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose stop anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cari lokasi storage:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker inspect anythingllm \&lt;br /&gt;
  --format '{{range .Mounts}}{{println .Source &amp;quot;-&amp;gt;&amp;quot; .Destination}}{{end}}'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/anythingllm/storage -&amp;gt; /app/server/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Backup dan ganti nama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mv \&lt;br /&gt;
  /opt/ai-stack/anythingllm/storage \&lt;br /&gt;
  &amp;quot;/opt/ai-stack/anythingllm/storage.factory-reset.$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat storage kosong:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mkdir -p /opt/ai-stack/anythingllm/storage&lt;br /&gt;
sudo chown -R 1000:1000 /opt/ai-stack/anythingllm/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose up -d anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
AnythingLLM kemudian tampil seperti instalasi pertama. Anda harus mengatur ulang:&lt;br /&gt;
&lt;br /&gt;
* Akun administrator.&lt;br /&gt;
* LLM provider.&lt;br /&gt;
* Embedding provider.&lt;br /&gt;
* Vector database.&lt;br /&gt;
* API key.&lt;br /&gt;
* MCP dan agent skills.&lt;br /&gt;
* Workspace.&lt;br /&gt;
* Dokumen.&lt;br /&gt;
&lt;br /&gt;
Karena tujuan Anda adalah membersihkan workspace dan membangun ulang seluruh embedding, **gunakan script API-reset, bukan factory reset dan bukan install ulang**.&lt;br /&gt;
&lt;br /&gt;
[1]: https://docs.anythingllm.com/installation-docker/local-docker &amp;quot;Local Docker Installation ~ AnythingLLM&amp;quot;&lt;br /&gt;
[2]: https://docs.anythingllm.com/features/api &amp;quot;API Access &amp;amp; Keys ~ AnythingLLM&amp;quot;&lt;br /&gt;
[3]: https://docs.anythingllm.com/features/privacy-and-data-handling &amp;quot;Privacy &amp;amp; Data ~ AnythingLLM&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73726</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73726"/>
		<updated>2026-07-26T02:47:25Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* MCP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==MCP==&lt;br /&gt;
&lt;br /&gt;
* [[MCP: Instalasi]]&lt;br /&gt;
* [[MCP: Convert PDF ke .md]]&lt;br /&gt;
* [[MCP: Instalasi pip]]&lt;br /&gt;
* [[MCP: Regenerate Vector Database untuk update content documents]]&lt;br /&gt;
* [[MCP: Reset dari nol, embed semua doc, isi vector database]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Regenerate_Vector_Database_untuk_update_content_documents&amp;diff=73725</id>
		<title>MCP: Regenerate Vector Database untuk update content documents</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Regenerate_Vector_Database_untuk_update_content_documents&amp;diff=73725"/>
		<updated>2026-07-26T02:44:03Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Teknik memperbarui vector database AnythingLLM&lt;br /&gt;
&lt;br /&gt;
## Prinsip utama&lt;br /&gt;
&lt;br /&gt;
**Tidak perlu me-reset seluruh vector database setiap kali ada file `.md` baru.**&lt;br /&gt;
&lt;br /&gt;
Gunakan dua pola:&lt;br /&gt;
&lt;br /&gt;
| Perubahan folder            | Tindakan                                                 |&lt;br /&gt;
| --------------------------- | -------------------------------------------------------- |&lt;br /&gt;
| Ada file `.md` baru         | Upload dan embed file baru saja                          |&lt;br /&gt;
| Isi file `.md` lama berubah | Hapus embedding versi lama, lalu upload ulang            |&lt;br /&gt;
| File `.md` dihapus          | Hapus dari workspace dan hapus permanen dari AnythingLLM |&lt;br /&gt;
| Ganti embedding model       | Rebuild seluruh vector database                          |&lt;br /&gt;
| Ganti vector database       | Rebuild seluruh vector database                          |&lt;br /&gt;
| Ubah chunking secara besar  | Sebaiknya rebuild seluruh database                       |&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menetapkan embedding model dan vector database secara system-wide. Ketika embedder atau vector database diganti, dokumen lama perlu dihapus dan di-embed ulang; AnythingLLM tidak otomatis memindahkan vector lama. ([AnythingLLM][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 1. Folder `documents` bukan vector database&lt;br /&gt;
&lt;br /&gt;
Misalnya perpustakaan berada di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menambahkan file:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents/AI/buku-baru.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**tidak otomatis membuat embedding baru di AnythingLLM.**&lt;br /&gt;
&lt;br /&gt;
Folder tersebut sebaiknya dianggap sebagai:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Source Library / Master Documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sedangkan database AnythingLLM berada pada storage internal AnythingLLM, misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/anythingllm/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Fitur Automatic Document Sync AnythingLLM belum dapat mengawasi satu direktori lokal secara keseluruhan. Pada instalasi Docker, file lokal yang hanya disalin ke folder host juga tidak otomatis disinkronkan sebagai dokumen baru. ([docs.anythingllm.com][2])&lt;br /&gt;
&lt;br /&gt;
Arsitektur yang direkomendasikan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/&lt;br /&gt;
├── documents/                    # Dokumen master&lt;br /&gt;
│   ├── AI/&lt;br /&gt;
│   ├── CYBER-SECURITY/&lt;br /&gt;
│   └── ONNO-PDF/&lt;br /&gt;
│&lt;br /&gt;
├── anythingllm/&lt;br /&gt;
│   └── storage/                  # Database internal AnythingLLM&lt;br /&gt;
│&lt;br /&gt;
└── batch/&lt;br /&gt;
    ├── sync-anythingllm.sh&lt;br /&gt;
    └── .anythingllm-sync/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 2. Metode manual untuk file baru&lt;br /&gt;
&lt;br /&gt;
Untuk jumlah file sedikit:&lt;br /&gt;
&lt;br /&gt;
1. Masuk ke AnythingLLM.&lt;br /&gt;
2. Buka workspace tujuan.&lt;br /&gt;
3. Buka pengelolaan dokumen workspace.&lt;br /&gt;
4. Upload file `.md` baru.&lt;br /&gt;
5. Pindahkan file ke workspace.&lt;br /&gt;
6. Klik **Save and Embed** atau tombol embedding yang tersedia.&lt;br /&gt;
7. Tunggu sampai proses embedding selesai.&lt;br /&gt;
8. Uji dengan pertanyaan yang hanya dapat dijawab oleh file baru.&lt;br /&gt;
&lt;br /&gt;
Metode ini hanya menambah vector untuk file baru. Dokumen lama tidak perlu diproses ulang.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 3. Metode API untuk banyak file `.md`&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menyediakan Developer API untuk meng-upload, mengelola, meng-embed, dan memperbarui dokumen workspace. Dokumentasi API instance tersedia pada `/api/docs`. API key harus dirahasiakan karena siapa pun yang memilikinya dapat menggunakan API instance. ([AnythingLLM][3])&lt;br /&gt;
&lt;br /&gt;
Misalnya alamat AnythingLLM:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://127.0.0.1:3001&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dokumentasi API:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://127.0.0.1:3001/api/docs&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Membuat API key&lt;br /&gt;
&lt;br /&gt;
Di AnythingLLM:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Settings&lt;br /&gt;
→ Developer API&lt;br /&gt;
→ API Keys&lt;br /&gt;
→ New API Key&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Simpan key, misalnya:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_API_KEY='MASUKKAN_API_KEY'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan memasukkan API key ke Git repository.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Tentukan konfigurasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_URL=&amp;quot;http://127.0.0.1:3001&amp;quot;&lt;br /&gt;
export WORKSPACE_SLUG=&amp;quot;perpustakaan&amp;quot;&lt;br /&gt;
export DOCUMENT_ROOT=&amp;quot;/opt/ai-stack/documents&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`WORKSPACE_SLUG` bukan selalu nama tampilan workspace.&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Nama workspace : Perpustakaan Onno&lt;br /&gt;
Slug           : perpustakaan-onno&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Uji API key&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/auth&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;authenticated&amp;quot;: true&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Upload satu file dan langsung embed&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -X POST \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  -F &amp;quot;file=@/opt/ai-stack/documents/AI/buku-baru.md&amp;quot; \&lt;br /&gt;
  -F &amp;quot;addToWorkspaces=${WORKSPACE_SLUG}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/document/upload&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Endpoint upload resmi menerima file multipart dan parameter `addToWorkspaces`, yaitu daftar slug workspace tempat dokumen akan langsung di-embed setelah upload. Responsnya mengembalikan lokasi dokumen internal AnythingLLM. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
Contoh respons:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;success&amp;quot;: true,&lt;br /&gt;
  &amp;quot;error&amp;quot;: null,&lt;br /&gt;
  &amp;quot;documents&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;location&amp;quot;: &amp;quot;custom-documents/buku-baru.md-uuid.json&amp;quot;,&lt;br /&gt;
      &amp;quot;title&amp;quot;: &amp;quot;buku-baru.md&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Nilai `location` perlu disimpan karena digunakan saat menghapus atau mengganti dokumen.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 4. Script untuk folder yang hanya bertambah&lt;br /&gt;
&lt;br /&gt;
Metode ini cocok jika:&lt;br /&gt;
&lt;br /&gt;
* File yang sudah masuk tidak diedit.&lt;br /&gt;
* File tidak diganti dengan nama yang sama.&lt;br /&gt;
* Folder hanya mendapatkan file baru.&lt;br /&gt;
&lt;br /&gt;
Instal `jq`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y jq&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat folder script:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mkdir -p /opt/ai-stack/batch&lt;br /&gt;
sudo chown -R &amp;quot;$USER&amp;quot;:&amp;quot;$USER&amp;quot; /opt/ai-stack/batch&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat script:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nano /opt/ai-stack/batch/sync-new-md-anythingllm.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
#!/usr/bin/env bash&lt;br /&gt;
&lt;br /&gt;
set -Eeuo pipefail&lt;br /&gt;
&lt;br /&gt;
DOCUMENT_ROOT=&amp;quot;${DOCUMENT_ROOT:-/opt/ai-stack/documents}&amp;quot;&lt;br /&gt;
ANYTHINGLLM_URL=&amp;quot;${ANYTHINGLLM_URL:-http://127.0.0.1:3001}&amp;quot;&lt;br /&gt;
WORKSPACE_SLUG=&amp;quot;${WORKSPACE_SLUG:-perpustakaan}&amp;quot;&lt;br /&gt;
STATE_DIR=&amp;quot;${STATE_DIR:-/opt/ai-stack/batch/.anythingllm-sync}&amp;quot;&lt;br /&gt;
MARKER_FILE=&amp;quot;${STATE_DIR}/last-successful-sync&amp;quot;&lt;br /&gt;
LOG_FILE=&amp;quot;${STATE_DIR}/sync.log&amp;quot;&lt;br /&gt;
&lt;br /&gt;
: &amp;quot;${ANYTHINGLLM_API_KEY:?ANYTHINGLLM_API_KEY belum di-set}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
mkdir -p &amp;quot;$STATE_DIR&amp;quot;&lt;br /&gt;
touch &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
log() {&lt;br /&gt;
    printf '[%s] %s\n' &amp;quot;$(date '+%F %T')&amp;quot; &amp;quot;$*&amp;quot; | tee -a &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [[ ! -d &amp;quot;$DOCUMENT_ROOT&amp;quot; ]]; then&lt;br /&gt;
    log &amp;quot;ERROR: folder tidak ditemukan: $DOCUMENT_ROOT&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
# Marker sangat lama untuk proses pertama.&lt;br /&gt;
if [[ ! -e &amp;quot;$MARKER_FILE&amp;quot; ]]; then&lt;br /&gt;
    touch -t 197001010000 &amp;quot;$MARKER_FILE&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
TEMP_MARKER=&amp;quot;$(mktemp &amp;quot;${STATE_DIR}/sync-marker.XXXXXX&amp;quot;)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
success_count=0&lt;br /&gt;
failed_count=0&lt;br /&gt;
&lt;br /&gt;
while IFS= read -r -d '' file; do&lt;br /&gt;
    log &amp;quot;Upload: $file&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    response=&amp;quot;$(&lt;br /&gt;
        curl --fail --silent --show-error \&lt;br /&gt;
            -X POST \&lt;br /&gt;
            -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
            -F &amp;quot;file=@${file}&amp;quot; \&lt;br /&gt;
            -F &amp;quot;addToWorkspaces=${WORKSPACE_SLUG}&amp;quot; \&lt;br /&gt;
            &amp;quot;${ANYTHINGLLM_URL}/api/v1/document/upload&amp;quot;&lt;br /&gt;
    )&amp;quot; || {&lt;br /&gt;
        log &amp;quot;GAGAL upload: $file&amp;quot;&lt;br /&gt;
        failed_count=$((failed_count + 1))&lt;br /&gt;
        continue&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    success=&amp;quot;$(jq -r '.success // false' &amp;lt;&amp;lt;&amp;lt;&amp;quot;$response&amp;quot;)&amp;quot;&lt;br /&gt;
    error=&amp;quot;$(jq -r '.error // empty' &amp;lt;&amp;lt;&amp;lt;&amp;quot;$response&amp;quot;)&amp;quot;&lt;br /&gt;
    location=&amp;quot;$(jq -r '.documents[0].location // empty' &amp;lt;&amp;lt;&amp;lt;&amp;quot;$response&amp;quot;)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if [[ &amp;quot;$success&amp;quot; != &amp;quot;true&amp;quot; || -n &amp;quot;$error&amp;quot; || -z &amp;quot;$location&amp;quot; ]]; then&lt;br /&gt;
        log &amp;quot;GAGAL diproses: $file&amp;quot;&lt;br /&gt;
        log &amp;quot;Respons: $response&amp;quot;&lt;br /&gt;
        failed_count=$((failed_count + 1))&lt;br /&gt;
        continue&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    log &amp;quot;BERHASIL: $file&amp;quot;&lt;br /&gt;
    log &amp;quot;AnythingLLM location: $location&amp;quot;&lt;br /&gt;
    success_count=$((success_count + 1))&lt;br /&gt;
&lt;br /&gt;
done &amp;lt; &amp;lt;(&lt;br /&gt;
    find &amp;quot;$DOCUMENT_ROOT&amp;quot; \&lt;br /&gt;
        -type f \&lt;br /&gt;
        -iname '*.md' \&lt;br /&gt;
        -newer &amp;quot;$MARKER_FILE&amp;quot; \&lt;br /&gt;
        -print0&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
if (( failed_count == 0 )); then&lt;br /&gt;
    mv &amp;quot;$TEMP_MARKER&amp;quot; &amp;quot;$MARKER_FILE&amp;quot;&lt;br /&gt;
    log &amp;quot;Sinkronisasi selesai. Berhasil=$success_count Gagal=0&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    rm -f &amp;quot;$TEMP_MARKER&amp;quot;&lt;br /&gt;
    log &amp;quot;Sinkronisasi belum ditandai selesai karena ada kegagalan.&amp;quot;&lt;br /&gt;
    log &amp;quot;Berhasil=$success_count Gagal=$failed_count&amp;quot;&lt;br /&gt;
    exit 1&lt;br /&gt;
fi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Simpan lalu beri izin:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod +x /opt/ai-stack/batch/sync-new-md-anythingllm.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
export ANYTHINGLLM_API_KEY='MASUKKAN_API_KEY'&lt;br /&gt;
export WORKSPACE_SLUG='perpustakaan-onno'&lt;br /&gt;
&lt;br /&gt;
/opt/ai-stack/batch/sync-new-md-anythingllm.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lihat log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
tail -f /opt/ai-stack/batch/.anythingllm-sync/sync.log&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Peringatan&lt;br /&gt;
&lt;br /&gt;
Script marker ini akan menganggap file yang diedit sebagai file baru. AnythingLLM dapat membuat dokumen baru dengan UUID baru sehingga embedding versi lama masih ada.&lt;br /&gt;
&lt;br /&gt;
Karena itu, metode ini hanya aman untuk perpustakaan **append-only**.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 5. Teknik yang benar ketika isi `.md` diperbarui&lt;br /&gt;
&lt;br /&gt;
Misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents/AI/pengenalan-rag.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
sudah pernah di-embed, kemudian isinya diedit.&lt;br /&gt;
&lt;br /&gt;
Jangan langsung upload ulang tanpa menghapus versi lama karena dapat menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Embedding lama&lt;br /&gt;
+&lt;br /&gt;
Embedding baru&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Akibatnya, hasil RAG dapat mengambil informasi lama dan baru sekaligus.&lt;br /&gt;
&lt;br /&gt;
Gunakan urutan berikut:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
1. Remove embedding lama dari workspace&lt;br /&gt;
2. Delete dokumen lama secara permanen&lt;br /&gt;
3. Upload file versi terbaru&lt;br /&gt;
4. Embed file baru ke workspace&lt;br /&gt;
5. Simpan mapping UUID/location yang baru&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Menghapus embedding lama dari workspace&lt;br /&gt;
&lt;br /&gt;
Misalnya lokasi internal dokumen lama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
custom-documents/pengenalan-rag.md-abc123.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -X POST \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
  -d '{&lt;br /&gt;
        &amp;quot;adds&amp;quot;: [],&lt;br /&gt;
        &amp;quot;deletes&amp;quot;: [&lt;br /&gt;
          &amp;quot;custom-documents/pengenalan-rag.md-abc123.json&amp;quot;&lt;br /&gt;
        ]&lt;br /&gt;
      }' \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/workspace/${WORKSPACE_SLUG}/update-embeddings&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Endpoint `update-embeddings` memang digunakan untuk menambah atau menghapus dokumen dari vector namespace sebuah workspace. Nilainya harus berupa path internal seperti `custom-documents/nama-file-uuid.json`, bukan nama file asli pada host. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Menghapus dokumen lama secara permanen&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -X DELETE \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
  -d '{&lt;br /&gt;
        &amp;quot;names&amp;quot;: [&lt;br /&gt;
          &amp;quot;custom-documents/pengenalan-rag.md-abc123.json&amp;quot;&lt;br /&gt;
        ]&lt;br /&gt;
      }' \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/system/remove-documents&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Developer API menyediakan endpoint `DELETE /v1/system/remove-documents` untuk menghapus dokumen internal secara permanen. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Upload versi baru&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl --fail --silent --show-error \&lt;br /&gt;
  -X POST \&lt;br /&gt;
  -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
  -F &amp;quot;file=@/opt/ai-stack/documents/AI/pengenalan-rag.md&amp;quot; \&lt;br /&gt;
  -F &amp;quot;addToWorkspaces=${WORKSPACE_SLUG}&amp;quot; \&lt;br /&gt;
  &amp;quot;${ANYTHINGLLM_URL}/api/v1/document/upload&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Simpan `documents[0].location` dari respons sebagai mapping baru.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 6. Gunakan hash untuk mendeteksi perubahan&lt;br /&gt;
&lt;br /&gt;
Untuk perpustakaan yang sering berubah, teknik terbaik adalah menyimpan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
path file&lt;br /&gt;
SHA-256&lt;br /&gt;
AnythingLLM document location&lt;br /&gt;
workspace slug&lt;br /&gt;
last sync&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh database manifest:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;/opt/ai-stack/documents/AI/pengenalan-rag.md&amp;quot;: {&lt;br /&gt;
    &amp;quot;sha256&amp;quot;: &amp;quot;1d2af7...&amp;quot;,&lt;br /&gt;
    &amp;quot;location&amp;quot;: &amp;quot;custom-documents/pengenalan-rag.md-abc123.json&amp;quot;,&lt;br /&gt;
    &amp;quot;workspace&amp;quot;: &amp;quot;perpustakaan-onno&amp;quot;,&lt;br /&gt;
    &amp;quot;last_sync&amp;quot;: &amp;quot;2026-07-26T09:30:00+07:00&amp;quot;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Saat sinkronisasi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
File belum ada di manifest&lt;br /&gt;
→ Upload dan embed&lt;br /&gt;
&lt;br /&gt;
Hash sama&lt;br /&gt;
→ Tidak melakukan apa-apa&lt;br /&gt;
&lt;br /&gt;
Hash berubah&lt;br /&gt;
→ Hapus embedding lama&lt;br /&gt;
→ Hapus dokumen lama&lt;br /&gt;
→ Upload dan embed versi baru&lt;br /&gt;
→ Update manifest&lt;br /&gt;
&lt;br /&gt;
File ada di manifest tetapi hilang dari folder&lt;br /&gt;
→ Hapus embedding&lt;br /&gt;
→ Hapus dokumen internal&lt;br /&gt;
→ Hapus entry dari manifest&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hitung hash:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sha256sum &amp;quot;/opt/ai-stack/documents/AI/pengenalan-rag.md&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Keuntungan metode hash:&lt;br /&gt;
&lt;br /&gt;
* Tidak melakukan embedding berulang tanpa alasan.&lt;br /&gt;
* Tidak membuat vector duplikat.&lt;br /&gt;
* Bisa menangani file yang berubah.&lt;br /&gt;
* Bisa menangani file yang dihapus.&lt;br /&gt;
* Bisa melakukan audit dokumen.&lt;br /&gt;
* Bisa melanjutkan proses setelah kegagalan.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 7. Kapan melakukan full regenerate&lt;br /&gt;
&lt;br /&gt;
Lakukan rebuild total jika:&lt;br /&gt;
&lt;br /&gt;
* Embedding model diganti.&lt;br /&gt;
* Provider embedder diganti.&lt;br /&gt;
* Vector database diganti, misalnya LanceDB menjadi Qdrant.&lt;br /&gt;
* Chunk size atau chunk overlap diubah secara signifikan.&lt;br /&gt;
* Banyak dokumen lama sudah tidak sinkron.&lt;br /&gt;
* Terjadi banyak embedding duplikat.&lt;br /&gt;
* Retrieval masih menampilkan isi dokumen yang sudah dihapus.&lt;br /&gt;
* Struktur koleksi diubah secara besar.&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menyatakan bahwa penggantian embedder atau vector database membutuhkan penghapusan dan embedding ulang dokumen. ([AnythingLLM][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 8. Prosedur full regenerate yang aman&lt;br /&gt;
&lt;br /&gt;
## Langkah 1 — Hentikan proses upload&lt;br /&gt;
&lt;br /&gt;
Jangan menambah atau mengedit dokumen selama rebuild.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 2 — Backup storage AnythingLLM&lt;br /&gt;
&lt;br /&gt;
Cari mount container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker inspect anythingllm \&lt;br /&gt;
  --format '{{range .Mounts}}{{println .Source &amp;quot;-&amp;gt;&amp;quot; .Destination}}{{end}}'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Misalnya hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/anythingllm/storage -&amp;gt; /app/server/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Backup:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo tar \&lt;br /&gt;
  -czf &amp;quot;anythingllm-storage-$(date +%F-%H%M%S).tar.gz&amp;quot; \&lt;br /&gt;
  anythingllm/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lh /opt/ai-stack/anythingllm-storage-*.tar.gz&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 3 — Reset melalui AnythingLLM&lt;br /&gt;
&lt;br /&gt;
Untuk tiap workspace:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Workspace&lt;br /&gt;
→ Settings&lt;br /&gt;
→ Vector Database&lt;br /&gt;
→ Reset Vector Database&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian hapus dokumen lama dari daftar dokumen apabila memang akan membangun ulang semuanya.&lt;br /&gt;
&lt;br /&gt;
**Jangan langsung menghapus folder LanceDB secara manual** sementara AnythingLLM berjalan. Database vector, database aplikasi, cache dokumen, dan relasi workspace dapat menjadi tidak konsisten.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 4 — Pastikan konfigurasi embedder final&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Embedding provider : Ollama&lt;br /&gt;
Embedding model    : nomic-embed-text&lt;br /&gt;
Vector database    : LanceDB&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan mengganti model embedding di tengah proses ingest.&lt;br /&gt;
&lt;br /&gt;
Model chat dan model embedding adalah dua hal berbeda:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Model chat:&lt;br /&gt;
qwen3:8b&lt;br /&gt;
&lt;br /&gt;
Model embedding:&lt;br /&gt;
nomic-embed-text&lt;br /&gt;
atau model embedding lain&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 5 — Upload semua `.md`&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
find /opt/ai-stack/documents \&lt;br /&gt;
  -type f \&lt;br /&gt;
  -iname '*.md' \&lt;br /&gt;
  -print0 |&lt;br /&gt;
while IFS= read -r -d '' file; do&lt;br /&gt;
    echo &amp;quot;Embedding: $file&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    curl --fail --silent --show-error \&lt;br /&gt;
      -X POST \&lt;br /&gt;
      -H &amp;quot;Authorization: Bearer ${ANYTHINGLLM_API_KEY}&amp;quot; \&lt;br /&gt;
      -F &amp;quot;file=@${file}&amp;quot; \&lt;br /&gt;
      -F &amp;quot;addToWorkspaces=${WORKSPACE_SLUG}&amp;quot; \&lt;br /&gt;
      &amp;quot;${ANYTHINGLLM_URL}/api/v1/document/upload&amp;quot; |&lt;br /&gt;
      jq .&lt;br /&gt;
done&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 6 — Pantau log&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose logs -f anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atau:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker logs -f anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perhatikan error seperti:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
failed to embed&lt;br /&gt;
failed to vectorize&lt;br /&gt;
document processing API is not online&lt;br /&gt;
fetch failed&lt;br /&gt;
out of memory&lt;br /&gt;
connection refused&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Langkah 7 — Verifikasi RAG&lt;br /&gt;
&lt;br /&gt;
Buat satu file pengujian:&lt;br /&gt;
&lt;br /&gt;
```markdown&lt;br /&gt;
---&lt;br /&gt;
title: Dokumen Uji Sinkronisasi&lt;br /&gt;
document_id: TEST-RAG-20260726&lt;br /&gt;
version: 1&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
Kode verifikasi perpustakaan adalah MERAH-7261.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Upload lalu tanyakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Apa kode verifikasi perpustakaan dari dokumen TEST-RAG-20260726?&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jawaban yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
MERAH-7261&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah berhasil, ubah file menjadi:&lt;br /&gt;
&lt;br /&gt;
```markdown&lt;br /&gt;
version: 2&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Kode verifikasi perpustakaan adalah BIRU-9928.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lakukan prosedur replace, lalu tanyakan kembali. Jawaban seharusnya hanya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
BIRU-9928&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika masih muncul `MERAH-7261`, embedding lama belum benar-benar dihapus.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 9. Rekomendasi operasional&lt;br /&gt;
&lt;br /&gt;
Untuk perpustakaan Anda, gunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents&lt;br /&gt;
    ↓&lt;br /&gt;
SHA-256 scanner&lt;br /&gt;
    ↓&lt;br /&gt;
AnythingLLM Developer API&lt;br /&gt;
    ↓&lt;br /&gt;
Workspace&lt;br /&gt;
    ↓&lt;br /&gt;
Embedding model&lt;br /&gt;
    ↓&lt;br /&gt;
LanceDB&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aturan sinkronisasi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
File baru        → ADD&lt;br /&gt;
File berubah     → DELETE OLD + ADD NEW&lt;br /&gt;
File hilang      → DELETE&lt;br /&gt;
Embedder berubah → FULL REBUILD&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jadwal yang masuk akal:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Perpustakaan sering diperbarui : setiap malam&lt;br /&gt;
Perpustakaan jarang diperbarui  : dijalankan manual&lt;br /&gt;
Update besar                     : full rebuild terjadwal&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk kondisi Anda, pilihan paling aman adalah **incremental sync berbasis SHA-256**, bukan reset vector database setiap kali ada `.md` baru.&lt;br /&gt;
&lt;br /&gt;
[1]: https://docs.anythingllm.com/setup/embedder-configuration/overview &amp;quot;Overview ~ AnythingLLM&amp;quot;&lt;br /&gt;
[2]: https://docs.anythingllm.com/beta-preview/active-features/live-document-sync &amp;quot;Automatic document sync ~ AnythingLLM&amp;quot;&lt;br /&gt;
[3]: https://docs.anythingllm.com/features/api &amp;quot;API Access &amp;amp; Keys ~ AnythingLLM&amp;quot;&lt;br /&gt;
[4]: https://raw.githubusercontent.com/Mintplex-Labs/anything-llm/master/server/swagger/openapi.json &amp;quot;raw.githubusercontent.com&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Regenerate_Vector_Database_untuk_update_content_documents&amp;diff=73724</id>
		<title>MCP: Regenerate Vector Database untuk update content documents</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Regenerate_Vector_Database_untuk_update_content_documents&amp;diff=73724"/>
		<updated>2026-07-26T02:40:37Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created blank page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73723</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73723"/>
		<updated>2026-07-26T02:39:40Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* MCP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==MCP==&lt;br /&gt;
&lt;br /&gt;
* [[MCP: Instalasi]]&lt;br /&gt;
* [[MCP: Convert PDF ke .md]]&lt;br /&gt;
* [[MCP: Instalasi pip]]&lt;br /&gt;
* [[MCP: Regenerate Vector Database untuk update content documents]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Instalasi_pip&amp;diff=73722</id>
		<title>MCP: Instalasi pip</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Instalasi_pip&amp;diff=73722"/>
		<updated>2026-07-26T02:04:46Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Error tersebut berarti Python sudah ada, tetapi modul **pip** belum terpasang. Gunakan virtual environment supaya tidak mengganggu Python sistem Ubuntu. Ubuntu juga merekomend...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Error tersebut berarti Python sudah ada, tetapi modul **pip** belum terpasang. Gunakan virtual environment supaya tidak mengganggu Python sistem Ubuntu. Ubuntu juga merekomendasikan penggunaan `venv` untuk paket yang dipasang melalui pip. ([Ubuntu Documentation][1])&lt;br /&gt;
&lt;br /&gt;
Jalankan sebagai `root`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack/batch&lt;br /&gt;
&lt;br /&gt;
apt update&lt;br /&gt;
apt install -y python3-full python3-venv python3-pip&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat virtual environment:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python3 -m venv .venv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
source .venv/bin/activate&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Prompt biasanya berubah menjadi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
(.venv) root@server2:/opt/ai-stack/batch#&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan Python sudah memakai virtual environment:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
which python3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Seharusnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/batch/.venv/bin/python3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian instal dependensi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python3 -m pip install --upgrade pip&lt;br /&gt;
python3 -m pip install pymupdf pyyaml&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Verifikasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python3 - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import pymupdf&lt;br /&gt;
import yaml&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;PyMuPDF berhasil:&amp;quot;, pymupdf.__version__)&lt;br /&gt;
print(&amp;quot;PyYAML berhasil:&amp;quot;, yaml.__version__)&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah itu jalankan batch converter:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod +x batch_pdf_to_md.sh&lt;br /&gt;
chmod +x pdf_to_rag_md.py&lt;br /&gt;
&lt;br /&gt;
./batch_pdf_to_md.sh /path/folder/pdf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh \&lt;br /&gt;
  /opt/ai-stack/documents \&lt;br /&gt;
  /opt/ai-stack/output&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setiap kali keluar dari terminal atau login ulang, aktifkan kembali environment sebelum menjalankan script:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack/batch&lt;br /&gt;
source .venv/bin/activate&lt;br /&gt;
./batch_pdf_to_md.sh /opt/ai-stack/documents /opt/ai-stack/output&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan gunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
pip install --break-system-packages&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
karena pemasangan langsung ke Python sistem dapat berbenturan dengan paket bawaan Ubuntu.&lt;br /&gt;
&lt;br /&gt;
[1]: https://documentation.ubuntu.com/ubuntu-for-developers/tutorials/python-use/?utm_source=chatgpt.com &amp;quot;Develop with Python on Ubuntu - Ubuntu for Developers&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73721</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73721"/>
		<updated>2026-07-26T02:04:32Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* MCP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==MCP==&lt;br /&gt;
&lt;br /&gt;
* [[MCP: Instalasi]]&lt;br /&gt;
* [[MCP: Convert PDF ke .md]]&lt;br /&gt;
* [[MCP: Instalasi pip]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Batch_pdf_to_md.sh&amp;diff=73720</id>
		<title>Batch pdf to md.sh</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Batch_pdf_to_md.sh&amp;diff=73720"/>
		<updated>2026-07-26T01:47:44Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;&amp;lt;pre&amp;gt;  #!/usr/bin/env bash # Batch wrapper untuk pdf_to_rag_md.py # # Penggunaan: #   ./batch_pdf_to_md.sh /path/folder_pdf #   ./batch_pdf_to_md.sh /path/folder_pdf /path/fol...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#!/usr/bin/env bash&lt;br /&gt;
# Batch wrapper untuk pdf_to_rag_md.py&lt;br /&gt;
#&lt;br /&gt;
# Penggunaan:&lt;br /&gt;
#   ./batch_pdf_to_md.sh /path/folder_pdf&lt;br /&gt;
#   ./batch_pdf_to_md.sh /path/folder_pdf /path/folder_output&lt;br /&gt;
#   ./batch_pdf_to_md.sh /path/folder_pdf /path/folder_output /path/pdf_to_rag_md.py&lt;br /&gt;
#&lt;br /&gt;
# Hasil:&lt;br /&gt;
#   OUTPUT_DIR/&amp;lt;path-relatif&amp;gt;/&amp;lt;nama-pdf&amp;gt;/&lt;br /&gt;
#       ├── *.md&lt;br /&gt;
#       └── manifest.json&lt;br /&gt;
&lt;br /&gt;
set -Eeuo pipefail&lt;br /&gt;
IFS=$'\n\t'&lt;br /&gt;
&lt;br /&gt;
PROGRAM_NAME=&amp;quot;$(basename &amp;quot;$0&amp;quot;)&amp;quot;&lt;br /&gt;
SCRIPT_DIR=&amp;quot;$(cd -- &amp;quot;$(dirname -- &amp;quot;${BASH_SOURCE[0]}&amp;quot;)&amp;quot; &amp;amp;&amp;amp; pwd -P)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
usage() {&lt;br /&gt;
    cat &amp;lt;&amp;lt;EOF&lt;br /&gt;
Penggunaan:&lt;br /&gt;
  $PROGRAM_NAME INPUT_PATH [OUTPUT_DIR] [PYTHON_SCRIPT]&lt;br /&gt;
&lt;br /&gt;
Argumen:&lt;br /&gt;
  INPUT_PATH      Folder yang akan dicari secara rekursif, atau satu file PDF.&lt;br /&gt;
  OUTPUT_DIR      Folder induk hasil konversi.&lt;br /&gt;
                  Default: INPUT_PATH/output untuk input folder,&lt;br /&gt;
                  atau folder_file/output untuk input satu PDF.&lt;br /&gt;
  PYTHON_SCRIPT   Lokasi script Python konverter.&lt;br /&gt;
                  Default: dicari di folder yang sama dengan shell script.&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
  $PROGRAM_NAME /opt/ai-stack/documents&lt;br /&gt;
  $PROGRAM_NAME /opt/ai-stack/documents /opt/ai-stack/output&lt;br /&gt;
  $PROGRAM_NAME ./pdf ./output ./pdf_to_rag_md.py&lt;br /&gt;
EOF&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
log() {&lt;br /&gt;
    printf '[%s] %s\n' &amp;quot;$(date '+%Y-%m-%d %H:%M:%S')&amp;quot; &amp;quot;$*&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fail() {&lt;br /&gt;
    printf 'ERROR: %s\n' &amp;quot;$*&amp;quot; &amp;gt;&amp;amp;2&lt;br /&gt;
    exit 1&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if [[ ${1:-} == &amp;quot;-h&amp;quot; || ${1:-} == &amp;quot;--help&amp;quot; ]]; then&lt;br /&gt;
    usage&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
[[ $# -ge 1 &amp;amp;&amp;amp; $# -le 3 ]] || {&lt;br /&gt;
    usage &amp;gt;&amp;amp;2&lt;br /&gt;
    exit 2&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
command -v python3 &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || fail &amp;quot;python3 tidak ditemukan.&amp;quot;&lt;br /&gt;
command -v find &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 || fail &amp;quot;Perintah find tidak ditemukan.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
INPUT_PATH=&amp;quot;$1&amp;quot;&lt;br /&gt;
[[ -e &amp;quot;$INPUT_PATH&amp;quot; ]] || fail &amp;quot;Path input tidak ditemukan: $INPUT_PATH&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Ubah menjadi absolute path tanpa membutuhkan realpath.&lt;br /&gt;
if [[ -d &amp;quot;$INPUT_PATH&amp;quot; ]]; then&lt;br /&gt;
    INPUT_PATH=&amp;quot;$(cd -- &amp;quot;$INPUT_PATH&amp;quot; &amp;amp;&amp;amp; pwd -P)&amp;quot;&lt;br /&gt;
    INPUT_IS_DIR=1&lt;br /&gt;
else&lt;br /&gt;
    INPUT_DIR=&amp;quot;$(cd -- &amp;quot;$(dirname -- &amp;quot;$INPUT_PATH&amp;quot;)&amp;quot; &amp;amp;&amp;amp; pwd -P)&amp;quot;&lt;br /&gt;
    INPUT_PATH=&amp;quot;$INPUT_DIR/$(basename -- &amp;quot;$INPUT_PATH&amp;quot;)&amp;quot;&lt;br /&gt;
    INPUT_IS_DIR=0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
if [[ $# -ge 2 ]]; then&lt;br /&gt;
    OUTPUT_DIR=&amp;quot;$2&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    if (( INPUT_IS_DIR )); then&lt;br /&gt;
        OUTPUT_DIR=&amp;quot;$INPUT_PATH/output&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
        OUTPUT_DIR=&amp;quot;$(dirname -- &amp;quot;$INPUT_PATH&amp;quot;)/output&amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
fi&lt;br /&gt;
mkdir -p -- &amp;quot;$OUTPUT_DIR&amp;quot;&lt;br /&gt;
OUTPUT_DIR=&amp;quot;$(cd -- &amp;quot;$OUTPUT_DIR&amp;quot; &amp;amp;&amp;amp; pwd -P)&amp;quot;&lt;br /&gt;
[[ &amp;quot;$OUTPUT_DIR&amp;quot; != &amp;quot;$INPUT_PATH&amp;quot; ]] \&lt;br /&gt;
    || fail &amp;quot;OUTPUT_DIR tidak boleh sama persis dengan folder input. Gunakan subfolder, misalnya: $INPUT_PATH/output&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if [[ $# -ge 3 ]]; then&lt;br /&gt;
    PYTHON_SCRIPT=&amp;quot;$3&amp;quot;&lt;br /&gt;
else&lt;br /&gt;
    if [[ -f &amp;quot;$SCRIPT_DIR/pdf_to_rag_md.py&amp;quot; ]]; then&lt;br /&gt;
        PYTHON_SCRIPT=&amp;quot;$SCRIPT_DIR/pdf_to_rag_md.py&amp;quot;&lt;br /&gt;
    elif [[ -f &amp;quot;$SCRIPT_DIR/pdf_to_rag_md(2).py&amp;quot; ]]; then&lt;br /&gt;
        PYTHON_SCRIPT=&amp;quot;$SCRIPT_DIR/pdf_to_rag_md(2).py&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
        fail &amp;quot;Script Python tidak ditemukan. Letakkan pdf_to_rag_md.py di $SCRIPT_DIR atau berikan argumen PYTHON_SCRIPT.&amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
[[ -f &amp;quot;$PYTHON_SCRIPT&amp;quot; ]] || fail &amp;quot;Script Python tidak ditemukan: $PYTHON_SCRIPT&amp;quot;&lt;br /&gt;
PYTHON_SCRIPT=&amp;quot;$(cd -- &amp;quot;$(dirname -- &amp;quot;$PYTHON_SCRIPT&amp;quot;)&amp;quot; &amp;amp;&amp;amp; pwd -P)/$(basename -- &amp;quot;$PYTHON_SCRIPT&amp;quot;)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Pastikan script Python valid dan dependensinya tersedia sebelum batch dimulai.&lt;br /&gt;
python3 -m py_compile &amp;quot;$PYTHON_SCRIPT&amp;quot; \&lt;br /&gt;
    || fail &amp;quot;Script Python gagal diperiksa dengan py_compile.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
python3 - &amp;lt;&amp;lt;'PY' \&lt;br /&gt;
    || fail &amp;quot;Dependensi Python belum lengkap. Instal dengan: python3 -m pip install pymupdf pyyaml&amp;quot;&lt;br /&gt;
try:&lt;br /&gt;
    import pymupdf  # noqa: F401&lt;br /&gt;
except ImportError:&lt;br /&gt;
    import fitz  # noqa: F401&lt;br /&gt;
import yaml  # noqa: F401&lt;br /&gt;
PY&lt;br /&gt;
&lt;br /&gt;
find_input_files() {&lt;br /&gt;
    if [[ &amp;quot;$OUTPUT_DIR&amp;quot; == &amp;quot;$INPUT_PATH/&amp;quot;* ]]; then&lt;br /&gt;
        find &amp;quot;$INPUT_PATH&amp;quot; -path &amp;quot;$OUTPUT_DIR&amp;quot; -prune -o -type f &amp;quot;$@&amp;quot; -print0&lt;br /&gt;
    else&lt;br /&gt;
        find &amp;quot;$INPUT_PATH&amp;quot; -type f &amp;quot;$@&amp;quot; -print0&lt;br /&gt;
    fi&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
printf '\n=== Daftar semua file pada input ===\n'&lt;br /&gt;
if (( INPUT_IS_DIR )); then&lt;br /&gt;
    while IFS= read -r -d '' file; do&lt;br /&gt;
        printf '%s\n' &amp;quot;$file&amp;quot;&lt;br /&gt;
    done &amp;lt; &amp;lt;(find_input_files | sort -z)&lt;br /&gt;
else&lt;br /&gt;
    printf '%s\n' &amp;quot;$INPUT_PATH&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
printf '=== Akhir daftar file ===\n\n'&lt;br /&gt;
&lt;br /&gt;
PDF_FILES=()&lt;br /&gt;
if (( INPUT_IS_DIR )); then&lt;br /&gt;
    while IFS= read -r -d '' pdf; do&lt;br /&gt;
        PDF_FILES+=(&amp;quot;$pdf&amp;quot;)&lt;br /&gt;
    done &amp;lt; &amp;lt;(find_input_files -iname '*.pdf' | sort -z)&lt;br /&gt;
else&lt;br /&gt;
    [[ &amp;quot;${INPUT_PATH,,}&amp;quot; == *.pdf ]] \&lt;br /&gt;
        || fail &amp;quot;File input bukan PDF: $INPUT_PATH&amp;quot;&lt;br /&gt;
    PDF_FILES+=(&amp;quot;$INPUT_PATH&amp;quot;)&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
TOTAL=${#PDF_FILES[@]}&lt;br /&gt;
if (( TOTAL == 0 )); then&lt;br /&gt;
    log &amp;quot;Tidak ada file PDF yang ditemukan.&amp;quot;&lt;br /&gt;
    exit 0&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
LOG_FILE=&amp;quot;$OUTPUT_DIR/batch_conversion.log&amp;quot;&lt;br /&gt;
SUMMARY_FILE=&amp;quot;$OUTPUT_DIR/batch_summary.tsv&amp;quot;&lt;br /&gt;
printf 'status\tinput_pdf\toutput_folder\n' &amp;gt; &amp;quot;$SUMMARY_FILE&amp;quot;&lt;br /&gt;
: &amp;gt; &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
log &amp;quot;Ditemukan $TOTAL file PDF.&amp;quot;&lt;br /&gt;
log &amp;quot;Output utama: $OUTPUT_DIR&amp;quot;&lt;br /&gt;
log &amp;quot;Log batch: $LOG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SUCCESS=0&lt;br /&gt;
FAILED=0&lt;br /&gt;
INDEX=0&lt;br /&gt;
&lt;br /&gt;
for PDF_FILE in &amp;quot;${PDF_FILES[@]}&amp;quot;; do&lt;br /&gt;
    ((INDEX += 1))&lt;br /&gt;
&lt;br /&gt;
    if (( INPUT_IS_DIR )); then&lt;br /&gt;
        RELATIVE_PATH=&amp;quot;${PDF_FILE#&amp;quot;$INPUT_PATH&amp;quot;/}&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
        RELATIVE_PATH=&amp;quot;$(basename -- &amp;quot;$PDF_FILE&amp;quot;)&amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    RELATIVE_PARENT=&amp;quot;$(dirname -- &amp;quot;$RELATIVE_PATH&amp;quot;)&amp;quot;&lt;br /&gt;
    PDF_NAME=&amp;quot;$(basename -- &amp;quot;$RELATIVE_PATH&amp;quot;)&amp;quot;&lt;br /&gt;
    PDF_STEM=&amp;quot;${PDF_NAME%.*}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    if [[ &amp;quot;$RELATIVE_PARENT&amp;quot; == &amp;quot;.&amp;quot; ]]; then&lt;br /&gt;
        PDF_OUTPUT_DIR=&amp;quot;$OUTPUT_DIR/$PDF_STEM&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
        PDF_OUTPUT_DIR=&amp;quot;$OUTPUT_DIR/$RELATIVE_PARENT/$PDF_STEM&amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
&lt;br /&gt;
    mkdir -p -- &amp;quot;$PDF_OUTPUT_DIR&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    printf '\n[%d/%d] Konversi: %s\n' &amp;quot;$INDEX&amp;quot; &amp;quot;$TOTAL&amp;quot; &amp;quot;$PDF_FILE&amp;quot;&lt;br /&gt;
    printf '        Output   : %s\n' &amp;quot;$PDF_OUTPUT_DIR&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    printf '\n===== [%d/%d] %s =====\n' &amp;quot;$INDEX&amp;quot; &amp;quot;$TOTAL&amp;quot; &amp;quot;$PDF_FILE&amp;quot; \&lt;br /&gt;
        | tee -a &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    set +e&lt;br /&gt;
    python3 &amp;quot;$PYTHON_SCRIPT&amp;quot; \&lt;br /&gt;
        &amp;quot;$PDF_FILE&amp;quot; \&lt;br /&gt;
        --output-dir &amp;quot;$PDF_OUTPUT_DIR&amp;quot; \&lt;br /&gt;
        --overwrite 2&amp;gt;&amp;amp;1 | tee -a &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
    EXIT_CODE=${PIPESTATUS[0]}&lt;br /&gt;
    set -e&lt;br /&gt;
&lt;br /&gt;
    if (( EXIT_CODE == 0 )); then&lt;br /&gt;
        printf 'SUCCESS\t%s\t%s\n' &amp;quot;$PDF_FILE&amp;quot; &amp;quot;$PDF_OUTPUT_DIR&amp;quot; \&lt;br /&gt;
            &amp;gt;&amp;gt; &amp;quot;$SUMMARY_FILE&amp;quot;&lt;br /&gt;
        ((SUCCESS += 1))&lt;br /&gt;
        log &amp;quot;BERHASIL: $PDF_FILE&amp;quot; | tee -a &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
    else&lt;br /&gt;
        printf 'FAILED(%d)\t%s\t%s\n' &amp;quot;$EXIT_CODE&amp;quot; &amp;quot;$PDF_FILE&amp;quot; &amp;quot;$PDF_OUTPUT_DIR&amp;quot; \&lt;br /&gt;
            &amp;gt;&amp;gt; &amp;quot;$SUMMARY_FILE&amp;quot;&lt;br /&gt;
        ((FAILED += 1))&lt;br /&gt;
        log &amp;quot;GAGAL (exit $EXIT_CODE): $PDF_FILE&amp;quot; | tee -a &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
    fi&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
printf '\n=== Ringkasan batch ===\n'&lt;br /&gt;
printf 'Total PDF : %d\n' &amp;quot;$TOTAL&amp;quot;&lt;br /&gt;
printf 'Berhasil  : %d\n' &amp;quot;$SUCCESS&amp;quot;&lt;br /&gt;
printf 'Gagal     : %d\n' &amp;quot;$FAILED&amp;quot;&lt;br /&gt;
printf 'Output    : %s\n' &amp;quot;$OUTPUT_DIR&amp;quot;&lt;br /&gt;
printf 'Ringkasan : %s\n' &amp;quot;$SUMMARY_FILE&amp;quot;&lt;br /&gt;
printf 'Log       : %s\n' &amp;quot;$LOG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
(( FAILED == 0 ))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Convert_PDF_ke_.md&amp;diff=73719</id>
		<title>MCP: Convert PDF ke .md</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Convert_PDF_ke_.md&amp;diff=73719"/>
		<updated>2026-07-26T01:45:10Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shell script sudah dibuat berdasarkan opsi CLI pada Python terlampir. &lt;br /&gt;
&lt;br /&gt;
### File&lt;br /&gt;
&lt;br /&gt;
* [Download paket lengkap ZIP](sandbox:/mnt/data/pdf_batch_converter.zip)&lt;br /&gt;
* [Download shell script][[batch_pdf_to_md.sh]]&lt;br /&gt;
* [Download Python script dengan nama sederhana][[pdf_to_rag_md.py]]&lt;br /&gt;
&lt;br /&gt;
### Instalasi&lt;br /&gt;
&lt;br /&gt;
Letakkan `batch_pdf_to_md.sh` dan `pdf_to_rag_md.py` dalam folder yang sama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod +x batch_pdf_to_md.sh&lt;br /&gt;
chmod +x pdf_to_rag_md.py&lt;br /&gt;
&lt;br /&gt;
python3 -m pip install pymupdf pyyaml&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Menjalankan&lt;br /&gt;
&lt;br /&gt;
Output otomatis ditempatkan di subfolder `output`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh /opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dengan folder output khusus:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh \&lt;br /&gt;
  /opt/ai-stack/documents \&lt;br /&gt;
  /opt/ai-stack/output&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atau menentukan lokasi Python script secara eksplisit:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh \&lt;br /&gt;
  /opt/ai-stack/documents \&lt;br /&gt;
  /opt/ai-stack/output \&lt;br /&gt;
  /opt/scripts/pdf_to_rag_md.py&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Script akan:&lt;br /&gt;
&lt;br /&gt;
1. Menampilkan semua file dalam path input.&lt;br /&gt;
2. Mencari seluruh PDF secara rekursif, termasuk subfolder.&lt;br /&gt;
3. Menjalankan Python converter untuk setiap PDF.&lt;br /&gt;
4. Membuat folder output terpisah untuk setiap PDF agar `manifest.json` tidak saling menimpa.&lt;br /&gt;
5. Membuat `batch_conversion.log`.&lt;br /&gt;
6. Membuat `batch_summary.tsv` berisi status berhasil atau gagal.&lt;br /&gt;
&lt;br /&gt;
Contoh hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/output/&lt;br /&gt;
├── Buku Pertama/&lt;br /&gt;
│   ├── Buku Pertama 01 Topik.md&lt;br /&gt;
│   ├── Buku Pertama 02 Topik.md&lt;br /&gt;
│   └── manifest.json&lt;br /&gt;
├── AI/&lt;br /&gt;
│   └── Buku Kedua/&lt;br /&gt;
│       ├── Buku Kedua 01 Topik.md&lt;br /&gt;
│       └── manifest.json&lt;br /&gt;
├── batch_conversion.log&lt;br /&gt;
└── batch_summary.tsv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Shell script tersebut sudah diuji dengan beberapa PDF, nama file yang mengandung spasi, dan PDF di dalam subfolder.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Convert_PDF_ke_.md&amp;diff=73718</id>
		<title>MCP: Convert PDF ke .md</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Convert_PDF_ke_.md&amp;diff=73718"/>
		<updated>2026-07-26T01:44:24Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Shell script sudah dibuat berdasarkan opsi CLI pada Python terlampir.   ### File  * [Download paket lengkap ZIP](sandbox:/mnt/data/pdf_batch_converter.zip) * [Download shell s...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Shell script sudah dibuat berdasarkan opsi CLI pada Python terlampir. &lt;br /&gt;
&lt;br /&gt;
### File&lt;br /&gt;
&lt;br /&gt;
* [Download paket lengkap ZIP](sandbox:/mnt/data/pdf_batch_converter.zip)&lt;br /&gt;
* [Download shell script](sandbox:/mnt/data/batch_pdf_to_md.sh)&lt;br /&gt;
* [Download Python script dengan nama sederhana](sandbox:/mnt/data/pdf_to_rag_md.py)&lt;br /&gt;
&lt;br /&gt;
### Instalasi&lt;br /&gt;
&lt;br /&gt;
Letakkan `batch_pdf_to_md.sh` dan `pdf_to_rag_md.py` dalam folder yang sama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod +x batch_pdf_to_md.sh&lt;br /&gt;
chmod +x pdf_to_rag_md.py&lt;br /&gt;
&lt;br /&gt;
python3 -m pip install pymupdf pyyaml&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Menjalankan&lt;br /&gt;
&lt;br /&gt;
Output otomatis ditempatkan di subfolder `output`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh /opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dengan folder output khusus:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh \&lt;br /&gt;
  /opt/ai-stack/documents \&lt;br /&gt;
  /opt/ai-stack/output&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atau menentukan lokasi Python script secara eksplisit:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
./batch_pdf_to_md.sh \&lt;br /&gt;
  /opt/ai-stack/documents \&lt;br /&gt;
  /opt/ai-stack/output \&lt;br /&gt;
  /opt/scripts/pdf_to_rag_md.py&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Script akan:&lt;br /&gt;
&lt;br /&gt;
1. Menampilkan semua file dalam path input.&lt;br /&gt;
2. Mencari seluruh PDF secara rekursif, termasuk subfolder.&lt;br /&gt;
3. Menjalankan Python converter untuk setiap PDF.&lt;br /&gt;
4. Membuat folder output terpisah untuk setiap PDF agar `manifest.json` tidak saling menimpa.&lt;br /&gt;
5. Membuat `batch_conversion.log`.&lt;br /&gt;
6. Membuat `batch_summary.tsv` berisi status berhasil atau gagal.&lt;br /&gt;
&lt;br /&gt;
Contoh hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/output/&lt;br /&gt;
├── Buku Pertama/&lt;br /&gt;
│   ├── Buku Pertama 01 Topik.md&lt;br /&gt;
│   ├── Buku Pertama 02 Topik.md&lt;br /&gt;
│   └── manifest.json&lt;br /&gt;
├── AI/&lt;br /&gt;
│   └── Buku Kedua/&lt;br /&gt;
│       ├── Buku Kedua 01 Topik.md&lt;br /&gt;
│       └── manifest.json&lt;br /&gt;
├── batch_conversion.log&lt;br /&gt;
└── batch_summary.tsv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Shell script tersebut sudah diuji dengan beberapa PDF, nama file yang mengandung spasi, dan PDF di dalam subfolder.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73717</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73717"/>
		<updated>2026-07-26T01:44:11Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* MCP */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==MCP==&lt;br /&gt;
&lt;br /&gt;
* [[MCP: Instalasi]]&lt;br /&gt;
* [[MCP: Convert PDF ke .md]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Pdf_to_rag_md.py&amp;diff=73716</id>
		<title>Pdf to rag md.py</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Pdf_to_rag_md.py&amp;diff=73716"/>
		<updated>2026-07-24T21:03:25Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;&amp;lt;pre&amp;gt; #!/usr/bin/env python3 &amp;quot;&amp;quot;&amp;quot; Convert a text-based PDF into RAG-friendly Markdown files, one file per topic.  Main features ------------- - Uses the PDF table of contents w...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python3&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Convert a text-based PDF into RAG-friendly Markdown files, one file per topic.&lt;br /&gt;
&lt;br /&gt;
Main features&lt;br /&gt;
-------------&lt;br /&gt;
- Uses the PDF table of contents when available.&lt;br /&gt;
- Falls back to font-size / bold / numbering heuristics for headings.&lt;br /&gt;
- Falls back again to page groups if no reliable headings exist.&lt;br /&gt;
- Ignores images and other non-text PDF blocks.&lt;br /&gt;
- Removes repeated headers and footers.&lt;br /&gt;
- Removes standalone page numbers.&lt;br /&gt;
- Removes likely footnotes conservatively.&lt;br /&gt;
- Writes YAML front matter containing traceable RAG metadata.&lt;br /&gt;
- Creates a JSON manifest for auditing and bulk ingestion.&lt;br /&gt;
&lt;br /&gt;
Notes&lt;br /&gt;
-----&lt;br /&gt;
This script is intended for PDFs that already contain selectable text.&lt;br /&gt;
Scanned/image-only PDFs must be OCRed first.&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
from __future__ import annotations&lt;br /&gt;
&lt;br /&gt;
import argparse&lt;br /&gt;
import hashlib&lt;br /&gt;
import json&lt;br /&gt;
import math&lt;br /&gt;
import re&lt;br /&gt;
import sys&lt;br /&gt;
import unicodedata&lt;br /&gt;
from collections import Counter, defaultdict&lt;br /&gt;
from dataclasses import dataclass, field&lt;br /&gt;
from datetime import datetime, timezone&lt;br /&gt;
from pathlib import Path&lt;br /&gt;
from typing import Any, Iterable, Sequence&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    import pymupdf  # PyMuPDF &amp;gt;= modern releases&lt;br /&gt;
except ImportError:  # compatibility with older PyMuPDF installations&lt;br /&gt;
    try:&lt;br /&gt;
        import fitz as pymupdf  # type: ignore&lt;br /&gt;
    except ImportError as exc:&lt;br /&gt;
        raise SystemExit(&lt;br /&gt;
            &amp;quot;PyMuPDF belum terpasang. Jalankan: pip install pymupdf pyyaml&amp;quot;&lt;br /&gt;
        ) from exc&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    import yaml&lt;br /&gt;
except ImportError as exc:&lt;br /&gt;
    raise SystemExit(&lt;br /&gt;
        &amp;quot;PyYAML belum terpasang. Jalankan: pip install pymupdf pyyaml&amp;quot;&lt;br /&gt;
    ) from exc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
PAGE_NUMBER_RE = re.compile(&lt;br /&gt;
    r&amp;quot;^\s*(?:(?:page|halaman|hlm\.?|p\.)\s*)?&amp;quot;&lt;br /&gt;
    r&amp;quot;[-–—]?\s*(?:\d{1,5}|[ivxlcdm]{1,12})\s*[-–—]?\s*$&amp;quot;,&lt;br /&gt;
    re.IGNORECASE,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
NUMBERED_HEADING_RE = re.compile(&lt;br /&gt;
    r&amp;quot;^\s*(?:&amp;quot;&lt;br /&gt;
    r&amp;quot;(?:bab|chapter|bagian|part|section|seksi)\s+[A-Z0-9IVXLCDM]+&amp;quot;&lt;br /&gt;
    r&amp;quot;|(?:\d+(?:\.\d+){0,4})[\s.)–—:-]+&amp;quot;&lt;br /&gt;
    r&amp;quot;)&amp;quot;,&lt;br /&gt;
    re.IGNORECASE,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
FOOTNOTE_MARKER_RE = re.compile(&lt;br /&gt;
    r&amp;quot;^\s*(?:\[?\d{1,3}\]?|[*†‡])(?:[.)\]:-]|\s)+&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
BULLET_RE = re.compile(r&amp;quot;^\s*(?:[-*•◦▪‣]|\d+[.)]|[a-zA-Z][.)])\s+&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
SKIP_TOPIC_RE = re.compile(&lt;br /&gt;
    r&amp;quot;^\s*(?:&amp;quot;&lt;br /&gt;
    r&amp;quot;daftar\s+isi|table\s+of\s+contents|contents|&amp;quot;&lt;br /&gt;
    r&amp;quot;daftar\s+gambar|list\s+of\s+figures|&amp;quot;&lt;br /&gt;
    r&amp;quot;daftar\s+tabel|list\s+of\s+tables&amp;quot;&lt;br /&gt;
    r&amp;quot;)\s*$&amp;quot;,&lt;br /&gt;
    re.IGNORECASE,&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(slots=True)&lt;br /&gt;
class TextBlock:&lt;br /&gt;
    page_index: int&lt;br /&gt;
    page_number: int&lt;br /&gt;
    page_width: float&lt;br /&gt;
    page_height: float&lt;br /&gt;
    x0: float&lt;br /&gt;
    y0: float&lt;br /&gt;
    x1: float&lt;br /&gt;
    y1: float&lt;br /&gt;
    text: str&lt;br /&gt;
    avg_font_size: float&lt;br /&gt;
    max_font_size: float&lt;br /&gt;
    bold_ratio: float&lt;br /&gt;
    line_count: int&lt;br /&gt;
&lt;br /&gt;
    @property&lt;br /&gt;
    def top_ratio(self) -&amp;gt; float:&lt;br /&gt;
        return self.y0 / self.page_height if self.page_height else 0.0&lt;br /&gt;
&lt;br /&gt;
    @property&lt;br /&gt;
    def bottom_ratio(self) -&amp;gt; float:&lt;br /&gt;
        return self.y1 / self.page_height if self.page_height else 0.0&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(slots=True)&lt;br /&gt;
class HeadingInfo:&lt;br /&gt;
    title: str&lt;br /&gt;
    level: int&lt;br /&gt;
    source: str&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass&lt;br /&gt;
class Topic:&lt;br /&gt;
    title: str&lt;br /&gt;
    index: int&lt;br /&gt;
    detection_method: str&lt;br /&gt;
    blocks: list[TextBlock] = field(default_factory=list)&lt;br /&gt;
    body_parts: list[str] = field(default_factory=list)&lt;br /&gt;
    pages: set[int] = field(default_factory=set)&lt;br /&gt;
&lt;br /&gt;
    def add(self, block: TextBlock, markdown: str) -&amp;gt; None:&lt;br /&gt;
        self.blocks.append(block)&lt;br /&gt;
        self.body_parts.append(markdown)&lt;br /&gt;
        self.pages.add(block.page_number)&lt;br /&gt;
&lt;br /&gt;
    @property&lt;br /&gt;
    def body(self) -&amp;gt; str:&lt;br /&gt;
        text = &amp;quot;\n\n&amp;quot;.join(part.strip() for part in self.body_parts if part.strip())&lt;br /&gt;
        return clean_markdown_spacing(text)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@dataclass(slots=True)&lt;br /&gt;
class Config:&lt;br /&gt;
    topic_level: int&lt;br /&gt;
    fallback_pages: int&lt;br /&gt;
    top_band: float&lt;br /&gt;
    bottom_band: float&lt;br /&gt;
    repeat_ratio: float&lt;br /&gt;
    drop_footnotes: bool&lt;br /&gt;
    footnote_bottom_band: float&lt;br /&gt;
    footnote_font_ratio: float&lt;br /&gt;
    language: str&lt;br /&gt;
    tags: list[str]&lt;br /&gt;
    source_uri: str | None&lt;br /&gt;
    include_page_comments: bool&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def parse_args() -&amp;gt; argparse.Namespace:&lt;br /&gt;
    parser = argparse.ArgumentParser(&lt;br /&gt;
        description=(&lt;br /&gt;
            &amp;quot;Ubah PDF menjadi file Markdown per topik untuk RAG, lengkap &amp;quot;&lt;br /&gt;
            &amp;quot;dengan YAML metadata dan pembersihan artefak PDF.&amp;quot;&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&amp;quot;pdf&amp;quot;, type=Path, help=&amp;quot;File PDF sumber&amp;quot;)&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;-o&amp;quot;,&lt;br /&gt;
        &amp;quot;--output-dir&amp;quot;,&lt;br /&gt;
        type=Path,&lt;br /&gt;
        default=None,&lt;br /&gt;
        help=&amp;quot;Folder output. Default: &amp;lt;nama-pdf&amp;gt;_rag_md&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--topic-level&amp;quot;,&lt;br /&gt;
        type=int,&lt;br /&gt;
        choices=(1, 2, 3, 4),&lt;br /&gt;
        default=2,&lt;br /&gt;
        help=&amp;quot;Heading sampai level ini akan menjadi file topik baru. Default: 2&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--fallback-pages&amp;quot;,&lt;br /&gt;
        type=int,&lt;br /&gt;
        default=5,&lt;br /&gt;
        help=&amp;quot;Jika heading tidak terdeteksi, buat satu topik per N halaman. Default: 5&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--language&amp;quot;,&lt;br /&gt;
        default=&amp;quot;id&amp;quot;,&lt;br /&gt;
        help=&amp;quot;Kode bahasa metadata, misalnya id atau en. Default: id&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--tags&amp;quot;,&lt;br /&gt;
        default=&amp;quot;&amp;quot;,&lt;br /&gt;
        help=&amp;quot;Tag metadata dipisahkan koma, misalnya: keamanan,soc,wazuh&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--source-uri&amp;quot;,&lt;br /&gt;
        default=None,&lt;br /&gt;
        help=&amp;quot;URI/URL sumber asli, jika ada&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--password&amp;quot;,&lt;br /&gt;
        default=None,&lt;br /&gt;
        help=&amp;quot;Password PDF terenkripsi, jika diperlukan&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--keep-footnotes&amp;quot;,&lt;br /&gt;
        action=&amp;quot;store_true&amp;quot;,&lt;br /&gt;
        help=&amp;quot;Jangan hapus blok yang terdeteksi sebagai footnote&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--page-comments&amp;quot;,&lt;br /&gt;
        action=&amp;quot;store_true&amp;quot;,&lt;br /&gt;
        help=&amp;quot;Tambahkan komentar HTML saat halaman berubah untuk trace lebih rinci&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--top-band&amp;quot;,&lt;br /&gt;
        type=float,&lt;br /&gt;
        default=0.12,&lt;br /&gt;
        help=&amp;quot;Proporsi area atas untuk deteksi header berulang. Default: 0.12&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--bottom-band&amp;quot;,&lt;br /&gt;
        type=float,&lt;br /&gt;
        default=0.12,&lt;br /&gt;
        help=&amp;quot;Proporsi area bawah untuk deteksi footer berulang. Default: 0.12&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--repeat-ratio&amp;quot;,&lt;br /&gt;
        type=float,&lt;br /&gt;
        default=0.35,&lt;br /&gt;
        help=&amp;quot;Rasio halaman minimum agar teks dianggap header/footer berulang. Default: 0.35&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--footnote-bottom-band&amp;quot;,&lt;br /&gt;
        type=float,&lt;br /&gt;
        default=0.18,&lt;br /&gt;
        help=&amp;quot;Proporsi area bawah untuk deteksi footnote. Default: 0.18&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    parser.add_argument(&lt;br /&gt;
        &amp;quot;--footnote-font-ratio&amp;quot;,&lt;br /&gt;
        type=float,&lt;br /&gt;
        default=0.86,&lt;br /&gt;
        help=&amp;quot;Ukuran font footnote relatif terhadap font isi. Default: 0.86&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
    return parser.parse_args()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def utc_now_iso() -&amp;gt; str:&lt;br /&gt;
    return datetime.now(timezone.utc).replace(microsecond=0).isoformat()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def sha256_file(path: Path, chunk_size: int = 1024 * 1024) -&amp;gt; str:&lt;br /&gt;
    digest = hashlib.sha256()&lt;br /&gt;
    with path.open(&amp;quot;rb&amp;quot;) as handle:&lt;br /&gt;
        while chunk := handle.read(chunk_size):&lt;br /&gt;
            digest.update(chunk)&lt;br /&gt;
    return digest.hexdigest()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def normalize_unicode(text: str) -&amp;gt; str:&lt;br /&gt;
    text = unicodedata.normalize(&amp;quot;NFKC&amp;quot;, text)&lt;br /&gt;
    return (&lt;br /&gt;
        text.replace(&amp;quot;\u00ad&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        .replace(&amp;quot;\u200b&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        .replace(&amp;quot;\ufeff&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        .replace(&amp;quot;\xa0&amp;quot;, &amp;quot; &amp;quot;)&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def normalize_repeat_key(text: str) -&amp;gt; str:&lt;br /&gt;
    text = normalize_unicode(text).lower()&lt;br /&gt;
    text = re.sub(r&amp;quot;\b\d+\b&amp;quot;, &amp;quot;#&amp;quot;, text)&lt;br /&gt;
    text = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, text).strip(&amp;quot; -–—|•\t&amp;quot;)&lt;br /&gt;
    return text&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def normalize_heading_key(text: str) -&amp;gt; str:&lt;br /&gt;
    text = normalize_unicode(text).casefold()&lt;br /&gt;
    text = re.sub(r&amp;quot;[^\w\s]&amp;quot;, &amp;quot; &amp;quot;, text, flags=re.UNICODE)&lt;br /&gt;
    return re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, text).strip()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def weighted_mode_font_size(samples: Iterable[tuple[float, int]]) -&amp;gt; float:&lt;br /&gt;
    buckets: Counter[float] = Counter()&lt;br /&gt;
    for size, weight in samples:&lt;br /&gt;
        if size &amp;lt;= 0 or weight &amp;lt;= 0:&lt;br /&gt;
            continue&lt;br /&gt;
        bucket = round(size * 2) / 2.0&lt;br /&gt;
        buckets[bucket] += weight&lt;br /&gt;
    if not buckets:&lt;br /&gt;
        return 11.0&lt;br /&gt;
    return float(buckets.most_common(1)[0][0])&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def join_pdf_lines(lines: Sequence[str]) -&amp;gt; str:&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Join visual PDF lines into cleaner paragraphs while preserving list items.&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    output: list[str] = []&lt;br /&gt;
    current = &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    for raw_line in lines:&lt;br /&gt;
        line = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, normalize_unicode(raw_line)).strip()&lt;br /&gt;
        if not line:&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        if BULLET_RE.match(line):&lt;br /&gt;
            if current:&lt;br /&gt;
                output.append(current.strip())&lt;br /&gt;
                current = &amp;quot;&amp;quot;&lt;br /&gt;
            bullet = re.sub(r&amp;quot;^\s*[•◦▪‣]\s+&amp;quot;, &amp;quot;- &amp;quot;, line)&lt;br /&gt;
            output.append(bullet)&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        if not current:&lt;br /&gt;
            current = line&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        if current.endswith(&amp;quot;-&amp;quot;) and line[:1].islower():&lt;br /&gt;
            current = current[:-1] + line&lt;br /&gt;
        else:&lt;br /&gt;
            current += &amp;quot; &amp;quot; + line&lt;br /&gt;
&lt;br /&gt;
    if current:&lt;br /&gt;
        output.append(current.strip())&lt;br /&gt;
&lt;br /&gt;
    return &amp;quot;\n&amp;quot;.join(output)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def extract_raw_blocks(doc: Any) -&amp;gt; tuple[list[TextBlock], list[tuple[float, int]]]:&lt;br /&gt;
    blocks: list[TextBlock] = []&lt;br /&gt;
    font_samples: list[tuple[float, int]] = []&lt;br /&gt;
&lt;br /&gt;
    for page_index in range(doc.page_count):&lt;br /&gt;
        page = doc.load_page(page_index)&lt;br /&gt;
        page_dict = page.get_text(&amp;quot;dict&amp;quot;, sort=True)&lt;br /&gt;
        page_width = float(page.rect.width)&lt;br /&gt;
        page_height = float(page.rect.height)&lt;br /&gt;
&lt;br /&gt;
        for raw_block in page_dict.get(&amp;quot;blocks&amp;quot;, []):&lt;br /&gt;
            # type 0 is text. Image and drawing blocks are deliberately ignored.&lt;br /&gt;
            if raw_block.get(&amp;quot;type&amp;quot;) != 0:&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            line_texts: list[str] = []&lt;br /&gt;
            block_font_weight = 0&lt;br /&gt;
            block_font_total = 0.0&lt;br /&gt;
            block_max_font = 0.0&lt;br /&gt;
            bold_chars = 0&lt;br /&gt;
            total_chars = 0&lt;br /&gt;
&lt;br /&gt;
            for line in raw_block.get(&amp;quot;lines&amp;quot;, []):&lt;br /&gt;
                span_texts: list[str] = []&lt;br /&gt;
                for span in line.get(&amp;quot;spans&amp;quot;, []):&lt;br /&gt;
                    text = normalize_unicode(str(span.get(&amp;quot;text&amp;quot;, &amp;quot;&amp;quot;)))&lt;br /&gt;
                    if not text:&lt;br /&gt;
                        continue&lt;br /&gt;
&lt;br /&gt;
                    size = float(span.get(&amp;quot;size&amp;quot;, 0.0) or 0.0)&lt;br /&gt;
                    chars = max(len(text.strip()), 1)&lt;br /&gt;
                    font_name = str(span.get(&amp;quot;font&amp;quot;, &amp;quot;&amp;quot;)).casefold()&lt;br /&gt;
                    is_bold = &amp;quot;bold&amp;quot; in font_name or &amp;quot;black&amp;quot; in font_name or &amp;quot;semibold&amp;quot; in font_name&lt;br /&gt;
&lt;br /&gt;
                    span_texts.append(text)&lt;br /&gt;
                    block_font_total += size * chars&lt;br /&gt;
                    block_font_weight += chars&lt;br /&gt;
                    block_max_font = max(block_max_font, size)&lt;br /&gt;
                    total_chars += chars&lt;br /&gt;
                    if is_bold:&lt;br /&gt;
                        bold_chars += chars&lt;br /&gt;
                    font_samples.append((size, min(chars, 200)))&lt;br /&gt;
&lt;br /&gt;
                line_text = &amp;quot;&amp;quot;.join(span_texts).strip()&lt;br /&gt;
                if line_text:&lt;br /&gt;
                    line_texts.append(line_text)&lt;br /&gt;
&lt;br /&gt;
            text = join_pdf_lines(line_texts).strip()&lt;br /&gt;
            if not text:&lt;br /&gt;
                continue&lt;br /&gt;
&lt;br /&gt;
            bbox = raw_block.get(&amp;quot;bbox&amp;quot;, (0.0, 0.0, 0.0, 0.0))&lt;br /&gt;
            avg_font = block_font_total / block_font_weight if block_font_weight else 0.0&lt;br /&gt;
            bold_ratio = bold_chars / total_chars if total_chars else 0.0&lt;br /&gt;
&lt;br /&gt;
            blocks.append(&lt;br /&gt;
                TextBlock(&lt;br /&gt;
                    page_index=page_index,&lt;br /&gt;
                    page_number=page_index + 1,&lt;br /&gt;
                    page_width=page_width,&lt;br /&gt;
                    page_height=page_height,&lt;br /&gt;
                    x0=float(bbox[0]),&lt;br /&gt;
                    y0=float(bbox[1]),&lt;br /&gt;
                    x1=float(bbox[2]),&lt;br /&gt;
                    y1=float(bbox[3]),&lt;br /&gt;
                    text=text,&lt;br /&gt;
                    avg_font_size=avg_font,&lt;br /&gt;
                    max_font_size=block_max_font,&lt;br /&gt;
                    bold_ratio=bold_ratio,&lt;br /&gt;
                    line_count=len(line_texts),&lt;br /&gt;
                )&lt;br /&gt;
            )&lt;br /&gt;
&lt;br /&gt;
    return blocks, font_samples&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def detect_repeated_margin_text(&lt;br /&gt;
    blocks: Sequence[TextBlock],&lt;br /&gt;
    page_count: int,&lt;br /&gt;
    top_band: float,&lt;br /&gt;
    bottom_band: float,&lt;br /&gt;
    repeat_ratio: float,&lt;br /&gt;
) -&amp;gt; set[str]:&lt;br /&gt;
    occurrences: dict[str, set[int]] = defaultdict(set)&lt;br /&gt;
&lt;br /&gt;
    for block in blocks:&lt;br /&gt;
        is_top = block.top_ratio &amp;lt;= top_band&lt;br /&gt;
        is_bottom = block.bottom_ratio &amp;gt;= 1.0 - bottom_band&lt;br /&gt;
        if not (is_top or is_bottom):&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        key = normalize_repeat_key(block.text)&lt;br /&gt;
        if 2 &amp;lt;= len(key) &amp;lt;= 180:&lt;br /&gt;
            occurrences[key].add(block.page_number)&lt;br /&gt;
&lt;br /&gt;
    threshold = max(3, math.ceil(page_count * repeat_ratio))&lt;br /&gt;
    return {key for key, pages in occurrences.items() if len(pages) &amp;gt;= threshold}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def is_standalone_page_number(text: str) -&amp;gt; bool:&lt;br /&gt;
    compact = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, text).strip()&lt;br /&gt;
    return bool(PAGE_NUMBER_RE.fullmatch(compact))&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def is_likely_footnote(block: TextBlock, body_font: float, config: Config) -&amp;gt; bool:&lt;br /&gt;
    if not config.drop_footnotes:&lt;br /&gt;
        return False&lt;br /&gt;
&lt;br /&gt;
    small_font = block.avg_font_size &amp;lt;= body_font * config.footnote_font_ratio&lt;br /&gt;
    in_bottom_area = block.top_ratio &amp;gt;= 1.0 - config.footnote_bottom_band&lt;br /&gt;
    marker = bool(FOOTNOTE_MARKER_RE.match(block.text))&lt;br /&gt;
    shortish = len(block.text) &amp;lt;= 900&lt;br /&gt;
&lt;br /&gt;
    # Conservative: require both positional/font evidence, or a strong marker&lt;br /&gt;
    # combined with small font near the lower half of the page.&lt;br /&gt;
    if small_font and in_bottom_area and shortish:&lt;br /&gt;
        return True&lt;br /&gt;
    if marker and small_font and block.top_ratio &amp;gt;= 0.55 and shortish:&lt;br /&gt;
        return True&lt;br /&gt;
    return False&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def clean_blocks(&lt;br /&gt;
    blocks: Sequence[TextBlock],&lt;br /&gt;
    repeated_margin_text: set[str],&lt;br /&gt;
    body_font: float,&lt;br /&gt;
    config: Config,&lt;br /&gt;
) -&amp;gt; list[TextBlock]:&lt;br /&gt;
    cleaned: list[TextBlock] = []&lt;br /&gt;
&lt;br /&gt;
    for block in blocks:&lt;br /&gt;
        key = normalize_repeat_key(block.text)&lt;br /&gt;
        is_margin = (&lt;br /&gt;
            block.top_ratio &amp;lt;= config.top_band&lt;br /&gt;
            or block.bottom_ratio &amp;gt;= 1.0 - config.bottom_band&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        if is_margin and key in repeated_margin_text:&lt;br /&gt;
            continue&lt;br /&gt;
        if is_standalone_page_number(block.text):&lt;br /&gt;
            continue&lt;br /&gt;
        if is_likely_footnote(block, body_font, config):&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        text = clean_block_text(block.text)&lt;br /&gt;
        if not text:&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        cleaned.append(&lt;br /&gt;
            TextBlock(&lt;br /&gt;
                page_index=block.page_index,&lt;br /&gt;
                page_number=block.page_number,&lt;br /&gt;
                page_width=block.page_width,&lt;br /&gt;
                page_height=block.page_height,&lt;br /&gt;
                x0=block.x0,&lt;br /&gt;
                y0=block.y0,&lt;br /&gt;
                x1=block.x1,&lt;br /&gt;
                y1=block.y1,&lt;br /&gt;
                text=text,&lt;br /&gt;
                avg_font_size=block.avg_font_size,&lt;br /&gt;
                max_font_size=block.max_font_size,&lt;br /&gt;
                bold_ratio=block.bold_ratio,&lt;br /&gt;
                line_count=block.line_count,&lt;br /&gt;
            )&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    return cleaned&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def clean_block_text(text: str) -&amp;gt; str:&lt;br /&gt;
    text = normalize_unicode(text)&lt;br /&gt;
    lines: list[str] = []&lt;br /&gt;
    for line in text.splitlines():&lt;br /&gt;
        line = re.sub(r&amp;quot;[ \t]+&amp;quot;, &amp;quot; &amp;quot;, line).strip()&lt;br /&gt;
        if not line or is_standalone_page_number(line):&lt;br /&gt;
            continue&lt;br /&gt;
        line = re.sub(r&amp;quot;^\s*[•◦▪‣]\s+&amp;quot;, &amp;quot;- &amp;quot;, line)&lt;br /&gt;
        lines.append(line)&lt;br /&gt;
    return &amp;quot;\n&amp;quot;.join(lines).strip()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def get_toc_map(doc: Any) -&amp;gt; tuple[dict[int, list[tuple[int, str]]], list[list[Any]]]:&lt;br /&gt;
    toc = doc.get_toc(simple=True) or []&lt;br /&gt;
    by_page: dict[int, list[tuple[int, str]]] = defaultdict(list)&lt;br /&gt;
&lt;br /&gt;
    for entry in toc:&lt;br /&gt;
        if len(entry) &amp;lt; 3:&lt;br /&gt;
            continue&lt;br /&gt;
        level, title, page_number = entry[:3]&lt;br /&gt;
        title = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, str(title)).strip()&lt;br /&gt;
        if not title or not isinstance(page_number, int) or page_number &amp;lt; 1:&lt;br /&gt;
            continue&lt;br /&gt;
        by_page[page_number].append((int(level), title))&lt;br /&gt;
&lt;br /&gt;
    return by_page, toc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def match_toc_heading(&lt;br /&gt;
    block: TextBlock,&lt;br /&gt;
    toc_by_page: dict[int, list[tuple[int, str]]],&lt;br /&gt;
) -&amp;gt; HeadingInfo | None:&lt;br /&gt;
    block_key = normalize_heading_key(block.text)&lt;br /&gt;
    if not block_key:&lt;br /&gt;
        return None&lt;br /&gt;
&lt;br /&gt;
    candidates: list[tuple[int, str]] = []&lt;br /&gt;
    for page_number in (block.page_number - 1, block.page_number, block.page_number + 1):&lt;br /&gt;
        candidates.extend(toc_by_page.get(page_number, []))&lt;br /&gt;
&lt;br /&gt;
    for level, title in candidates:&lt;br /&gt;
        title_key = normalize_heading_key(title)&lt;br /&gt;
        if not title_key:&lt;br /&gt;
            continue&lt;br /&gt;
        exact = block_key == title_key&lt;br /&gt;
        contained = (&lt;br /&gt;
            len(title_key) &amp;gt;= 5&lt;br /&gt;
            and (block_key.startswith(title_key) or title_key.startswith(block_key))&lt;br /&gt;
            and min(len(block_key), len(title_key)) / max(len(block_key), len(title_key)) &amp;gt;= 0.72&lt;br /&gt;
        )&lt;br /&gt;
        if exact or contained:&lt;br /&gt;
            return HeadingInfo(title=title, level=max(1, min(level, 6)), source=&amp;quot;pdf_toc&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    return None&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def looks_like_heading_text(text: str) -&amp;gt; bool:&lt;br /&gt;
    one_line = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, text).strip()&lt;br /&gt;
    if not one_line or len(one_line) &amp;gt; 180:&lt;br /&gt;
        return False&lt;br /&gt;
    if one_line.count(&amp;quot;.&amp;quot;) &amp;gt;= 4 and len(one_line) &amp;gt; 90:&lt;br /&gt;
        return False&lt;br /&gt;
    if len(one_line.split()) &amp;gt; 22:&lt;br /&gt;
        return False&lt;br /&gt;
    if one_line.endswith((&amp;quot;.&amp;quot;, &amp;quot;;&amp;quot;, &amp;quot;,&amp;quot;)) and not NUMBERED_HEADING_RE.match(one_line):&lt;br /&gt;
        return False&lt;br /&gt;
    return True&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def infer_heading_level(text: str, font_ratio: float) -&amp;gt; int:&lt;br /&gt;
    compact = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, text).strip()&lt;br /&gt;
    lowered = compact.casefold()&lt;br /&gt;
&lt;br /&gt;
    if re.match(r&amp;quot;^(bab|chapter|bagian|part)\s+&amp;quot;, lowered):&lt;br /&gt;
        return 1&lt;br /&gt;
&lt;br /&gt;
    numbered = re.match(r&amp;quot;^(\d+(?:\.\d+){0,4})[\s.)–—:-]+&amp;quot;, compact)&lt;br /&gt;
    if numbered:&lt;br /&gt;
        depth = numbered.group(1).count(&amp;quot;.&amp;quot;) + 1&lt;br /&gt;
        return min(depth, 4)&lt;br /&gt;
&lt;br /&gt;
    if font_ratio &amp;gt;= 1.65:&lt;br /&gt;
        return 1&lt;br /&gt;
    if font_ratio &amp;gt;= 1.38:&lt;br /&gt;
        return 2&lt;br /&gt;
    return 3&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def detect_heading(&lt;br /&gt;
    block: TextBlock,&lt;br /&gt;
    body_font: float,&lt;br /&gt;
    toc_by_page: dict[int, list[tuple[int, str]]],&lt;br /&gt;
) -&amp;gt; HeadingInfo | None:&lt;br /&gt;
    toc_match = match_toc_heading(block, toc_by_page)&lt;br /&gt;
    if toc_match:&lt;br /&gt;
        return toc_match&lt;br /&gt;
&lt;br /&gt;
    if not looks_like_heading_text(block.text):&lt;br /&gt;
        return None&lt;br /&gt;
&lt;br /&gt;
    font_ratio = block.avg_font_size / body_font if body_font else 1.0&lt;br /&gt;
    compact = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, block.text).strip()&lt;br /&gt;
    numbered = bool(NUMBERED_HEADING_RE.match(compact))&lt;br /&gt;
    mostly_bold = block.bold_ratio &amp;gt;= 0.55&lt;br /&gt;
    mostly_upper = len(compact) &amp;gt;= 4 and compact.upper() == compact and any(c.isalpha() for c in compact)&lt;br /&gt;
&lt;br /&gt;
    strong_size = font_ratio &amp;gt;= 1.20&lt;br /&gt;
    modest_size_with_signal = font_ratio &amp;gt;= 1.04 and (mostly_bold or numbered or mostly_upper)&lt;br /&gt;
&lt;br /&gt;
    if not (strong_size or modest_size_with_signal):&lt;br /&gt;
        return None&lt;br /&gt;
&lt;br /&gt;
    level = infer_heading_level(compact, font_ratio)&lt;br /&gt;
    return HeadingInfo(title=compact, level=level, source=&amp;quot;font_heuristic&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def unique_toc_starts_for_page(&lt;br /&gt;
    page_number: int,&lt;br /&gt;
    toc_by_page: dict[int, list[tuple[int, str]]],&lt;br /&gt;
    topic_level: int,&lt;br /&gt;
) -&amp;gt; list[tuple[int, str]]:&lt;br /&gt;
    seen: set[str] = set()&lt;br /&gt;
    result: list[tuple[int, str]] = []&lt;br /&gt;
    for level, title in toc_by_page.get(page_number, []):&lt;br /&gt;
        if level &amp;gt; topic_level:&lt;br /&gt;
            continue&lt;br /&gt;
        key = normalize_heading_key(title)&lt;br /&gt;
        if not key or key in seen:&lt;br /&gt;
            continue&lt;br /&gt;
        seen.add(key)&lt;br /&gt;
        result.append((level, title))&lt;br /&gt;
    return result&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def topic_default_title(doc_title: str, pdf_stem: str) -&amp;gt; str:&lt;br /&gt;
    title = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, doc_title or &amp;quot;&amp;quot;).strip()&lt;br /&gt;
    return title if title else pdf_stem.replace(&amp;quot;_&amp;quot;, &amp;quot; &amp;quot;).replace(&amp;quot;-&amp;quot;, &amp;quot; &amp;quot;).strip().title()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def build_topics_from_headings(&lt;br /&gt;
    blocks: Sequence[TextBlock],&lt;br /&gt;
    body_font: float,&lt;br /&gt;
    toc_by_page: dict[int, list[tuple[int, str]]],&lt;br /&gt;
    default_title: str,&lt;br /&gt;
    config: Config,&lt;br /&gt;
) -&amp;gt; tuple[list[Topic], int]:&lt;br /&gt;
    topics: list[Topic] = []&lt;br /&gt;
    current: Topic | None = None&lt;br /&gt;
    detected_splits = 0&lt;br /&gt;
    last_page: int | None = None&lt;br /&gt;
    page_toc_started: set[int] = set()&lt;br /&gt;
    last_body_page: int | None = None&lt;br /&gt;
&lt;br /&gt;
    def start_topic(title: str, method: str) -&amp;gt; Topic:&lt;br /&gt;
        nonlocal detected_splits&lt;br /&gt;
        cleaned_title = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, title).strip() or default_title&lt;br /&gt;
        topic = Topic(&lt;br /&gt;
            title=cleaned_title,&lt;br /&gt;
            index=len(topics) + 1,&lt;br /&gt;
            detection_method=method,&lt;br /&gt;
        )&lt;br /&gt;
        topics.append(topic)&lt;br /&gt;
        detected_splits += 1&lt;br /&gt;
        return topic&lt;br /&gt;
&lt;br /&gt;
    for block in blocks:&lt;br /&gt;
        if block.page_number != last_page:&lt;br /&gt;
            last_page = block.page_number&lt;br /&gt;
            toc_starts = unique_toc_starts_for_page(&lt;br /&gt;
                block.page_number, toc_by_page, config.topic_level&lt;br /&gt;
            )&lt;br /&gt;
            if toc_starts and block.page_number not in page_toc_started:&lt;br /&gt;
                _, toc_title = toc_starts[0]&lt;br /&gt;
                if current is None or normalize_heading_key(current.title) != normalize_heading_key(toc_title):&lt;br /&gt;
                    current = start_topic(toc_title, &amp;quot;pdf_toc&amp;quot;)&lt;br /&gt;
                page_toc_started.add(block.page_number)&lt;br /&gt;
&lt;br /&gt;
        heading = detect_heading(block, body_font, toc_by_page)&lt;br /&gt;
&lt;br /&gt;
        if heading and heading.level &amp;lt;= config.topic_level:&lt;br /&gt;
            same_as_current = (&lt;br /&gt;
                current is not None&lt;br /&gt;
                and normalize_heading_key(current.title) == normalize_heading_key(heading.title)&lt;br /&gt;
            )&lt;br /&gt;
            if not same_as_current:&lt;br /&gt;
                current = start_topic(heading.title, heading.source)&lt;br /&gt;
            # The topic title is already emitted as H1 during writing.&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        if current is None:&lt;br /&gt;
            current = Topic(&lt;br /&gt;
                title=default_title,&lt;br /&gt;
                index=1,&lt;br /&gt;
                detection_method=&amp;quot;document_intro&amp;quot;,&lt;br /&gt;
            )&lt;br /&gt;
            topics.append(current)&lt;br /&gt;
&lt;br /&gt;
        if config.include_page_comments and last_body_page != block.page_number:&lt;br /&gt;
            current.body_parts.append(f&amp;quot;&amp;lt;!-- source_page: {block.page_number} --&amp;gt;&amp;quot;)&lt;br /&gt;
            last_body_page = block.page_number&lt;br /&gt;
&lt;br /&gt;
        if heading:&lt;br /&gt;
            markdown_level = max(2, min(heading.level + 1, 6))&lt;br /&gt;
            current.add(block, f&amp;quot;{'#' * markdown_level} {heading.title}&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            current.add(block, block.text)&lt;br /&gt;
&lt;br /&gt;
    # Remove empty topics and fix indexes.&lt;br /&gt;
    topics = [topic for topic in topics if topic.body.strip()]&lt;br /&gt;
    for index, topic in enumerate(topics, start=1):&lt;br /&gt;
        topic.index = index&lt;br /&gt;
    return topics, detected_splits&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def best_fallback_title(blocks: Sequence[TextBlock], default: str) -&amp;gt; str:&lt;br /&gt;
    for block in blocks:&lt;br /&gt;
        compact = re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, block.text).strip()&lt;br /&gt;
        if looks_like_heading_text(compact) and len(compact) &amp;lt;= 110:&lt;br /&gt;
            if block.bold_ratio &amp;gt;= 0.45 or block.line_count == 1:&lt;br /&gt;
                return compact&lt;br /&gt;
    return default&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def build_topics_by_page_groups(&lt;br /&gt;
    blocks: Sequence[TextBlock],&lt;br /&gt;
    page_count: int,&lt;br /&gt;
    fallback_pages: int,&lt;br /&gt;
    default_title: str,&lt;br /&gt;
    include_page_comments: bool,&lt;br /&gt;
) -&amp;gt; list[Topic]:&lt;br /&gt;
    by_page: dict[int, list[TextBlock]] = defaultdict(list)&lt;br /&gt;
    for block in blocks:&lt;br /&gt;
        by_page[block.page_number].append(block)&lt;br /&gt;
&lt;br /&gt;
    topics: list[Topic] = []&lt;br /&gt;
    fallback_pages = max(1, fallback_pages)&lt;br /&gt;
&lt;br /&gt;
    for start_page in range(1, page_count + 1, fallback_pages):&lt;br /&gt;
        end_page = min(page_count, start_page + fallback_pages - 1)&lt;br /&gt;
        group_blocks: list[TextBlock] = []&lt;br /&gt;
        for page_number in range(start_page, end_page + 1):&lt;br /&gt;
            group_blocks.extend(by_page.get(page_number, []))&lt;br /&gt;
&lt;br /&gt;
        if not group_blocks:&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        fallback_title = f&amp;quot;{default_title} — Halaman {start_page}-{end_page}&amp;quot;&lt;br /&gt;
        title = best_fallback_title(group_blocks, fallback_title)&lt;br /&gt;
        topic = Topic(&lt;br /&gt;
            title=title,&lt;br /&gt;
            index=len(topics) + 1,&lt;br /&gt;
            detection_method=&amp;quot;page_group_fallback&amp;quot;,&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        last_page: int | None = None&lt;br /&gt;
        for block in group_blocks:&lt;br /&gt;
            if include_page_comments and last_page != block.page_number:&lt;br /&gt;
                topic.body_parts.append(f&amp;quot;&amp;lt;!-- source_page: {block.page_number} --&amp;gt;&amp;quot;)&lt;br /&gt;
                last_page = block.page_number&lt;br /&gt;
            topic.add(block, block.text)&lt;br /&gt;
&lt;br /&gt;
        topics.append(topic)&lt;br /&gt;
&lt;br /&gt;
    return topics&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def clean_markdown_spacing(text: str) -&amp;gt; str:&lt;br /&gt;
    text = normalize_unicode(text)&lt;br /&gt;
    text = re.sub(r&amp;quot;[ \t]+\n&amp;quot;, &amp;quot;\n&amp;quot;, text)&lt;br /&gt;
    text = re.sub(r&amp;quot;\n{3,}&amp;quot;, &amp;quot;\n\n&amp;quot;, text)&lt;br /&gt;
    return text.strip()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def slugify(text: str, max_length: int = 100) -&amp;gt; str:&lt;br /&gt;
    text = normalize_unicode(text).casefold()&lt;br /&gt;
    text = unicodedata.normalize(&amp;quot;NFKD&amp;quot;, text)&lt;br /&gt;
    text = &amp;quot;&amp;quot;.join(char for char in text if not unicodedata.combining(char))&lt;br /&gt;
    text = re.sub(r&amp;quot;[^a-z0-9]+&amp;quot;, &amp;quot;-&amp;quot;, text)&lt;br /&gt;
    text = re.sub(r&amp;quot;-+&amp;quot;, &amp;quot;-&amp;quot;, text).strip(&amp;quot;-&amp;quot;)&lt;br /&gt;
    return (text[:max_length].rstrip(&amp;quot;-&amp;quot;) or &amp;quot;topik&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def ensure_unique_filename(base_name: str, used: set[str]) -&amp;gt; str:&lt;br /&gt;
    candidate = base_name&lt;br /&gt;
    counter = 2&lt;br /&gt;
    while candidate in used:&lt;br /&gt;
        stem = Path(base_name).stem&lt;br /&gt;
        suffix = Path(base_name).suffix&lt;br /&gt;
        candidate = f&amp;quot;{stem}-{counter}{suffix}&amp;quot;&lt;br /&gt;
        counter += 1&lt;br /&gt;
    used.add(candidate)&lt;br /&gt;
    return candidate&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def metadata_value(value: Any) -&amp;gt; Any:&lt;br /&gt;
    if isinstance(value, str):&lt;br /&gt;
        return re.sub(r&amp;quot;\s+&amp;quot;, &amp;quot; &amp;quot;, value).strip()&lt;br /&gt;
    return value&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def build_front_matter(&lt;br /&gt;
    *,&lt;br /&gt;
    topic: Topic,&lt;br /&gt;
    filename: str,&lt;br /&gt;
    source_pdf: Path,&lt;br /&gt;
    source_sha256: str,&lt;br /&gt;
    document_id: str,&lt;br /&gt;
    pdf_metadata: dict[str, Any],&lt;br /&gt;
    config: Config,&lt;br /&gt;
    body: str,&lt;br /&gt;
    generated_at: str,&lt;br /&gt;
    body_font: float,&lt;br /&gt;
) -&amp;gt; dict[str, Any]:&lt;br /&gt;
    pages = sorted(topic.pages)&lt;br /&gt;
    page_start = pages[0] if pages else None&lt;br /&gt;
    page_end = pages[-1] if pages else None&lt;br /&gt;
    topic_id = f&amp;quot;{document_id}-topic-{topic.index:04d}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        &amp;quot;schema_version&amp;quot;: &amp;quot;1.0&amp;quot;,&lt;br /&gt;
        &amp;quot;document_id&amp;quot;: document_id,&lt;br /&gt;
        &amp;quot;topic_id&amp;quot;: topic_id,&lt;br /&gt;
        &amp;quot;chunk_id&amp;quot;: topic_id,&lt;br /&gt;
        &amp;quot;title&amp;quot;: topic.title,&lt;br /&gt;
        &amp;quot;topic&amp;quot;: topic.title,&lt;br /&gt;
        &amp;quot;topic_index&amp;quot;: topic.index,&lt;br /&gt;
        &amp;quot;language&amp;quot;: config.language,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: config.tags,&lt;br /&gt;
        &amp;quot;content_type&amp;quot;: &amp;quot;text/markdown&amp;quot;,&lt;br /&gt;
        &amp;quot;source&amp;quot;: {&lt;br /&gt;
            &amp;quot;file&amp;quot;: source_pdf.name,&lt;br /&gt;
            &amp;quot;uri&amp;quot;: config.source_uri,&lt;br /&gt;
            &amp;quot;sha256&amp;quot;: source_sha256,&lt;br /&gt;
            &amp;quot;page_start&amp;quot;: page_start,&lt;br /&gt;
            &amp;quot;page_end&amp;quot;: page_end,&lt;br /&gt;
            &amp;quot;pages&amp;quot;: pages,&lt;br /&gt;
            &amp;quot;trace&amp;quot;: (&lt;br /&gt;
                f&amp;quot;{source_pdf.name}#page={page_start}-{page_end}&amp;quot;&lt;br /&gt;
                if page_start is not None&lt;br /&gt;
                else source_pdf.name&lt;br /&gt;
            ),&lt;br /&gt;
            &amp;quot;pdf_title&amp;quot;: metadata_value(pdf_metadata.get(&amp;quot;title&amp;quot;, &amp;quot;&amp;quot;)) or None,&lt;br /&gt;
            &amp;quot;pdf_author&amp;quot;: metadata_value(pdf_metadata.get(&amp;quot;author&amp;quot;, &amp;quot;&amp;quot;)) or None,&lt;br /&gt;
            &amp;quot;pdf_subject&amp;quot;: metadata_value(pdf_metadata.get(&amp;quot;subject&amp;quot;, &amp;quot;&amp;quot;)) or None,&lt;br /&gt;
            &amp;quot;pdf_keywords&amp;quot;: metadata_value(pdf_metadata.get(&amp;quot;keywords&amp;quot;, &amp;quot;&amp;quot;)) or None,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;rag&amp;quot;: {&lt;br /&gt;
            &amp;quot;unit&amp;quot;: &amp;quot;topic&amp;quot;,&lt;br /&gt;
            &amp;quot;topic_detection&amp;quot;: topic.detection_method,&lt;br /&gt;
            &amp;quot;word_count&amp;quot;: len(re.findall(r&amp;quot;\b\w+\b&amp;quot;, body, flags=re.UNICODE)),&lt;br /&gt;
            &amp;quot;character_count&amp;quot;: len(body),&lt;br /&gt;
            &amp;quot;suggested_splitter&amp;quot;: &amp;quot;markdown_headers_then_token_window&amp;quot;,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;extraction&amp;quot;: {&lt;br /&gt;
            &amp;quot;engine&amp;quot;: &amp;quot;PyMuPDF&amp;quot;,&lt;br /&gt;
            &amp;quot;body_font_size_estimate&amp;quot;: round(body_font, 2),&lt;br /&gt;
            &amp;quot;images&amp;quot;: &amp;quot;ignored&amp;quot;,&lt;br /&gt;
            &amp;quot;repeated_header_footer_filter&amp;quot;: &amp;quot;position_and_frequency&amp;quot;,&lt;br /&gt;
            &amp;quot;standalone_page_number_filter&amp;quot;: &amp;quot;enabled&amp;quot;,&lt;br /&gt;
            &amp;quot;footnote_filter&amp;quot;: (&lt;br /&gt;
                &amp;quot;bottom_position_and_small_font&amp;quot;&lt;br /&gt;
                if config.drop_footnotes&lt;br /&gt;
                else &amp;quot;disabled&amp;quot;&lt;br /&gt;
            ),&lt;br /&gt;
            &amp;quot;page_comments_in_body&amp;quot;: config.include_page_comments,&lt;br /&gt;
        },&lt;br /&gt;
        &amp;quot;output_file&amp;quot;: filename,&lt;br /&gt;
        &amp;quot;generated_at&amp;quot;: generated_at,&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def write_topic_files(&lt;br /&gt;
    topics: Sequence[Topic],&lt;br /&gt;
    output_dir: Path,&lt;br /&gt;
    source_pdf: Path,&lt;br /&gt;
    source_sha256: str,&lt;br /&gt;
    document_id: str,&lt;br /&gt;
    pdf_metadata: dict[str, Any],&lt;br /&gt;
    config: Config,&lt;br /&gt;
    body_font: float,&lt;br /&gt;
) -&amp;gt; list[dict[str, Any]]:&lt;br /&gt;
    output_dir.mkdir(parents=True, exist_ok=True)&lt;br /&gt;
    generated_at = utc_now_iso()&lt;br /&gt;
    used_filenames: set[str] = set()&lt;br /&gt;
    manifest_topics: list[dict[str, Any]] = []&lt;br /&gt;
&lt;br /&gt;
    for topic in topics:&lt;br /&gt;
        if SKIP_TOPIC_RE.fullmatch(topic.title.strip()):&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        body = topic.body&lt;br /&gt;
        if not body:&lt;br /&gt;
            continue&lt;br /&gt;
&lt;br /&gt;
        base_filename = f&amp;quot;{topic.index:03d}-{slugify(topic.title)}.md&amp;quot;&lt;br /&gt;
        filename = ensure_unique_filename(base_filename, used_filenames)&lt;br /&gt;
        metadata = build_front_matter(&lt;br /&gt;
            topic=topic,&lt;br /&gt;
            filename=filename,&lt;br /&gt;
            source_pdf=source_pdf,&lt;br /&gt;
            source_sha256=source_sha256,&lt;br /&gt;
            document_id=document_id,&lt;br /&gt;
            pdf_metadata=pdf_metadata,&lt;br /&gt;
            config=config,&lt;br /&gt;
            body=body,&lt;br /&gt;
            generated_at=generated_at,&lt;br /&gt;
            body_font=body_font,&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        front_matter = yaml.safe_dump(&lt;br /&gt;
            metadata,&lt;br /&gt;
            allow_unicode=True,&lt;br /&gt;
            sort_keys=False,&lt;br /&gt;
            default_flow_style=False,&lt;br /&gt;
            width=120,&lt;br /&gt;
        ).strip()&lt;br /&gt;
&lt;br /&gt;
        markdown = f&amp;quot;---\n{front_matter}\n---\n\n# {topic.title}\n\n{body}\n&amp;quot;&lt;br /&gt;
        destination = output_dir / filename&lt;br /&gt;
        destination.write_text(markdown, encoding=&amp;quot;utf-8&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
        manifest_topics.append(&lt;br /&gt;
            {&lt;br /&gt;
                &amp;quot;topic_index&amp;quot;: topic.index,&lt;br /&gt;
                &amp;quot;topic_id&amp;quot;: metadata[&amp;quot;topic_id&amp;quot;],&lt;br /&gt;
                &amp;quot;title&amp;quot;: topic.title,&lt;br /&gt;
                &amp;quot;file&amp;quot;: filename,&lt;br /&gt;
                &amp;quot;page_start&amp;quot;: metadata[&amp;quot;source&amp;quot;][&amp;quot;page_start&amp;quot;],&lt;br /&gt;
                &amp;quot;page_end&amp;quot;: metadata[&amp;quot;source&amp;quot;][&amp;quot;page_end&amp;quot;],&lt;br /&gt;
                &amp;quot;word_count&amp;quot;: metadata[&amp;quot;rag&amp;quot;][&amp;quot;word_count&amp;quot;],&lt;br /&gt;
                &amp;quot;detection&amp;quot;: topic.detection_method,&lt;br /&gt;
            }&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
    return manifest_topics&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def write_manifest(&lt;br /&gt;
    output_dir: Path,&lt;br /&gt;
    source_pdf: Path,&lt;br /&gt;
    source_sha256: str,&lt;br /&gt;
    document_id: str,&lt;br /&gt;
    page_count: int,&lt;br /&gt;
    body_font: float,&lt;br /&gt;
    removed_repeated_items: int,&lt;br /&gt;
    topics: list[dict[str, Any]],&lt;br /&gt;
    config: Config,&lt;br /&gt;
) -&amp;gt; None:&lt;br /&gt;
    manifest = {&lt;br /&gt;
        &amp;quot;schema_version&amp;quot;: &amp;quot;1.0&amp;quot;,&lt;br /&gt;
        &amp;quot;document_id&amp;quot;: document_id,&lt;br /&gt;
        &amp;quot;source_file&amp;quot;: source_pdf.name,&lt;br /&gt;
        &amp;quot;source_sha256&amp;quot;: source_sha256,&lt;br /&gt;
        &amp;quot;page_count&amp;quot;: page_count,&lt;br /&gt;
        &amp;quot;body_font_size_estimate&amp;quot;: round(body_font, 2),&lt;br /&gt;
        &amp;quot;repeated_header_footer_patterns_removed&amp;quot;: removed_repeated_items,&lt;br /&gt;
        &amp;quot;topic_count&amp;quot;: len(topics),&lt;br /&gt;
        &amp;quot;language&amp;quot;: config.language,&lt;br /&gt;
        &amp;quot;tags&amp;quot;: config.tags,&lt;br /&gt;
        &amp;quot;generated_at&amp;quot;: utc_now_iso(),&lt;br /&gt;
        &amp;quot;topics&amp;quot;: topics,&lt;br /&gt;
    }&lt;br /&gt;
    (output_dir / &amp;quot;manifest.json&amp;quot;).write_text(&lt;br /&gt;
        json.dumps(manifest, ensure_ascii=False, indent=2) + &amp;quot;\n&amp;quot;,&lt;br /&gt;
        encoding=&amp;quot;utf-8&amp;quot;,&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def open_pdf(path: Path, password: str | None) -&amp;gt; Any:&lt;br /&gt;
    try:&lt;br /&gt;
        doc = pymupdf.open(path)&lt;br /&gt;
    except Exception as exc:&lt;br /&gt;
        raise RuntimeError(f&amp;quot;Gagal membuka PDF: {exc}&amp;quot;) from exc&lt;br /&gt;
&lt;br /&gt;
    if getattr(doc, &amp;quot;needs_pass&amp;quot;, False):&lt;br /&gt;
        if not password:&lt;br /&gt;
            doc.close()&lt;br /&gt;
            raise RuntimeError(&amp;quot;PDF terenkripsi. Gunakan opsi --password.&amp;quot;)&lt;br /&gt;
        if not doc.authenticate(password):&lt;br /&gt;
            doc.close()&lt;br /&gt;
            raise RuntimeError(&amp;quot;Password PDF salah.&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
    return doc&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
def main() -&amp;gt; int:&lt;br /&gt;
    args = parse_args()&lt;br /&gt;
    pdf_path = args.pdf.expanduser().resolve()&lt;br /&gt;
&lt;br /&gt;
    if not pdf_path.is_file():&lt;br /&gt;
        print(f&amp;quot;ERROR: File tidak ditemukan: {pdf_path}&amp;quot;, file=sys.stderr)&lt;br /&gt;
        return 2&lt;br /&gt;
    if pdf_path.suffix.casefold() != &amp;quot;.pdf&amp;quot;:&lt;br /&gt;
        print(&amp;quot;ERROR: Input harus berupa file .pdf&amp;quot;, file=sys.stderr)&lt;br /&gt;
        return 2&lt;br /&gt;
&lt;br /&gt;
    output_dir = (&lt;br /&gt;
        args.output_dir.expanduser().resolve()&lt;br /&gt;
        if args.output_dir&lt;br /&gt;
        else pdf_path.with_name(f&amp;quot;{pdf_path.stem}_rag_md&amp;quot;)&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    tags = [item.strip() for item in args.tags.split(&amp;quot;,&amp;quot;) if item.strip()]&lt;br /&gt;
    config = Config(&lt;br /&gt;
        topic_level=args.topic_level,&lt;br /&gt;
        fallback_pages=max(1, args.fallback_pages),&lt;br /&gt;
        top_band=min(max(args.top_band, 0.02), 0.30),&lt;br /&gt;
        bottom_band=min(max(args.bottom_band, 0.02), 0.30),&lt;br /&gt;
        repeat_ratio=min(max(args.repeat_ratio, 0.10), 0.95),&lt;br /&gt;
        drop_footnotes=not args.keep_footnotes,&lt;br /&gt;
        footnote_bottom_band=min(max(args.footnote_bottom_band, 0.05), 0.40),&lt;br /&gt;
        footnote_font_ratio=min(max(args.footnote_font_ratio, 0.50), 1.0),&lt;br /&gt;
        language=args.language.strip() or &amp;quot;und&amp;quot;,&lt;br /&gt;
        tags=tags,&lt;br /&gt;
        source_uri=args.source_uri,&lt;br /&gt;
        include_page_comments=args.page_comments,&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
    source_sha256 = sha256_file(pdf_path)&lt;br /&gt;
    document_id = f&amp;quot;pdf-{source_sha256[:20]}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
        doc = open_pdf(pdf_path, args.password)&lt;br /&gt;
    except RuntimeError as exc:&lt;br /&gt;
        print(f&amp;quot;ERROR: {exc}&amp;quot;, file=sys.stderr)&lt;br /&gt;
        return 2&lt;br /&gt;
&lt;br /&gt;
    try:&lt;br /&gt;
        raw_blocks, font_samples = extract_raw_blocks(doc)&lt;br /&gt;
        if not raw_blocks:&lt;br /&gt;
            print(&lt;br /&gt;
                &amp;quot;ERROR: Tidak ditemukan selectable text. PDF kemungkinan hasil scan; lakukan OCR terlebih dahulu.&amp;quot;,&lt;br /&gt;
                file=sys.stderr,&lt;br /&gt;
            )&lt;br /&gt;
            return 3&lt;br /&gt;
&lt;br /&gt;
        body_font = weighted_mode_font_size(font_samples)&lt;br /&gt;
        repeated_margin_text = detect_repeated_margin_text(&lt;br /&gt;
            raw_blocks,&lt;br /&gt;
            doc.page_count,&lt;br /&gt;
            config.top_band,&lt;br /&gt;
            config.bottom_band,&lt;br /&gt;
            config.repeat_ratio,&lt;br /&gt;
        )&lt;br /&gt;
        blocks = clean_blocks(raw_blocks, repeated_margin_text, body_font, config)&lt;br /&gt;
        if not blocks:&lt;br /&gt;
            print(&amp;quot;ERROR: Semua teks terhapus oleh filter. Coba gunakan --keep-footnotes.&amp;quot;, file=sys.stderr)&lt;br /&gt;
            return 3&lt;br /&gt;
&lt;br /&gt;
        toc_by_page, toc = get_toc_map(doc)&lt;br /&gt;
        pdf_metadata = dict(doc.metadata or {})&lt;br /&gt;
        default_title = topic_default_title(&lt;br /&gt;
            str(pdf_metadata.get(&amp;quot;title&amp;quot;, &amp;quot;&amp;quot;)), pdf_path.stem&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        topics, detected_splits = build_topics_from_headings(&lt;br /&gt;
            blocks,&lt;br /&gt;
            body_font,&lt;br /&gt;
            toc_by_page,&lt;br /&gt;
            default_title,&lt;br /&gt;
            config,&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        # If the PDF has no usable TOC/headings, a single very large topic is not&lt;br /&gt;
        # ideal for retrieval. Split it into deterministic page groups instead.&lt;br /&gt;
        if detected_splits == 0 or (len(topics) &amp;lt;= 1 and doc.page_count &amp;gt; config.fallback_pages):&lt;br /&gt;
            topics = build_topics_by_page_groups(&lt;br /&gt;
                blocks,&lt;br /&gt;
                doc.page_count,&lt;br /&gt;
                config.fallback_pages,&lt;br /&gt;
                default_title,&lt;br /&gt;
                config.include_page_comments,&lt;br /&gt;
            )&lt;br /&gt;
&lt;br /&gt;
        manifest_topics = write_topic_files(&lt;br /&gt;
            topics,&lt;br /&gt;
            output_dir,&lt;br /&gt;
            pdf_path,&lt;br /&gt;
            source_sha256,&lt;br /&gt;
            document_id,&lt;br /&gt;
            pdf_metadata,&lt;br /&gt;
            config,&lt;br /&gt;
            body_font,&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        write_manifest(&lt;br /&gt;
            output_dir,&lt;br /&gt;
            pdf_path,&lt;br /&gt;
            source_sha256,&lt;br /&gt;
            document_id,&lt;br /&gt;
            doc.page_count,&lt;br /&gt;
            body_font,&lt;br /&gt;
            len(repeated_margin_text),&lt;br /&gt;
            manifest_topics,&lt;br /&gt;
            config,&lt;br /&gt;
        )&lt;br /&gt;
&lt;br /&gt;
        print(f&amp;quot;Selesai: {len(manifest_topics)} file topik dibuat di {output_dir}&amp;quot;)&lt;br /&gt;
        print(f&amp;quot;Manifest: {output_dir / 'manifest.json'}&amp;quot;)&lt;br /&gt;
        if toc:&lt;br /&gt;
            print(f&amp;quot;Struktur PDF: TOC tersedia ({len(toc)} entri)&amp;quot;)&lt;br /&gt;
        else:&lt;br /&gt;
            print(&amp;quot;Struktur PDF: TOC tidak tersedia; memakai heading/font atau fallback halaman&amp;quot;)&lt;br /&gt;
        return 0&lt;br /&gt;
    finally:&lt;br /&gt;
        doc.close()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    raise SystemExit(main())&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Requirements-pdf-to-rag-md.txt&amp;diff=73715</id>
		<title>Requirements-pdf-to-rag-md.txt</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Requirements-pdf-to-rag-md.txt&amp;diff=73715"/>
		<updated>2026-07-24T20:57:25Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot; pymupdf&amp;gt;=1.26,&amp;lt;2  pyyaml&amp;gt;=6,&amp;lt;7&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt; pymupdf&amp;gt;=1.26,&amp;lt;2&lt;br /&gt;
 pyyaml&amp;gt;=6,&amp;lt;7&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73714</id>
		<title>RAG: PDF to md</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73714"/>
		<updated>2026-07-24T20:56:52Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;## File Python&lt;br /&gt;
&lt;br /&gt;
* [[pdf_to_rag_md.py]]&lt;br /&gt;
* [[requirements-pdf-to-rag-md.txt]]&lt;br /&gt;
&lt;br /&gt;
Skrip sudah diperiksa dengan `py_compile` dan diuji pada:&lt;br /&gt;
&lt;br /&gt;
* PDF dengan bookmark dan struktur heading.&lt;br /&gt;
* PDF tanpa heading, menggunakan fallback setiap lima halaman.&lt;br /&gt;
&lt;br /&gt;
## Instalasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p ~/Apps/pdf-to-rag&lt;br /&gt;
cd ~/Apps/pdf-to-rag&lt;br /&gt;
&lt;br /&gt;
python3 -m venv .venv&lt;br /&gt;
source .venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
pip install --upgrade pip&lt;br /&gt;
pip install -r requirements-pdf-to-rag-md.txt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Menjalankan&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menentukan folder output:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --output-dir hasil-rag&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menambahkan tag metadata:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --tags &amp;quot;RAG,AI,LLM,dokumentasi&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika folder output sudah ada:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --overwrite&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Format filename&lt;br /&gt;
&lt;br /&gt;
Untuk PDF yang memiliki heading:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 BAB 1 Pendahuluan.md&lt;br /&gt;
Judul Buku 02 1.1 Latar Belakang.md&lt;br /&gt;
Judul Buku 03 1.2 Tujuan.md&lt;br /&gt;
Judul Buku 04 BAB 2 Metode.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika PDF tidak memiliki heading, otomatis fallback per lima halaman:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 Bagian Halaman 1-5.md&lt;br /&gt;
Judul Buku 02 Bagian Halaman 6-10.md&lt;br /&gt;
Judul Buku 03 Bagian Halaman 11-15.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Judul buku diambil secara berurutan dari:&lt;br /&gt;
&lt;br /&gt;
1. Metadata title PDF.&lt;br /&gt;
2. Teks judul dengan font terbesar pada halaman awal.&lt;br /&gt;
3. Nama file PDF.&lt;br /&gt;
&lt;br /&gt;
## Konten yang dibuang&lt;br /&gt;
&lt;br /&gt;
Secara default, skrip membuang:&lt;br /&gt;
&lt;br /&gt;
* Gambar dan blok nonteks.&lt;br /&gt;
* Caption `Gambar`, `Figure`, atau `Fig`.&lt;br /&gt;
* Baris `Sumber:` dan `Source:` pada caption.&lt;br /&gt;
* Nomor halaman.&lt;br /&gt;
* Header dan footer berulang.&lt;br /&gt;
* Footnote yang terdeteksi di bagian bawah halaman.&lt;br /&gt;
* Daftar isi.&lt;br /&gt;
* Daftar gambar dan daftar tabel.&lt;br /&gt;
* Daftar istilah dan glosarium.&lt;br /&gt;
* Daftar singkatan, simbol, dan nomenklatur.&lt;br /&gt;
* Indeks.&lt;br /&gt;
* Daftar pustaka, bibliography, dan references.&lt;br /&gt;
* Kata pengantar, prakata, dan foreword.&lt;br /&gt;
* Ucapan terima kasih.&lt;br /&gt;
* Tentang penulis.&lt;br /&gt;
* Halaman sampul dan copyright yang terdeteksi.&lt;br /&gt;
* Karakter tersembunyi, soft hyphen, dan spasi berlebihan.&lt;br /&gt;
&lt;br /&gt;
## Metadata pada setiap file Markdown&lt;br /&gt;
&lt;br /&gt;
Setiap file memiliki YAML front matter seperti:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
---&lt;br /&gt;
schema_version: '1.0'&lt;br /&gt;
document_id: pdf-914f553ce7c36f8704e4&lt;br /&gt;
topic_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
chunk_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
&lt;br /&gt;
book_title: Buku Uji RAG&lt;br /&gt;
title: BAB 1 Pendahuluan&lt;br /&gt;
topic: BAB 1 Pendahuluan&lt;br /&gt;
topic_index: 1&lt;br /&gt;
&lt;br /&gt;
language: id&lt;br /&gt;
tags:&lt;br /&gt;
  - RAG&lt;br /&gt;
  - AI&lt;br /&gt;
&lt;br /&gt;
source:&lt;br /&gt;
  file: Buku Uji RAG.pdf&lt;br /&gt;
  sha256: 914f553ce7c36f8704e412b1fcb51b90&lt;br /&gt;
  page_start: 3&lt;br /&gt;
  page_end: 8&lt;br /&gt;
  pages:&lt;br /&gt;
    - 3&lt;br /&gt;
    - 4&lt;br /&gt;
    - 5&lt;br /&gt;
    - 6&lt;br /&gt;
    - 7&lt;br /&gt;
    - 8&lt;br /&gt;
  trace: Buku Uji RAG.pdf#page=3-8&lt;br /&gt;
  pdf_title: Buku Uji RAG&lt;br /&gt;
  pdf_author: Nama Penulis&lt;br /&gt;
&lt;br /&gt;
rag:&lt;br /&gt;
  unit: topic&lt;br /&gt;
  filename_pattern: Judul Buku 00 Topik.md&lt;br /&gt;
  topic_detection: pdf_toc&lt;br /&gt;
  word_count: 1450&lt;br /&gt;
  character_count: 9860&lt;br /&gt;
  content_sha256: 76a95b85fe3c9e48882c351138aa5f86&lt;br /&gt;
  suggested_splitter: markdown_headers_then_token_window&lt;br /&gt;
&lt;br /&gt;
extraction:&lt;br /&gt;
  engine: PyMuPDF&lt;br /&gt;
  images: ignored&lt;br /&gt;
  figure_captions: removed&lt;br /&gt;
  junk_sections: removed&lt;br /&gt;
  standalone_page_number_filter: enabled&lt;br /&gt;
  footnote_filter: bottom_position_and_small_font&lt;br /&gt;
&lt;br /&gt;
output_file: Buku Uji RAG 01 BAB 1 Pendahuluan.md&lt;br /&gt;
generated_at: '2026-07-25T03:00:00+00:00'&lt;br /&gt;
---&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Skrip juga menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
manifest.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Manifest berisi daftar semua topik, filename, rentang halaman, metode pendeteksian topik, hash dokumen, dan halaman nonkonten yang dibuang.&lt;br /&gt;
&lt;br /&gt;
PDF hasil scan yang tidak memiliki selectable text harus menjalani OCR terlebih dahulu.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73713</id>
		<title>RAG: PDF to md</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73713"/>
		<updated>2026-07-24T20:56:30Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;## File Python&lt;br /&gt;
&lt;br /&gt;
* [pdf_to_rag_md.py]&lt;br /&gt;
* [requirements-pdf-to-rag-md.txt]&lt;br /&gt;
&lt;br /&gt;
Skrip sudah diperiksa dengan `py_compile` dan diuji pada:&lt;br /&gt;
&lt;br /&gt;
* PDF dengan bookmark dan struktur heading.&lt;br /&gt;
* PDF tanpa heading, menggunakan fallback setiap lima halaman.&lt;br /&gt;
&lt;br /&gt;
## Instalasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p ~/Apps/pdf-to-rag&lt;br /&gt;
cd ~/Apps/pdf-to-rag&lt;br /&gt;
&lt;br /&gt;
python3 -m venv .venv&lt;br /&gt;
source .venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
pip install --upgrade pip&lt;br /&gt;
pip install -r requirements-pdf-to-rag-md.txt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Menjalankan&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menentukan folder output:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --output-dir hasil-rag&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menambahkan tag metadata:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --tags &amp;quot;RAG,AI,LLM,dokumentasi&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika folder output sudah ada:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --overwrite&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Format filename&lt;br /&gt;
&lt;br /&gt;
Untuk PDF yang memiliki heading:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 BAB 1 Pendahuluan.md&lt;br /&gt;
Judul Buku 02 1.1 Latar Belakang.md&lt;br /&gt;
Judul Buku 03 1.2 Tujuan.md&lt;br /&gt;
Judul Buku 04 BAB 2 Metode.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika PDF tidak memiliki heading, otomatis fallback per lima halaman:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 Bagian Halaman 1-5.md&lt;br /&gt;
Judul Buku 02 Bagian Halaman 6-10.md&lt;br /&gt;
Judul Buku 03 Bagian Halaman 11-15.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Judul buku diambil secara berurutan dari:&lt;br /&gt;
&lt;br /&gt;
1. Metadata title PDF.&lt;br /&gt;
2. Teks judul dengan font terbesar pada halaman awal.&lt;br /&gt;
3. Nama file PDF.&lt;br /&gt;
&lt;br /&gt;
## Konten yang dibuang&lt;br /&gt;
&lt;br /&gt;
Secara default, skrip membuang:&lt;br /&gt;
&lt;br /&gt;
* Gambar dan blok nonteks.&lt;br /&gt;
* Caption `Gambar`, `Figure`, atau `Fig`.&lt;br /&gt;
* Baris `Sumber:` dan `Source:` pada caption.&lt;br /&gt;
* Nomor halaman.&lt;br /&gt;
* Header dan footer berulang.&lt;br /&gt;
* Footnote yang terdeteksi di bagian bawah halaman.&lt;br /&gt;
* Daftar isi.&lt;br /&gt;
* Daftar gambar dan daftar tabel.&lt;br /&gt;
* Daftar istilah dan glosarium.&lt;br /&gt;
* Daftar singkatan, simbol, dan nomenklatur.&lt;br /&gt;
* Indeks.&lt;br /&gt;
* Daftar pustaka, bibliography, dan references.&lt;br /&gt;
* Kata pengantar, prakata, dan foreword.&lt;br /&gt;
* Ucapan terima kasih.&lt;br /&gt;
* Tentang penulis.&lt;br /&gt;
* Halaman sampul dan copyright yang terdeteksi.&lt;br /&gt;
* Karakter tersembunyi, soft hyphen, dan spasi berlebihan.&lt;br /&gt;
&lt;br /&gt;
## Metadata pada setiap file Markdown&lt;br /&gt;
&lt;br /&gt;
Setiap file memiliki YAML front matter seperti:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
---&lt;br /&gt;
schema_version: '1.0'&lt;br /&gt;
document_id: pdf-914f553ce7c36f8704e4&lt;br /&gt;
topic_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
chunk_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
&lt;br /&gt;
book_title: Buku Uji RAG&lt;br /&gt;
title: BAB 1 Pendahuluan&lt;br /&gt;
topic: BAB 1 Pendahuluan&lt;br /&gt;
topic_index: 1&lt;br /&gt;
&lt;br /&gt;
language: id&lt;br /&gt;
tags:&lt;br /&gt;
  - RAG&lt;br /&gt;
  - AI&lt;br /&gt;
&lt;br /&gt;
source:&lt;br /&gt;
  file: Buku Uji RAG.pdf&lt;br /&gt;
  sha256: 914f553ce7c36f8704e412b1fcb51b90&lt;br /&gt;
  page_start: 3&lt;br /&gt;
  page_end: 8&lt;br /&gt;
  pages:&lt;br /&gt;
    - 3&lt;br /&gt;
    - 4&lt;br /&gt;
    - 5&lt;br /&gt;
    - 6&lt;br /&gt;
    - 7&lt;br /&gt;
    - 8&lt;br /&gt;
  trace: Buku Uji RAG.pdf#page=3-8&lt;br /&gt;
  pdf_title: Buku Uji RAG&lt;br /&gt;
  pdf_author: Nama Penulis&lt;br /&gt;
&lt;br /&gt;
rag:&lt;br /&gt;
  unit: topic&lt;br /&gt;
  filename_pattern: Judul Buku 00 Topik.md&lt;br /&gt;
  topic_detection: pdf_toc&lt;br /&gt;
  word_count: 1450&lt;br /&gt;
  character_count: 9860&lt;br /&gt;
  content_sha256: 76a95b85fe3c9e48882c351138aa5f86&lt;br /&gt;
  suggested_splitter: markdown_headers_then_token_window&lt;br /&gt;
&lt;br /&gt;
extraction:&lt;br /&gt;
  engine: PyMuPDF&lt;br /&gt;
  images: ignored&lt;br /&gt;
  figure_captions: removed&lt;br /&gt;
  junk_sections: removed&lt;br /&gt;
  standalone_page_number_filter: enabled&lt;br /&gt;
  footnote_filter: bottom_position_and_small_font&lt;br /&gt;
&lt;br /&gt;
output_file: Buku Uji RAG 01 BAB 1 Pendahuluan.md&lt;br /&gt;
generated_at: '2026-07-25T03:00:00+00:00'&lt;br /&gt;
---&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Skrip juga menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
manifest.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Manifest berisi daftar semua topik, filename, rentang halaman, metode pendeteksian topik, hash dokumen, dan halaman nonkonten yang dibuang.&lt;br /&gt;
&lt;br /&gt;
PDF hasil scan yang tidak memiliki selectable text harus menjalani OCR terlebih dahulu.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73712</id>
		<title>RAG: PDF to md</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=RAG:_PDF_to_md&amp;diff=73712"/>
		<updated>2026-07-24T20:54:35Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;## File Python  * [Unduh `pdf_to_rag_md.py`](sandbox:/mnt/data/pdf_to_rag_md.py) * [Unduh `requirements-pdf-to-rag-md.txt`](sandbox:/mnt/data/requirements-pdf-to-rag-md.txt)...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;## File Python&lt;br /&gt;
&lt;br /&gt;
* [Unduh `pdf_to_rag_md.py`](sandbox:/mnt/data/pdf_to_rag_md.py)&lt;br /&gt;
* [Unduh `requirements-pdf-to-rag-md.txt`](sandbox:/mnt/data/requirements-pdf-to-rag-md.txt)&lt;br /&gt;
&lt;br /&gt;
Skrip sudah diperiksa dengan `py_compile` dan diuji pada:&lt;br /&gt;
&lt;br /&gt;
* PDF dengan bookmark dan struktur heading.&lt;br /&gt;
* PDF tanpa heading, menggunakan fallback setiap lima halaman.&lt;br /&gt;
&lt;br /&gt;
## Instalasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p ~/Apps/pdf-to-rag&lt;br /&gt;
cd ~/Apps/pdf-to-rag&lt;br /&gt;
&lt;br /&gt;
python3 -m venv .venv&lt;br /&gt;
source .venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
pip install --upgrade pip&lt;br /&gt;
pip install -r requirements-pdf-to-rag-md.txt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Menjalankan&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menentukan folder output:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --output-dir hasil-rag&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menambahkan tag metadata:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --tags &amp;quot;RAG,AI,LLM,dokumentasi&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika folder output sudah ada:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
python pdf_to_rag_md.py &amp;quot;Judul Buku.pdf&amp;quot; \&lt;br /&gt;
    --overwrite&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Format filename&lt;br /&gt;
&lt;br /&gt;
Untuk PDF yang memiliki heading:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 BAB 1 Pendahuluan.md&lt;br /&gt;
Judul Buku 02 1.1 Latar Belakang.md&lt;br /&gt;
Judul Buku 03 1.2 Tujuan.md&lt;br /&gt;
Judul Buku 04 BAB 2 Metode.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika PDF tidak memiliki heading, otomatis fallback per lima halaman:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Judul Buku 01 Bagian Halaman 1-5.md&lt;br /&gt;
Judul Buku 02 Bagian Halaman 6-10.md&lt;br /&gt;
Judul Buku 03 Bagian Halaman 11-15.md&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Judul buku diambil secara berurutan dari:&lt;br /&gt;
&lt;br /&gt;
1. Metadata title PDF.&lt;br /&gt;
2. Teks judul dengan font terbesar pada halaman awal.&lt;br /&gt;
3. Nama file PDF.&lt;br /&gt;
&lt;br /&gt;
## Konten yang dibuang&lt;br /&gt;
&lt;br /&gt;
Secara default, skrip membuang:&lt;br /&gt;
&lt;br /&gt;
* Gambar dan blok nonteks.&lt;br /&gt;
* Caption `Gambar`, `Figure`, atau `Fig`.&lt;br /&gt;
* Baris `Sumber:` dan `Source:` pada caption.&lt;br /&gt;
* Nomor halaman.&lt;br /&gt;
* Header dan footer berulang.&lt;br /&gt;
* Footnote yang terdeteksi di bagian bawah halaman.&lt;br /&gt;
* Daftar isi.&lt;br /&gt;
* Daftar gambar dan daftar tabel.&lt;br /&gt;
* Daftar istilah dan glosarium.&lt;br /&gt;
* Daftar singkatan, simbol, dan nomenklatur.&lt;br /&gt;
* Indeks.&lt;br /&gt;
* Daftar pustaka, bibliography, dan references.&lt;br /&gt;
* Kata pengantar, prakata, dan foreword.&lt;br /&gt;
* Ucapan terima kasih.&lt;br /&gt;
* Tentang penulis.&lt;br /&gt;
* Halaman sampul dan copyright yang terdeteksi.&lt;br /&gt;
* Karakter tersembunyi, soft hyphen, dan spasi berlebihan.&lt;br /&gt;
&lt;br /&gt;
## Metadata pada setiap file Markdown&lt;br /&gt;
&lt;br /&gt;
Setiap file memiliki YAML front matter seperti:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
---&lt;br /&gt;
schema_version: '1.0'&lt;br /&gt;
document_id: pdf-914f553ce7c36f8704e4&lt;br /&gt;
topic_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
chunk_id: pdf-914f553ce7c36f8704e4-topic-0001&lt;br /&gt;
&lt;br /&gt;
book_title: Buku Uji RAG&lt;br /&gt;
title: BAB 1 Pendahuluan&lt;br /&gt;
topic: BAB 1 Pendahuluan&lt;br /&gt;
topic_index: 1&lt;br /&gt;
&lt;br /&gt;
language: id&lt;br /&gt;
tags:&lt;br /&gt;
  - RAG&lt;br /&gt;
  - AI&lt;br /&gt;
&lt;br /&gt;
source:&lt;br /&gt;
  file: Buku Uji RAG.pdf&lt;br /&gt;
  sha256: 914f553ce7c36f8704e412b1fcb51b90&lt;br /&gt;
  page_start: 3&lt;br /&gt;
  page_end: 8&lt;br /&gt;
  pages:&lt;br /&gt;
    - 3&lt;br /&gt;
    - 4&lt;br /&gt;
    - 5&lt;br /&gt;
    - 6&lt;br /&gt;
    - 7&lt;br /&gt;
    - 8&lt;br /&gt;
  trace: Buku Uji RAG.pdf#page=3-8&lt;br /&gt;
  pdf_title: Buku Uji RAG&lt;br /&gt;
  pdf_author: Nama Penulis&lt;br /&gt;
&lt;br /&gt;
rag:&lt;br /&gt;
  unit: topic&lt;br /&gt;
  filename_pattern: Judul Buku 00 Topik.md&lt;br /&gt;
  topic_detection: pdf_toc&lt;br /&gt;
  word_count: 1450&lt;br /&gt;
  character_count: 9860&lt;br /&gt;
  content_sha256: 76a95b85fe3c9e48882c351138aa5f86&lt;br /&gt;
  suggested_splitter: markdown_headers_then_token_window&lt;br /&gt;
&lt;br /&gt;
extraction:&lt;br /&gt;
  engine: PyMuPDF&lt;br /&gt;
  images: ignored&lt;br /&gt;
  figure_captions: removed&lt;br /&gt;
  junk_sections: removed&lt;br /&gt;
  standalone_page_number_filter: enabled&lt;br /&gt;
  footnote_filter: bottom_position_and_small_font&lt;br /&gt;
&lt;br /&gt;
output_file: Buku Uji RAG 01 BAB 1 Pendahuluan.md&lt;br /&gt;
generated_at: '2026-07-25T03:00:00+00:00'&lt;br /&gt;
---&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Skrip juga menghasilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
manifest.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Manifest berisi daftar semua topik, filename, rentang halaman, metode pendeteksian topik, hash dokumen, dan halaman nonkonten yang dibuang.&lt;br /&gt;
&lt;br /&gt;
PDF hasil scan yang tidak memiliki selectable text harus menjalani OCR terlebih dahulu.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=RAG&amp;diff=73711</id>
		<title>RAG</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=RAG&amp;diff=73711"/>
		<updated>2026-07-24T20:53:52Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;   ==Pranala Menarik==  * RAG: PDF to md&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[RAG: PDF to md]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=MCP:_Instalasi&amp;diff=73710</id>
		<title>MCP: Instalasi</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=MCP:_Instalasi&amp;diff=73710"/>
		<updated>2026-07-24T09:56:10Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;# PANDUAN INSTALASI LOCAL AI STACK BERBASIS DOCKER  ## Ollama + Open WebUI + AnythingLLM + MCP + n8n  **Perangkat:**  ```text Laptop       : Dell RAM          : 16 GB GPU...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# PANDUAN INSTALASI LOCAL AI STACK BERBASIS DOCKER&lt;br /&gt;
&lt;br /&gt;
## Ollama + Open WebUI + AnythingLLM + MCP + n8n&lt;br /&gt;
&lt;br /&gt;
**Perangkat:**&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Laptop       : Dell&lt;br /&gt;
RAM          : 16 GB&lt;br /&gt;
GPU          : NVIDIA RTX 4060&lt;br /&gt;
VRAM         : 8 GB&lt;br /&gt;
Penyimpanan  : SSD 250 GB&lt;br /&gt;
Sistem       : Ubuntu Server 26.04 LTS&lt;br /&gt;
Folder utama : /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
**Model yang digunakan:**&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Model LLM       : qwen3:8b&lt;br /&gt;
Model embedding : bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Panduan ini diverifikasi pada **24 Juli 2026**. Docker Engine saat ini mencantumkan Ubuntu Resolute 26.04 LTS sebagai sistem yang didukung.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 1. TUJUAN INSTALASI&lt;br /&gt;
&lt;br /&gt;
Sistem ini akan menyediakan:&lt;br /&gt;
&lt;br /&gt;
1. **Ollama**&lt;br /&gt;
&lt;br /&gt;
   * Menjalankan `qwen3:8b` menggunakan GPU RTX 4060.&lt;br /&gt;
   * Menjalankan `bge-m3` untuk embedding dokumen.&lt;br /&gt;
&lt;br /&gt;
2. **Open WebUI**&lt;br /&gt;
&lt;br /&gt;
   * Antarmuka chat berbasis web.&lt;br /&gt;
   * Tidak diberi akses GPU secara langsung.&lt;br /&gt;
   * Menggunakan Ollama sebagai backend.&lt;br /&gt;
   * Menggunakan `bge-m3` untuk embedding file Markdown dan PDF.&lt;br /&gt;
&lt;br /&gt;
3. **AnythingLLM**&lt;br /&gt;
&lt;br /&gt;
   * Menjalankan RAG.&lt;br /&gt;
   * Menganalisis PDF, DOCX, Markdown, dan teks.&lt;br /&gt;
   * Melakukan ekstraksi entitas atau NER.&lt;br /&gt;
   * Menggunakan `qwen3:8b` melalui Ollama.&lt;br /&gt;
   * Menggunakan `bge-m3` sebagai embedding model.&lt;br /&gt;
   * Menggunakan LanceDB sebagai vector database lokal.&lt;br /&gt;
&lt;br /&gt;
4. **MCP**&lt;br /&gt;
&lt;br /&gt;
   * Mengambil halaman web.&lt;br /&gt;
   * Melakukan ekstraksi isi halaman HTML menjadi Markdown.&lt;br /&gt;
   * Melihat dan membaca file lokal.&lt;br /&gt;
   * Mengubah PDF dan DOCX menjadi Markdown.&lt;br /&gt;
&lt;br /&gt;
5. **n8n**&lt;br /&gt;
&lt;br /&gt;
   * Menjalankan otomasi workflow.&lt;br /&gt;
   * Menghubungkan Ollama dengan API, database, file, dan aplikasi lain.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 2. ARSITEKTUR SISTEM&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
                         RTX 4060 8 GB&lt;br /&gt;
                               │&lt;br /&gt;
                               ▼&lt;br /&gt;
                         Ollama Docker&lt;br /&gt;
                    ┌──────────┴──────────┐&lt;br /&gt;
                    │                     │&lt;br /&gt;
                qwen3:8b               bge-m3&lt;br /&gt;
                    │                     │&lt;br /&gt;
          ┌─────────┼─────────┐           │&lt;br /&gt;
          │         │         │           │&lt;br /&gt;
          ▼         ▼         ▼           ▼&lt;br /&gt;
   AnythingLLM  Open WebUI    n8n    Embedding RAG&lt;br /&gt;
          │&lt;br /&gt;
          ▼&lt;br /&gt;
     MCP Client&lt;br /&gt;
          │&lt;br /&gt;
     ┌────┼─────────────────┐&lt;br /&gt;
     │    │                 │&lt;br /&gt;
     ▼    ▼                 ▼&lt;br /&gt;
Filesystem MCP         Fetch MCP       MarkItDown MCP&lt;br /&gt;
     │                     │                 │&lt;br /&gt;
     ▼                     ▼                 ▼&lt;br /&gt;
File lokal          Web/HTML biasa      PDF dan DOCX&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Hubungan Ollama dengan MCP&lt;br /&gt;
&lt;br /&gt;
Ollama bukan MCP server dan bukan komponen yang menjalankan MCP tool secara langsung.&lt;br /&gt;
&lt;br /&gt;
Alurnya adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Pengguna&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
AnythingLLM&lt;br /&gt;
   │&lt;br /&gt;
   ├── mengirim prompt dan definisi tool ke qwen3:8b&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
qwen3:8b memilih tool&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
AnythingLLM menjalankan MCP tool&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
Hasil tool dikirim kembali ke qwen3:8b&lt;br /&gt;
   │&lt;br /&gt;
   ▼&lt;br /&gt;
Jawaban akhir&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
AnythingLLM Docker mendukung MCP **Tools**, tetapi dokumentasinya saat ini tidak menyatakan dukungan MCP Resources, Prompts, atau Sampling. AnythingLLM juga sudah menyertakan `npx`, `uv`, `uvx`, Node.js, dan Bash yang diperlukan untuk menjalankan MCP server.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 3. PEMILIHAN MODEL&lt;br /&gt;
&lt;br /&gt;
## 3.1 Model utama: `qwen3:8b`&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Nama          : qwen3:8b&lt;br /&gt;
Parameter     : sekitar 8,19 miliar&lt;br /&gt;
Quantization  : Q4_K_M&lt;br /&gt;
Ukuran file   : sekitar 5,2 GB&lt;br /&gt;
Jenis input   : teks&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Qwen3 mendukung lebih dari 100 bahasa dan dialek, mempunyai kemampuan tool use, serta dirancang untuk penggunaan agent dan integrasi external tools. Hal tersebut menjadikannya pilihan yang masuk akal untuk Bahasa Indonesia, RAG, analisis teks, ekstraksi informasi, dan MCP pada GPU 8 GB.&lt;br /&gt;
&lt;br /&gt;
Model ini digunakan oleh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
AnythingLLM&lt;br /&gt;
Open WebUI&lt;br /&gt;
n8n&lt;br /&gt;
MCP agent melalui AnythingLLM&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 3.2 Model embedding: `bge-m3`&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Nama          : bge-m3&lt;br /&gt;
Parameter     : sekitar 567 juta&lt;br /&gt;
Ukuran file   : sekitar 1,2 GB&lt;br /&gt;
Context       : hingga 8192 token&lt;br /&gt;
Jenis         : embedding model&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
BGE-M3 dirancang untuk embedding multibahasa, mendukung lebih dari 100 bahasa, dan dapat memproses teks sampai sekitar 8192 token. Model ini digunakan untuk mengubah teks menjadi vector sebelum disimpan dalam vector database.&lt;br /&gt;
&lt;br /&gt;
Model ini digunakan oleh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Open WebUI&lt;br /&gt;
AnythingLLM&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 3.3 Perkiraan penyimpanan model&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
qwen3:8b : sekitar 5,2 GB&lt;br /&gt;
bge-m3   : sekitar 1,2 GB&lt;br /&gt;
--------------------------------&lt;br /&gt;
Total    : sekitar 6,4 GB&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Angka tersebut hanya ukuran file model. Docker images, cache, dokumen, log, database, dan vector database memerlukan kapasitas tambahan.&lt;br /&gt;
&lt;br /&gt;
Karena SSD hanya 250 GB:&lt;br /&gt;
&lt;br /&gt;
* gunakan hanya satu LLM utama;&lt;br /&gt;
* gunakan satu embedding model;&lt;br /&gt;
* jangan memasang model 14B, 27B, 32B, atau lebih besar;&lt;br /&gt;
* simpan backup pada disk eksternal;&lt;br /&gt;
* periksa penggunaan disk secara berkala.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 4. BATASAN SISTEM&lt;br /&gt;
&lt;br /&gt;
Konfigurasi awal yang aman:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Context Ollama          : 4096&lt;br /&gt;
Request paralel         : 1&lt;br /&gt;
Model aktif bersamaan   : 1&lt;br /&gt;
Embedding               : bge-m3&lt;br /&gt;
Jumlah pengguna         : satu atau beberapa pengguna ringan&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dokumentasi Ollama menggunakan context default 4096 pada GPU dengan VRAM di bawah 24 GiB. Context yang lebih besar membutuhkan lebih banyak memori.&lt;br /&gt;
&lt;br /&gt;
Pengaturan satu model aktif berarti Ollama dapat bergantian memuat `bge-m3` dan `qwen3:8b`. Ini lebih aman untuk VRAM 8 GB, walaupun respons RAG pertama dapat sedikit lebih lambat.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 5. PEMERIKSAAN AWAL&lt;br /&gt;
&lt;br /&gt;
Login ke Ubuntu Server melalui console atau SSH.&lt;br /&gt;
&lt;br /&gt;
Periksa sistem operasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat /etc/os-release&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa arsitektur:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
uname -m&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
x86_64&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
lspci | grep -Ei 'NVIDIA|VGA|3D'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa RAM:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
free -h&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa kapasitas disk:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
df -h /&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa alamat IP:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ip -br address&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Catat alamat IP server, misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
192.168.0.10&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 6. UPDATE UBUNTU&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt full-upgrade -y&lt;br /&gt;
&lt;br /&gt;
sudo apt install -y \&lt;br /&gt;
    ca-certificates \&lt;br /&gt;
    curl \&lt;br /&gt;
    gnupg \&lt;br /&gt;
    jq \&lt;br /&gt;
    openssl \&lt;br /&gt;
    pciutils \&lt;br /&gt;
    ubuntu-drivers-common \&lt;br /&gt;
    linux-headers-$(uname -r)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Reboot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo reboot&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Login kembali setelah server aktif.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 7. INSTALASI DRIVER NVIDIA&lt;br /&gt;
&lt;br /&gt;
## 7.1 Periksa driver yang tersedia&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ubuntu-drivers list --gpgpu&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 7.2 Instal driver rekomendasi Ubuntu&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ubuntu-drivers install --gpgpu&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ubuntu merekomendasikan penggunaan `ubuntu-drivers` untuk memilih driver yang sesuai. Opsi `--gpgpu` ditujukan untuk sistem komputasi atau server GPU.&lt;br /&gt;
&lt;br /&gt;
Reboot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo reboot&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 7.3 Verifikasi GPU&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil harus menampilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NVIDIA GeForce RTX 4060&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan melanjutkan ke instalasi Ollama GPU sebelum `nvidia-smi` berhasil.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 8. INSTALASI DOCKER ENGINE&lt;br /&gt;
&lt;br /&gt;
Hapus paket Docker lama yang mungkin terpasang:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt remove -y \&lt;br /&gt;
    docker.io \&lt;br /&gt;
    docker-compose \&lt;br /&gt;
    docker-compose-v2 \&lt;br /&gt;
    docker-doc \&lt;br /&gt;
    podman-docker \&lt;br /&gt;
    containerd \&lt;br /&gt;
    runc 2&amp;gt;/dev/null || true&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tambahkan repository resmi Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y ca-certificates curl&lt;br /&gt;
&lt;br /&gt;
sudo install -m 0755 -d /etc/apt/keyrings&lt;br /&gt;
&lt;br /&gt;
sudo curl -fsSL \&lt;br /&gt;
    https://download.docker.com/linux/ubuntu/gpg \&lt;br /&gt;
    -o /etc/apt/keyrings/docker.asc&lt;br /&gt;
&lt;br /&gt;
sudo chmod a+r /etc/apt/keyrings/docker.asc&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat file repository:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /etc/apt/sources.list.d/docker.sources &amp;gt;/dev/null &amp;lt;&amp;lt;EOF&lt;br /&gt;
Types: deb&lt;br /&gt;
URIs: https://download.docker.com/linux/ubuntu&lt;br /&gt;
Suites: $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&amp;quot;)&lt;br /&gt;
Components: stable&lt;br /&gt;
Architectures: $(dpkg --print-architecture)&lt;br /&gt;
Signed-By: /etc/apt/keyrings/docker.asc&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instal Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
&lt;br /&gt;
sudo apt install -y \&lt;br /&gt;
    docker-ce \&lt;br /&gt;
    docker-ce-cli \&lt;br /&gt;
    containerd.io \&lt;br /&gt;
    docker-buildx-plugin \&lt;br /&gt;
    docker-compose-plugin&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perintah tersebut mengikuti metode instalasi repository resmi Docker untuk Ubuntu.&lt;br /&gt;
&lt;br /&gt;
Aktifkan Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl enable --now docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl status docker --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa versi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker version&lt;br /&gt;
sudo docker compose version&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tes:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm hello-world&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 9. INSTALASI NVIDIA CONTAINER TOOLKIT&lt;br /&gt;
&lt;br /&gt;
Tambahkan repository NVIDIA:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsSL \&lt;br /&gt;
    https://nvidia.github.io/libnvidia-container/gpgkey \&lt;br /&gt;
    | sudo gpg --dearmor \&lt;br /&gt;
    -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -s -L \&lt;br /&gt;
    https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \&lt;br /&gt;
    | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \&lt;br /&gt;
    | sudo tee \&lt;br /&gt;
    /etc/apt/sources.list.d/nvidia-container-toolkit.list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instal toolkit:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y nvidia-container-toolkit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasikan Docker runtime:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nvidia-ctk runtime configure --runtime=docker&lt;br /&gt;
sudo systemctl restart docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
NVIDIA menggunakan `nvidia-ctk runtime configure --runtime=docker` untuk menghubungkan NVIDIA Container Runtime dengan Docker.&lt;br /&gt;
&lt;br /&gt;
Tes akses GPU dari container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm --gpus all ubuntu nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil harus menampilkan RTX 4060. Ollama juga merekomendasikan pengujian container GPU dengan metode tersebut ketika melakukan troubleshooting.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 10. MEMBUAT STRUKTUR DIREKTORI&lt;br /&gt;
&lt;br /&gt;
Gunakan folder utama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat direktori:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mkdir -p \&lt;br /&gt;
    /opt/ai-stack/ollama \&lt;br /&gt;
    /opt/ai-stack/open-webui \&lt;br /&gt;
    /opt/ai-stack/anythingllm/storage/plugins \&lt;br /&gt;
    /opt/ai-stack/documents \&lt;br /&gt;
    /opt/ai-stack/n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur pemilik:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown -R &amp;quot;$USER&amp;quot;:&amp;quot;$USER&amp;quot; /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
AnythingLLM dan n8n biasanya menggunakan UID 1000 di dalam container. Atur direktori penyimpanannya:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown -R 1000:1000 \&lt;br /&gt;
    /opt/ai-stack/anythingllm/storage \&lt;br /&gt;
    /opt/ai-stack/n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur direktori dokumen:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chmod 755 /opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Struktur akhir:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/&lt;br /&gt;
├── .env&lt;br /&gt;
├── docker-compose.yml&lt;br /&gt;
├── ollama/&lt;br /&gt;
├── open-webui/&lt;br /&gt;
├── anythingllm/&lt;br /&gt;
│   └── storage/&lt;br /&gt;
│       └── plugins/&lt;br /&gt;
├── documents/&lt;br /&gt;
└── n8n/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Seluruh data persisten aplikasi disimpan di bawah `/opt/ai-stack`. Docker tetap menyimpan image dan layer internalnya di direktori standar Docker.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 11. MEMBUAT SECRET&lt;br /&gt;
&lt;br /&gt;
Masuk ke direktori:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat `.env`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
umask 077&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; .env &amp;lt;&amp;lt;EOF&lt;br /&gt;
WEBUI_SECRET_KEY=$(openssl rand -hex 32)&lt;br /&gt;
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lindungi file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod 600 /opt/ai-stack/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa nama variabel tanpa menampilkan secret:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cut -d= -f1 /opt/ai-stack/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
WEBUI_SECRET_KEY&lt;br /&gt;
N8N_ENCRYPTION_KEY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI menggunakan secret persisten untuk keamanan session, sedangkan n8n menggunakan encryption key untuk mengenkripsi credential yang disimpan.&lt;br /&gt;
&lt;br /&gt;
Jangan mengunggah file `.env` ke GitHub atau membagikannya.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 12. MEMBUAT KONFIGURASI MCP&lt;br /&gt;
&lt;br /&gt;
AnythingLLM menyimpan konfigurasi MCP pada:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/app/server/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Karena storage dipasang ke host, lokasi file pada host adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat &amp;gt; \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json \&lt;br /&gt;
&amp;lt;&amp;lt;'JSON'&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;mcpServers&amp;quot;: {&lt;br /&gt;
    &amp;quot;filesystem-local&amp;quot;: {&lt;br /&gt;
      &amp;quot;command&amp;quot;: &amp;quot;npx&amp;quot;,&lt;br /&gt;
      &amp;quot;args&amp;quot;: [&lt;br /&gt;
        &amp;quot;-y&amp;quot;,&lt;br /&gt;
        &amp;quot;@modelcontextprotocol/server-filesystem&amp;quot;,&lt;br /&gt;
        &amp;quot;/documents&amp;quot;&lt;br /&gt;
      ]&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;fetch-web&amp;quot;: {&lt;br /&gt;
      &amp;quot;command&amp;quot;: &amp;quot;uvx&amp;quot;,&lt;br /&gt;
      &amp;quot;args&amp;quot;: [&lt;br /&gt;
        &amp;quot;mcp-server-fetch&amp;quot;&lt;br /&gt;
      ]&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;markitdown-documents&amp;quot;: {&lt;br /&gt;
      &amp;quot;command&amp;quot;: &amp;quot;uvx&amp;quot;,&lt;br /&gt;
      &amp;quot;args&amp;quot;: [&lt;br /&gt;
        &amp;quot;markitdown-mcp&amp;quot;&lt;br /&gt;
      ]&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
JSON&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur pemilik dan permission:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown 1000:1000 \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
&lt;br /&gt;
sudo chmod 600 \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Validasi JSON:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
jq . \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 12.1 Fungsi `filesystem-local`&lt;br /&gt;
&lt;br /&gt;
Filesystem MCP hanya diberi akses ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Package resmi yang digunakan adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
@modelcontextprotocol/server-filesystem&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
MCP server ini membatasi akses pada direktori yang diberikan sebagai argument.&lt;br /&gt;
&lt;br /&gt;
Dalam Docker Compose, folder tersebut akan dipasang sebagai read-only:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents:/documents:ro&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dengan demikian, agent dapat membaca tetapi tidak dapat mengubah file pada host.&lt;br /&gt;
&lt;br /&gt;
## 12.2 Fungsi `fetch-web`&lt;br /&gt;
&lt;br /&gt;
Fetch MCP digunakan untuk:&lt;br /&gt;
&lt;br /&gt;
* mengambil HTML halaman web;&lt;br /&gt;
* mengubah HTML menjadi Markdown;&lt;br /&gt;
* membaca artikel;&lt;br /&gt;
* membaca dokumentasi;&lt;br /&gt;
* mengambil konten URL biasa.&lt;br /&gt;
&lt;br /&gt;
Perintah resminya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
uvx mcp-server-fetch&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Secara default, permintaan yang dibuat model mengikuti aturan `robots.txt`. Fetch MCP juga dapat mengakses alamat internal jika tidak dibatasi, sehingga AnythingLLM hanya boleh digunakan oleh pengguna tepercaya.&lt;br /&gt;
&lt;br /&gt;
Fetch MCP bukan browser lengkap. Sistem ini tidak dijanjikan dapat melewati:&lt;br /&gt;
&lt;br /&gt;
* login;&lt;br /&gt;
* CAPTCHA;&lt;br /&gt;
* proteksi anti-bot;&lt;br /&gt;
* situs yang seluruh isinya membutuhkan JavaScript browser;&lt;br /&gt;
* larangan scraping dari pemilik situs.&lt;br /&gt;
&lt;br /&gt;
## 12.3 Fungsi `markitdown-documents`&lt;br /&gt;
&lt;br /&gt;
MarkItDown MCP digunakan untuk mengubah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
PDF&lt;br /&gt;
DOCX&lt;br /&gt;
HTML&lt;br /&gt;
file teks&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
menjadi Markdown.&lt;br /&gt;
&lt;br /&gt;
Perintahnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
uvx markitdown-mcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tool yang diekspos adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
convert_to_markdown(uri)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
URI yang didukung meliputi `file:`, `http:`, `https:`, dan `data:`. MarkItDown dapat membaca file yang dapat diakses prosesnya, sehingga hanya folder `/documents` yang dipasang ke AnythingLLM.&lt;br /&gt;
&lt;br /&gt;
PDF hasil scan yang hanya berisi gambar mungkin tidak menghasilkan teks yang baik. OCR tidak dipasang dalam panduan dasar ini.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 13. MEMBUAT `docker-compose.yml`&lt;br /&gt;
&lt;br /&gt;
Masuk ke direktori:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat &amp;gt; docker-compose.yml &amp;lt;&amp;lt;'YAML'&lt;br /&gt;
name: ai-stack&lt;br /&gt;
&lt;br /&gt;
x-logging: &amp;amp;default-logging&lt;br /&gt;
  driver: json-file&lt;br /&gt;
  options:&lt;br /&gt;
    max-size: &amp;quot;10m&amp;quot;&lt;br /&gt;
    max-file: &amp;quot;3&amp;quot;&lt;br /&gt;
&lt;br /&gt;
services:&lt;br /&gt;
  ollama:&lt;br /&gt;
    image: ollama/ollama:latest&lt;br /&gt;
    container_name: ollama&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      OLLAMA_CONTEXT_LENGTH: &amp;quot;4096&amp;quot;&lt;br /&gt;
      OLLAMA_MAX_LOADED_MODELS: &amp;quot;1&amp;quot;&lt;br /&gt;
      OLLAMA_NUM_PARALLEL: &amp;quot;1&amp;quot;&lt;br /&gt;
      OLLAMA_FLASH_ATTENTION: &amp;quot;1&amp;quot;&lt;br /&gt;
      OLLAMA_KV_CACHE_TYPE: &amp;quot;q8_0&amp;quot;&lt;br /&gt;
      OLLAMA_KEEP_ALIVE: &amp;quot;5m&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    deploy:&lt;br /&gt;
      resources:&lt;br /&gt;
        reservations:&lt;br /&gt;
          devices:&lt;br /&gt;
            - driver: nvidia&lt;br /&gt;
              count: all&lt;br /&gt;
              capabilities:&lt;br /&gt;
                - gpu&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /opt/ai-stack/ollama:/root/.ollama&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;127.0.0.1:11434:11434&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-network&lt;br /&gt;
&lt;br /&gt;
    logging: *default-logging&lt;br /&gt;
&lt;br /&gt;
  open-webui:&lt;br /&gt;
    image: ghcr.io/open-webui/open-webui:main-slim&lt;br /&gt;
    container_name: open-webui&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    depends_on:&lt;br /&gt;
      - ollama&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      OLLAMA_BASE_URL: http://ollama:11434&lt;br /&gt;
      WEBUI_SECRET_KEY: ${WEBUI_SECRET_KEY}&lt;br /&gt;
&lt;br /&gt;
      RAG_EMBEDDING_ENGINE: ollama&lt;br /&gt;
      RAG_EMBEDDING_MODEL: bge-m3&lt;br /&gt;
      RAG_OLLAMA_BASE_URL: http://ollama:11434&lt;br /&gt;
      RAG_TOP_K: &amp;quot;5&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /opt/ai-stack/open-webui:/app/backend/data&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;3000:8080&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-network&lt;br /&gt;
&lt;br /&gt;
    logging: *default-logging&lt;br /&gt;
&lt;br /&gt;
  anythingllm:&lt;br /&gt;
    image: mintplexlabs/anythingllm:latest&lt;br /&gt;
    container_name: anythingllm&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    depends_on:&lt;br /&gt;
      - ollama&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /opt/ai-stack/anythingllm/storage:/app/server/storage&lt;br /&gt;
      - /opt/ai-stack/documents:/documents:ro&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;3001:3001&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-network&lt;br /&gt;
&lt;br /&gt;
    logging: *default-logging&lt;br /&gt;
&lt;br /&gt;
  n8n:&lt;br /&gt;
    image: docker.n8n.io/n8nio/n8n:latest&lt;br /&gt;
    container_name: n8n&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      TZ: Asia/Jakarta&lt;br /&gt;
      GENERIC_TIMEZONE: Asia/Jakarta&lt;br /&gt;
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - /opt/ai-stack/n8n:/home/node/.n8n&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;5678:5678&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-network&lt;br /&gt;
&lt;br /&gt;
    logging: *default-logging&lt;br /&gt;
&lt;br /&gt;
networks:&lt;br /&gt;
  ai-network:&lt;br /&gt;
    name: ai-network&lt;br /&gt;
    driver: bridge&lt;br /&gt;
YAML&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Penjelasan konfigurasi penting&lt;br /&gt;
&lt;br /&gt;
### Ollama&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_CONTEXT_LENGTH=4096&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membatasi context awal agar sesuai dengan VRAM 8 GB.&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_MAX_LOADED_MODELS=1&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membatasi satu model aktif dalam memori.&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_NUM_PARALLEL=1&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membatasi satu proses inference pada satu waktu. Kebutuhan memori Ollama meningkat sesuai jumlah request paralel dan context yang digunakan.&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_FLASH_ATTENTION=1&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Mengaktifkan Flash Attention ketika didukung.&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_KV_CACHE_TYPE=q8_0&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Mengurangi penggunaan memori KV cache. Dokumentasi Ollama menyatakan `q8_0` menggunakan sekitar setengah memori dibandingkan `f16`, dengan penurunan presisi yang relatif kecil.&lt;br /&gt;
&lt;br /&gt;
### Open WebUI&lt;br /&gt;
&lt;br /&gt;
Image:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
ghcr.io/open-webui/open-webui:main-slim&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dipilih karena lebih kecil dan tidak membawa model lokal bawaan. Image tersebut ditujukan untuk sistem dengan keterbatasan penyimpanan.&lt;br /&gt;
&lt;br /&gt;
Open WebUI tidak diberi konfigurasi GPU. Semua inference dan embedding diteruskan ke container Ollama.&lt;br /&gt;
&lt;br /&gt;
### AnythingLLM&lt;br /&gt;
&lt;br /&gt;
Storage persisten:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/anythingllm/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dipasang pada:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/app/server/storage&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini mengikuti struktur penyimpanan Docker AnythingLLM.&lt;br /&gt;
&lt;br /&gt;
### n8n&lt;br /&gt;
&lt;br /&gt;
Data n8n disimpan di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dan dipasang pada:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/home/node/.n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
n8n dijalankan menggunakan image resmi `docker.n8n.io/n8nio/n8n`.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 14. VALIDASI DOCKER COMPOSE&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose config&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika terdapat kesalahan YAML atau environment variable, Docker akan menampilkannya.&lt;br /&gt;
&lt;br /&gt;
Download image:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose pull&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa penggunaan disk:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker system df&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 15. MENJALANKAN OLLAMA&lt;br /&gt;
&lt;br /&gt;
Jalankan Ollama terlebih dahulu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose up -d ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose ps&lt;br /&gt;
sudo docker compose logs --tail=100 ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Verifikasi GPU dari container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker exec ollama nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika perintah tersebut tidak tersedia di dalam image, gunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm --gpus all ubuntu nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 16. DOWNLOAD MODEL&lt;br /&gt;
&lt;br /&gt;
Download Qwen3:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama \&lt;br /&gt;
    ollama pull qwen3:8b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Download embedding model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama \&lt;br /&gt;
    ollama pull bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa daftar model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil harus memuat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
qwen3:8b&lt;br /&gt;
bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan menarik model tambahan sebelum memeriksa ruang SSD.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 17. MENGUJI QWEN3&lt;br /&gt;
&lt;br /&gt;
Uji dari command line:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama \&lt;br /&gt;
    ollama run qwen3:8b \&lt;br /&gt;
    &amp;quot;Jawab singkat dalam bahasa Indonesia: jelaskan fungsi RAG.&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji melalui API:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl http://127.0.0.1:11434/api/chat \&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
    -d '{&lt;br /&gt;
      &amp;quot;model&amp;quot;: &amp;quot;qwen3:8b&amp;quot;,&lt;br /&gt;
      &amp;quot;messages&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
          &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
          &amp;quot;content&amp;quot;: &amp;quot;Jawab dalam bahasa Indonesia. Apa fungsi RAG?&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
      ],&lt;br /&gt;
      &amp;quot;stream&amp;quot;: false&lt;br /&gt;
    }' | jq -r '.message.content'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa model yang sedang aktif:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perhatikan kolom:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
PROCESSOR&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Target yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
100% GPU&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ollama menggunakan `ollama ps` untuk memperlihatkan apakah model berada di GPU, CPU, atau dibagi antara keduanya.&lt;br /&gt;
&lt;br /&gt;
Pantau GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
watch -n 1 nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 18. MENGUJI EMBEDDING BGE-M3&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl http://127.0.0.1:11434/api/embed \&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
    -d '{&lt;br /&gt;
      &amp;quot;model&amp;quot;: &amp;quot;bge-m3&amp;quot;,&lt;br /&gt;
      &amp;quot;input&amp;quot;: &amp;quot;Dokumen ini membahas kebijakan keamanan informasi.&amp;quot;&lt;br /&gt;
    }' | jq '.embeddings[0] | length'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil harus berupa jumlah dimensi vector, bukan pesan error.&lt;br /&gt;
&lt;br /&gt;
Embedding mengubah teks menjadi vector numerik yang digunakan untuk pencarian semantik dan RAG.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 19. MENJALANKAN SEMUA SERVICE&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Container berikut harus berstatus `Up`:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
ollama&lt;br /&gt;
open-webui&lt;br /&gt;
anythingllm&lt;br /&gt;
n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose logs --tail=100 open-webui&lt;br /&gt;
sudo docker compose logs --tail=100 anythingllm&lt;br /&gt;
sudo docker compose logs --tail=100 n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tampilkan alamat IP server:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
hostname -I&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Alamat layanan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Open WebUI : http://IP-SERVER:3000&lt;br /&gt;
AnythingLLM: http://IP-SERVER:3001&lt;br /&gt;
n8n       : http://IP-SERVER:5678&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.10:3000&lt;br /&gt;
http://192.168.0.10:3001&lt;br /&gt;
http://192.168.0.10:5678&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 20. KONFIGURASI OPEN WEBUI&lt;br /&gt;
&lt;br /&gt;
Buka:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:3000&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat akun administrator pertama.&lt;br /&gt;
&lt;br /&gt;
## 20.1 Koneksi Ollama&lt;br /&gt;
&lt;br /&gt;
Masuk ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Admin Panel&lt;br /&gt;
→ Settings&lt;br /&gt;
→ Connections&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ollama Base URL: http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Variabel resmi Open WebUI untuk koneksi ini adalah `OLLAMA_BASE_URL`.&lt;br /&gt;
&lt;br /&gt;
## 20.2 Konfigurasi embedding&lt;br /&gt;
&lt;br /&gt;
Masuk ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Admin Panel&lt;br /&gt;
→ Settings&lt;br /&gt;
→ Documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Embedding Engine : Ollama&lt;br /&gt;
Ollama URL       : http://ollama:11434&lt;br /&gt;
Embedding Model  : bge-m3&lt;br /&gt;
Top K            : 5&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI mendukung penggunaan Ollama sebagai embedding engine melalui `RAG_EMBEDDING_ENGINE`, `RAG_EMBEDDING_MODEL`, dan `RAG_OLLAMA_BASE_URL`.&lt;br /&gt;
&lt;br /&gt;
## 20.3 Membuat Knowledge Base&lt;br /&gt;
&lt;br /&gt;
Masuk ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Workspace&lt;br /&gt;
→ Knowledge&lt;br /&gt;
→ Create Knowledge&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Upload:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
.md&lt;br /&gt;
.pdf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian gunakan Knowledge tersebut dalam percakapan.&lt;br /&gt;
&lt;br /&gt;
Contoh prompt:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Gunakan hanya informasi dari dokumen yang diberikan.&lt;br /&gt;
&lt;br /&gt;
Buat ringkasan dalam bahasa Indonesia.&lt;br /&gt;
&lt;br /&gt;
Pisahkan:&lt;br /&gt;
- fakta yang tertulis;&lt;br /&gt;
- interpretasi;&lt;br /&gt;
- informasi yang tidak tersedia.&lt;br /&gt;
&lt;br /&gt;
Jangan menambahkan fakta dari luar dokumen.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI melakukan alur:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
PDF atau Markdown&lt;br /&gt;
       ↓&lt;br /&gt;
Ekstraksi teks&lt;br /&gt;
       ↓&lt;br /&gt;
Chunking&lt;br /&gt;
       ↓&lt;br /&gt;
Embedding dengan bge-m3&lt;br /&gt;
       ↓&lt;br /&gt;
Vector database&lt;br /&gt;
       ↓&lt;br /&gt;
Retrieval&lt;br /&gt;
       ↓&lt;br /&gt;
qwen3:8b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Apabila embedding model diganti, dokumen lama harus diindeks ulang karena vector dari embedding model berbeda tidak kompatibel.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 21. KONFIGURASI ANYTHINGLLM&lt;br /&gt;
&lt;br /&gt;
Buka:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:3001&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lakukan konfigurasi awal.&lt;br /&gt;
&lt;br /&gt;
## 21.1 LLM Provider&lt;br /&gt;
&lt;br /&gt;
Pilih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
LLM Provider : Ollama&lt;br /&gt;
Base URL     : http://ollama:11434&lt;br /&gt;
Model        : qwen3:8b&lt;br /&gt;
Context      : 4096&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 21.2 Embedding Provider&lt;br /&gt;
&lt;br /&gt;
Pilih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Embedding Provider : Ollama&lt;br /&gt;
Base URL           : http://ollama:11434&lt;br /&gt;
Embedding Model    : bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 21.3 Vector database&lt;br /&gt;
&lt;br /&gt;
Gunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Vector Database: LanceDB&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
LanceDB tersedia sebagai vector database lokal bawaan sehingga tidak memerlukan container database tambahan. AnythingLLM mendukung Ollama sebagai LLM dan embedding provider serta menyediakan pilihan vector database lokal.&lt;br /&gt;
&lt;br /&gt;
## 21.4 Membuat workspace&lt;br /&gt;
&lt;br /&gt;
Buat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Nama workspace: Analisis Dokumen dan NER&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Rekomendasi awal:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Model            : qwen3:8b&lt;br /&gt;
Context           : 4096&lt;br /&gt;
Temperature       : 0.1–0.2&lt;br /&gt;
Retrieved chunks  : 4–6&lt;br /&gt;
Embedding         : bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 22. DUA CARA MEMBACA DOKUMEN DI ANYTHINGLLM&lt;br /&gt;
&lt;br /&gt;
## 22.1 Menggunakan RAG&lt;br /&gt;
&lt;br /&gt;
Upload PDF atau DOCX ke workspace AnythingLLM.&lt;br /&gt;
&lt;br /&gt;
Alurnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Dokumen&lt;br /&gt;
   ↓&lt;br /&gt;
Parser AnythingLLM&lt;br /&gt;
   ↓&lt;br /&gt;
Chunking&lt;br /&gt;
   ↓&lt;br /&gt;
Embedding bge-m3&lt;br /&gt;
   ↓&lt;br /&gt;
LanceDB&lt;br /&gt;
   ↓&lt;br /&gt;
Retrieval&lt;br /&gt;
   ↓&lt;br /&gt;
qwen3:8b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Gunakan metode ini untuk:&lt;br /&gt;
&lt;br /&gt;
* koleksi dokumen;&lt;br /&gt;
* tanya jawab berulang;&lt;br /&gt;
* pencarian semantik;&lt;br /&gt;
* knowledge base;&lt;br /&gt;
* dokumen yang ingin digunakan jangka panjang.&lt;br /&gt;
&lt;br /&gt;
## 22.2 Menggunakan MCP MarkItDown&lt;br /&gt;
&lt;br /&gt;
Gunakan MarkItDown MCP untuk membaca file tertentu secara langsung.&lt;br /&gt;
&lt;br /&gt;
Alurnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
File PDF atau DOCX&lt;br /&gt;
        ↓&lt;br /&gt;
MarkItDown MCP&lt;br /&gt;
        ↓&lt;br /&gt;
Markdown&lt;br /&gt;
        ↓&lt;br /&gt;
qwen3:8b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Metode ini tidak otomatis memasukkan file ke vector database.&lt;br /&gt;
&lt;br /&gt;
Gunakan untuk:&lt;br /&gt;
&lt;br /&gt;
* membaca satu file;&lt;br /&gt;
* mengonversi PDF atau DOCX;&lt;br /&gt;
* menganalisis file secara langsung;&lt;br /&gt;
* ekstraksi informasi sekali jalan.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 23. MENGAKTIFKAN MCP DI ANYTHINGLLM&lt;br /&gt;
&lt;br /&gt;
Masuk ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Settings&lt;br /&gt;
→ Agent Skills&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Klik:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Refresh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan muncul:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
filesystem-local&lt;br /&gt;
fetch-web&lt;br /&gt;
markitdown-documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
AnythingLLM memuat konfigurasi dari file `anythingllm_mcp_servers.json`. MCP dapat dijalankan melalui Agent Skills atau menggunakan mode `@agent`.&lt;br /&gt;
&lt;br /&gt;
Pada penggunaan pertama, `npx` dan `uvx` dapat mengunduh package MCP yang dibutuhkan. Package tersebut berada di dalam container dan mungkin perlu diunduh ulang jika container dihapus dan dibuat ulang.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 24. MEMASUKKAN FILE LOKAL&lt;br /&gt;
&lt;br /&gt;
Contoh menyalin PDF:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo cp /lokasi/asli/laporan.pdf \&lt;br /&gt;
    /opt/ai-stack/documents/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh menyalin DOCX:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo cp /lokasi/asli/proposal.docx \&lt;br /&gt;
    /opt/ai-stack/documents/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur permission:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo find /opt/ai-stack/documents \&lt;br /&gt;
    -type d -exec chmod 755 {} \;&lt;br /&gt;
&lt;br /&gt;
sudo find /opt/ai-stack/documents \&lt;br /&gt;
    -type f -exec chmod 644 {} \;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa dari host:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lah /opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa dari container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker exec anythingllm ls -lah /documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 25. PENGUJIAN MCP FILESYSTEM&lt;br /&gt;
&lt;br /&gt;
Aktifkan agent di AnythingLLM, kemudian gunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
@agent&lt;br /&gt;
&lt;br /&gt;
Gunakan tool filesystem-local.&lt;br /&gt;
&lt;br /&gt;
Tampilkan daftar file yang berada di direktori /documents.&lt;br /&gt;
&lt;br /&gt;
Jangan membuat, mengubah, memindahkan, atau menghapus file.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Karena volume menggunakan mode `:ro`, proses di dalam container tidak dapat mengubah file host.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 26. PENGUJIAN MCP PDF&lt;br /&gt;
&lt;br /&gt;
Misalnya terdapat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents/laporan.pdf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Gunakan prompt:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
@agent&lt;br /&gt;
&lt;br /&gt;
Gunakan tool markitdown-documents untuk membaca:&lt;br /&gt;
&lt;br /&gt;
file:///documents/laporan.pdf&lt;br /&gt;
&lt;br /&gt;
Setelah file berhasil dibaca:&lt;br /&gt;
&lt;br /&gt;
1. Buat ringkasan dalam bahasa Indonesia.&lt;br /&gt;
2. Sebutkan fakta penting.&lt;br /&gt;
3. Sebutkan orang, organisasi, lokasi, tanggal, dan nilai uang.&lt;br /&gt;
4. Pisahkan fakta dan interpretasi.&lt;br /&gt;
5. Jangan menambahkan informasi yang tidak terdapat dalam dokumen.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 27. PENGUJIAN MCP DOCX&lt;br /&gt;
&lt;br /&gt;
Misalnya terdapat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents/proposal.docx&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Gunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
@agent&lt;br /&gt;
&lt;br /&gt;
Gunakan tool markitdown-documents untuk membaca:&lt;br /&gt;
&lt;br /&gt;
file:///documents/proposal.docx&lt;br /&gt;
&lt;br /&gt;
Ekstrak:&lt;br /&gt;
&lt;br /&gt;
- tujuan dokumen;&lt;br /&gt;
- nama orang;&lt;br /&gt;
- organisasi;&lt;br /&gt;
- lokasi;&lt;br /&gt;
- tanggal;&lt;br /&gt;
- nilai uang;&lt;br /&gt;
- risiko;&lt;br /&gt;
- keputusan;&lt;br /&gt;
- tindakan lanjutan.&lt;br /&gt;
&lt;br /&gt;
Jangan menebak informasi yang tidak ditulis.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 28. PENGUJIAN MCP WEB&lt;br /&gt;
&lt;br /&gt;
Gunakan situs yang memang boleh diakses dan dibaca.&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
@agent&lt;br /&gt;
&lt;br /&gt;
Gunakan tool fetch-web untuk mengambil:&lt;br /&gt;
&lt;br /&gt;
https://example.com&lt;br /&gt;
&lt;br /&gt;
Jelaskan:&lt;br /&gt;
&lt;br /&gt;
- judul halaman;&lt;br /&gt;
- pokok isi;&lt;br /&gt;
- organisasi yang disebutkan;&lt;br /&gt;
- tanggal jika tersedia;&lt;br /&gt;
- informasi yang tidak dapat diverifikasi.&lt;br /&gt;
&lt;br /&gt;
Jangan menambahkan informasi dari luar halaman.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk halaman lain, ganti URL tersebut.&lt;br /&gt;
&lt;br /&gt;
MCP fetch tidak boleh digunakan untuk:&lt;br /&gt;
&lt;br /&gt;
* melewati login;&lt;br /&gt;
* melewati CAPTCHA;&lt;br /&gt;
* mengabaikan larangan scraping;&lt;br /&gt;
* mengambil data pribadi tanpa izin;&lt;br /&gt;
* menyerang alamat internal;&lt;br /&gt;
* mengakses sistem yang tidak berwenang.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 29. PROMPT NER UNTUK ANYTHINGLLM&lt;br /&gt;
&lt;br /&gt;
`qwen3:8b` merupakan general-purpose instruction model, bukan model NER statistik khusus. Model ini dapat melakukan zero-shot NER, tetapi hasil penting tetap perlu diverifikasi manusia.&lt;br /&gt;
&lt;br /&gt;
Gunakan prompt berikut:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Anda adalah mesin ekstraksi entitas.&lt;br /&gt;
&lt;br /&gt;
Gunakan hanya teks yang terdapat dalam dokumen atau konteks.&lt;br /&gt;
&lt;br /&gt;
Kembalikan JSON valid dengan format berikut:&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;entities&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;text&amp;quot;: &amp;quot;teks persis dari dokumen&amp;quot;,&lt;br /&gt;
      &amp;quot;type&amp;quot;: &amp;quot;PERSON|ORGANIZATION|LOCATION|DATE|TIME|MONEY|PERCENTAGE|PRODUCT|EVENT|LAW|OTHER&amp;quot;,&lt;br /&gt;
      &amp;quot;evidence&amp;quot;: &amp;quot;kalimat tempat entitas ditemukan&amp;quot;,&lt;br /&gt;
      &amp;quot;confidence&amp;quot;: &amp;quot;high|medium|low&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Aturan:&lt;br /&gt;
&lt;br /&gt;
1. Jangan menulis teks di luar JSON.&lt;br /&gt;
2. Jangan membuat entitas yang tidak tertulis.&lt;br /&gt;
3. Jangan memperluas singkatan jika kepanjangannya tidak tersedia.&lt;br /&gt;
4. Jangan mengubah ejaan nama.&lt;br /&gt;
5. Jangan menebak hubungan antarentitas.&lt;br /&gt;
6. Jangan menyimpulkan kewarganegaraan, jabatan, atau afiliasi jika tidak ditulis.&lt;br /&gt;
7. Jika tidak ditemukan entitas, kembalikan:&lt;br /&gt;
&lt;br /&gt;
{&amp;quot;entities&amp;quot;:[]}&lt;br /&gt;
&lt;br /&gt;
8. Confidence menunjukkan kejelasan teks, bukan probabilitas statistik.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk ekstraksi hubungan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Berdasarkan entitas yang ditemukan, ekstrak hanya hubungan yang dinyatakan&lt;br /&gt;
secara eksplisit.&lt;br /&gt;
&lt;br /&gt;
Kembalikan JSON:&lt;br /&gt;
&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;relations&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;subject&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
      &amp;quot;predicate&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
      &amp;quot;object&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
      &amp;quot;evidence&amp;quot;: &amp;quot;&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Jangan membuat hubungan berdasarkan asumsi.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 30. KONFIGURASI N8N&lt;br /&gt;
&lt;br /&gt;
Buka:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:5678&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat akun administrator.&lt;br /&gt;
&lt;br /&gt;
## 30.1 Koneksi n8n ke Ollama&lt;br /&gt;
&lt;br /&gt;
Gunakan alamat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan gunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://localhost:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Di dalam container n8n, `localhost` menunjuk ke container n8n sendiri. Dokumentasi n8n menjelaskan bahwa container dalam Docker network yang sama harus mengakses Ollama menggunakan nama container atau nama service.&lt;br /&gt;
&lt;br /&gt;
## 30.2 Pengujian menggunakan HTTP Request&lt;br /&gt;
&lt;br /&gt;
Tambahkan node:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
HTTP Request&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Method : POST&lt;br /&gt;
URL    : http://ollama:11434/api/chat&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Header:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Content-Type: application/json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Body JSON:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;model&amp;quot;: &amp;quot;qwen3:8b&amp;quot;,&lt;br /&gt;
  &amp;quot;messages&amp;quot;: [&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;role&amp;quot;: &amp;quot;system&amp;quot;,&lt;br /&gt;
      &amp;quot;content&amp;quot;: &amp;quot;Jawab dalam bahasa Indonesia. Jangan menambahkan fakta yang tidak tersedia.&amp;quot;&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      &amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;,&lt;br /&gt;
      &amp;quot;content&amp;quot;: &amp;quot;Ringkas teks berikut: {{$json.text}}&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
  ],&lt;br /&gt;
  &amp;quot;stream&amp;quot;: false&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh workflow:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Schedule Trigger&lt;br /&gt;
       ↓&lt;br /&gt;
Read File atau HTTP Request&lt;br /&gt;
       ↓&lt;br /&gt;
Ollama qwen3:8b&lt;br /&gt;
       ↓&lt;br /&gt;
Ekstraksi atau ringkasan&lt;br /&gt;
       ↓&lt;br /&gt;
Database, email, webhook, atau aplikasi lain&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 31. PEMANTAUAN RESOURCE&lt;br /&gt;
&lt;br /&gt;
Periksa container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
sudo docker compose ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa CPU dan RAM:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker stats --no-stream&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa RAM host:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
free -h&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa model Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa penyimpanan Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker system df&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa ukuran data:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo du -h -d 2 /opt/ai-stack | sort -h&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa kapasitas filesystem:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
df -h / /opt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cari file lebih besar dari 1 GB:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo find /opt/ai-stack \&lt;br /&gt;
    -xdev \&lt;br /&gt;
    -type f \&lt;br /&gt;
    -size +1G \&lt;br /&gt;
    -printf '%s %p\n' \&lt;br /&gt;
    | sort -nr \&lt;br /&gt;
    | head -20&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 32. PENGELOLAAN SSD 250 GB&lt;br /&gt;
&lt;br /&gt;
## Pembersihan image yang tidak digunakan&lt;br /&gt;
&lt;br /&gt;
Periksa dahulu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker system df&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hapus dangling image:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker image prune -f&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hapus build cache yang tidak digunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker builder prune -f&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Menghapus model Ollama&lt;br /&gt;
&lt;br /&gt;
Lihat model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hapus model tertentu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama \&lt;br /&gt;
    ollama rm NAMA_MODEL&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan menghapus:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
qwen3:8b&lt;br /&gt;
bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
selama masih digunakan.&lt;br /&gt;
&lt;br /&gt;
## Hindari perintah berikut&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose down -v&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Opsi `-v` dapat menghapus volume.&lt;br /&gt;
&lt;br /&gt;
Jangan menjalankan tanpa memahami akibatnya:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker system prune -a --volumes&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perintah tersebut dapat menghapus image, cache, network, dan volume yang masih diperlukan.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 33. START, STOP, DAN RESTART&lt;br /&gt;
&lt;br /&gt;
Masuk ke folder:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan semua service:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hentikan sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose stop&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose start&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose restart&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart satu service:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose restart anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hapus container tanpa menghapus bind-mounted data:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose down&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 34. UPDATE CONTAINER&lt;br /&gt;
&lt;br /&gt;
Lakukan backup terlebih dahulu.&lt;br /&gt;
&lt;br /&gt;
Kemudian:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose pull&lt;br /&gt;
sudo docker compose up -d&lt;br /&gt;
sudo docker image prune -f&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose ps&lt;br /&gt;
sudo docker compose logs --tail=100&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tag `latest` dan `main-slim` dapat berubah. Setelah sistem terbukti stabil, penggunaan versi atau image digest yang sudah diuji lebih aman untuk instalasi produksi.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 35. BACKUP&lt;br /&gt;
&lt;br /&gt;
Pasang disk eksternal, misalnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/mnt/backup&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hentikan aplikasi yang menyimpan database:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
sudo docker compose stop \&lt;br /&gt;
    open-webui \&lt;br /&gt;
    anythingllm \&lt;br /&gt;
    n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat backup:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tar \&lt;br /&gt;
    -C /opt \&lt;br /&gt;
    -czf /mnt/backup/ai-stack-data-$(date +%F).tar.gz \&lt;br /&gt;
    ai-stack/docker-compose.yml \&lt;br /&gt;
    ai-stack/.env \&lt;br /&gt;
    ai-stack/open-webui \&lt;br /&gt;
    ai-stack/anythingllm \&lt;br /&gt;
    ai-stack/n8n \&lt;br /&gt;
    ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose start \&lt;br /&gt;
    open-webui \&lt;br /&gt;
    anythingllm \&lt;br /&gt;
    n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Folder model Ollama tidak dimasukkan agar backup lebih kecil. Model dapat diunduh kembali menggunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama pull qwen3:8b&lt;br /&gt;
sudo docker compose exec ollama ollama pull bge-m3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 36. KEAMANAN&lt;br /&gt;
&lt;br /&gt;
## 36.1 Jangan membuka port ke Internet&lt;br /&gt;
&lt;br /&gt;
Port berikut hanya untuk LAN atau VPN:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
3000 : Open WebUI&lt;br /&gt;
3001 : AnythingLLM&lt;br /&gt;
5678 : n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan membuat port forwarding langsung dari router.&lt;br /&gt;
&lt;br /&gt;
Gunakan salah satu:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
WireGuard&lt;br /&gt;
Tailscale&lt;br /&gt;
Reverse proxy dengan HTTPS&lt;br /&gt;
Firewall dengan pembatasan IP&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Docker memperingatkan bahwa port container yang dipublikasikan dapat melewati sebagian aturan UFW atau firewalld. Karena itu, jangan hanya mengandalkan UFW untuk melindungi service Docker yang dipublikasikan.&lt;br /&gt;
&lt;br /&gt;
## 36.2 Ollama hanya tersedia pada host dan Docker network&lt;br /&gt;
&lt;br /&gt;
Compose menggunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
127.0.0.1:11434:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ollama tidak dapat diakses langsung dari komputer LAN, tetapi masih dapat diakses oleh container melalui:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 36.3 Batasi filesystem MCP&lt;br /&gt;
&lt;br /&gt;
AnythingLLM hanya diberi akses ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan memasang:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/&lt;br /&gt;
/etc&lt;br /&gt;
/root&lt;br /&gt;
/home&lt;br /&gt;
/var/run/docker.sock&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ke AnythingLLM.&lt;br /&gt;
&lt;br /&gt;
Jangan menyimpan di folder dokumen:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
password&lt;br /&gt;
SSH private key&lt;br /&gt;
API key&lt;br /&gt;
file .env&lt;br /&gt;
database credential&lt;br /&gt;
token autentikasi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 36.4 Jangan memberikan Docker socket kepada AI&lt;br /&gt;
&lt;br /&gt;
Jangan menambahkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/var/run/docker.sock:/var/run/docker.sock&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ke AnythingLLM, Open WebUI, n8n, atau MCP.&lt;br /&gt;
&lt;br /&gt;
Akses Docker socket dapat memberikan kontrol administratif terhadap host.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 37. TROUBLESHOOTING&lt;br /&gt;
&lt;br /&gt;
## 37.1 Ollama tidak menggunakan GPU&lt;br /&gt;
&lt;br /&gt;
Periksa host:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm --gpus all ubuntu nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi ulang:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nvidia-ctk runtime configure --runtime=docker&lt;br /&gt;
sudo systemctl restart docker&lt;br /&gt;
&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
sudo docker compose restart ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 37.2 Kehabisan VRAM atau RAM&lt;br /&gt;
&lt;br /&gt;
Gejala:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA out of memory&lt;br /&gt;
container exited&lt;br /&gt;
killed&lt;br /&gt;
system memakai swap berlebihan&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pertahankan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Context            : 4096&lt;br /&gt;
Parallel request   : 1&lt;br /&gt;
Loaded models      : 1&lt;br /&gt;
Model              : qwen3:8b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
free -h&lt;br /&gt;
nvidia-smi&lt;br /&gt;
sudo docker stats&lt;br /&gt;
sudo docker compose exec ollama ollama ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan menaikkan context ke 8192 sebelum konfigurasi 4096 terbukti stabil.&lt;br /&gt;
&lt;br /&gt;
## 37.3 AnythingLLM tidak melihat Ollama&lt;br /&gt;
&lt;br /&gt;
Periksa network:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker network inspect ai-network&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji koneksi dengan container sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm \&lt;br /&gt;
    --network ai-network \&lt;br /&gt;
    curlimages/curl:latest \&lt;br /&gt;
    http://ollama:11434/api/tags&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan AnythingLLM menggunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://localhost:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 37.4 MCP tidak muncul&lt;br /&gt;
&lt;br /&gt;
Validasi JSON:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
jq . \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa permission:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lah \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perbaiki jika perlu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown 1000:1000 \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
&lt;br /&gt;
sudo chmod 600 \&lt;br /&gt;
/opt/ai-stack/anythingllm/storage/plugins/anythingllm_mcp_servers.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
sudo docker compose restart anythingllm&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masuk kembali ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Settings&lt;br /&gt;
→ Agent Skills&lt;br /&gt;
→ Refresh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose logs --tail=200 anythingllm \&lt;br /&gt;
    | grep -Ei \&lt;br /&gt;
    'mcp|npx|uvx|fetch|markitdown|filesystem|error'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 37.5 File tidak terlihat&lt;br /&gt;
&lt;br /&gt;
Periksa host:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lah /opt/ai-stack/documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker exec anythingllm ls -lah /documents&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa mount:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker inspect anythingllm \&lt;br /&gt;
    --format '{{json .Mounts}}' | jq&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 37.6 Open WebUI gagal melakukan embedding&lt;br /&gt;
&lt;br /&gt;
Periksa model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker compose exec ollama ollama list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tes:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl http://127.0.0.1:11434/api/embed \&lt;br /&gt;
    -H &amp;quot;Content-Type: application/json&amp;quot; \&lt;br /&gt;
    -d '{&lt;br /&gt;
      &amp;quot;model&amp;quot;: &amp;quot;bge-m3&amp;quot;,&lt;br /&gt;
      &amp;quot;input&amp;quot;: &amp;quot;tes embedding&amp;quot;&lt;br /&gt;
    }' | jq&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan konfigurasi Open WebUI:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Embedding Engine : Ollama&lt;br /&gt;
Embedding Model  : bge-m3&lt;br /&gt;
Ollama URL       : http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian lakukan reindex dokumen.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 38. CHECKLIST AKHIR&lt;br /&gt;
&lt;br /&gt;
## Sistem dan GPU&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[ ] Ubuntu Server 26.04 sudah diperbarui&lt;br /&gt;
[ ] nvidia-smi mendeteksi RTX 4060&lt;br /&gt;
[ ] Docker Engine aktif&lt;br /&gt;
[ ] Docker Compose Plugin tersedia&lt;br /&gt;
[ ] NVIDIA Container Toolkit aktif&lt;br /&gt;
[ ] Container dapat mengakses GPU&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Model&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[ ] qwen3:8b tersedia&lt;br /&gt;
[ ] bge-m3 tersedia&lt;br /&gt;
[ ] qwen3:8b berjalan pada GPU&lt;br /&gt;
[ ] endpoint embedding bge-m3 berhasil&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## Open WebUI&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[ ] Open WebUI dapat dibuka pada port 3000&lt;br /&gt;
[ ] Open WebUI tidak mempunyai akses GPU langsung&lt;br /&gt;
[ ] Ollama URL menggunakan http://ollama:11434&lt;br /&gt;
[ ] Model chat menggunakan qwen3:8b&lt;br /&gt;
[ ] Embedding menggunakan bge-m3&lt;br /&gt;
[ ] File Markdown dapat diindeks&lt;br /&gt;
[ ] PDF berbasis teks dapat diindeks&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## AnythingLLM&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[ ] AnythingLLM dapat dibuka pada port 3001&lt;br /&gt;
[ ] LLM Provider menggunakan Ollama&lt;br /&gt;
[ ] Model menggunakan qwen3:8b&lt;br /&gt;
[ ] Embedder menggunakan bge-m3&lt;br /&gt;
[ ] Vector database menggunakan LanceDB&lt;br /&gt;
[ ] filesystem-local aktif&lt;br /&gt;
[ ] fetch-web aktif&lt;br /&gt;
[ ] markitdown-documents aktif&lt;br /&gt;
[ ] PDF dapat dibaca&lt;br /&gt;
[ ] DOCX dapat dibaca&lt;br /&gt;
[ ] NER menghasilkan JSON valid&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## n8n&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[ ] n8n dapat dibuka pada port 5678&lt;br /&gt;
[ ] Data n8n persisten&lt;br /&gt;
[ ] Timezone Asia/Jakarta&lt;br /&gt;
[ ] n8n dapat mengakses http://ollama:11434&lt;br /&gt;
[ ] qwen3:8b dapat dipanggil dari workflow&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 39. KONFIGURASI FINAL&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Folder utama              : /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
Ollama image              : ollama/ollama:latest&lt;br /&gt;
Ollama model              : qwen3:8b&lt;br /&gt;
Embedding model           : bge-m3&lt;br /&gt;
Context awal              : 4096&lt;br /&gt;
Request paralel           : 1&lt;br /&gt;
Model aktif               : 1&lt;br /&gt;
Ollama host port          : 127.0.0.1:11434&lt;br /&gt;
&lt;br /&gt;
Open WebUI image          : open-webui:main-slim&lt;br /&gt;
Open WebUI GPU            : tidak&lt;br /&gt;
Open WebUI port           : 3000&lt;br /&gt;
Open WebUI LLM            : qwen3:8b melalui Ollama&lt;br /&gt;
Open WebUI embedding      : bge-m3 melalui Ollama&lt;br /&gt;
&lt;br /&gt;
AnythingLLM port          : 3001&lt;br /&gt;
AnythingLLM LLM           : qwen3:8b&lt;br /&gt;
AnythingLLM embedding     : bge-m3&lt;br /&gt;
AnythingLLM vector DB     : LanceDB&lt;br /&gt;
&lt;br /&gt;
MCP filesystem            : @modelcontextprotocol/server-filesystem&lt;br /&gt;
MCP web                   : mcp-server-fetch&lt;br /&gt;
MCP PDF/DOCX              : markitdown-mcp&lt;br /&gt;
Folder dokumen host       : /opt/ai-stack/documents&lt;br /&gt;
Folder dokumen container  : /documents:ro&lt;br /&gt;
&lt;br /&gt;
n8n port                  : 5678&lt;br /&gt;
n8n Ollama URL            : http://ollama:11434&lt;br /&gt;
Timezone                  : Asia/Jakarta&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi ini menggunakan hanya dua model sehingga lebih sesuai untuk RTX 4060 8 GB, RAM 16 GB, dan SSD 250 GB. Open WebUI, AnythingLLM, dan n8n tidak memuat model sendiri; semuanya menggunakan Ollama sebagai backend bersama.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73709</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73709"/>
		<updated>2026-07-24T03:47:33Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* ComfyUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==MCP==&lt;br /&gt;
&lt;br /&gt;
* [[MCP: Instalasi]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Text_to_Speech&amp;diff=73708</id>
		<title>ComfyUI: Text to Speech</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Text_to_Speech&amp;diff=73708"/>
		<updated>2026-07-24T02:38:57Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut catatan instalasi yang telah dibersihkan dari langkah percobaan yang tidak diperlukan. Prosedur ini khusus untuk konfigurasi server Anda.&lt;br /&gt;
&lt;br /&gt;
# Instalasi ComfyUI EdgeTTS Bahasa Indonesia di Docker&lt;br /&gt;
&lt;br /&gt;
## 1. Tujuan&lt;br /&gt;
&lt;br /&gt;
Menambahkan kemampuan *text-to-speech* Bahasa Indonesia pada ComfyUI menggunakan custom node `ComfyUI-EdgeTTS`.&lt;br /&gt;
&lt;br /&gt;
Workflow yang digunakan terdiri dari:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
EdgeTTS → SaveAudio&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pengaturan awal workflow:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Teks   : Halo, selamat datang. Ini adalah contoh text to speech Bahasa Indonesia menggunakan ComfyUI.&lt;br /&gt;
Suara  : [Indonesian] id-ID Gadis&lt;br /&gt;
Speed  : 1.0&lt;br /&gt;
Pitch  : 0&lt;br /&gt;
Output : audio/tts_indonesia&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Workflow menggunakan nama internal node:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
EdgeTTS&lt;br /&gt;
SaveAudio&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`EdgeTTS` merupakan custom node, sedangkan `SaveAudio` merupakan node bawaan ComfyUI. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. Lingkungan yang digunakan&lt;br /&gt;
&lt;br /&gt;
Konfigurasi yang telah terverifikasi pada server:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Folder Docker Compose : /opt/ai-stack&lt;br /&gt;
Nama service          : comfyui&lt;br /&gt;
Folder ComfyUI         : /opt/ComfyUI&lt;br /&gt;
Folder custom node     : /opt/ComfyUI/custom_nodes&lt;br /&gt;
Python virtual env     : /opt/venv/bin/python&lt;br /&gt;
Port ComfyUI           : 8188&lt;br /&gt;
PyTorch                : 2.11.0+cu128&lt;br /&gt;
Torchaudio             : 2.11.0+cu128&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masuk ke folder proyek:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan container ComfyUI aktif:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan endpoint ComfyUI dapat diakses:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/system_stats \&lt;br /&gt;
    | python3 -m json.tool&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. Penyebab error awal&lt;br /&gt;
&lt;br /&gt;
Workflow awal menampilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Missing node type&lt;br /&gt;
&lt;br /&gt;
Node 'Edge TTS 🔊' not found.&lt;br /&gt;
The custom node may not be installed.&lt;br /&gt;
class_type: EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Artinya backend ComfyUI belum mendaftarkan node dengan nama internal:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Baris log seperti berikut:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
0.0 seconds: /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
hanya menunjukkan bahwa folder custom node telah diperiksa saat startup. Registrasi node harus dipastikan melalui endpoint:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/object_info/EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah instalasi selesai, server telah mengembalikan definisi lengkap `EdgeTTS`, termasuk suara Bahasa Indonesia `id-ID Gadis` dan `id-ID Ardi`. Ini membuktikan node sudah terdaftar dengan benar. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN A — INSTALASI&lt;br /&gt;
&lt;br /&gt;
## 4. Instal dependency sistem&lt;br /&gt;
&lt;br /&gt;
Custom node menggunakan pemrosesan audio. Instal `git`, `ffmpeg`, dan sertifikat CA di dalam container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose exec -u root -T comfyui bash -lc '&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
apt-get update&lt;br /&gt;
&lt;br /&gt;
DEBIAN_FRONTEND=noninteractive apt-get install -y \&lt;br /&gt;
    --no-install-recommends \&lt;br /&gt;
    git \&lt;br /&gt;
    ffmpeg \&lt;br /&gt;
    ca-certificates&lt;br /&gt;
&lt;br /&gt;
rm -rf /var/lib/apt/lists/*&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Verifikasi FFmpeg:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    ffmpeg -version | head -1&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
TorchCodec menggunakan instalasi FFmpeg yang tersedia pada sistem. Dokumentasi resminya menyatakan dukungan untuk FFmpeg versi 4 sampai 8. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. Clone custom node ComfyUI-EdgeTTS&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose exec -u root -T comfyui bash -lc '&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
cd /opt/ComfyUI/custom_nodes&lt;br /&gt;
&lt;br /&gt;
if [ -d ComfyUI-EdgeTTS/.git ]; then&lt;br /&gt;
    echo &amp;quot;ComfyUI-EdgeTTS sudah ada. Melakukan update.&amp;quot;&lt;br /&gt;
    git -C ComfyUI-EdgeTTS pull --ff-only&lt;br /&gt;
else&lt;br /&gt;
    rm -rf ComfyUI-EdgeTTS&lt;br /&gt;
&lt;br /&gt;
    git clone --depth 1 \&lt;br /&gt;
        https://github.com/1038lab/ComfyUI-EdgeTTS.git&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
echo&lt;br /&gt;
echo &amp;quot;Isi direktori plugin:&amp;quot;&lt;br /&gt;
ls -lah /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Repository resmi memang meminta plugin ditempatkan di dalam folder:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
ComfyUI/custom_nodes&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Plugin menyediakan node `EdgeTTS`, dukungan banyak bahasa, pengaturan kecepatan, pengaturan pitch, dan output audio ComfyUI. ([GitHub][2])&lt;br /&gt;
&lt;br /&gt;
Pastikan file utama tersedia:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui bash -lc '&lt;br /&gt;
test -f /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS/__init__.py&lt;br /&gt;
test -f /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS/ailab_edgeTTS.py&lt;br /&gt;
test -f /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS/config.json&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;File utama ComfyUI-EdgeTTS tersedia.&amp;quot;&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Periksa versi PyTorch sebelum memasang TorchCodec&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui /opt/venv/bin/python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import torch&lt;br /&gt;
import torchaudio&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;torch      :&amp;quot;, torch.__version__)&lt;br /&gt;
print(&amp;quot;torchaudio :&amp;quot;, torchaudio.__version__)&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada server ini hasil yang telah diperoleh adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
torch      : 2.11.0+cu128&lt;br /&gt;
torchaudio : 2.11.0+cu128&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
TorchCodec harus disesuaikan dengan versi PyTorch.&lt;br /&gt;
&lt;br /&gt;
Matriks kompatibilitas resmi menyatakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
torch 2.11  → torchcodec 0.11&lt;br /&gt;
torch 2.10  → torchcodec 0.10&lt;br /&gt;
torch 2.9   → torchcodec 0.9&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Karena server menggunakan PyTorch 2.11, gunakan TorchCodec seri `0.11`, bukan `0.9`. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Instal dependency Python untuk EdgeTTS&lt;br /&gt;
&lt;br /&gt;
Untuk workflow TTS ini, instal:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose exec -u root -T comfyui \&lt;br /&gt;
    /opt/venv/bin/python -m pip install \&lt;br /&gt;
    --no-cache-dir \&lt;br /&gt;
    --upgrade \&lt;br /&gt;
    &amp;quot;edge-tts&amp;gt;=7.0.0&amp;quot; \&lt;br /&gt;
    &amp;quot;torchcodec&amp;gt;=0.11,&amp;lt;0.12&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan menjalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
pip install -r requirements.txt&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
secara langsung pada konfigurasi ini tanpa memeriksa isinya.&lt;br /&gt;
&lt;br /&gt;
`requirements.txt` repository saat ini mencantumkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
edge-tts&amp;gt;=7.0.0&lt;br /&gt;
torchaudio&lt;br /&gt;
torchcodec==0.9&lt;br /&gt;
openai-whisper&lt;br /&gt;
numpy&lt;br /&gt;
torch&lt;br /&gt;
googletrans-py&lt;br /&gt;
deep-translator&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pin `torchcodec==0.9` ditujukan untuk PyTorch 2.9, sedangkan server menggunakan PyTorch 2.11. Menginstal seluruh file tersebut juga dapat mencoba mengubah instalasi `torch` dan `torchaudio` yang sudah berfungsi. ([GitHub][3])&lt;br /&gt;
&lt;br /&gt;
Node `EdgeTTS` sendiri mengimpor:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
edge_tts&lt;br /&gt;
torch&lt;br /&gt;
torchaudio&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dan menggunakan `torchaudio.load()` untuk membaca hasil audio. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Verifikasi dependency Python&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui /opt/venv/bin/python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import importlib.metadata as metadata&lt;br /&gt;
import torch&lt;br /&gt;
import torchaudio&lt;br /&gt;
import torchcodec&lt;br /&gt;
import edge_tts&lt;br /&gt;
&lt;br /&gt;
packages = [&lt;br /&gt;
    &amp;quot;torch&amp;quot;,&lt;br /&gt;
    &amp;quot;torchaudio&amp;quot;,&lt;br /&gt;
    &amp;quot;torchcodec&amp;quot;,&lt;br /&gt;
    &amp;quot;edge-tts&amp;quot;,&lt;br /&gt;
]&lt;br /&gt;
&lt;br /&gt;
for package in packages:&lt;br /&gt;
    try:&lt;br /&gt;
        print(f&amp;quot;{package:12}: {metadata.version(package)}&amp;quot;)&lt;br /&gt;
    except metadata.PackageNotFoundError:&lt;br /&gt;
        print(f&amp;quot;{package:12}: NOT INSTALLED&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print()&lt;br /&gt;
print(&amp;quot;Semua modul utama berhasil di-import.&amp;quot;)&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang diharapkan kurang lebih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
torch       : 2.11.0&lt;br /&gt;
torchaudio  : 2.11.0&lt;br /&gt;
torchcodec  : 0.11.x&lt;br /&gt;
edge-tts    : 7.x.x&lt;br /&gt;
&lt;br /&gt;
Semua modul utama berhasil di-import.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Nomor revisi kecil dapat berbeda, tetapi kombinasi utamanya harus:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
torch      2.11.x&lt;br /&gt;
torchcodec 0.11.x&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. Restart ComfyUI&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pantau startup:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hentikan tampilan log dengan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ctrl+C&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa error terbaru:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --since=5m comfyui \&lt;br /&gt;
    | grep -Ei \&lt;br /&gt;
    'EdgeTTS|ComfyUI-EdgeTTS|torchcodec|error loading|import failed|traceback|exception'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Baris berikut bukan error:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
0.0 seconds: /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Baris tersebut merupakan informasi waktu pemuatan plugin.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN B — VERIFIKASI&lt;br /&gt;
&lt;br /&gt;
## 10. Pastikan node EdgeTTS terdaftar&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/EdgeTTS \&lt;br /&gt;
| python3 -c '&lt;br /&gt;
import json&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
data = json.load(sys.stdin)&lt;br /&gt;
&lt;br /&gt;
if &amp;quot;EdgeTTS&amp;quot; not in data:&lt;br /&gt;
    raise SystemExit(&amp;quot;GAGAL: EdgeTTS belum terdaftar&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
node = data[&amp;quot;EdgeTTS&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;STATUS       : OK&amp;quot;)&lt;br /&gt;
print(&amp;quot;NAME         :&amp;quot;, node.get(&amp;quot;name&amp;quot;))&lt;br /&gt;
print(&amp;quot;DISPLAY NAME :&amp;quot;, node.get(&amp;quot;display_name&amp;quot;))&lt;br /&gt;
print(&amp;quot;MODULE       :&amp;quot;, node.get(&amp;quot;python_module&amp;quot;))&lt;br /&gt;
print(&amp;quot;OUTPUT       :&amp;quot;, node.get(&amp;quot;output&amp;quot;))&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
STATUS       : OK&lt;br /&gt;
NAME         : EdgeTTS&lt;br /&gt;
DISPLAY NAME : Edge TTS 🔊&lt;br /&gt;
MODULE       : custom_nodes.ComfyUI-EdgeTTS&lt;br /&gt;
OUTPUT       : ['AUDIO']&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini merupakan pemeriksaan paling penting.&lt;br /&gt;
&lt;br /&gt;
Jika endpoint tersebut mengembalikan definisi node, backend ComfyUI sudah mengenali `EdgeTTS`.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 11. Pastikan SaveAudio tersedia&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/SaveAudio \&lt;br /&gt;
| python3 -c '&lt;br /&gt;
import json&lt;br /&gt;
import sys&lt;br /&gt;
&lt;br /&gt;
data = json.load(sys.stdin)&lt;br /&gt;
&lt;br /&gt;
if &amp;quot;SaveAudio&amp;quot; not in data:&lt;br /&gt;
    raise SystemExit(&amp;quot;GAGAL: SaveAudio tidak tersedia&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;STATUS : OK&amp;quot;)&lt;br /&gt;
print(&amp;quot;NODE   : SaveAudio&amp;quot;)&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`SaveAudio` merupakan node bawaan ComfyUI yang menerima input `AUDIO` dan menyimpan hasil sebagai file FLAC. ([ComfyUI][5])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 12. Verifikasi suara Bahasa Indonesia&lt;br /&gt;
&lt;br /&gt;
Karena Edge TTS menggunakan layanan online, container harus dapat mengakses internet.&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    /opt/venv/bin/edge-tts --list-voices \&lt;br /&gt;
    | grep -E 'id-ID-(Gadis|Ardi)Neural'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil harus memuat suara seperti:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
id-ID-ArdiNeural&lt;br /&gt;
id-ID-GadisNeural&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Program resmi `edge-tts` menyediakan opsi `--list-voices` untuk memperoleh daftar suara yang tersedia dari layanan Edge TTS. ([GitHub][6])&lt;br /&gt;
&lt;br /&gt;
Jika perintah ini gagal akibat koneksi, periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    getent hosts speech.platform.bing.com&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Edge TTS bukan TTS lokal atau offline. Plugin menggunakan layanan text-to-speech online Microsoft Edge. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN C — PENGUJIAN&lt;br /&gt;
&lt;br /&gt;
## 13. Uji EdgeTTS langsung melalui ComfyUI API&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS \&lt;br /&gt;
    -X POST \&lt;br /&gt;
    http://127.0.0.1:8188/prompt \&lt;br /&gt;
    -H 'Content-Type: application/json' \&lt;br /&gt;
    -d '{&lt;br /&gt;
        &amp;quot;prompt&amp;quot;: {&lt;br /&gt;
            &amp;quot;1&amp;quot;: {&lt;br /&gt;
                &amp;quot;class_type&amp;quot;: &amp;quot;EdgeTTS&amp;quot;,&lt;br /&gt;
                &amp;quot;inputs&amp;quot;: {&lt;br /&gt;
                    &amp;quot;text&amp;quot;: &amp;quot;Halo, ini adalah pengujian text to speech Bahasa Indonesia menggunakan ComfyUI.&amp;quot;,&lt;br /&gt;
                    &amp;quot;voice&amp;quot;: &amp;quot;[Indonesian] id-ID Gadis&amp;quot;,&lt;br /&gt;
                    &amp;quot;speed&amp;quot;: 1.0,&lt;br /&gt;
                    &amp;quot;pitch&amp;quot;: 0&lt;br /&gt;
                }&lt;br /&gt;
            },&lt;br /&gt;
            &amp;quot;2&amp;quot;: {&lt;br /&gt;
                &amp;quot;class_type&amp;quot;: &amp;quot;SaveAudio&amp;quot;,&lt;br /&gt;
                &amp;quot;inputs&amp;quot;: {&lt;br /&gt;
                    &amp;quot;audio&amp;quot;: [&lt;br /&gt;
                        &amp;quot;1&amp;quot;,&lt;br /&gt;
                        0&lt;br /&gt;
                    ],&lt;br /&gt;
                    &amp;quot;filename_prefix&amp;quot;: &amp;quot;audio/tts_indonesia_test&amp;quot;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }' \&lt;br /&gt;
    | python3 -m json.tool&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Respons yang benar akan memuat:&lt;br /&gt;
&lt;br /&gt;
```json&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;prompt_id&amp;quot;: &amp;quot;...&amp;quot;,&lt;br /&gt;
    &amp;quot;number&amp;quot;: 1,&lt;br /&gt;
    &amp;quot;node_errors&amp;quot;: {}&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`prompt_id` akan berbeda pada setiap eksekusi.&lt;br /&gt;
&lt;br /&gt;
Pantau proses:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 14. Cari hasil audio&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    find /opt/ComfyUI/output \&lt;br /&gt;
    -type f \&lt;br /&gt;
    -iname '*tts_indonesia_test*' \&lt;br /&gt;
    -printf '%TY-%Tm-%Td %TH:%TM:%TS %p\n' \&lt;br /&gt;
    | sort&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lokasi hasil umumnya berada di bawah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ComfyUI/output/audio/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Karena prefix yang digunakan adalah:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
audio/tts_indonesia_test&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
File hasil `SaveAudio` menggunakan format FLAC.&lt;br /&gt;
&lt;br /&gt;
Untuk melihat file terakhir:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui bash -lc '&lt;br /&gt;
find /opt/ComfyUI/output/audio \&lt;br /&gt;
    -type f \&lt;br /&gt;
    -iname &amp;quot;*tts_indonesia_test*&amp;quot; \&lt;br /&gt;
    -printf &amp;quot;%T@ %p\n&amp;quot; \&lt;br /&gt;
    | sort -n \&lt;br /&gt;
    | tail -1 \&lt;br /&gt;
    | cut -d&amp;quot; &amp;quot; -f2-&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN D — MENJALANKAN WORKFLOW DI BROWSER&lt;br /&gt;
&lt;br /&gt;
## 15. Buka ComfyUI&lt;br /&gt;
&lt;br /&gt;
Buka dari komputer pengguna:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER5:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ganti `IP-SERVER5` dengan alamat IP server.&lt;br /&gt;
&lt;br /&gt;
Setelah plugin baru dipasang:&lt;br /&gt;
&lt;br /&gt;
1. Tutup tab ComfyUI lama.&lt;br /&gt;
2. Buka kembali ComfyUI.&lt;br /&gt;
3. Tekan `Ctrl+Shift+R`.&lt;br /&gt;
4. Load ulang workflow JSON.&lt;br /&gt;
5. Pastikan node `Edge TTS 🔊` tidak berwarna merah.&lt;br /&gt;
6. Pilih suara:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[Indonesian] id-ID Gadis&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
atau:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[Indonesian] id-ID Ardi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
7. Hubungkan output `AUDIO` dari `EdgeTTS` ke input `audio` pada `SaveAudio`.&lt;br /&gt;
8. Klik **Queue Prompt** atau **Run**.&lt;br /&gt;
&lt;br /&gt;
Node `EdgeTTS` resmi menghasilkan output bertipe `AUDIO`, sehingga dapat langsung dihubungkan ke `SaveAudio`. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN E — TROUBLESHOOTING&lt;br /&gt;
&lt;br /&gt;
## 16. Error “Missing node type” masih terlihat di log&lt;br /&gt;
&lt;br /&gt;
Perintah:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=200 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
dapat menampilkan peringatan lama yang tercatat sebelum node berhasil dipasang.&lt;br /&gt;
&lt;br /&gt;
Gunakan log berdasarkan waktu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --since=2m comfyui \&lt;br /&gt;
    | grep -Ei \&lt;br /&gt;
    'missing_node_type|EdgeTTS|error|exception|traceback'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
sudah mengembalikan definisi lengkap `EdgeTTS`, backend sudah benar. Peringatan lama di log tidak berarti error masih aktif. Kondisi inilah yang terverifikasi pada server setelah instalasi. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 17. Backend mengenali EdgeTTS, tetapi browser masih menampilkan node hilang&lt;br /&gt;
&lt;br /&gt;
Kemungkinan browser masih menyimpan definisi node lama atau browser membuka instance ComfyUI yang berbeda.&lt;br /&gt;
&lt;br /&gt;
Lakukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ctrl+Shift+R&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian pastikan alamat browser menggunakan server dan port yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER5:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bila masih bermasalah:&lt;br /&gt;
&lt;br /&gt;
1. Tekan `F12`.&lt;br /&gt;
2. Buka tab **Application**.&lt;br /&gt;
3. Pilih **Storage**.&lt;br /&gt;
4. Klik **Clear site data**.&lt;br /&gt;
5. Tutup tab.&lt;br /&gt;
6. Buka kembali ComfyUI.&lt;br /&gt;
&lt;br /&gt;
Tidak perlu mengubah workflow apabila backend sudah mengembalikan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/object_info/EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 18. Node tersedia tetapi audio kosong atau sangat pendek&lt;br /&gt;
&lt;br /&gt;
Periksa log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --since=5m comfyui \&lt;br /&gt;
    | grep -Ei \&lt;br /&gt;
    'TTS Error|NoAudioReceived|torchcodec|ffmpeg|audio|exception|traceback'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kode plugin menangkap error TTS dan, pada kondisi gagal, dapat mengembalikan waveform kosong sepanjang satu detik. Karena itu workflow bisa terlihat selesai walaupun layanan TTS sebenarnya gagal. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
Penyebab yang harus diperiksa:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Koneksi internet dari container&lt;br /&gt;
DNS container&lt;br /&gt;
Layanan Edge TTS tidak dapat dijangkau&lt;br /&gt;
TorchCodec tidak cocok dengan PyTorch&lt;br /&gt;
FFmpeg tidak tersedia&lt;br /&gt;
Voice ID sudah berubah atau tidak tersedia&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji layanan Edge TTS secara langsung:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    /opt/venv/bin/edge-tts \&lt;br /&gt;
    --voice id-ID-GadisNeural \&lt;br /&gt;
    --text &amp;quot;Halo, ini adalah pengujian suara Bahasa Indonesia.&amp;quot; \&lt;br /&gt;
    --write-media /tmp/edgetts-test.mp3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    ls -lh /tmp/edgetts-test.mp3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika file terbentuk dan ukurannya lebih dari nol, layanan Edge TTS berfungsi.&lt;br /&gt;
&lt;br /&gt;
Hapus file uji:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui \&lt;br /&gt;
    rm -f /tmp/edgetts-test.mp3&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 19. TorchCodec gagal di-import&lt;br /&gt;
&lt;br /&gt;
Periksa versi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui /opt/venv/bin/python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import importlib.metadata as metadata&lt;br /&gt;
import torch&lt;br /&gt;
import torchaudio&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;torch      :&amp;quot;, torch.__version__)&lt;br /&gt;
print(&amp;quot;torchaudio :&amp;quot;, torchaudio.__version__)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    print(&amp;quot;torchcodec :&amp;quot;, metadata.version(&amp;quot;torchcodec&amp;quot;))&lt;br /&gt;
except metadata.PackageNotFoundError:&lt;br /&gt;
    print(&amp;quot;torchcodec : NOT INSTALLED&amp;quot;)&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk server ini, instal ulang seri yang sesuai:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -u root -T comfyui \&lt;br /&gt;
    /opt/venv/bin/python -m pip uninstall -y torchcodec&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -u root -T comfyui \&lt;br /&gt;
    /opt/venv/bin/python -m pip install \&lt;br /&gt;
    --no-cache-dir \&lt;br /&gt;
    &amp;quot;torchcodec&amp;gt;=0.11,&amp;lt;0.12&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan memasang `torchcodec==0.9` pada PyTorch 2.11 karena matriks kompatibilitas resmi memasangkan TorchCodec 0.9 dengan PyTorch 2.9. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 20. Plugin tidak muncul pada object_info&lt;br /&gt;
&lt;br /&gt;
Periksa isi plugin:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui bash -lc '&lt;br /&gt;
ls -lah /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&lt;br /&gt;
&lt;br /&gt;
grep -Rni &amp;quot;EdgeTTS&amp;quot; \&lt;br /&gt;
    /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS \&lt;br /&gt;
    --include=&amp;quot;*.py&amp;quot; \&lt;br /&gt;
    | head -30&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji modul node secara langsung:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui /opt/venv/bin/python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import sys&lt;br /&gt;
import traceback&lt;br /&gt;
&lt;br /&gt;
plugin_path = &amp;quot;/opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&amp;quot;&lt;br /&gt;
sys.path.insert(0, plugin_path)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    import ailab_edgeTTS&lt;br /&gt;
&lt;br /&gt;
    print(&amp;quot;Import ailab_edgeTTS: OK&amp;quot;)&lt;br /&gt;
    print(&lt;br /&gt;
        &amp;quot;Node mappings:&amp;quot;,&lt;br /&gt;
        list(ailab_edgeTTS.NODE_CLASS_MAPPINGS.keys())&lt;br /&gt;
    )&lt;br /&gt;
except Exception:&lt;br /&gt;
    print(&amp;quot;Import ailab_edgeTTS: GAGAL&amp;quot;)&lt;br /&gt;
    traceback.print_exc()&lt;br /&gt;
    raise&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Import ailab_edgeTTS: OK&lt;br /&gt;
Node mappings: ['EdgeTTS']&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kode resmi plugin mendaftarkan:&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
NODE_CLASS_MAPPINGS = {&lt;br /&gt;
    &amp;quot;EdgeTTS&amp;quot;: EdgeTTS&lt;br /&gt;
}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Karena itu nama internal workflow harus tetap:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
bukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Edge TTS&lt;br /&gt;
Edge TTS 🔊&lt;br /&gt;
ComfyUI-EdgeTTS&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN F — PEMELIHARAAN&lt;br /&gt;
&lt;br /&gt;
## 21. Update plugin&lt;br /&gt;
&lt;br /&gt;
Untuk memperbarui plugin:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose exec -u root -T comfyui bash -lc '&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
git -C /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS \&lt;br /&gt;
    pull --ff-only&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah update, jangan langsung menjalankan seluruh `requirements.txt` tanpa mengecek perubahan versi.&lt;br /&gt;
&lt;br /&gt;
Tampilkan isi dependency terbaru:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui bash -lc '&lt;br /&gt;
cat /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS/requirements.txt&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa kembali kompatibilitas:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -T comfyui /opt/venv/bin/python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
import importlib.metadata as metadata&lt;br /&gt;
import torch&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;torch      :&amp;quot;, torch.__version__)&lt;br /&gt;
print(&amp;quot;torchcodec :&amp;quot;, metadata.version(&amp;quot;torchcodec&amp;quot;))&lt;br /&gt;
print(&amp;quot;edge-tts   :&amp;quot;, metadata.version(&amp;quot;edge-tts&amp;quot;))&lt;br /&gt;
PY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Verifikasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/EdgeTTS \&lt;br /&gt;
    | python3 -m json.tool \&lt;br /&gt;
    | head -50&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 22. Catatan persistensi Docker&lt;br /&gt;
&lt;br /&gt;
Perintah instalasi di atas memasang plugin dan paket ke dalam filesystem container yang sedang berjalan.&lt;br /&gt;
&lt;br /&gt;
Perubahan dalam writable layer container dapat hilang ketika container dihapus dan dibuat ulang. Volume atau bind mount diperlukan agar file bertahan di luar lifecycle container, atau instalasi harus dimasukkan ke dalam Dockerfile. ([Docker Documentation][7])&lt;br /&gt;
&lt;br /&gt;
Periksa apakah folder custom node memakai mount:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker inspect &amp;quot;$(docker compose ps -q comfyui)&amp;quot; \&lt;br /&gt;
    --format '{{range .Mounts}}{{println .Source &amp;quot;-&amp;gt;&amp;quot; .Destination}}{{end}}'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cari tujuan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ComfyUI/custom_nodes&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika folder tersebut tidak menggunakan volume atau bind mount, plugin harus dimasukkan ke Dockerfile agar tidak hilang setelah container dibuat ulang.&lt;br /&gt;
&lt;br /&gt;
Hal yang sama berlaku untuk paket Python di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/venv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instalasi permanen harus memasukkan langkah berikut ke proses build image, setelah `/opt/venv` dan `/opt/ComfyUI` tersedia:&lt;br /&gt;
&lt;br /&gt;
```dockerfile&lt;br /&gt;
RUN apt-get update \&lt;br /&gt;
    &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br /&gt;
       git \&lt;br /&gt;
       ffmpeg \&lt;br /&gt;
       ca-certificates \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
RUN git clone --depth 1 \&lt;br /&gt;
    https://github.com/1038lab/ComfyUI-EdgeTTS.git \&lt;br /&gt;
    /opt/ComfyUI/custom_nodes/ComfyUI-EdgeTTS&lt;br /&gt;
&lt;br /&gt;
RUN /opt/venv/bin/python -m pip install \&lt;br /&gt;
    --no-cache-dir \&lt;br /&gt;
    &amp;quot;edge-tts&amp;gt;=7.0.0&amp;quot; \&lt;br /&gt;
    &amp;quot;torchcodec&amp;gt;=0.11,&amp;lt;0.12&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah Dockerfile diperbarui:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose build comfyui&lt;br /&gt;
docker compose up -d comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Verifikasi ulang:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/EdgeTTS \&lt;br /&gt;
    | python3 -m json.tool \&lt;br /&gt;
    | head -50&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN G — RINGKASAN PERINTAH UTAMA&lt;br /&gt;
&lt;br /&gt;
## 23. Instalasi ringkas&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -u root -T comfyui bash -lc '&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
apt-get update&lt;br /&gt;
&lt;br /&gt;
DEBIAN_FRONTEND=noninteractive apt-get install -y \&lt;br /&gt;
    --no-install-recommends \&lt;br /&gt;
    git \&lt;br /&gt;
    ffmpeg \&lt;br /&gt;
    ca-certificates&lt;br /&gt;
&lt;br /&gt;
rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
cd /opt/ComfyUI/custom_nodes&lt;br /&gt;
&lt;br /&gt;
if [ -d ComfyUI-EdgeTTS/.git ]; then&lt;br /&gt;
    git -C ComfyUI-EdgeTTS pull --ff-only&lt;br /&gt;
else&lt;br /&gt;
    rm -rf ComfyUI-EdgeTTS&lt;br /&gt;
&lt;br /&gt;
    git clone --depth 1 \&lt;br /&gt;
        https://github.com/1038lab/ComfyUI-EdgeTTS.git&lt;br /&gt;
fi&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -u root -T comfyui \&lt;br /&gt;
    /opt/venv/bin/python -m pip install \&lt;br /&gt;
    --no-cache-dir \&lt;br /&gt;
    --upgrade \&lt;br /&gt;
    &amp;quot;edge-tts&amp;gt;=7.0.0&amp;quot; \&lt;br /&gt;
    &amp;quot;torchcodec&amp;gt;=0.11,&amp;lt;0.12&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsS http://127.0.0.1:8188/object_info/EdgeTTS \&lt;br /&gt;
    | python3 -m json.tool \&lt;br /&gt;
    | head -80&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# 24. Kondisi akhir yang benar&lt;br /&gt;
&lt;br /&gt;
Instalasi dinyatakan berhasil jika seluruh kondisi berikut terpenuhi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Container comfyui aktif.&lt;br /&gt;
FFmpeg tersedia di dalam container.&lt;br /&gt;
edge-tts berhasil di-import.&lt;br /&gt;
torchcodec 0.11.x terpasang.&lt;br /&gt;
PyTorch tetap 2.11.x.&lt;br /&gt;
Torchaudio tetap 2.11.x.&lt;br /&gt;
Endpoint /object_info/EdgeTTS mengembalikan node EdgeTTS.&lt;br /&gt;
Endpoint /object_info/SaveAudio mengembalikan SaveAudio.&lt;br /&gt;
Daftar suara memuat id-ID-GadisNeural dan id-ID-ArdiNeural.&lt;br /&gt;
Workflow tidak lagi menghasilkan missing_node_type.&lt;br /&gt;
File audio tersimpan di /opt/ComfyUI/output/audio.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada pemeriksaan terakhir server Anda, endpoint `object_info/EdgeTTS` sudah mengembalikan node lengkap dengan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
name          : EdgeTTS&lt;br /&gt;
display_name  : Edge TTS 🔊&lt;br /&gt;
python_module : custom_nodes.ComfyUI-EdgeTTS&lt;br /&gt;
output        : AUDIO&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dengan demikian masalah `Missing node type` pada backend telah selesai. &lt;br /&gt;
&lt;br /&gt;
Catatan ini memakai prosedur minimal untuk **TTS Bahasa Indonesia**, tanpa memasang ulang PyTorch, Torchaudio, Whisper, atau dependency lain yang tidak diperlukan oleh workflow tersebut.&lt;br /&gt;
&lt;br /&gt;
[1]: https://github.com/meta-pytorch/torchcodec &amp;quot;GitHub - meta-pytorch/torchcodec: PyTorch media decoding and encoding · GitHub&amp;quot;&lt;br /&gt;
[2]: https://github.com/1038lab/ComfyUI-EdgeTTS &amp;quot;GitHub - 1038lab/ComfyUI-EdgeTTS: ComfyUI-EdgeTTS is a powerful text-to-speech node for ComfyUI, leveraging Microsoft's Edge TTS capabilities. It enables seamless conversion of text into natural-sounding speech, supporting multiple languages and voices. Ideal for enhancing user interactions, this node is easy to integrate and customize, making it perfect for various applications. · GitHub&amp;quot;&lt;br /&gt;
[3]: https://github.com/1038lab/ComfyUI-EdgeTTS/blob/main/requirements.txt &amp;quot;ComfyUI-EdgeTTS/requirements.txt at main · 1038lab/ComfyUI-EdgeTTS · GitHub&amp;quot;&lt;br /&gt;
[4]: https://github.com/1038lab/ComfyUI-EdgeTTS/blob/main/ailab_edgeTTS.py &amp;quot;ComfyUI-EdgeTTS/ailab_edgeTTS.py at main · 1038lab/ComfyUI-EdgeTTS · GitHub&amp;quot;&lt;br /&gt;
[5]: https://docs.comfy.org/built-in-nodes/SaveAudio?utm_source=chatgpt.com &amp;quot;SaveAudio - ComfyUI Built-in Node Documentation&amp;quot;&lt;br /&gt;
[6]: https://github.com/rany2/edge-tts/blob/master/README.md?utm_source=chatgpt.com &amp;quot;README.md - rany2/edge-tts&amp;quot;&lt;br /&gt;
[7]: https://docs.docker.com/get-started/docker-concepts/running-containers/persisting-container-data/?utm_source=chatgpt.com &amp;quot;Persisting container data | Docker Docs&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Text_to_Speech&amp;diff=73707</id>
		<title>ComfyUI: Text to Speech</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Text_to_Speech&amp;diff=73707"/>
		<updated>2026-07-23T23:43:35Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Saya sudah membuat workflow **Text-to-Speech Bahasa Indonesia** paling sederhana:  [Download workflow JSON ComfyUI TTS Indonesia](sandbox:/mnt/data/comfyui_tts_bahasa_indonesi...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Saya sudah membuat workflow **Text-to-Speech Bahasa Indonesia** paling sederhana:&lt;br /&gt;
&lt;br /&gt;
[Download workflow JSON ComfyUI TTS Indonesia](sandbox:/mnt/data/comfyui_tts_bahasa_indonesia_sederhana.json)&lt;br /&gt;
&lt;br /&gt;
Workflow hanya menggunakan dua node:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Edge TTS → Save Audio&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Node menggunakan suara perempuan Indonesia **Gadis**, kecepatan normal, dan menyimpan hasil sebagai WAV. Custom node tersebut juga menyediakan suara laki-laki Indonesia **Ardi**, serta pengaturan kecepatan dan tinggi nada. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
## 1. Instal custom node&lt;br /&gt;
&lt;br /&gt;
Pada server:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose exec -u root comfyui bash -lc '&lt;br /&gt;
set -e&lt;br /&gt;
&lt;br /&gt;
cd /opt/ComfyUI/custom_nodes&lt;br /&gt;
&lt;br /&gt;
if [ ! -d ComfyUI-EdgeTTS ]; then&lt;br /&gt;
    git clone https://github.com/1038lab/ComfyUI-EdgeTTS.git&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
python -m pip install --no-cache-dir \&lt;br /&gt;
    -r ComfyUI-EdgeTTS/requirements.txt&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Repositori resminya memang mengarahkan instalasi ke folder `custom_nodes`, dilanjutkan dengan pemasangan `requirements.txt`. ([GitHub][2])&lt;br /&gt;
&lt;br /&gt;
Periksa apakah berhasil:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cari apakah node berikut berhasil dimuat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
EdgeTTS&lt;br /&gt;
Save_Audio&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 2. Upload workflow&lt;br /&gt;
&lt;br /&gt;
Buka:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.230:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian seret file berikut ke canvas ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
comfyui_tts_bahasa_indonesia_sederhana.json&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Workflow JSON merupakan format resmi untuk menyimpan graph, node, widget, dan hubungan antar-node ComfyUI. ([ComfyUI][3])&lt;br /&gt;
&lt;br /&gt;
## 3. Jalankan TTS&lt;br /&gt;
&lt;br /&gt;
Pada node **Edge TTS**, ubah teks:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Halo, selamat datang. Ini adalah contoh text to speech sederhana dalam Bahasa Indonesia menggunakan ComfyUI.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Suara default:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[Indonesian] id-ID Gadis&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk suara laki-laki, pilih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[Indonesian] id-ID Ardi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lalu tekan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ctrl + Enter&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
atau klik **Queue**.&lt;br /&gt;
&lt;br /&gt;
## 4. Lokasi hasil&lt;br /&gt;
&lt;br /&gt;
File akan tersimpan sebagai:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ComfyUI/output/TTS/indonesia-0001.wav&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Nomor akan bertambah otomatis:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
indonesia-0002.wav&lt;br /&gt;
indonesia-0003.wav&lt;br /&gt;
indonesia-0004.wav&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Node `Save_Audio` memang menyimpan keluaran di direktori output ComfyUI dan memberikan nomor urut ketika opsi overwrite dimatikan. ([GitHub][4])&lt;br /&gt;
&lt;br /&gt;
**Catatan:** workflow ini menggunakan layanan Microsoft Edge TTS secara online, sehingga container ComfyUI memerlukan akses internet ketika menghasilkan suara. Tidak memerlukan API key. ([GitHub][5])&lt;br /&gt;
&lt;br /&gt;
[1]: https://github.com/1038lab/ComfyUI-EdgeTTS/blob/main/ailab_edgeTTS.py &amp;quot;ComfyUI-EdgeTTS/ailab_edgeTTS.py at main · 1038lab/ComfyUI-EdgeTTS · GitHub&amp;quot;&lt;br /&gt;
[2]: https://github.com/1038lab/ComfyUI-EdgeTTS &amp;quot;GitHub - 1038lab/ComfyUI-EdgeTTS: ComfyUI-EdgeTTS is a powerful text-to-speech node for ComfyUI, leveraging Microsoft's Edge TTS capabilities. It enables seamless conversion of text into natural-sounding speech, supporting multiple languages and voices. Ideal for enhancing user interactions, this node is easy to integrate and customize, making it perfect for various applications. · GitHub&amp;quot;&lt;br /&gt;
[3]: https://docs.comfy.org/specs/workflow_json_0.4?utm_source=chatgpt.com &amp;quot;Workflow JSON 0.4 - ComfyUI&amp;quot;&lt;br /&gt;
[4]: https://github.com/1038lab/ComfyUI-EdgeTTS/blob/main/ailab_audio.py &amp;quot;ComfyUI-EdgeTTS/ailab_audio.py at main · 1038lab/ComfyUI-EdgeTTS · GitHub&amp;quot;&lt;br /&gt;
[5]: https://github.com/rany2/edge-tts?utm_source=chatgpt.com &amp;quot;GitHub - rany2/edge-tts: Use Microsoft Edge's online text-to-speech service from Python WITHOUT needing Microsoft Edge or Windows or an API key · GitHub&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73706</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73706"/>
		<updated>2026-07-23T23:43:30Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* ComfyUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
* [[ComfyUI: Text to Speech]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM:_Ubuntu_26.04_server_Ollama_GPU_%2B_Open-WebUI_%2B_n8n_%2B_WAHA_%2B_ComfyUI_docker&amp;diff=73705</id>
		<title>LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM:_Ubuntu_26.04_server_Ollama_GPU_%2B_Open-WebUI_%2B_n8n_%2B_WAHA_%2B_ComfyUI_docker&amp;diff=73705"/>
		<updated>2026-07-23T18:10:39Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;# Instalasi AI Stack di Ubuntu Server 26.04  Target perangkat:  * Laptop Dell * NVIDIA GeForce RTX 4060 Laptop GPU 8 GB * Ubuntu Server 26.04 * Docker Engine + Docker Compose...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Instalasi AI Stack di Ubuntu Server 26.04&lt;br /&gt;
&lt;br /&gt;
Target perangkat:&lt;br /&gt;
&lt;br /&gt;
* Laptop Dell&lt;br /&gt;
* NVIDIA GeForce RTX 4060 Laptop GPU 8 GB&lt;br /&gt;
* Ubuntu Server 26.04&lt;br /&gt;
* Docker Engine + Docker Compose&lt;br /&gt;
* Ollama memakai GPU&lt;br /&gt;
* ComfyUI memakai GPU&lt;br /&gt;
* Open WebUI **tanpa GPU**&lt;br /&gt;
* n8n tanpa GPU&lt;br /&gt;
* WAHA tanpa GPU&lt;br /&gt;
&lt;br /&gt;
Karena bagian “gunakan folder awal …” belum lengkap, panduan ini memakai:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Docker secara resmi sudah mencantumkan Ubuntu 26.04 LTS sebagai sistem yang didukung. ([Docker Documentation][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 1. Arsitektur akhir&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/&lt;br /&gt;
├── .env&lt;br /&gt;
├── compose.yaml&lt;br /&gt;
├── ollama/&lt;br /&gt;
├── open-webui/&lt;br /&gt;
├── n8n/&lt;br /&gt;
├── waha/&lt;br /&gt;
│   ├── .env&lt;br /&gt;
│   ├── sessions/&lt;br /&gt;
│   └── media/&lt;br /&gt;
└── comfyui/&lt;br /&gt;
    ├── Dockerfile&lt;br /&gt;
    ├── models/&lt;br /&gt;
    │   ├── checkpoints/&lt;br /&gt;
    │   ├── vae/&lt;br /&gt;
    │   ├── loras/&lt;br /&gt;
    │   ├── clip/&lt;br /&gt;
    │   ├── controlnet/&lt;br /&gt;
    │   └── upscale_models/&lt;br /&gt;
    ├── input/&lt;br /&gt;
    ├── output/&lt;br /&gt;
    ├── custom_nodes/&lt;br /&gt;
    └── user/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Port yang digunakan:&lt;br /&gt;
&lt;br /&gt;
| Aplikasi   |  Port | Alamat                              |&lt;br /&gt;
| ---------- | ----: | ----------------------------------- |&lt;br /&gt;
| Open WebUI |  3000 | `http://IP-SERVER:3000`             |&lt;br /&gt;
| n8n        |  5678 | `http://IP-SERVER:5678`             |&lt;br /&gt;
| WAHA       |  3001 | `http://IP-SERVER:3001/dashboard`   |&lt;br /&gt;
| ComfyUI    |  8188 | `http://IP-SERVER:8188`             |&lt;br /&gt;
| Ollama     | 11434 | Hanya localhost dan jaringan Docker |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN A — PERSIAPAN UBUNTU&lt;br /&gt;
&lt;br /&gt;
## 2. Update Ubuntu Server&lt;br /&gt;
&lt;br /&gt;
Masuk melalui terminal atau SSH, kemudian jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt full-upgrade -y&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instal paket dasar:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt install -y \&lt;br /&gt;
  ca-certificates \&lt;br /&gt;
  curl \&lt;br /&gt;
  gnupg \&lt;br /&gt;
  git \&lt;br /&gt;
  openssl \&lt;br /&gt;
  ubuntu-drivers-common \&lt;br /&gt;
  ufw&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Reboot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo reboot&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah server hidup kembali, login lagi melalui SSH.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN B — DRIVER NVIDIA RTX 4060&lt;br /&gt;
&lt;br /&gt;
## 3. Pastikan GPU terdeteksi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
lspci | grep -i nvidia&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh hasil:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NVIDIA Corporation AD107M [GeForce RTX 4060 Max-Q / Mobile]&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lihat driver yang tersedia:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ubuntu-drivers list --gpgpu&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk server AI/headless, instal driver komputasi yang direkomendasikan otomatis:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ubuntu-drivers install --gpgpu&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ubuntu merekomendasikan `ubuntu-drivers` karena alat ini memilih paket driver yang sesuai dan mendukung penggunaan Secure Boot melalui modul yang ditandatangani. ([Ubuntu][2])&lt;br /&gt;
&lt;br /&gt;
Reboot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo reboot&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. Periksa driver NVIDIA&lt;br /&gt;
&lt;br /&gt;
Setelah login kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar kurang lebih seperti:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NVIDIA-SMI ...&lt;br /&gt;
Driver Version: ...&lt;br /&gt;
CUDA Version: ...&lt;br /&gt;
NVIDIA GeForce RTX 4060 Laptop GPU&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan lanjut ke instalasi Docker GPU sebelum `nvidia-smi` berhasil.&lt;br /&gt;
&lt;br /&gt;
Apabila muncul:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa Secure Boot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mokutil --sb-state&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada beberapa laptop, Secure Boot harus dinonaktifkan melalui BIOS atau kunci MOK driver harus dikonfirmasi ketika boot.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN C — INSTALASI DOCKER&lt;br /&gt;
&lt;br /&gt;
## 5. Hapus paket Docker lama yang mungkin konflik&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
for pkg in \&lt;br /&gt;
  docker.io \&lt;br /&gt;
  docker-doc \&lt;br /&gt;
  docker-compose \&lt;br /&gt;
  docker-compose-v2 \&lt;br /&gt;
  podman-docker \&lt;br /&gt;
  containerd \&lt;br /&gt;
  runc&lt;br /&gt;
do&lt;br /&gt;
  sudo apt remove -y &amp;quot;$pkg&amp;quot; 2&amp;gt;/dev/null || true&lt;br /&gt;
done&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Docker menyarankan menghapus paket distribusi yang dapat bertabrakan dengan Docker Engine resmi. ([Docker Documentation][1])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Tambahkan repository resmi Docker&lt;br /&gt;
&lt;br /&gt;
Buat direktori keyring:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo install -m 0755 -d /etc/apt/keyrings&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ambil kunci resmi Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo curl -fsSL \&lt;br /&gt;
  https://download.docker.com/linux/ubuntu/gpg \&lt;br /&gt;
  -o /etc/apt/keyrings/docker.asc&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur agar kunci dapat dibaca APT:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chmod a+r /etc/apt/keyrings/docker.asc&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tambahkan repository Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /etc/apt/sources.list.d/docker.sources &amp;gt;/dev/null &amp;lt;&amp;lt;EOF&lt;br /&gt;
Types: deb&lt;br /&gt;
URIs: https://download.docker.com/linux/ubuntu&lt;br /&gt;
Suites: $(. /etc/os-release &amp;amp;&amp;amp; echo &amp;quot;${UBUNTU_CODENAME:-$VERSION_CODENAME}&amp;quot;)&lt;br /&gt;
Components: stable&lt;br /&gt;
Architectures: $(dpkg --print-architecture)&lt;br /&gt;
Signed-By: /etc/apt/keyrings/docker.asc&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Update repository:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Instal Docker Engine dan Docker Compose&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt install -y \&lt;br /&gt;
  docker-ce \&lt;br /&gt;
  docker-ce-cli \&lt;br /&gt;
  containerd.io \&lt;br /&gt;
  docker-buildx-plugin \&lt;br /&gt;
  docker-compose-plugin&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aktifkan Docker saat boot:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl enable --now docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl status docker --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo docker run --rm hello-world&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Izinkan user menjalankan Docker tanpa sudo&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo usermod -aG docker &amp;quot;$USER&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Arti opsi:&lt;br /&gt;
&lt;br /&gt;
* `-a` berarti menambahkan user tanpa menghapus grup yang sudah dimiliki.&lt;br /&gt;
* `-G docker` berarti menambahkan user ke grup Docker.&lt;br /&gt;
&lt;br /&gt;
Logout dari SSH:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
exit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Login kembali, kemudian periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker version&lt;br /&gt;
docker compose version&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji kembali tanpa `sudo`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm hello-world&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN D — NVIDIA CONTAINER TOOLKIT&lt;br /&gt;
&lt;br /&gt;
## 9. Tambahkan repository NVIDIA Container Toolkit&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \&lt;br /&gt;
  | sudo gpg --dearmor \&lt;br /&gt;
  -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tambahkan repository:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsSL \&lt;br /&gt;
  https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \&lt;br /&gt;
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \&lt;br /&gt;
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Update APT:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instal NVIDIA Container Toolkit:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt install -y nvidia-container-toolkit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasikan Docker agar mengenali NVIDIA Runtime:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nvidia-ctk runtime configure --runtime=docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl restart docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Langkah tersebut mengikuti prosedur NVIDIA untuk mengaktifkan GPU di dalam container Docker. ([NVIDIA Docs][3])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 10. Uji GPU dari dalam Docker&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm --gpus all ubuntu:24.04 nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan RTX 4060 muncul di hasil perintah.&lt;br /&gt;
&lt;br /&gt;
Ollama juga menyarankan pengujian GPU Docker sebelum mencoba menjalankan model. Ollama membutuhkan NVIDIA Container Toolkit untuk akselerasi NVIDIA di Docker. ([Ollama][4])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN E — MEMBUAT STRUKTUR FOLDER&lt;br /&gt;
&lt;br /&gt;
## 11. Buat folder utama&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mkdir -p /opt/ai-stack&lt;br /&gt;
sudo chown -R &amp;quot;$USER&amp;quot;:&amp;quot;$USER&amp;quot; /opt/ai-stack&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat folder data:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p \&lt;br /&gt;
  ollama \&lt;br /&gt;
  open-webui \&lt;br /&gt;
  n8n \&lt;br /&gt;
  waha/sessions \&lt;br /&gt;
  waha/media \&lt;br /&gt;
  comfyui/input \&lt;br /&gt;
  comfyui/output \&lt;br /&gt;
  comfyui/custom_nodes \&lt;br /&gt;
  comfyui/user&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat folder model ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p \&lt;br /&gt;
  comfyui/models/checkpoints \&lt;br /&gt;
  comfyui/models/vae \&lt;br /&gt;
  comfyui/models/loras \&lt;br /&gt;
  comfyui/models/clip \&lt;br /&gt;
  comfyui/models/controlnet \&lt;br /&gt;
  comfyui/models/upscale_models&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur kepemilikan folder n8n. Container resmi n8n berjalan dengan UID `1000`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown -R 1000:1000 /opt/ai-stack/n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lihat struktur:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
find /opt/ai-stack -maxdepth 3 -type d | sort&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN F — KONFIGURASI RAHASIA&lt;br /&gt;
&lt;br /&gt;
## 12. Cari IP server&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
SERVER_IP=$(ip route get 1.1.1.1 | awk '{print $7; exit}')&lt;br /&gt;
echo &amp;quot;$SERVER_IP&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa juga dengan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
hostname -I&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Apabila ada beberapa IP, gunakan IP LAN yang dipakai komputer lain untuk mengakses server.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 13. Buat file `.env` utama&lt;br /&gt;
&lt;br /&gt;
Pastikan sedang di:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat konfigurasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
SERVER_IP=$(ip route get 1.1.1.1 | awk '{print $7; exit}')&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; .env &amp;lt;&amp;lt;EOF&lt;br /&gt;
SERVER_IP=${SERVER_IP}&lt;br /&gt;
WEBUI_SECRET_KEY=$(openssl rand -hex 32)&lt;br /&gt;
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Amankan file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod 600 .env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat .env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
SERVER_IP=192.168.0.100&lt;br /&gt;
WEBUI_SECRET_KEY=...&lt;br /&gt;
N8N_ENCRYPTION_KEY=...&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN G — KONFIGURASI WAHA&lt;br /&gt;
&lt;br /&gt;
## 14. Generate konfigurasi WAHA&lt;br /&gt;
&lt;br /&gt;
WAHA menyediakan perintah `init-waha` untuk membuat username, password dashboard, dan API key secara acak. ([GitHub][5])&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker run --rm \&lt;br /&gt;
  -v &amp;quot;$PWD/waha:/app/env&amp;quot; \&lt;br /&gt;
  devlikeapro/waha:latest \&lt;br /&gt;
  init-waha /app/env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat waha/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Biasanya terdapat variabel seperti:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
WAHA_API_KEY=...&lt;br /&gt;
WAHA_DASHBOARD_USERNAME=...&lt;br /&gt;
WAHA_DASHBOARD_PASSWORD=...&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Amankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
chmod 600 waha/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur alamat eksternal WAHA agar menggunakan port host `3001`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
SERVER_IP=$(grep '^SERVER_IP=' .env | cut -d= -f2)&lt;br /&gt;
&lt;br /&gt;
if grep -q '^WAHA_BASE_URL=' waha/.env; then&lt;br /&gt;
  sed -i \&lt;br /&gt;
    &amp;quot;s#^WAHA_BASE_URL=.*#WAHA_BASE_URL=http://${SERVER_IP}:3001#&amp;quot; \&lt;br /&gt;
    waha/.env&lt;br /&gt;
else&lt;br /&gt;
  echo &amp;quot;WAHA_BASE_URL=http://${SERVER_IP}:3001&amp;quot; &amp;gt;&amp;gt; waha/.env&lt;br /&gt;
fi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
grep -E 'WAHA_BASE_URL|WAHA_DASHBOARD_USERNAME|WAHA_API_KEY' waha/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
WAHA menyimpan sesi pada `/app/.sessions` dan media pada `/app/.media`; kedua lokasi ini akan dipetakan ke folder host agar tidak hilang saat container dibuat ulang. ([GitHub][6])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN H — DOCKERFILE COMFYUI&lt;br /&gt;
&lt;br /&gt;
## 15. Buat Dockerfile ComfyUI&lt;br /&gt;
&lt;br /&gt;
Panduan ini membangun image dari repository resmi ComfyUI dan memasang PyTorch CUDA. Repository resmi ComfyUI berada di organisasi Comfy-Org. ([GitHub][7])&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; comfyui/Dockerfile &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
FROM nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04&lt;br /&gt;
&lt;br /&gt;
ENV DEBIAN_FRONTEND=noninteractive&lt;br /&gt;
ENV PIP_NO_CACHE_DIR=1&lt;br /&gt;
ENV PYTHONUNBUFFERED=1&lt;br /&gt;
ENV PATH=&amp;quot;/opt/venv/bin:${PATH}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br /&gt;
    ca-certificates \&lt;br /&gt;
    git \&lt;br /&gt;
    curl \&lt;br /&gt;
    ffmpeg \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    python3 \&lt;br /&gt;
    python3-dev \&lt;br /&gt;
    python3-pip \&lt;br /&gt;
    python3-venv \&lt;br /&gt;
    libgl1 \&lt;br /&gt;
    libglib2.0-0 \&lt;br /&gt;
    libsm6 \&lt;br /&gt;
    libxext6 \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
RUN python3 -m venv /opt/venv \&lt;br /&gt;
    &amp;amp;&amp;amp; pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt&lt;br /&gt;
&lt;br /&gt;
RUN git clone --depth 1 \&lt;br /&gt;
    https://github.com/Comfy-Org/ComfyUI.git \&lt;br /&gt;
    /opt/ComfyUI&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt/ComfyUI&lt;br /&gt;
&lt;br /&gt;
RUN pip install \&lt;br /&gt;
    torch \&lt;br /&gt;
    torchvision \&lt;br /&gt;
    torchaudio \&lt;br /&gt;
    --index-url https://download.pytorch.org/whl/cu128&lt;br /&gt;
&lt;br /&gt;
RUN pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
EXPOSE 8188&lt;br /&gt;
&lt;br /&gt;
CMD [&amp;quot;python&amp;quot;, &amp;quot;main.py&amp;quot;, \&lt;br /&gt;
     &amp;quot;--listen&amp;quot;, &amp;quot;0.0.0.0&amp;quot;, \&lt;br /&gt;
     &amp;quot;--port&amp;quot;, &amp;quot;8188&amp;quot;, \&lt;br /&gt;
     &amp;quot;--preview-method&amp;quot;, &amp;quot;auto&amp;quot;]&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
PyTorch menyediakan paket CUDA untuk Linux melalui indeks wheel CUDA yang sesuai. ([PyTorch Documentation][8])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN I — DOCKER COMPOSE&lt;br /&gt;
&lt;br /&gt;
## 16. Buat file `compose.yaml`&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; compose.yaml &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
name: ai-stack&lt;br /&gt;
&lt;br /&gt;
services:&lt;br /&gt;
&lt;br /&gt;
  ollama:&lt;br /&gt;
    image: ollama/ollama:latest&lt;br /&gt;
    container_name: ollama&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;127.0.0.1:11434:11434&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./ollama:/root/.ollama&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      OLLAMA_HOST: &amp;quot;0.0.0.0:11434&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      # Lepaskan model dari VRAM setelah tidak digunakan.&lt;br /&gt;
      OLLAMA_KEEP_ALIVE: &amp;quot;5m&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      # RTX 4060 Laptop hanya memiliki VRAM 8 GB.&lt;br /&gt;
      OLLAMA_MAX_LOADED_MODELS: &amp;quot;1&amp;quot;&lt;br /&gt;
      OLLAMA_NUM_PARALLEL: &amp;quot;1&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    deploy:&lt;br /&gt;
      resources:&lt;br /&gt;
        reservations:&lt;br /&gt;
          devices:&lt;br /&gt;
            - driver: nvidia&lt;br /&gt;
              count: all&lt;br /&gt;
              capabilities:&lt;br /&gt;
                - gpu&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-net&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  open-webui:&lt;br /&gt;
    image: ghcr.io/open-webui/open-webui:main&lt;br /&gt;
    container_name: open-webui&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    depends_on:&lt;br /&gt;
      - ollama&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;3000:8080&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./open-webui:/app/backend/data&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      OLLAMA_BASE_URL: &amp;quot;http://ollama:11434&amp;quot;&lt;br /&gt;
      WEBUI_SECRET_KEY: &amp;quot;${WEBUI_SECRET_KEY}&amp;quot;&lt;br /&gt;
      TZ: &amp;quot;Asia/Jakarta&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-net&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  n8n:&lt;br /&gt;
    image: docker.n8n.io/n8nio/n8n:latest&lt;br /&gt;
    container_name: n8n&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;5678:5678&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./n8n:/home/node/.n8n&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      N8N_HOST: &amp;quot;${SERVER_IP}&amp;quot;&lt;br /&gt;
      N8N_PORT: &amp;quot;5678&amp;quot;&lt;br /&gt;
      N8N_PROTOCOL: &amp;quot;http&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      N8N_EDITOR_BASE_URL: &amp;quot;http://${SERVER_IP}:5678/&amp;quot;&lt;br /&gt;
      WEBHOOK_URL: &amp;quot;http://${SERVER_IP}:5678/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      N8N_ENCRYPTION_KEY: &amp;quot;${N8N_ENCRYPTION_KEY}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      # Diperlukan karena akses masih menggunakan HTTP lokal.&lt;br /&gt;
      # Ubah menjadi true setelah memakai HTTPS.&lt;br /&gt;
      N8N_SECURE_COOKIE: &amp;quot;false&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: &amp;quot;true&amp;quot;&lt;br /&gt;
      N8N_DIAGNOSTICS_ENABLED: &amp;quot;false&amp;quot;&lt;br /&gt;
      N8N_PERSONALIZATION_ENABLED: &amp;quot;false&amp;quot;&lt;br /&gt;
&lt;br /&gt;
      GENERIC_TIMEZONE: &amp;quot;Asia/Jakarta&amp;quot;&lt;br /&gt;
      TZ: &amp;quot;Asia/Jakarta&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-net&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  waha:&lt;br /&gt;
    image: devlikeapro/waha:latest&lt;br /&gt;
    container_name: waha&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;3001:3000&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    env_file:&lt;br /&gt;
      - ./waha/.env&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./waha/sessions:/app/.sessions&lt;br /&gt;
      - ./waha/media:/app/.media&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-net&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
  comfyui:&lt;br /&gt;
    build:&lt;br /&gt;
      context: ./comfyui&lt;br /&gt;
      dockerfile: Dockerfile&lt;br /&gt;
&lt;br /&gt;
    image: local/comfyui:cu128&lt;br /&gt;
    container_name: comfyui&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;8188:8188&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./comfyui/models:/opt/ComfyUI/models&lt;br /&gt;
      - ./comfyui/input:/opt/ComfyUI/input&lt;br /&gt;
      - ./comfyui/output:/opt/ComfyUI/output&lt;br /&gt;
      - ./comfyui/custom_nodes:/opt/ComfyUI/custom_nodes&lt;br /&gt;
      - ./comfyui/user:/opt/ComfyUI/user&lt;br /&gt;
&lt;br /&gt;
    shm_size: &amp;quot;4gb&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    deploy:&lt;br /&gt;
      resources:&lt;br /&gt;
        reservations:&lt;br /&gt;
          devices:&lt;br /&gt;
            - driver: nvidia&lt;br /&gt;
              count: all&lt;br /&gt;
              capabilities:&lt;br /&gt;
                - gpu&lt;br /&gt;
&lt;br /&gt;
    networks:&lt;br /&gt;
      - ai-net&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
networks:&lt;br /&gt;
  ai-net:&lt;br /&gt;
    name: ai-net&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi tersebut memastikan:&lt;br /&gt;
&lt;br /&gt;
* Ollama memperoleh akses GPU.&lt;br /&gt;
* ComfyUI memperoleh akses GPU.&lt;br /&gt;
* Open WebUI memakai image `main`, bukan image `cuda`.&lt;br /&gt;
* Open WebUI tidak mendapat reservasi perangkat GPU.&lt;br /&gt;
* n8n dan WAHA tidak mendapat reservasi perangkat GPU.&lt;br /&gt;
* Semua aplikasi dapat berkomunikasi melalui jaringan `ai-net`.&lt;br /&gt;
&lt;br /&gt;
Open WebUI mendokumentasikan image `main` untuk instalasi biasa dan koneksi ke Ollama menggunakan `OLLAMA_BASE_URL`; image `cuda` hanya diperlukan bila Open WebUI sendiri membutuhkan GPU. ([Open WebUI][9])&lt;br /&gt;
&lt;br /&gt;
n8n merekomendasikan Docker untuk sebagian besar instalasi self-hosted karena dependensi aplikasi dapat diisolasi dari sistem operasi. ([n8n Documentation][10])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 17. Validasi Docker Compose&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose config&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Apabila tidak muncul pesan error, konfigurasi YAML valid.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN J — MENJALANKAN STACK&lt;br /&gt;
&lt;br /&gt;
## 18. Download image aplikasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose pull&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perintah ini menarik image:&lt;br /&gt;
&lt;br /&gt;
* Ollama&lt;br /&gt;
* Open WebUI&lt;br /&gt;
* n8n&lt;br /&gt;
* WAHA&lt;br /&gt;
&lt;br /&gt;
ComfyUI akan dibangun secara lokal.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 19. Build ComfyUI&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build --pull comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa image yang dibuat:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker images | grep comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
local/comfyui    cu128&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 20. Jalankan semua aplikasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NAME          STATUS&lt;br /&gt;
ollama        Up&lt;br /&gt;
open-webui    Up&lt;br /&gt;
n8n           Up&lt;br /&gt;
waha          Up&lt;br /&gt;
comfyui       Up&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 21. Periksa log&lt;br /&gt;
&lt;br /&gt;
Semua aplikasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 open-webui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
n8n:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
WAHA:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 waha&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk melihat log secara langsung:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tekan `Ctrl+C` untuk keluar dari tampilan log. Container tetap berjalan.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN K — PENGUJIAN&lt;br /&gt;
&lt;br /&gt;
## 22. Uji Ollama&lt;br /&gt;
&lt;br /&gt;
Periksa API:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl http://127.0.0.1:11434/api/tags&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa GPU dari container Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec ollama nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Download contoh model ringan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec -it ollama ollama pull llama3.2:3b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec -it ollama ollama run llama3.2:3b&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ollama mendokumentasikan penggunaan container resmi `ollama/ollama`, akses GPU NVIDIA, dan perintah `docker exec ... ollama run`. ([Ollama][11])&lt;br /&gt;
&lt;br /&gt;
Keluar dari chat Ollama dengan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/bye&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec ollama ollama list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 23. Buka Open WebUI&lt;br /&gt;
&lt;br /&gt;
Dari komputer lain pada jaringan yang sama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:3000&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.100:3000&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Akun pertama yang dibuat akan menjadi administrator.&lt;br /&gt;
&lt;br /&gt;
Open WebUI sudah diarahkan ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jadi tidak perlu memasukkan alamat Ollama secara manual.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 24. Buka n8n&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:5678&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.100:5678&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat akun administrator n8n melalui halaman awal.&lt;br /&gt;
&lt;br /&gt;
Dari node HTTP Request di n8n, alamat internal yang dapat digunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ollama:&lt;br /&gt;
http://ollama:11434&lt;br /&gt;
&lt;br /&gt;
WAHA:&lt;br /&gt;
http://waha:3000&lt;br /&gt;
&lt;br /&gt;
Open WebUI:&lt;br /&gt;
http://open-webui:8080&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh endpoint Ollama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://ollama:11434/api/generate&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh endpoint WAHA:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://waha:3000/api/sendText&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 25. Buka WAHA&lt;br /&gt;
&lt;br /&gt;
Dashboard:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:3001/dashboard&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Swagger/API:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:3001&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lihat username dan password:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
grep -E \&lt;br /&gt;
  'WAHA_DASHBOARD_USERNAME|WAHA_DASHBOARD_PASSWORD|WAHA_API_KEY' \&lt;br /&gt;
  /opt/ai-stack/waha/.env&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masuk ke dashboard, buat sesi `default`, kemudian scan QR menggunakan WhatsApp pada telepon.&lt;br /&gt;
&lt;br /&gt;
WAHA menggunakan QR untuk menghubungkan sesi dan menyediakan endpoint HTTP untuk mengirim pesan. ([GitHub][5])&lt;br /&gt;
&lt;br /&gt;
**Catatan penting:** WAHA merupakan klien otomatisasi tidak resmi. Dokumentasi WAHA sendiri menjelaskan bahwa WhatsApp tidak mengizinkan bot atau klien tidak resmi sehingga penggunaannya tidak sepenuhnya aman dari pemblokiran akun. Gunakan nomor pengujian atau nomor nonkritis dan jangan melakukan spam. ([WAHA][12])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 26. Buka ComfyUI&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://IP-SERVER:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.100:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa apakah PyTorch mendeteksi GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec comfyui python -c \&lt;br /&gt;
'import torch; print(&amp;quot;CUDA:&amp;quot;, torch.cuda.is_available()); print(&amp;quot;GPU:&amp;quot;, torch.cuda.get_device_name(0) if torch.cuda.is_available() else &amp;quot;Tidak terdeteksi&amp;quot;)'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA: True&lt;br /&gt;
GPU: NVIDIA GeForce RTX 4060 Laptop GPU&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN L — MEMASUKKAN MODEL COMFYUI&lt;br /&gt;
&lt;br /&gt;
## 27. Copy checkpoint Stable Diffusion&lt;br /&gt;
&lt;br /&gt;
Misalnya model berada pada:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
~/Downloads/DreamShaper_8_pruned.safetensors&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Copy:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cp \&lt;br /&gt;
  ~/Downloads/DreamShaper_8_pruned.safetensors \&lt;br /&gt;
  /opt/ai-stack/comfyui/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lh /opt/ai-stack/comfyui/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lokasi umum model:&lt;br /&gt;
&lt;br /&gt;
| Jenis      | Folder                           |&lt;br /&gt;
| ---------- | -------------------------------- |&lt;br /&gt;
| Checkpoint | `comfyui/models/checkpoints/`    |&lt;br /&gt;
| LoRA       | `comfyui/models/loras/`          |&lt;br /&gt;
| VAE        | `comfyui/models/vae/`            |&lt;br /&gt;
| CLIP       | `comfyui/models/clip/`           |&lt;br /&gt;
| ControlNet | `comfyui/models/controlnet/`     |&lt;br /&gt;
| Upscaler   | `comfyui/models/upscale_models/` |&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN M — PENGELOLAAN GPU 8 GB&lt;br /&gt;
&lt;br /&gt;
## 28. Hindari Ollama dan ComfyUI memakai VRAM berat bersamaan&lt;br /&gt;
&lt;br /&gt;
RTX 4060 memiliki VRAM 8 GB. Ollama dan ComfyUI boleh hidup bersamaan, tetapi model baru memakai banyak VRAM ketika sedang dimuat.&lt;br /&gt;
&lt;br /&gt;
Konfigurasi berikut sudah membantu Ollama melepaskan model setelah lima menit:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
OLLAMA_KEEP_ALIVE: &amp;quot;5m&amp;quot;&lt;br /&gt;
OLLAMA_MAX_LOADED_MODELS: &amp;quot;1&amp;quot;&lt;br /&gt;
OLLAMA_NUM_PARALLEL: &amp;quot;1&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa pemakaian GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
watch -n 1 nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Keluar dengan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ctrl+C&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Apabila ComfyUI mengalami `CUDA out of memory`, hentikan Ollama sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose stop ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali setelah selesai memakai ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sebaliknya, untuk memberikan GPU sepenuhnya kepada Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose stop comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN N — FIREWALL&lt;br /&gt;
&lt;br /&gt;
## 29. Batasi akses hanya dari jaringan lokal&lt;br /&gt;
&lt;br /&gt;
Contoh jaringan lokal:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
192.168.0.0/24&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan SSH terlebih dahulu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow OpenSSH&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan Open WebUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.0.0/24 to any port 3000 proto tcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan n8n:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.0.0/24 to any port 5678 proto tcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan WAHA:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.0.0/24 to any port 3001 proto tcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.0.0/24 to any port 8188 proto tcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aktifkan firewall:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw enable&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw status numbered&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Port Ollama tidak perlu dibuka karena dipetakan hanya ke:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
127.0.0.1:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI dan n8n tetap dapat mengakses Ollama melalui jaringan internal Docker.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN O — PERINTAH OPERASIONAL&lt;br /&gt;
&lt;br /&gt;
## 30. Start semua aplikasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 31. Stop semua aplikasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose stop&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 32. Start kembali&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 33. Restart semua aplikasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 34. Hapus container tanpa menghapus data&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose down&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Folder data tetap berada di `/opt/ai-stack`.&lt;br /&gt;
&lt;br /&gt;
Jalankan kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 35. Periksa status&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 36. Periksa penggunaan resource&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker stats&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN P — UPDATE&lt;br /&gt;
&lt;br /&gt;
## 37. Update Ollama, Open WebUI, n8n, dan WAHA&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose pull&lt;br /&gt;
docker compose up -d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Open WebUI menyarankan memakai tag versi tertentu untuk lingkungan produksi daripada selalu memakai tag bergerak seperti `main`. Setelah sistem stabil, image sebaiknya dipasangi nomor versi agar update tidak mendadak mengubah perilaku aplikasi. ([Open WebUI][9])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 38. Update ComfyUI&lt;br /&gt;
&lt;br /&gt;
Karena source ComfyUI diambil saat proses build:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
docker compose build \&lt;br /&gt;
  --pull \&lt;br /&gt;
  --no-cache \&lt;br /&gt;
  comfyui&lt;br /&gt;
&lt;br /&gt;
docker compose up -d comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# BAGIAN Q — TROUBLESHOOTING&lt;br /&gt;
&lt;br /&gt;
## 39. Docker tidak mendeteksi GPU&lt;br /&gt;
&lt;br /&gt;
Pesan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
could not select device driver &amp;quot;nvidia&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nvidia-ctk runtime configure --runtime=docker&lt;br /&gt;
sudo systemctl restart docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm --gpus all ubuntu:24.04 nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 40. n8n mengalami `permission denied`&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown -R 1000:1000 /opt/ai-stack/n8n&lt;br /&gt;
docker compose restart n8n&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 41. Open WebUI tidak menemukan Ollama&lt;br /&gt;
&lt;br /&gt;
Periksa Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps ollama&lt;br /&gt;
docker compose logs --tail=100 ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji melalui jaringan Docker:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm \&lt;br /&gt;
  --network ai-net \&lt;br /&gt;
  curlimages/curl:latest \&lt;br /&gt;
  http://ollama:11434/api/tags&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa konfigurasi Open WebUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker inspect open-webui \&lt;br /&gt;
  --format '{{range .Config.Env}}{{println .}}{{end}}' \&lt;br /&gt;
  | grep OLLAMA&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang benar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
OLLAMA_BASE_URL=http://ollama:11434&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 42. ComfyUI kehabisan VRAM&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hentikan Ollama sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose stop ollama&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Gunakan model lebih ringan atau kurangi resolusi gambar.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 43. WAHA kehilangan sesi setelah restart&lt;br /&gt;
&lt;br /&gt;
Periksa pemetaan volume:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker inspect waha \&lt;br /&gt;
  --format '{{json .Mounts}}' \&lt;br /&gt;
  | python3 -m json.tool&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan terdapat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/waha/sessions -&amp;gt; /app/.sessions&lt;br /&gt;
/opt/ai-stack/waha/media    -&amp;gt; /app/.media&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa folder:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lah /opt/ai-stack/waha/sessions&lt;br /&gt;
ls -lah /opt/ai-stack/waha/media&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
# Checklist akhir&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
&lt;br /&gt;
nvidia-smi&lt;br /&gt;
docker version&lt;br /&gt;
docker compose version&lt;br /&gt;
docker compose ps&lt;br /&gt;
curl http://127.0.0.1:11434/api/tags&lt;br /&gt;
docker exec comfyui python -c 'import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil akhir yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Ollama      : GPU RTX 4060&lt;br /&gt;
ComfyUI     : GPU RTX 4060&lt;br /&gt;
Open WebUI  : CPU, terhubung ke Ollama&lt;br /&gt;
n8n         : CPU&lt;br /&gt;
WAHA        : CPU&lt;br /&gt;
Data        : tersimpan di /opt/ai-stack&lt;br /&gt;
Timezone    : Asia/Jakarta&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
[1]: https://docs.docker.com/engine/install/ubuntu/ &amp;quot;Install Docker Engine on Ubuntu | Docker Docs&amp;quot;&lt;br /&gt;
[2]: https://ubuntu.com/server/docs/how-to/graphics/install-nvidia-drivers/ &amp;quot;NVIDIA drivers installation - Ubuntu Server documentation&amp;quot;&lt;br /&gt;
[3]: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html &amp;quot;Installing the NVIDIA Container Toolkit — NVIDIA Container Toolkit&amp;quot;&lt;br /&gt;
[4]: https://docs.ollama.com/troubleshooting?utm_source=chatgpt.com &amp;quot;Troubleshooting - Ollama&amp;quot;&lt;br /&gt;
[5]: https://github.com/devlikeapro/waha-docs/blob/main/content//docs/overview/quick-start/index.md &amp;quot;waha-docs/content/docs/overview/quick-start/index.md at main · devlikeapro/waha-docs · GitHub&amp;quot;&lt;br /&gt;
[6]: https://github.com/devlikeapro/waha/blob/core/docker-compose.yaml &amp;quot;waha/docker-compose.yaml at core · devlikeapro/waha · GitHub&amp;quot;&lt;br /&gt;
[7]: https://github.com/comfyanonymous &amp;quot;comfyanonymous (comfyanonymous) · GitHub&amp;quot;&lt;br /&gt;
[8]: https://docs.pytorch.org/get-started/locally/?utm_source=chatgpt.com &amp;quot;Start Locally | PyTorch&amp;quot;&lt;br /&gt;
[9]: https://docs.openwebui.com/getting-started/quick-start/ &amp;quot;Quick Start / Open WebUI&amp;quot;&lt;br /&gt;
[10]: https://docs.n8n.io/deploy/host-n8n/install-options/install-with-docker?utm_source=chatgpt.com &amp;quot;Install with Docker | Deploy&amp;quot;&lt;br /&gt;
[11]: https://docs.ollama.com/docker?utm_source=chatgpt.com &amp;quot;Docker - Ollama&amp;quot;&lt;br /&gt;
[12]: https://waha.devlike.pro/docs/overview/introduction/?utm_source=chatgpt.com &amp;quot;📖 Introduction | WAHA&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73704</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73704"/>
		<updated>2026-07-23T18:10:23Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Pranala Menarik */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + ComfyUI docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Instalasi_via_docker_compose&amp;diff=73703</id>
		<title>ComfyUI: Instalasi via docker compose</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Instalasi_via_docker_compose&amp;diff=73703"/>
		<updated>2026-07-21T11:39:13Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut rangkuman final yang sesuai dengan instalasi yang baru dilakukan.&lt;br /&gt;
&lt;br /&gt;
# Instalasi ComfyUI GPU dengan Docker Compose di Ubuntu 24.04&lt;br /&gt;
&lt;br /&gt;
Panduan ini mendokumentasikan instalasi ComfyUI pada server Ubuntu 24.04 dengan alamat IP `192.168.0.230`. ComfyUI ditambahkan ke dalam Docker Compose yang sebelumnya sudah menjalankan Ollama, Open-WebUI, n8n, dan WAHA.&lt;br /&gt;
&lt;br /&gt;
Server menggunakan GPU NVIDIA GeForce RTX 4060 Laptop GPU dengan VRAM sekitar 8 GB.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 1. Lokasi instalasi&lt;br /&gt;
&lt;br /&gt;
Seluruh stack berada di:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
/opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
File utama Docker Compose:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
/opt/ai-stack/compose.yaml&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Direktori ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
/opt/ai-stack/comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. Memastikan GPU NVIDIA tersedia&lt;br /&gt;
&lt;br /&gt;
Periksa GPU pada host:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian periksa apakah Docker dapat mengakses GPU:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm --gpus all \&lt;br /&gt;
  nvidia/cuda:12.9.0-base-ubuntu22.04 \&lt;br /&gt;
  nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pengujian berhasil apabila container menampilkan GPU NVIDIA, driver, CUDA, dan kapasitas VRAM.&lt;br /&gt;
&lt;br /&gt;
Pada instalasi ini, Docker berhasil mendeteksi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
NVIDIA GeForce RTX 4060 Laptop GPU&lt;br /&gt;
VRAM sekitar 8188 MiB&lt;br /&gt;
NVIDIA Driver 595.71.05&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Artinya NVIDIA Container Toolkit dan integrasi GPU Docker sudah berjalan dengan benar.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. Membuat direktori ComfyUI&lt;br /&gt;
&lt;br /&gt;
Masuk ke direktori stack:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat direktori utama dan direktori data ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p comfyui/data/{models,input,output,custom_nodes,user,cache}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Buat subdirektori model:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p comfyui/data/models/{checkpoints,vae,loras,controlnet,clip,clip_vision,diffusion_models,text_encoders,unet,upscale_models,embeddings}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Struktur akhirnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/&lt;br /&gt;
├── compose.yaml&lt;br /&gt;
└── comfyui/&lt;br /&gt;
    ├── Dockerfile&lt;br /&gt;
    ├── .dockerignore&lt;br /&gt;
    └── data/&lt;br /&gt;
        ├── models/&lt;br /&gt;
        │   ├── checkpoints/&lt;br /&gt;
        │   ├── vae/&lt;br /&gt;
        │   ├── loras/&lt;br /&gt;
        │   ├── controlnet/&lt;br /&gt;
        │   ├── clip/&lt;br /&gt;
        │   ├── clip_vision/&lt;br /&gt;
        │   ├── diffusion_models/&lt;br /&gt;
        │   ├── text_encoders/&lt;br /&gt;
        │   ├── unet/&lt;br /&gt;
        │   ├── upscale_models/&lt;br /&gt;
        │   └── embeddings/&lt;br /&gt;
        ├── input/&lt;br /&gt;
        ├── output/&lt;br /&gt;
        ├── custom_nodes/&lt;br /&gt;
        ├── user/&lt;br /&gt;
        └── cache/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. Membuat Dockerfile ComfyUI&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat &amp;gt; /opt/ai-stack/comfyui/Dockerfile &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
FROM python:3.12-slim-bookworm&lt;br /&gt;
&lt;br /&gt;
ENV DEBIAN_FRONTEND=noninteractive&lt;br /&gt;
ENV PYTHONUNBUFFERED=1&lt;br /&gt;
ENV PIP_NO_CACHE_DIR=1&lt;br /&gt;
&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br /&gt;
    git \&lt;br /&gt;
    ca-certificates \&lt;br /&gt;
    curl \&lt;br /&gt;
    ffmpeg \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    libgl1 \&lt;br /&gt;
    libglib2.0-0 \&lt;br /&gt;
    libgomp1 \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt&lt;br /&gt;
&lt;br /&gt;
RUN git clone --depth 1 \&lt;br /&gt;
    https://github.com/Comfy-Org/ComfyUI.git \&lt;br /&gt;
    /opt/ComfyUI&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt/ComfyUI&lt;br /&gt;
&lt;br /&gt;
RUN python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
RUN python -m pip install \&lt;br /&gt;
    torch==2.11.0 \&lt;br /&gt;
    torchvision==0.26.0 \&lt;br /&gt;
    torchaudio==2.11.0 \&lt;br /&gt;
    --index-url https://download.pytorch.org/whl/cu128&lt;br /&gt;
&lt;br /&gt;
RUN python -m pip install -r requirements.txt \&lt;br /&gt;
    &amp;amp;&amp;amp; python -m pip install -r manager_requirements.txt&lt;br /&gt;
&lt;br /&gt;
EXPOSE 8188&lt;br /&gt;
&lt;br /&gt;
CMD [&amp;quot;python&amp;quot;, &amp;quot;main.py&amp;quot;, \&lt;br /&gt;
     &amp;quot;--listen&amp;quot;, &amp;quot;0.0.0.0&amp;quot;, \&lt;br /&gt;
     &amp;quot;--port&amp;quot;, &amp;quot;8188&amp;quot;, \&lt;br /&gt;
     &amp;quot;--enable-manager&amp;quot;, \&lt;br /&gt;
     &amp;quot;--preview-method&amp;quot;, &amp;quot;auto&amp;quot;]&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa bahwa file sudah dibuat:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lah /opt/ai-stack/comfyui/Dockerfile&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil instalasi ini menunjukkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
-rw-r--r-- 1 root root 1001 Jul 21 10:58 comfyui/Dockerfile&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. Membuat `.dockerignore`&lt;br /&gt;
&lt;br /&gt;
File ini mencegah direktori model dan hasil gambar ikut dimasukkan ke Docker build context.&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat &amp;gt; /opt/ai-stack/comfyui/.dockerignore &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
data/&lt;br /&gt;
.git/&lt;br /&gt;
__pycache__/&lt;br /&gt;
*.pyc&lt;br /&gt;
*.pyo&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Menambahkan ComfyUI ke Docker Compose&lt;br /&gt;
&lt;br /&gt;
Tambahkan service berikut ke dalam `/opt/ai-stack/compose.yaml`.&lt;br /&gt;
&lt;br /&gt;
Letakkan bagian ini setelah service WAHA dan sebelum bagian global `volumes:`.&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
  ################################&lt;br /&gt;
  # 5. COMFYUI (GPU)&lt;br /&gt;
  ################################&lt;br /&gt;
  comfyui:&lt;br /&gt;
    build:&lt;br /&gt;
      context: ./comfyui&lt;br /&gt;
      dockerfile: Dockerfile&lt;br /&gt;
&lt;br /&gt;
    image: local/comfyui:cu128&lt;br /&gt;
    container_name: comfyui&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;8188:8188&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      - TZ=Asia/Jakarta&lt;br /&gt;
      - NVIDIA_VISIBLE_DEVICES=all&lt;br /&gt;
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./comfyui/data/models:/opt/ComfyUI/models&lt;br /&gt;
      - ./comfyui/data/input:/opt/ComfyUI/input&lt;br /&gt;
      - ./comfyui/data/output:/opt/ComfyUI/output&lt;br /&gt;
      - ./comfyui/data/custom_nodes:/opt/ComfyUI/custom_nodes&lt;br /&gt;
      - ./comfyui/data/user:/opt/ComfyUI/user&lt;br /&gt;
      - ./comfyui/data/cache:/root/.cache&lt;br /&gt;
&lt;br /&gt;
    shm_size: &amp;quot;8gb&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    deploy:&lt;br /&gt;
      resources:&lt;br /&gt;
        reservations:&lt;br /&gt;
          devices:&lt;br /&gt;
            - driver: nvidia&lt;br /&gt;
              count: all&lt;br /&gt;
              capabilities:&lt;br /&gt;
                - gpu&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bagian volume utama tetap:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
volumes:&lt;br /&gt;
  ollama_data:&lt;br /&gt;
  openwebui_data:&lt;br /&gt;
  n8n_data:&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ComfyUI tidak membutuhkan named volume tambahan karena semua datanya menggunakan bind mount di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Memvalidasi Docker Compose&lt;br /&gt;
&lt;br /&gt;
Masuk ke direktori stack:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Validasi konfigurasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose config&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan Compose mendeteksi seluruh service:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose config --services&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasilnya harus mencakup:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
ollama&lt;br /&gt;
open-webui&lt;br /&gt;
n8n&lt;br /&gt;
waha&lt;br /&gt;
comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada instalasi ini, konfigurasi ComfyUI terbaca sebagai:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
build context: /opt/ai-stack/comfyui&lt;br /&gt;
dockerfile: Dockerfile&lt;br /&gt;
image: local/comfyui:cu128&lt;br /&gt;
port: 8188&lt;br /&gt;
GPU driver: nvidia&lt;br /&gt;
GPU count: all&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Kesalahan `docker compose pull`&lt;br /&gt;
&lt;br /&gt;
Ketika menjalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose pull&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
muncul pesan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
pull access denied for local/comfyui&lt;br /&gt;
repository does not exist or may require docker login&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hal ini terjadi karena:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
image: local/comfyui:cu128&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
merupakan image lokal yang harus dibangun dari Dockerfile, bukan diunduh dari Docker Hub.&lt;br /&gt;
&lt;br /&gt;
Tidak perlu melakukan `docker login`.&lt;br /&gt;
&lt;br /&gt;
Untuk service ComfyUI, gunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk memperbarui image service lain tanpa mencoba menarik image ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose pull --ignore-buildable&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. Membangun image ComfyUI&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose build comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Docker akan melakukan beberapa hal:&lt;br /&gt;
&lt;br /&gt;
* Mengunduh base image Python 3.12.&lt;br /&gt;
* Menginstal Git, FFmpeg, library OpenGL, dan compiler.&lt;br /&gt;
* Mengambil source code ComfyUI.&lt;br /&gt;
* Menginstal PyTorch dengan CUDA 12.8.&lt;br /&gt;
* Menginstal seluruh requirement ComfyUI.&lt;br /&gt;
* Menginstal ComfyUI-Manager.&lt;br /&gt;
* Memberikan nama image `local/comfyui:cu128`.&lt;br /&gt;
&lt;br /&gt;
Periksa image setelah build:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker image ls local/comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 10. Menjalankan ComfyUI&lt;br /&gt;
&lt;br /&gt;
Jalankan hanya service ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose up -d --no-deps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Opsi `--no-deps` mencegah Docker Compose menjalankan ulang atau mengubah service lain.&lt;br /&gt;
&lt;br /&gt;
Periksa status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instalasi berhasil ketika muncul:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
[INFO] Starting server&lt;br /&gt;
&lt;br /&gt;
[INFO] To see the GUI go to: http://0.0.0.0:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada instalasi ini ComfyUI berhasil menjalankan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
ComfyUI version: 0.28.0&lt;br /&gt;
comfyui-frontend-package version: 1.45.21&lt;br /&gt;
ComfyUI-Manager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 11. Peringatan yang aman diabaikan&lt;br /&gt;
&lt;br /&gt;
Log menampilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
The matrix sharing feature has been disabled because the matrix-nio dependency is not installed.&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini bukan error. Fitur berbagi melalui Matrix tidak diperlukan untuk penggunaan normal ComfyUI.&lt;br /&gt;
&lt;br /&gt;
Log juga menampilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
No OpenGL_accelerate module loaded&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Ini juga bukan error fatal. ComfyUI tetap dapat berjalan menggunakan CUDA dan antarmuka web.&lt;br /&gt;
&lt;br /&gt;
Tidak perlu memasang kedua modul tersebut apabila ComfyUI sudah berjalan normal.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 12. Mengakses ComfyUI&lt;br /&gt;
&lt;br /&gt;
Buka browser dari komputer yang berada dalam jaringan yang sama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.230:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Port `8188` diarahkan dari host ke container:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
ports:&lt;br /&gt;
  - &amp;quot;8188:8188&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 13. Memastikan ComfyUI menggunakan GPU&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec comfyui python -c '&lt;br /&gt;
import torch&lt;br /&gt;
&lt;br /&gt;
print(&amp;quot;PyTorch       :&amp;quot;, torch.__version__)&lt;br /&gt;
print(&amp;quot;CUDA runtime  :&amp;quot;, torch.version.cuda)&lt;br /&gt;
print(&amp;quot;CUDA tersedia :&amp;quot;, torch.cuda.is_available())&lt;br /&gt;
&lt;br /&gt;
if torch.cuda.is_available():&lt;br /&gt;
    print(&amp;quot;GPU           :&amp;quot;, torch.cuda.get_device_name(0))&lt;br /&gt;
    print(&lt;br /&gt;
        &amp;quot;VRAM          :&amp;quot;,&lt;br /&gt;
        round(torch.cuda.get_device_properties(0).total_memory / 1024**3, 2),&lt;br /&gt;
        &amp;quot;GB&amp;quot;&lt;br /&gt;
    )&lt;br /&gt;
'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA tersedia : True&lt;br /&gt;
GPU            : NVIDIA GeForce RTX 4060 Laptop GPU&lt;br /&gt;
VRAM           : sekitar 8 GB&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 14. Menyalin model DreamShaper ke server&lt;br /&gt;
&lt;br /&gt;
Model berada pada laptop `i3` di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/home/onno/Downloads/LIBRARY/DreamShaper_8_pruned.safetensors&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tujuan model di server:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dari laptop `i3`, jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd ~/Downloads/LIBRARY&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian salin menggunakan SCP:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
scp DreamShaper_8_pruned.safetensors \&lt;br /&gt;
  onno@192.168.0.230:/opt/ai-stack/comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masukkan password user `onno` pada server.&lt;br /&gt;
&lt;br /&gt;
Periksa file dari server:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ssh onno@192.168.0.230&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -lh /opt/ai-stack/comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
File yang harus terlihat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
DreamShaper_8_pruned.safetensors&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 15. Jika terjadi `Permission denied` saat SCP&lt;br /&gt;
&lt;br /&gt;
Salin dahulu ke home user:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
scp DreamShaper_8_pruned.safetensors \&lt;br /&gt;
  onno@192.168.0.230:/home/onno/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masuk ke server:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ssh onno@192.168.0.230&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pindahkan menggunakan `sudo`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo mv ~/DreamShaper_8_pruned.safetensors \&lt;br /&gt;
  /opt/ai-stack/comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur kepemilikan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown onno:onno \&lt;br /&gt;
  /opt/ai-stack/comfyui/data/models/checkpoints/DreamShaper_8_pruned.safetensors&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 16. Mengatur kepemilikan direktori ComfyUI&lt;br /&gt;
&lt;br /&gt;
Karena beberapa file dibuat sebagai `root`, ubah kepemilikannya agar user `onno` dapat mengelola model, input, dan output:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown -R onno:onno /opt/ai-stack/comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ls -ld /opt/ai-stack/comfyui&lt;br /&gt;
ls -ld /opt/ai-stack/comfyui/data/models/checkpoints&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 17. Memuat model yang baru disalin&lt;br /&gt;
&lt;br /&gt;
Setelah model selesai disalin, restart ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pantau log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian muat ulang halaman browser:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.230:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada node `Load Checkpoint`, pilih:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
DreamShaper_8_pruned.safetensors&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
DreamShaper 8 merupakan checkpoint berbasis Stable Diffusion 1.5, sehingga relatif sesuai untuk GPU dengan VRAM 8 GB.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 18. Perintah operasional sehari-hari&lt;br /&gt;
&lt;br /&gt;
Menjalankan ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose start comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menghentikan ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose stop comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Melihat status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Melihat log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membangun ulang setelah Dockerfile berubah:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build comfyui&lt;br /&gt;
docker compose up -d --no-deps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membangun ulang tanpa menggunakan build cache:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build --no-cache comfyui&lt;br /&gt;
docker compose up -d --no-deps comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 19. Penggunaan bersama Ollama&lt;br /&gt;
&lt;br /&gt;
Ollama dan ComfyUI menggunakan GPU yang sama.&lt;br /&gt;
&lt;br /&gt;
RTX 4060 memiliki VRAM sekitar 8 GB. Jika model Ollama masih berada dalam VRAM, ComfyUI dapat kehabisan memori dan menampilkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA out of memory&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sebelum menghasilkan gambar besar, Ollama dapat dihentikan sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd /opt/ai-stack&lt;br /&gt;
docker compose stop ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah selesai menggunakan ComfyUI, jalankan kembali Ollama:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 20. Lokasi file penting&lt;br /&gt;
&lt;br /&gt;
Dockerfile:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/Dockerfile&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Docker Compose:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/compose.yaml&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Checkpoint:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
LoRA:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/models/loras/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
VAE:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/models/vae/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Input gambar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/input/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil gambar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/output/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Custom node:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/custom_nodes/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cache model:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
/opt/ai-stack/comfyui/data/cache/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 21. Status akhir instalasi&lt;br /&gt;
&lt;br /&gt;
ComfyUI telah berhasil:&lt;br /&gt;
&lt;br /&gt;
* Dibangun menggunakan Dockerfile lokal.&lt;br /&gt;
* Ditambahkan sebagai service kelima di Docker Compose.&lt;br /&gt;
* Mengakses GPU NVIDIA melalui NVIDIA Container Toolkit.&lt;br /&gt;
* Menjalankan PyTorch dengan dukungan CUDA.&lt;br /&gt;
* Menjalankan ComfyUI-Manager.&lt;br /&gt;
* Membuka antarmuka web pada port `8188`.&lt;br /&gt;
* Menyimpan model, input, output, dan custom node secara persisten di host.&lt;br /&gt;
* Siap menggunakan checkpoint `DreamShaper_8_pruned.safetensors`.&lt;br /&gt;
&lt;br /&gt;
Alamat akses akhir:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.230:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Panduan ini dapat langsung disimpan sebagai `/opt/ai-stack/README-ComfyUI.md`.&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Instalasi_via_docker_compose&amp;diff=73702</id>
		<title>ComfyUI: Instalasi via docker compose</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ComfyUI:_Instalasi_via_docker_compose&amp;diff=73702"/>
		<updated>2026-07-21T09:17:44Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;## Menambahkan ComfyUI ke Docker Compose yang sudah ada  Cara yang relatif aman adalah **membangun image ComfyUI sendiri dari repositori resmi**, bukan memakai image komunitas...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;## Menambahkan ComfyUI ke Docker Compose yang sudah ada&lt;br /&gt;
&lt;br /&gt;
Cara yang relatif aman adalah **membangun image ComfyUI sendiri dari repositori resmi**, bukan memakai image komunitas yang isinya tidak selalu jelas. Instalasi resmi ComfyUI menggunakan repositori `Comfy-Org/ComfyUI`, memasang PyTorch dan `requirements.txt`, lalu menjalankan `main.py`. ComfyUI-Manager sekarang diaktifkan melalui `manager_requirements.txt` dan parameter `--enable-manager`. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
Struktur akhirnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
local-ai/&lt;br /&gt;
├── compose.yaml&lt;br /&gt;
└── comfyui/&lt;br /&gt;
    ├── Dockerfile&lt;br /&gt;
    ├── .dockerignore&lt;br /&gt;
    └── data/&lt;br /&gt;
        ├── models/&lt;br /&gt;
        ├── input/&lt;br /&gt;
        ├── output/&lt;br /&gt;
        ├── custom_nodes/&lt;br /&gt;
        ├── user/&lt;br /&gt;
        └── cache/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 1. Pastikan GPU NVIDIA dapat digunakan Docker&lt;br /&gt;
&lt;br /&gt;
Periksa driver:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa NVIDIA Container Toolkit:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
dpkg -l | grep nvidia-container-toolkit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika belum terpasang:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \&lt;br /&gt;
  | sudo gpg --dearmor \&lt;br /&gt;
  -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \&lt;br /&gt;
  | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' \&lt;br /&gt;
  | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt install -y nvidia-container-toolkit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasikan runtime NVIDIA:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nvidia-ctk runtime configure --runtime=docker&lt;br /&gt;
sudo systemctl restart docker&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Itu adalah prosedur resmi NVIDIA untuk Debian dan Ubuntu. ([NVIDIA Docs][2])&lt;br /&gt;
&lt;br /&gt;
Tes akses GPU dari container:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker run --rm --gpus all \&lt;br /&gt;
  nvidia/cuda:12.9.0-base-ubuntu22.04 \&lt;br /&gt;
  nvidia-smi&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Walaupun host memakai Ubuntu 24.04, container boleh menggunakan basis Ubuntu 22.04.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. Buat direktori ComfyUI&lt;br /&gt;
&lt;br /&gt;
Masuk ke direktori tempat `compose.yaml` berada:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cd ~/Apps/LocalAI&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sesuaikan apabila lokasi compose berbeda.&lt;br /&gt;
&lt;br /&gt;
Buat struktur folder:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p comfyui/data/{input,output,custom_nodes,user,cache}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
mkdir -p comfyui/data/models/{checkpoints,vae,loras,controlnet,clip,clip_vision,diffusion_models,text_encoders,unet,upscale_models,embeddings}&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
find comfyui -maxdepth 3 -type d&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. Buat Dockerfile ComfyUI&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nano comfyui/Dockerfile&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
```dockerfile&lt;br /&gt;
FROM python:3.12-slim-bookworm&lt;br /&gt;
&lt;br /&gt;
ENV DEBIAN_FRONTEND=noninteractive \&lt;br /&gt;
    PYTHONUNBUFFERED=1 \&lt;br /&gt;
    PIP_NO_CACHE_DIR=1&lt;br /&gt;
&lt;br /&gt;
# Paket sistem yang diperlukan ComfyUI dan berbagai custom node.&lt;br /&gt;
RUN apt-get update &amp;amp;&amp;amp; apt-get install -y --no-install-recommends \&lt;br /&gt;
    git \&lt;br /&gt;
    ca-certificates \&lt;br /&gt;
    curl \&lt;br /&gt;
    ffmpeg \&lt;br /&gt;
    build-essential \&lt;br /&gt;
    libgl1 \&lt;br /&gt;
    libglib2.0-0 \&lt;br /&gt;
    libgomp1 \&lt;br /&gt;
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt&lt;br /&gt;
&lt;br /&gt;
# Mengambil ComfyUI dari repositori resmi.&lt;br /&gt;
RUN git clone --depth 1 https://github.com/Comfy-Org/ComfyUI.git&lt;br /&gt;
&lt;br /&gt;
WORKDIR /opt/ComfyUI&lt;br /&gt;
&lt;br /&gt;
# Memasang PyTorch dengan dukungan NVIDIA CUDA 12.8.&lt;br /&gt;
RUN python -m pip install --upgrade pip setuptools wheel \&lt;br /&gt;
    &amp;amp;&amp;amp; python -m pip install \&lt;br /&gt;
       torch torchvision torchaudio \&lt;br /&gt;
       --index-url https://download.pytorch.org/whl/cu128 \&lt;br /&gt;
    &amp;amp;&amp;amp; python -m pip install -r requirements.txt \&lt;br /&gt;
    &amp;amp;&amp;amp; python -m pip install -r manager_requirements.txt&lt;br /&gt;
&lt;br /&gt;
EXPOSE 8188&lt;br /&gt;
&lt;br /&gt;
CMD [&amp;quot;python&amp;quot;, &amp;quot;main.py&amp;quot;, \&lt;br /&gt;
     &amp;quot;--listen&amp;quot;, &amp;quot;0.0.0.0&amp;quot;, \&lt;br /&gt;
     &amp;quot;--port&amp;quot;, &amp;quot;8188&amp;quot;, \&lt;br /&gt;
     &amp;quot;--enable-manager&amp;quot;, \&lt;br /&gt;
     &amp;quot;--preview-method&amp;quot;, &amp;quot;auto&amp;quot;]&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
CUDA 12.8 dipilih karena cocok untuk keluarga GPU NVIDIA modern seperti Turing, Ampere, dan Blackwell, termasuk RTX 20, RTX 30, RTX 40, dan RTX 50. PyTorch masih menyediakan wheel CUDA 12.8 secara terpisah. ([GitHub][3])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. Buat `.dockerignore`&lt;br /&gt;
&lt;br /&gt;
Ini penting agar file model yang ukurannya puluhan gigabyte tidak ikut dikirim sebagai Docker build context.&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
nano comfyui/.dockerignore&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
data/&lt;br /&gt;
__pycache__/&lt;br /&gt;
*.pyc&lt;br /&gt;
*.pyo&lt;br /&gt;
.git/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. Tambahkan service ComfyUI ke `compose.yaml`&lt;br /&gt;
&lt;br /&gt;
Tambahkan bagian berikut **setelah service `waha` tetapi sebelum bagian paling bawah `volumes:`**:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
  ################################&lt;br /&gt;
  # 5. COMFYUI (Image Generation)&lt;br /&gt;
  ################################&lt;br /&gt;
  comfyui:&lt;br /&gt;
    build:&lt;br /&gt;
      context: ./comfyui&lt;br /&gt;
      dockerfile: Dockerfile&lt;br /&gt;
    image: local/comfyui:cu128&lt;br /&gt;
    container_name: comfyui&lt;br /&gt;
    restart: unless-stopped&lt;br /&gt;
&lt;br /&gt;
    ports:&lt;br /&gt;
      - &amp;quot;192.168.0.230:8188:8188&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    environment:&lt;br /&gt;
      - TZ=Asia/Jakarta&lt;br /&gt;
      - NVIDIA_VISIBLE_DEVICES=all&lt;br /&gt;
      - NVIDIA_DRIVER_CAPABILITIES=compute,utility&lt;br /&gt;
&lt;br /&gt;
    volumes:&lt;br /&gt;
      - ./comfyui/data/models:/opt/ComfyUI/models&lt;br /&gt;
      - ./comfyui/data/input:/opt/ComfyUI/input&lt;br /&gt;
      - ./comfyui/data/output:/opt/ComfyUI/output&lt;br /&gt;
      - ./comfyui/data/custom_nodes:/opt/ComfyUI/custom_nodes&lt;br /&gt;
      - ./comfyui/data/user:/opt/ComfyUI/user&lt;br /&gt;
      - ./comfyui/data/cache:/root/.cache&lt;br /&gt;
&lt;br /&gt;
    shm_size: &amp;quot;8gb&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    deploy:&lt;br /&gt;
      resources:&lt;br /&gt;
        reservations:&lt;br /&gt;
          devices:&lt;br /&gt;
            - driver: nvidia&lt;br /&gt;
              count: all&lt;br /&gt;
              capabilities: [&amp;quot;gpu&amp;quot;]&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bagian akhir compose tetap seperti sebelumnya:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
volumes:&lt;br /&gt;
  ollama_data:&lt;br /&gt;
  openwebui_data:&lt;br /&gt;
  n8n_data:&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tidak perlu menambahkan `comfyui_data` karena ComfyUI menggunakan bind mount ke direktori `./comfyui/data`.&lt;br /&gt;
&lt;br /&gt;
Docker Compose memang mendukung reservasi GPU melalui `deploy.resources.reservations.devices`, dan `capabilities: [&amp;quot;gpu&amp;quot;]` wajib dicantumkan. ([Docker Documentation][4])&lt;br /&gt;
&lt;br /&gt;
### Tentang pengaturan port&lt;br /&gt;
&lt;br /&gt;
Baris ini:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
ports:&lt;br /&gt;
  - &amp;quot;192.168.0.230:8188:8188&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
berarti ComfyUI hanya mendengarkan melalui alamat LAN server `192.168.0.230`.&lt;br /&gt;
&lt;br /&gt;
Apabila alamat server berbeda, ubah IP tersebut. Untuk membuka melalui seluruh interface, gunakan:&lt;br /&gt;
&lt;br /&gt;
```yaml&lt;br /&gt;
ports:&lt;br /&gt;
  - &amp;quot;8188:8188&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Namun ComfyUI sebaiknya tidak langsung dibuka ke internet, terutama ketika Manager aktif karena Manager dapat memasang dan menjalankan kode dari custom node.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Validasi YAML&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose config&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika tidak ada pesan kesalahan, build hanya service ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose up -d comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Keterangan:&lt;br /&gt;
&lt;br /&gt;
* `up` membuat dan menjalankan container.&lt;br /&gt;
* `-d` menjalankan container di belakang layar.&lt;br /&gt;
* `comfyui` berarti hanya service ComfyUI yang dijalankan.&lt;br /&gt;
&lt;br /&gt;
Periksa status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose ps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Seharusnya terdapat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
comfyui    running    192.168.0.230:8188-&amp;gt;8188/tcp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Periksa log ComfyUI&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose logs -f --tail=100 comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Cari informasi seperti:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Device: cuda:0&lt;br /&gt;
Using pytorch attention&lt;br /&gt;
Starting server&lt;br /&gt;
To see the GUI go to: http://0.0.0.0:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tekan `Ctrl+C` untuk keluar dari tampilan log. Container tetap berjalan.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Verifikasi PyTorch dan GPU&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker exec comfyui python -c \&lt;br /&gt;
'import torch; print(&amp;quot;CUDA tersedia:&amp;quot;, torch.cuda.is_available()); print(&amp;quot;PyTorch:&amp;quot;, torch.__version__); print(&amp;quot;CUDA:&amp;quot;, torch.version.cuda); print(&amp;quot;GPU:&amp;quot;, torch.cuda.get_device_name(0) if torch.cuda.is_available() else &amp;quot;Tidak ada&amp;quot;)'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Hasil yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA tersedia: True&lt;br /&gt;
PyTorch: 2.x.x&lt;br /&gt;
CUDA: 12.8&lt;br /&gt;
GPU: NVIDIA GeForce RTX ...&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. Buka ComfyUI&lt;br /&gt;
&lt;br /&gt;
Dari komputer dalam jaringan yang sama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
http://192.168.0.230:8188&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
ComfyUI tidak menyertakan checkpoint model secara otomatis. Tempatkan file model `*.safetensors` di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
comfyui/data/models/checkpoints/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
VAE ditempatkan di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
comfyui/data/models/vae/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
LoRA ditempatkan di:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
comfyui/data/models/loras/&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lokasi checkpoint dan VAE tersebut sesuai struktur model resmi ComfyUI. ([GitHub][1])&lt;br /&gt;
&lt;br /&gt;
Setelah memasukkan model, restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 10. Perintah operasional&lt;br /&gt;
&lt;br /&gt;
Menghentikan ComfyUI saja:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose stop comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menjalankannya kembali:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Menghapus container tanpa menghapus model dan hasil gambar:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose rm -sf comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Membangun ulang ComfyUI versi terbaru:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose build --no-cache comfyui&lt;br /&gt;
docker compose up -d comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
`--no-cache` memaksa Docker mengambil ulang kode dan memasang ulang dependency, bukan menggunakan layer build lama.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Jika VRAM tidak cukup&lt;br /&gt;
&lt;br /&gt;
Ollama dan ComfyUI memakai GPU NVIDIA yang sama. Ketika model Ollama masih berada di VRAM, ComfyUI dapat mengalami:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
CUDA out of memory&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Untuk pengujian, hentikan Ollama sementara:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose stop ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan ComfyUI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose restart comfyui&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah selesai membuat gambar:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
docker compose start ollama&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Terakhir, sebaiknya pindahkan `WHATSAPP_API_KEY`, password dashboard WAHA, dan password Swagger dari YAML ke file `.env`, serta ganti nilai password yang saat ini masih sederhana sebelum server dapat diakses pengguna lain.&lt;br /&gt;
&lt;br /&gt;
[1]: https://github.com/comfy-org/ComfyUI &amp;quot;GitHub - Comfy-Org/ComfyUI: The most powerful and modular diffusion model GUI, api and backend with a graph/nodes interface. · GitHub&amp;quot;&lt;br /&gt;
[2]: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/1.17.7/install-guide.html &amp;quot;Installing the NVIDIA Container Toolkit — NVIDIA Container Toolkit&amp;quot;&lt;br /&gt;
[3]: https://github.com/pytorch/pytorch/releases?utm_source=chatgpt.com &amp;quot;Releases · pytorch/pytorch&amp;quot;&lt;br /&gt;
[4]: https://docs.docker.com/compose/how-tos/gpu-support/ &amp;quot;Run Docker Compose services with GPU access | Docker Docs&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73701</id>
		<title>LLM</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=LLM&amp;diff=73701"/>
		<updated>2026-07-21T09:13:23Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* ComfyUI */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Dalam bahasa awam, paling gampang bayangkan ChatGPT atau Gemini. Ini adalah keluarga LLM.&lt;br /&gt;
&lt;br /&gt;
Model Bahasa Besar (Large Language Models atau LLM) adalah sistem kecerdasan buatan yang dirancang untuk memahami dan menghasilkan teks yang menyerupai bahasa manusia. LLM dilatih menggunakan teknik pembelajaran mendalam (*deep learning*) pada kumpulan data teks yang sangat besar, memungkinkan mereka untuk mengenali pola, struktur, dan konteks dalam bahasa alami.&lt;br /&gt;
&lt;br /&gt;
Arsitektur utama yang mendasari LLM adalah *transformer*, yang terdiri dari jaringan saraf dengan kemampuan *self-attention*. Komponen ini memungkinkan model untuk memproses dan memahami hubungan antara kata dan frasa dalam sebuah teks, sehingga mampu menghasilkan prediksi atau respons yang relevan dan koheren.&lt;br /&gt;
&lt;br /&gt;
Penerapan LLM sangat luas, mencakup berbagai bidang seperti penerjemahan bahasa, pembuatan konten, analisis sentimen, dan interaksi melalui asisten virtual. Kemampuan mereka untuk memahami dan menghasilkan bahasa alami telah menjadikan LLM sebagai komponen penting dalam pengembangan teknologi berbasis bahasa. &lt;br /&gt;
&lt;br /&gt;
[[File:LLM-1.png|center|200px|thumb]]&lt;br /&gt;
&lt;br /&gt;
Cara kerja LLM (Large Language Model) bisa dijelaskan secara sederhana melalui gambar “Basic LLM Prompt Cycle” di atas.&lt;br /&gt;
&lt;br /&gt;
==1. Pengguna memberikan '''prompt'''==&lt;br /&gt;
&lt;br /&gt;
Siklus dimulai ketika pengguna (User) mengajukan sebuah pertanyaan atau instruksi, yang disebut sebagai '''prompt'''. Prompt ini bisa berupa kalimat, paragraf, atau bahkan percakapan yang kompleks. Pada gambar, ini ditunjukkan oleh panah dari '''User''' menuju kotak '''Prompt'''.&lt;br /&gt;
&lt;br /&gt;
==2. Prompt masuk ke dalam '''Context Window'''==  &lt;br /&gt;
&lt;br /&gt;
LLM memiliki yang namanya '''Context Window''', yaitu tempat di mana model mengingat semua informasi yang relevan untuk memahami apa yang sedang dibahas. Prompt dari pengguna akan masuk ke dalam '''context window''' ini (kotak merah di tengah gambar). Di sini, LLM menganalisis prompt berdasarkan konteks sebelumnya jika ada.&lt;br /&gt;
&lt;br /&gt;
==3. LLM menghasilkan jawaban berdasarkan konteks==&lt;br /&gt;
&lt;br /&gt;
Setelah memahami isi prompt dalam konteks yang diberikan, LLM (kotak kuning) memprosesnya menggunakan jaringan neural besar yang telah dilatih dari jutaan data teks. Hasilnya berupa '''output''' atau jawaban, yang muncul di bagian akhir siklus (kotak biru '''Output''').&lt;br /&gt;
&lt;br /&gt;
==4. '''Output''' menjadi bagian dari konteks berikutnya==&lt;br /&gt;
&lt;br /&gt;
Yang menarik, output ini akan secara otomatis dimasukkan kembali ke dalam '''context window''', bersama dengan prompt tambahan jika ada. Ini memungkinkan percakapan atau pemrosesan yang berkelanjutan, seperti chat dengan memori pendek. Pada gambar, ini ditunjukkan oleh panah melengkung dari '''Output''' kembali ke '''Context Window'''.&lt;br /&gt;
&lt;br /&gt;
Singkatnya, LLM bekerja seperti otak yang terus mengingat apa yang dikatakan sebelumnya (context), lalu memberikan jawaban berdasarkan pemahaman konteks dan prompt terbaru. Proses ini terjadi berulang-ulang selama interaksi berlangsung.&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://lmstudio.ai/&lt;br /&gt;
* https://huggingface.co/Ichsan2895/Merak-7B-v2 - Huggingface bahasa Indonesia.&lt;br /&gt;
* https://ubuntu.com/blog/deploying-open-language-models-on-ubuntu&lt;br /&gt;
&lt;br /&gt;
===GPT===&lt;br /&gt;
&lt;br /&gt;
GPT, or Generative Pre-trained Transformer, represents a category of Large Language Models (LLMs) proficient in generating human-like text, offering capabilities in content creation and personalized recommendations.&lt;br /&gt;
&lt;br /&gt;
* https://www.aporia.com/learn/exploring-architectures-and-capabilities-of-foundational-llms/&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: docker shell access]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh docker]]&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA + Wazuh + Webmail docker]] '''NOT RECOMMEND'''&lt;br /&gt;
* [[LLM: Ubuntu 26.04 server Ollama GPU + Open-WebUI + n8n + WAHA docker]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui orange GPU 4060]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA yaml ringan]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop - Ollama n8n open-webui WAHA]]&lt;br /&gt;
* [[LLM: Ubuntu 24.04 desktop pull ollama model]]&lt;br /&gt;
* [[LLM: LLama Instal Ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 docker open-webio]]&lt;br /&gt;
* [[LLM: ollama install ubuntu 24.04 python open-webio]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui gpu full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webio + n8n full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + postgresql full docker]] '''RECOMMENDED'''&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama + open-webui + n8n + comfyui + GPU nvidia docker]]&lt;br /&gt;
* [[LLM: ubuntu 24.04 ollama instalasi CUDA]]&lt;br /&gt;
* [[LLM: ollama serve run pull list rm]]&lt;br /&gt;
* [[LLM: ollama pull models minimalist]]&lt;br /&gt;
* [[LLM: ollama pull models]]&lt;br /&gt;
* [[LLM: tips untuk CPU]]&lt;br /&gt;
* [[LLM: ollama train model sendiri]]&lt;br /&gt;
* https://levelup.gitconnected.com/building-a-million-parameter-llm-from-scratch-using-python-f612398f06c2 '''Generate Model'''&lt;br /&gt;
* [[LLM: ollama PDF RAG]]&lt;br /&gt;
* [[LLM: ollama Indonesia]]&lt;br /&gt;
* [[LLM: Halusinasi Cek]]&lt;br /&gt;
&lt;br /&gt;
==LMStudio==&lt;br /&gt;
&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 NVIDIA Install]]&lt;br /&gt;
* [[LMStudio: Ubuntu 26.04 Install]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==ComfyUI==&lt;br /&gt;
&lt;br /&gt;
* [[ComfyUI: instalasi]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv]]&lt;br /&gt;
* [[ComfyUI: Instalasi venv GPU]]&lt;br /&gt;
* [[ComfyUI: Instalasi via docker compose]]&lt;br /&gt;
&lt;br /&gt;
==Nvidia==&lt;br /&gt;
&lt;br /&gt;
* [[nvidia: ubuntu 24.04]]&lt;br /&gt;
&lt;br /&gt;
==GPT4All==&lt;br /&gt;
&lt;br /&gt;
* https://www.linkedin.com/pulse/more-let-me-check-internal-knowledge-instant-answers-makes-dhani-b4yvc/?trackingId=sgChWaTfS8KsTx06aU6KSw%3D%3D&lt;br /&gt;
* https://linuxconfig.org/how-to-install-gpt4all-on-ubuntu-debian-linux&lt;br /&gt;
* [[GPT4All: vs llama.cpp]]&lt;br /&gt;
* [[GPT4All: Install]]&lt;br /&gt;
* [[GPT4All: Install CLI]]&lt;br /&gt;
* [[GPT4All: Install CLI + open-webui]]&lt;br /&gt;
* [[GPT4All: Pilihan Model Bahasa Indonesia]]&lt;br /&gt;
&lt;br /&gt;
==Ollama Create==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: ollama create Modelfile]]&lt;br /&gt;
* [[LLM: create model tanpa huggingface]]&lt;br /&gt;
* [[LLM: create model script]]&lt;br /&gt;
&lt;br /&gt;
==Open-WebUI==&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Open-WebUI sebaiknya di jalankan di ubuntu 22.04, karena versi python di 24.04 terlalu tinggi.&lt;br /&gt;
* https://www.leadergpu.com/catalog/584-open-webui-all-in-one&lt;br /&gt;
&lt;br /&gt;
* [[OpenWebUI: python knowledge PDF CLI API upload]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===RAG===&lt;br /&gt;
&lt;br /&gt;
* https://docs.openwebui.com/features/rag&lt;br /&gt;
* https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* [[LLM: multiple open-webui]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan vector database]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql]]&lt;br /&gt;
* [[LLM: RAG ollama menggunakan open-webui dan postgresql docker]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan chroma]]&lt;br /&gt;
* [[LLM: RAG ollama dengan open-webui dan qdrant]]&lt;br /&gt;
* [[LLM: Perbanding Berbagai Vector Database]]&lt;br /&gt;
* [[LLM: RAG menggunakan open-webui ollama]]&lt;br /&gt;
* [[LLM: RAG coba]]&lt;br /&gt;
* [[LLM: RAG contoh]]&lt;br /&gt;
* [[LLM: RAG Thomas Jay]]&lt;br /&gt;
* [[LLM: RAG-streamlit-llamaindex-ollama]]&lt;br /&gt;
* [[LLM: RAG-GPT]] '''tidak untuk ubuntu 24.04''''&lt;br /&gt;
* [[LLM: RAG open source no API di google collab]]&lt;br /&gt;
* [[LLM: RAG open source no API no Huggingface di google collab]]&lt;br /&gt;
* [[LLM: open-webui browse URL]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* https://lightning.ai/maxidiazbattan/studios/rag-streamlit-llamaindex-ollama&lt;br /&gt;
* https://medium.com/@pankaj_pandey/unleash-the-power-of-rag-in-python-a-simple-guide-6f59590a82c3&lt;br /&gt;
* https://hackernoon.com/simple-wonders-of-rag-using-ollama-langchain-and-chromadb&lt;br /&gt;
* https://github.com/ThomasJay/RAG&lt;br /&gt;
* https://medium.com/@vndee.huynh/build-your-own-rag-and-run-it-locally-langchain-ollama-streamlit-181d42805895&lt;br /&gt;
* https://medium.com/rahasak/build-rag-application-using-a-llm-running-on-local-computer-with-ollama-and-llamaindex-97703153db20 &lt;br /&gt;
* https://github.com/Isa1asN/local-rag&lt;br /&gt;
* https://github.com/AllAboutAI-YT/easy-local-rag&lt;br /&gt;
* * https://weaviate.io/blog/local-rag-with-ollama-and-weaviate&lt;br /&gt;
* https://dnsmichi.at/2024/01/10/local-ollama-running-mixtral-llm-llama-index-own-tweet-context/&lt;br /&gt;
* https://www.elastic.co/search-labs/blog/elasticsearch-rag-with-llama3-opensource-and-elastic&lt;br /&gt;
* https://github.com/infiniflow/ragflow?tab=readme-ov-file&lt;br /&gt;
&lt;br /&gt;
===RAG Youtube===&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=Ylz779Op9Pw - How to Improve LLMs with RAG (Overview + Python Code)&lt;br /&gt;
* https://www.youtube.com/watch?v=daZOrbMs61I - Gemma 2 - Local RAG with Ollama and LangChain&lt;br /&gt;
* https://www.youtube.com/watch?v=2TJxpyO3ei4 - Python RAG Tutorial (with Local LLMs): AI For Your PDFs&lt;br /&gt;
* https://www.youtube.com/watch?v=7VAs22LC7WE - Llama3 Full Rag - API with Ollama, LangChain and ChromaDB with Flask API and PDF upload&lt;br /&gt;
* https://github.com/elastic/elasticsearch-labs/tree/main/notebooks/integrations/llama3&lt;br /&gt;
&lt;br /&gt;
==Pentest==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Ollama Pentest]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==NER==&lt;br /&gt;
&lt;br /&gt;
* [[NER: Konsep]]&lt;br /&gt;
* [[NER: Scan JPG NER JSON]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Fine Tuning Model==&lt;br /&gt;
&lt;br /&gt;
* [[LLM: Extract .jsonl dari file pdf]]&lt;br /&gt;
* [[LLM: Fine Tuning]]&lt;br /&gt;
* [[LLM: Fine Tuning Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:1b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama gemma3:270m]]&lt;br /&gt;
* [[LLM: Fine Tine Ollama deepseek-r1:1.5b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:0.6b]]&lt;br /&gt;
* [[LLM: Fine Tune Ollama qwen3:1.7b]]&lt;br /&gt;
* [[LLM: Lora]]&lt;br /&gt;
* [[LLM: Lora vs Fine Tuning]]&lt;br /&gt;
* [[LLM: Lora tidak bisa dijalankan di ollama]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Internet_OFFLINE:_Ubuntu_26.04_install_asterisk&amp;diff=73700</id>
		<title>Internet OFFLINE: Ubuntu 26.04 install asterisk</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Internet_OFFLINE:_Ubuntu_26.04_install_asterisk&amp;diff=73700"/>
		<updated>2026-07-20T02:41:55Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;# Instalasi Asterisk Ubuntu Server 26.04  ## Extension SIP 1000–1100  Panduan berikut mengadaptasi pendekatan buku *VoIP Desa Menggunakan Asterisk*: instalasi melalui APT, p...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Instalasi Asterisk Ubuntu Server 26.04&lt;br /&gt;
&lt;br /&gt;
## Extension SIP 1000–1100&lt;br /&gt;
&lt;br /&gt;
Panduan berikut mengadaptasi pendekatan buku *VoIP Desa Menggunakan Asterisk*: instalasi melalui APT, penggunaan PJSIP, dialplan lokal, firewall, pengujian, dan dokumentasi akun. Buku menggunakan struktur satu akun PJSIP yang terdiri atas **endpoint, authentication, dan AOR**, serta menyarankan server memakai alamat IP statis. &lt;br /&gt;
&lt;br /&gt;
Ubuntu 26.04 LTS menyediakan paket **Asterisk 22.5.2** melalui komponen `universe`, sehingga tidak perlu melakukan kompilasi dari source code. ([Ubuntu Packages][1])&lt;br /&gt;
&lt;br /&gt;
Hasil akhir:&lt;br /&gt;
&lt;br /&gt;
* Asterisk aktif otomatis saat server hidup.&lt;br /&gt;
* SIP menggunakan PJSIP dan UDP port 5060.&lt;br /&gt;
* RTP menggunakan UDP port 10000–20000.&lt;br /&gt;
* Tersedia **101 akun**, dari 1000 sampai 1100.&lt;br /&gt;
* Setiap extension memiliki password acak berbeda.&lt;br /&gt;
* Semua extension dapat saling menelepon.&lt;br /&gt;
* Daftar username dan password tersimpan dalam CSV yang hanya dapat dibaca root.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 1. Siapkan informasi jaringan&lt;br /&gt;
&lt;br /&gt;
Contoh yang digunakan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Hostname server : asterisk-desa&lt;br /&gt;
IP server       : 192.168.10.10&lt;br /&gt;
Gateway         : 192.168.10.1&lt;br /&gt;
Jaringan LAN    : 192.168.10.0/24&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Sesuaikan dengan jaringan yang sebenarnya.&lt;br /&gt;
&lt;br /&gt;
Periksa jaringan server:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ip -br addr&lt;br /&gt;
ip route&lt;br /&gt;
hostnamectl&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Atur hostname:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo hostnamectl set-hostname asterisk-desa&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Tambahkan hostname ke `/etc/hosts`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo nano /etc/hosts&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan terdapat baris:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
127.0.1.1 asterisk-desa&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Server Asterisk sebaiknya menggunakan **IP statis** atau DHCP reservation agar alamat server tidak berubah.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 2. Perbarui Ubuntu Server&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt update&lt;br /&gt;
sudo apt full-upgrade -y&lt;br /&gt;
sudo reboot&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah server hidup kembali, masuk melalui SSH:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
ssh namauser@192.168.10.10&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa versi Ubuntu:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
lsb_release -a&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
atau:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
cat /etc/os-release&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 3. Instal Asterisk dan perangkat bantu&lt;br /&gt;
&lt;br /&gt;
Aktifkan repository `universe`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo add-apt-repository universe&lt;br /&gt;
sudo apt update&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Instal Asterisk:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo apt install -y \&lt;br /&gt;
    asterisk \&lt;br /&gt;
    asterisk-core-sounds-en \&lt;br /&gt;
    ufw \&lt;br /&gt;
    fail2ban \&lt;br /&gt;
    sngrep \&lt;br /&gt;
    tcpdump \&lt;br /&gt;
    openssl&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
APT merupakan mekanisme resmi Ubuntu untuk memasang dan memelihara paket perangkat lunak. ([Ubuntu][2])&lt;br /&gt;
&lt;br /&gt;
Aktifkan layanan Asterisk:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl enable --now asterisk&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa status:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl status asterisk --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa versi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;core show version&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa modul PJSIP:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;module show like pjsip&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
PJSIP menghubungkan sebuah endpoint dengan objek autentikasi dan AOR; endpoint harus memiliki AOR agar Asterisk mengetahui kontak tujuan panggilan. ([Asterisk Documentation][3])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 4. Backup konfigurasi bawaan&lt;br /&gt;
&lt;br /&gt;
Jangan langsung menghapus konfigurasi asli.&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
BACKUP_DIR=&amp;quot;/root/asterisk-config-$(date +%Y%m%d-%H%M%S)&amp;quot;&lt;br /&gt;
sudo mkdir -p &amp;quot;$BACKUP_DIR&amp;quot;&lt;br /&gt;
sudo cp -a /etc/asterisk/. &amp;quot;$BACKUP_DIR/&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa hasil backup:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ls -lah &amp;quot;$BACKUP_DIR&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 5. Membuat konfigurasi utama PJSIP&lt;br /&gt;
&lt;br /&gt;
Buat ulang `/etc/asterisk/pjsip.conf`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /etc/asterisk/pjsip.conf &amp;gt;/dev/null &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
;==========================================================&lt;br /&gt;
; Konfigurasi PJSIP Asterisk Desa&lt;br /&gt;
; Ubuntu Server 26.04&lt;br /&gt;
; Extension 1000-1100&lt;br /&gt;
;==========================================================&lt;br /&gt;
&lt;br /&gt;
[global]&lt;br /&gt;
type=global&lt;br /&gt;
user_agent=Asterisk-Desa&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Transport SIP&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[transport-udp]&lt;br /&gt;
type=transport&lt;br /&gt;
protocol=udp&lt;br /&gt;
bind=0.0.0.0:5060&lt;br /&gt;
&lt;br /&gt;
; Apabila seluruh perangkat hanya berada di LAN,&lt;br /&gt;
; external_media_address dan external_signaling_address&lt;br /&gt;
; tidak diperlukan.&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Template endpoint&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[endpoint-template](!)&lt;br /&gt;
type=endpoint&lt;br /&gt;
transport=transport-udp&lt;br /&gt;
context=internal&lt;br /&gt;
disallow=all&lt;br /&gt;
allow=ulaw&lt;br /&gt;
allow=alaw&lt;br /&gt;
&lt;br /&gt;
; DTMF untuk IVR dan layanan berbasis tombol telepon&lt;br /&gt;
dtmf_mode=rfc4733&lt;br /&gt;
&lt;br /&gt;
; Pengaturan yang membantu client Wi-Fi/NAT&lt;br /&gt;
direct_media=no&lt;br /&gt;
rtp_symmetric=yes&lt;br /&gt;
force_rport=yes&lt;br /&gt;
rewrite_contact=yes&lt;br /&gt;
&lt;br /&gt;
; Jangan izinkan pemanggilan tanpa autentikasi&lt;br /&gt;
allow_subscribe=yes&lt;br /&gt;
language=en&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Template autentikasi&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[auth-template](!)&lt;br /&gt;
type=auth&lt;br /&gt;
auth_type=userpass&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Template Address of Record&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[aor-template](!)&lt;br /&gt;
type=aor&lt;br /&gt;
&lt;br /&gt;
; Satu extension hanya boleh dipakai satu perangkat&lt;br /&gt;
max_contacts=1&lt;br /&gt;
&lt;br /&gt;
; Hapus registrasi lama bila perangkat berganti alamat&lt;br /&gt;
remove_existing=yes&lt;br /&gt;
&lt;br /&gt;
; Pemeriksaan berkala perangkat&lt;br /&gt;
qualify_frequency=60&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Akun extension dibuat otomatis di file berikut&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
#include &amp;quot;pjsip-extensions.conf&amp;quot;&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi sengaja menggunakan template agar 101 extension tidak harus memiliki seluruh parameter yang ditulis berulang kali.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 6. Membuat extension 1000–1100 otomatis&lt;br /&gt;
&lt;br /&gt;
Buat skrip generator:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /usr/local/sbin/generate-asterisk-extensions.sh &amp;gt;/dev/null &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
#!/usr/bin/env bash&lt;br /&gt;
&lt;br /&gt;
set -euo pipefail&lt;br /&gt;
&lt;br /&gt;
CONFIG_FILE=&amp;quot;/etc/asterisk/pjsip-extensions.conf&amp;quot;&lt;br /&gt;
PASSWORD_FILE=&amp;quot;/root/asterisk-extension-passwords.csv&amp;quot;&lt;br /&gt;
TEMP_CONFIG=&amp;quot;$(mktemp)&amp;quot;&lt;br /&gt;
TEMP_PASSWORD=&amp;quot;$(mktemp)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
cleanup() {&lt;br /&gt;
    rm -f &amp;quot;$TEMP_CONFIG&amp;quot; &amp;quot;$TEMP_PASSWORD&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
trap cleanup EXIT&lt;br /&gt;
&lt;br /&gt;
cat &amp;gt; &amp;quot;$TEMP_CONFIG&amp;quot; &amp;lt;&amp;lt;'HEADER'&lt;br /&gt;
;==========================================================&lt;br /&gt;
; Dibuat otomatis oleh generate-asterisk-extensions.sh&lt;br /&gt;
; Jangan menyimpan file password ke repository publik.&lt;br /&gt;
;==========================================================&lt;br /&gt;
&lt;br /&gt;
HEADER&lt;br /&gt;
&lt;br /&gt;
printf '%s\n' '&amp;quot;extension&amp;quot;,&amp;quot;username&amp;quot;,&amp;quot;password&amp;quot;,&amp;quot;server&amp;quot;,&amp;quot;transport&amp;quot;' \&lt;br /&gt;
    &amp;gt; &amp;quot;$TEMP_PASSWORD&amp;quot;&lt;br /&gt;
&lt;br /&gt;
SERVER_IP=&amp;quot;$(hostname -I | awk '{print $1}')&amp;quot;&lt;br /&gt;
&lt;br /&gt;
if [[ -z &amp;quot;$SERVER_IP&amp;quot; ]]; then&lt;br /&gt;
    SERVER_IP=&amp;quot;GANTI_DENGAN_IP_SERVER&amp;quot;&lt;br /&gt;
fi&lt;br /&gt;
&lt;br /&gt;
for EXTENSION in $(seq 1000 1100); do&lt;br /&gt;
    PASSWORD=&amp;quot;$(openssl rand -hex 16)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
    cat &amp;gt;&amp;gt; &amp;quot;$TEMP_CONFIG&amp;quot; &amp;lt;&amp;lt;EOF_CONFIG&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Extension ${EXTENSION}&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[${EXTENSION}](endpoint-template)&lt;br /&gt;
auth=auth-${EXTENSION}&lt;br /&gt;
aors=aor-${EXTENSION}&lt;br /&gt;
callerid=&amp;quot;Extension ${EXTENSION}&amp;quot; &amp;lt;${EXTENSION}&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[auth-${EXTENSION}](auth-template)&lt;br /&gt;
username=${EXTENSION}&lt;br /&gt;
password=${PASSWORD}&lt;br /&gt;
&lt;br /&gt;
[aor-${EXTENSION}](aor-template)&lt;br /&gt;
&lt;br /&gt;
EOF_CONFIG&lt;br /&gt;
&lt;br /&gt;
    printf '&amp;quot;%s&amp;quot;,&amp;quot;%s&amp;quot;,&amp;quot;%s&amp;quot;,&amp;quot;%s&amp;quot;,&amp;quot;UDP&amp;quot;\n' \&lt;br /&gt;
        &amp;quot;$EXTENSION&amp;quot; \&lt;br /&gt;
        &amp;quot;$EXTENSION&amp;quot; \&lt;br /&gt;
        &amp;quot;$PASSWORD&amp;quot; \&lt;br /&gt;
        &amp;quot;$SERVER_IP&amp;quot; &amp;gt;&amp;gt; &amp;quot;$TEMP_PASSWORD&amp;quot;&lt;br /&gt;
done&lt;br /&gt;
&lt;br /&gt;
install -o root -g asterisk -m 0640 \&lt;br /&gt;
    &amp;quot;$TEMP_CONFIG&amp;quot; &amp;quot;$CONFIG_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
install -o root -g root -m 0600 \&lt;br /&gt;
    &amp;quot;$TEMP_PASSWORD&amp;quot; &amp;quot;$PASSWORD_FILE&amp;quot;&lt;br /&gt;
&lt;br /&gt;
echo &amp;quot;Berhasil membuat extension 1000 sampai 1100.&amp;quot;&lt;br /&gt;
echo &amp;quot;Konfigurasi : $CONFIG_FILE&amp;quot;&lt;br /&gt;
echo &amp;quot;Password    : $PASSWORD_FILE&amp;quot;&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jadikan executable:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chmod 750 /usr/local/sbin/generate-asterisk-extensions.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo /usr/local/sbin/generate-asterisk-extensions.sh&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa jumlah extension:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo grep -Ec '^\[[0-9]{4}\]\(endpoint-template\)$' \&lt;br /&gt;
    /etc/asterisk/pjsip-extensions.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Output seharusnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
101&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa beberapa konfigurasi awal:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo sed -n '1,80p' /etc/asterisk/pjsip-extensions.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Lihat daftar akun:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo column -s, -t &amp;lt; /root/asterisk-extension-passwords.csv | head&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan membagikan seluruh file CSV secara terbuka karena berisi password semua pengguna.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 7. Membuat dialplan panggilan&lt;br /&gt;
&lt;br /&gt;
Buat `/etc/asterisk/extensions.conf`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /etc/asterisk/extensions.conf &amp;gt;/dev/null &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
;==========================================================&lt;br /&gt;
; Dialplan Asterisk Desa&lt;br /&gt;
; Extension yang diizinkan: 1000-1100&lt;br /&gt;
;==========================================================&lt;br /&gt;
&lt;br /&gt;
[general]&lt;br /&gt;
static=yes&lt;br /&gt;
writeprotect=no&lt;br /&gt;
clearglobalvars=no&lt;br /&gt;
&lt;br /&gt;
[globals]&lt;br /&gt;
RINGTIME=30&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Panggilan internal&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
[internal]&lt;br /&gt;
&lt;br /&gt;
; Extension 1000 sampai 1099&lt;br /&gt;
exten =&amp;gt; _10XX,1,NoOp(Panggilan internal ${CALLERID(num)} ke ${EXTEN})&lt;br /&gt;
 same =&amp;gt; n,Dial(PJSIP/${EXTEN},${RINGTIME})&lt;br /&gt;
 same =&amp;gt; n,Hangup()&lt;br /&gt;
&lt;br /&gt;
; Extension 1100&lt;br /&gt;
exten =&amp;gt; 1100,1,NoOp(Panggilan internal ${CALLERID(num)} ke 1100)&lt;br /&gt;
 same =&amp;gt; n,Dial(PJSIP/1100,${RINGTIME})&lt;br /&gt;
 same =&amp;gt; n,Hangup()&lt;br /&gt;
&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
; Nomor pengujian&lt;br /&gt;
;----------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
; 600 - Echo test&lt;br /&gt;
exten =&amp;gt; 600,1,Answer()&lt;br /&gt;
 same =&amp;gt; n,Wait(1)&lt;br /&gt;
 same =&amp;gt; n,Echo()&lt;br /&gt;
 same =&amp;gt; n,Hangup()&lt;br /&gt;
&lt;br /&gt;
; 601 - Menyebutkan nomor extension pemanggil&lt;br /&gt;
exten =&amp;gt; 601,1,Answer()&lt;br /&gt;
 same =&amp;gt; n,Playback(your)&lt;br /&gt;
 same =&amp;gt; n,Playback(extension)&lt;br /&gt;
 same =&amp;gt; n,SayDigits(${CALLERID(num)})&lt;br /&gt;
 same =&amp;gt; n,Hangup()&lt;br /&gt;
&lt;br /&gt;
; Nomor tidak dikenal&lt;br /&gt;
exten =&amp;gt; i,1,Playback(invalid)&lt;br /&gt;
 same =&amp;gt; n,Hangup()&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dialplan `_10XX` hanya menerima nomor 1000–1099, sementara 1100 dibuat secara eksplisit. Dengan demikian, nomor 1101 dan seterusnya tidak dapat dipanggil.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 8. Memastikan rentang RTP&lt;br /&gt;
&lt;br /&gt;
Periksa konfigurasi RTP:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo grep -Ev '^[[:space:]]*(;|$)' /etc/asterisk/rtp.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bila belum jelas, buat konfigurasi berikut:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tee /etc/asterisk/rtp.conf &amp;gt;/dev/null &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
[general]&lt;br /&gt;
rtpstart=10000&lt;br /&gt;
rtpend=20000&lt;br /&gt;
strictrtp=yes&lt;br /&gt;
icesupport=yes&lt;br /&gt;
EOF&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
SIP dipakai untuk mengatur sesi dan registrasi, sedangkan suara dikirim melalui RTP. Konsep ini juga menjadi dasar konfigurasi pada buku. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 9. Atur kepemilikan dan permission&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chown root:asterisk \&lt;br /&gt;
    /etc/asterisk/pjsip.conf \&lt;br /&gt;
    /etc/asterisk/pjsip-extensions.conf \&lt;br /&gt;
    /etc/asterisk/extensions.conf \&lt;br /&gt;
    /etc/asterisk/rtp.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chmod 640 \&lt;br /&gt;
    /etc/asterisk/pjsip.conf \&lt;br /&gt;
    /etc/asterisk/pjsip-extensions.conf \&lt;br /&gt;
    /etc/asterisk/extensions.conf \&lt;br /&gt;
    /etc/asterisk/rtp.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan file password hanya dapat dibaca root:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo chmod 600 /root/asterisk-extension-passwords.csv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 10. Validasi lalu restart Asterisk&lt;br /&gt;
&lt;br /&gt;
Restart:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl restart asterisk&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa layanan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl status asterisk --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa log jika gagal:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo journalctl -u asterisk -n 100 --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Masuk CLI:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rvvv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Di dalam CLI, jalankan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
core show version&lt;br /&gt;
pjsip show transports&lt;br /&gt;
pjsip show endpoints&lt;br /&gt;
dialplan show internal&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Keluar:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
exit&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa jumlah endpoint dari shell:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show endpoints&amp;quot; |&lt;br /&gt;
    grep -E 'Endpoint: +[0-9]{4}/' |&lt;br /&gt;
    wc -l&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Targetnya:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
101&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 11. Konfigurasi firewall&lt;br /&gt;
&lt;br /&gt;
Ubuntu menggunakan `ufw` sebagai perangkat firewall host yang mudah dikelola. ([Ubuntu][4])&lt;br /&gt;
&lt;br /&gt;
**Sangat penting:** izinkan SSH sebelum mengaktifkan firewall agar koneksi administrator tidak terputus.&lt;br /&gt;
&lt;br /&gt;
Contoh untuk LAN `192.168.10.0/24`:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw default deny incoming&lt;br /&gt;
sudo ufw default allow outgoing&lt;br /&gt;
sudo ufw allow OpenSSH&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan SIP hanya dari jaringan LAN:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.10.0/24 to any port 5060 proto udp \&lt;br /&gt;
    comment 'Asterisk SIP dari LAN'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Izinkan RTP hanya dari LAN:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw allow from 192.168.10.0/24 to any port 10000:20000 proto udp \&lt;br /&gt;
    comment 'Asterisk RTP dari LAN'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aktifkan firewall:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw enable&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw status numbered&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jangan membuka UDP 5060 dan 10000–20000 ke seluruh Internet kecuali benar-benar diperlukan. Untuk akses antarlokasi, pendekatan yang lebih aman adalah membawa SIP dan RTP melalui VPN seperti WireGuard. Buku juga merekomendasikan komunikasi antar-Asterisk melalui WireGuard daripada mengekspos SIP langsung ke Internet. &lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 12. Registrasi Linphone&lt;br /&gt;
&lt;br /&gt;
Ambil satu akun uji:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo grep '^&amp;quot;1000&amp;quot;' /root/asterisk-extension-passwords.csv&lt;br /&gt;
sudo grep '^&amp;quot;1001&amp;quot;' /root/asterisk-extension-passwords.csv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Contoh pengaturan perangkat pertama:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Display name : Extension 1000&lt;br /&gt;
Username     : 1000&lt;br /&gt;
Password     : password dari CSV&lt;br /&gt;
Domain       : 192.168.10.10&lt;br /&gt;
SIP server   : sip:192.168.10.10&lt;br /&gt;
Transport    : UDP&lt;br /&gt;
Port         : 5060&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Perangkat kedua:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Display name : Extension 1001&lt;br /&gt;
Username     : 1001&lt;br /&gt;
Password     : password dari CSV&lt;br /&gt;
Domain       : 192.168.10.10&lt;br /&gt;
Transport    : UDP&lt;br /&gt;
Port         : 5060&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pada beberapa versi Linphone, identitas SIP ditulis:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
sip:1000@192.168.10.10&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Proxy/server:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
sip:192.168.10.10;transport=udp&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan smartphone dan server berada dalam jaringan yang dapat saling menjangkau.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 13. Pengujian&lt;br /&gt;
&lt;br /&gt;
### Periksa registrasi&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show contacts&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
atau:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show endpoint 1000&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Endpoint belum terdaftar biasanya terlihat:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Unavailable&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Setelah registrasi berhasil, akan muncul alamat kontak perangkat.&lt;br /&gt;
&lt;br /&gt;
### Uji panggilan&lt;br /&gt;
&lt;br /&gt;
Lakukan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
1000 → 1001&lt;br /&gt;
1001 → 1000&lt;br /&gt;
1000 → 1100&lt;br /&gt;
1100 → 1000&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Uji juga nomor yang tidak tersedia:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
1101&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Panggilan ke 1101 seharusnya ditolak karena berada di luar numbering plan.&lt;br /&gt;
&lt;br /&gt;
### Uji suara&lt;br /&gt;
&lt;br /&gt;
Hubungi:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
600&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Bicaralah ke mikrofon. Suara seharusnya dikirim kembali melalui aplikasi `Echo()`.&lt;br /&gt;
&lt;br /&gt;
### Monitor panggilan langsung&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rvvv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kemudian:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
core show channels&lt;br /&gt;
pjsip show contacts&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Aktifkan SIP logger hanya ketika troubleshooting:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
pjsip set logger on&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Matikan kembali setelah selesai:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
pjsip set logger off&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Dokumentasi resmi Asterisk juga menyarankan pemeriksaan hubungan `auth`, endpoint, dan AOR ketika registrasi PJSIP gagal. ([Asterisk Documentation][5])&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 14. Troubleshooting cepat&lt;br /&gt;
&lt;br /&gt;
### Asterisk tidak dapat dijalankan&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo systemctl status asterisk&lt;br /&gt;
sudo journalctl -u asterisk -b --no-pager&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa konfigurasi:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show endpoints&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Client tidak dapat register&lt;br /&gt;
&lt;br /&gt;
Periksa port:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ss -lunp | grep ':5060'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Seharusnya terdapat proses Asterisk yang mendengarkan pada:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
0.0.0.0:5060&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa firewall:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw status verbose&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa log:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tail -f /var/log/asterisk/full&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Jika `/var/log/asterisk/full` belum tersedia, gunakan:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo journalctl -u asterisk -f&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### Username atau password ditolak&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show endpoint 1000&amp;quot;&lt;br /&gt;
sudo grep -A4 '\[auth-1000\]' \&lt;br /&gt;
    /etc/asterisk/pjsip-extensions.conf&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pastikan client menggunakan username **1000**, bukan `auth-1000`.&lt;br /&gt;
&lt;br /&gt;
### Telepon berdering tetapi suara tidak terdengar&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ufw status&lt;br /&gt;
sudo ss -lunp | grep asterisk&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Pantau RTP:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tcpdump -ni any udp portrange 10000-20000&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Penyebab umum:&lt;br /&gt;
&lt;br /&gt;
* Firewall RTP tertutup.&lt;br /&gt;
* Client berada pada jaringan NAT berbeda.&lt;br /&gt;
* Wi-Fi memiliki client isolation.&lt;br /&gt;
* Router memblokir komunikasi antarklien.&lt;br /&gt;
* Alamat server yang dimasukkan salah.&lt;br /&gt;
&lt;br /&gt;
### Melihat paket SIP dengan sngrep&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo sngrep&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Gunakan tombol:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Enter : membuka call flow&lt;br /&gt;
F10   : keluar&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 15. Backup setelah konfigurasi berhasil&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo tar \&lt;br /&gt;
    --create \&lt;br /&gt;
    --gzip \&lt;br /&gt;
    --preserve-permissions \&lt;br /&gt;
    --file=&amp;quot;/root/asterisk-ready-$(date +%Y%m%d-%H%M%S).tar.gz&amp;quot; \&lt;br /&gt;
    /etc/asterisk \&lt;br /&gt;
    /root/asterisk-extension-passwords.csv&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Periksa:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
sudo ls -lh /root/asterisk-ready-*.tar.gz&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Backup tersebut mengandung seluruh password extension. Simpan secara terenkripsi dan jangan diletakkan di web server atau repository Git publik.&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## 16. Checklist hasil akhir&lt;br /&gt;
&lt;br /&gt;
Jalankan seluruh pemeriksaan berikut:&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
systemctl is-enabled asterisk&lt;br /&gt;
systemctl is-active asterisk&lt;br /&gt;
sudo asterisk -rx &amp;quot;core show version&amp;quot;&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show transports&amp;quot;&lt;br /&gt;
sudo asterisk -rx &amp;quot;pjsip show endpoints&amp;quot;&lt;br /&gt;
sudo asterisk -rx &amp;quot;dialplan show internal&amp;quot;&lt;br /&gt;
sudo ufw status&lt;br /&gt;
sudo ss -lunp | grep -E ':5060|asterisk'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Kondisi yang diharapkan:&lt;br /&gt;
&lt;br /&gt;
```text&lt;br /&gt;
Asterisk service       : active&lt;br /&gt;
Start saat boot        : enabled&lt;br /&gt;
Transport SIP          : UDP 0.0.0.0:5060&lt;br /&gt;
Jumlah extension       : 101&lt;br /&gt;
Nomor pertama          : 1000&lt;br /&gt;
Nomor terakhir         : 1100&lt;br /&gt;
Dialplan               : internal&lt;br /&gt;
RTP                    : UDP 10000-20000&lt;br /&gt;
Password akun          : berbeda untuk setiap extension&lt;br /&gt;
Firewall               : hanya membuka SIP/RTP dari LAN&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
Konfigurasi ini sudah cukup untuk **telepon internal 1000–1100**. Layanan lanjutan seperti voicemail, ring group, IVR, ConfBridge, paging, queue, SIP trunk, dan WireGuard dapat ditambahkan setelah registrasi serta panggilan dasar stabil.&lt;br /&gt;
&lt;br /&gt;
[1]: https://packages.ubuntu.com/resolute/asterisk?utm_source=chatgpt.com &amp;quot;Details of package asterisk in resolute&amp;quot;&lt;br /&gt;
[2]: https://ubuntu.com/server/docs/how-to/software/package-management/?utm_source=chatgpt.com &amp;quot;Install and manage packages - Ubuntu Server documentation&amp;quot;&lt;br /&gt;
[3]: https://docs.asterisk.org/Configuration/Channel-Drivers/SIP/Configuring-res_pjsip/PJSIP-Configuration-Sections-and-Relationships/?utm_source=chatgpt.com &amp;quot;PJSIP Configuration Sections and Relationships&amp;quot;&lt;br /&gt;
[4]: https://ubuntu.com/server/docs/how-to/security/firewalls/?utm_source=chatgpt.com &amp;quot;Firewall - Ubuntu Server documentation&amp;quot;&lt;br /&gt;
[5]: https://docs.asterisk.org/Configuration/Channel-Drivers/SIP/Configuring-res_pjsip/Asterisk-PJSIP-Troubleshooting-Guide/?utm_source=chatgpt.com &amp;quot;Asterisk PJSIP Troubleshooting Guide&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Internet_offline&amp;diff=73699</id>
		<title>Internet offline</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Internet_offline&amp;diff=73699"/>
		<updated>2026-07-20T02:41:21Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Ubuntu 24.04 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Internet-offline.jpg|center|300px|thumb]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Internet OFFLINE: Harddisk Siap Pakai untuk Sekolah]]&lt;br /&gt;
* [[Internet OFFLINE: Harddisk Siap Pakai PETUNJUK PEMAKAIAN]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Youtube==&lt;br /&gt;
&lt;br /&gt;
* https://www.youtube.com/watch?v=cKuiRIQMZFE - Penjelasan tentang Internet Offline&lt;br /&gt;
* https://www.youtube.com/watch?v=VmtyRu6RGjM - Konfigurasi Jaringan Untuk Experimen&lt;br /&gt;
* https://www.youtube.com/watch?v=k0kx4MHrqLE - Membeli RaspberryPi atau OrangePi&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[Internet OFFLINE: Mengapa butuh Internet OFFLINE?]]&lt;br /&gt;
* [[Internet OFFLINE: Konsep]]&lt;br /&gt;
* [[Internet OFFLINE: Overview Teknologi Secara Umum]]&lt;br /&gt;
* [[Internet OFFLINE: Manajemen Operasi Internet OFFLINE]]&lt;br /&gt;
&lt;br /&gt;
==eLearning==&lt;br /&gt;
&lt;br /&gt;
* [[MoodleBox]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==RaspberryPi==&lt;br /&gt;
&lt;br /&gt;
* [[Raspbian: Burn ke MicroSD]]&lt;br /&gt;
* [[Raspbian: Internet Offline Topologi Jaringan]]&lt;br /&gt;
* [[Raspbian: cek IP address server raspberry]]&lt;br /&gt;
* [[Raspbian: login pi password raspberry]]&lt;br /&gt;
* [[Raspbian: edit rc.local]]&lt;br /&gt;
* [[Raspbian: Setup Network]]&lt;br /&gt;
* [[Raspbian: RPi3 Stand Alone Access Point]]&lt;br /&gt;
* [[Raspbian: NAT hostap ke eth0]]&lt;br /&gt;
&lt;br /&gt;
==OrangePi==&lt;br /&gt;
&lt;br /&gt;
* [[OrangePi: Burn img]]&lt;br /&gt;
* [[OrangePi: Burn Raspbian img]] '''RECOMMENDED'''&lt;br /&gt;
* [[OrangePi: Burn Ubuntu img]]&lt;br /&gt;
* [[OrangePi: Burn Debian img]]&lt;br /&gt;
* [[OrangePi: cek IP address server OrangePi]]&lt;br /&gt;
* [[OrangePi: install ssh server]]&lt;br /&gt;
* [[OrangePi: Remove Desktop &amp;amp; GUI]]&lt;br /&gt;
&lt;br /&gt;
==Server Apps==&lt;br /&gt;
&lt;br /&gt;
* [[Raspbian: install ssh server]]&lt;br /&gt;
* [[Raspbian: install web server]]&lt;br /&gt;
* [[Raspbian: Aktifkan https di apache]]&lt;br /&gt;
* [[Raspbian: install DNS server]]&lt;br /&gt;
* [[Raspbian: Konfigurasi DNS Server]]&lt;br /&gt;
* [[Raspbian: install samba file sharing server]]&lt;br /&gt;
* [[Raspbian: install DHCP server]] ''-- jangan pakai ini; pakai dnsmasq''&lt;br /&gt;
* [[Raspbian: install systemd systemctl]]&lt;br /&gt;
&lt;br /&gt;
* [[X86: repo update]]&lt;br /&gt;
* [[X86: install ssh server]]&lt;br /&gt;
* [[X86: install web server]]&lt;br /&gt;
* [[X86: install samba file sharing server]]&lt;br /&gt;
* [[X86: Perpustakaan Digital Server Internet OFFLINE]]&lt;br /&gt;
&lt;br /&gt;
===Web===&lt;br /&gt;
&lt;br /&gt;
* [[wget: offline web mirror]]&lt;br /&gt;
* [[Kiwix: Download &amp;amp; Instal]]&lt;br /&gt;
* [[Kiwix: X86 Download &amp;amp; Instal]]&lt;br /&gt;
* [[Apache: Virtual Host - lagi]]&lt;br /&gt;
* [[MoodleBox]]&lt;br /&gt;
* [[MoodleBox: Download dan dd]]&lt;br /&gt;
* [[MoodleBox: Admin Login]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==USB FlashDisk==&lt;br /&gt;
&lt;br /&gt;
===Debian 12.0 64 bit===&lt;br /&gt;
&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Install OS Server]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 edit sources.list]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 tambahkan user offline password 123456]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 install sudoer]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 install net-tools]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Install Moodle, Apache2, MariaDB, PHP 8]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Moodle admin Admin123!@#]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Moodle upload Bank Soal]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Install KIWIX]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 buat /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 setup /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Debian 12.0 Perpustakaan Lokal]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Debian 11.7 32bit===&lt;br /&gt;
&lt;br /&gt;
'''NOT RECOMMENDED:''' Moodle hanya mau dengan PHP 64 bit.&lt;br /&gt;
&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Install OS Server]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 edit sources.list]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 tambahkan user offline password 123456]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 install sudoer]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 install net-tools]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Install Moodle, Apache2, MariaDB, PHP 8]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Moodle admin Admin123!@#]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Moodle upload Bank Soal]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Install KIWIX]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 buat /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 setup /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Debian 11.7 Perpustakaan Lokal]]&lt;br /&gt;
&lt;br /&gt;
===Ubuntu 22.04===&lt;br /&gt;
&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Install OS Server]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 edit sources.list]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 tambahkan user offline password 123456]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 install sudoer]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 install net-tools]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Install Moodle, Apache2, MariaDB, PHP 8]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Moodle admin Admin123!@#]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Moodle upload Bank Soal]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Install KIWIX]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 setup /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 Perpustakaan Lokal]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 22.04 SLiMS]]&lt;br /&gt;
* [[USB OFFLINE: Password dll]]&lt;br /&gt;
* [[USB OFFLINE: Site Copy]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Ubuntu 24.04===&lt;br /&gt;
&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 tambahkan user offline password 123456]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 install sudoer]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 install net-tools]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Install Moodle, Apache2, MariaDB, PHP 8]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Moodle config]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Moodle admin Admin123!@#]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Moodle update course]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Moodle Backup]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 LLM Ollama Open-WebUI]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 mediawiki OnnoCenterWiki copy]]&lt;br /&gt;
&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Install KIWIX]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 setup /etc/rc.local]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 SLiMS]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 BIND]]&lt;br /&gt;
* [[USB OFFLINE: Ubuntu 24.04 Webmin]]&lt;br /&gt;
* [[USB OFFLINE: Password dll]]&lt;br /&gt;
&lt;br /&gt;
===Ubuntu 26.04===&lt;br /&gt;
&lt;br /&gt;
* [[Internet OFFLINE: Ubuntu 26.04 install asterisk]]&lt;br /&gt;
&lt;br /&gt;
===SLiMS===&lt;br /&gt;
&lt;br /&gt;
* [[SLiMS: Instalasi]]&lt;br /&gt;
&lt;br /&gt;
==IPv6==&lt;br /&gt;
&lt;br /&gt;
* [[Internet Offline: Setup IPv6]]&lt;br /&gt;
* [[Internet Offline: IPv6 Apache Benchmark]]&lt;br /&gt;
* [[Internet Offline: IPv6 ipref]]&lt;br /&gt;
* [[Internet Offline: IPv6 pps measurement]]&lt;br /&gt;
&lt;br /&gt;
==Internet in a Box==&lt;br /&gt;
&lt;br /&gt;
* [[Internet in a Box]]&lt;br /&gt;
&lt;br /&gt;
==Benchmark==&lt;br /&gt;
&lt;br /&gt;
===Teknik Mengukur===&lt;br /&gt;
&lt;br /&gt;
* [[Internet Offline: packets-per-second benchmark]]&lt;br /&gt;
* [[Internet Offline: Ukur Bandwidth]]&lt;br /&gt;
* [[Dbench: Internet Offline - Rpi 10-100 concurrent]]&lt;br /&gt;
* [[Dbench: Internet Offline - VM 1-4CORE 512-4096M RAM]]&lt;br /&gt;
* [[Internet Offline: UnixBench]]&lt;br /&gt;
* [[Internet Offline: Mengukur kiwix X86]]&lt;br /&gt;
* [[Internet Offline: Mengukur kiwix dengan ab]]&lt;br /&gt;
* [[Internet Offline: Mengukur SQL]]&lt;br /&gt;
* [[Internet Offline: mysqlslap script]]&lt;br /&gt;
&lt;br /&gt;
===Hasil===&lt;br /&gt;
&lt;br /&gt;
* [[Internet Offline: SQL - Rpi]]&lt;br /&gt;
* [[Internet Offline: SQL - Asus minipc]]&lt;br /&gt;
&lt;br /&gt;
===Teknik Pendukung===&lt;br /&gt;
&lt;br /&gt;
* [[Internet Offline: automatic ssh remote login]]&lt;br /&gt;
* [[Internet Offline: Redirect output ke file]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* Purbo OW. Narrowing the digital divide. Digital Indonesia: Connectivity and Divergence. 2017 May 9:75-92.&lt;br /&gt;
* Malandrino F, Chiasserini CF, Kirkpatrick S. Understanding the present and future of cellular networks through crowdsourced traces. In2017 IEEE 18th International Symposium on A World of Wireless, Mobile and Multimedia Networks (WoWMoM) 2017 Jun 12 (pp. 1-9). IEEE.&lt;br /&gt;
* Kaup F, Fischer F, Hausheer D. Measuring and predicting cellular network quality on trains. In2017 International Conference on Networked Systems (NetSys) 2017 Mar 13 (pp. 1-8). IEEE.&lt;br /&gt;
* Asrese AS, Walelgne EA, Bajpai V, Lutu A, Alay Ö, Ott J. Measuring Web Quality of Experience in Cellular Networks. InInternational Conference on Passive and Active Network Measurement 2019 Mar 27 (pp. 18-33). Springer, Cham.&lt;br /&gt;
* Purbo OW. Internet Offline Solution for Rural/Village Schools. In4th FREE &amp;amp; OPEN SOURCE SOFTWARE CONFERENCE (FOSSC’2019-OMAN) 2019 Feb 11.&lt;br /&gt;
* Morton A. Considerations for benchmarking virtual network functions and their infrastructure. 2017.&lt;br /&gt;
* Amalfitano EA, McKnight GJ, inventors; International Business Machines Corp, assignee. Method and system for automated network benchmark performance analysis. United States patent US 5,303,166. 1994 Apr 12.&lt;br /&gt;
* Huang B, Bauer M, Katchabaw M. Hpcbench-a Linux-based network benchmark for high performance networks. In19th International Symposium on High performance Computing Systems and applications (HPCS'05) 2005 May 15 (pp. 65-71). IEEE.&lt;br /&gt;
* Bellows J. Comparing Linux Operating Systems for the Raspberry Pi 2. InThe 16th Winona Computer Science Undergraduate Research Symposium 2016 Apr 27 (Vol. 922, No. 925MB, p. 8).&lt;br /&gt;
* Martin A, Marangozova‐Martin V. Automatic benchmark profiling through advanced workflow‐based trace analysis. Software: Practice and Experience. 2018 Jun;48(6):1195-217.&lt;br /&gt;
* Ahuja SP, Deval N. On the Performance Evaluation of IaaS Cloud Services With System-Level Benchmarks. International Journal of Cloud Applications and Computing (IJCAC). 2018 Jan 1;8(1):80-96.&lt;br /&gt;
* Wu H, Liu F, Lee RB. Cloud Server Benchmarks for Performance Evaluation of New Hardware Architecture. arXiv preprint arXiv:1603.01352. 2016 Mar 4.&lt;br /&gt;
* Almeida R, Madeira H. Evolving from Dependability to Resilience Benchmarks: Issues and Possibilities. In2016 Seventh Latin-American Symposium on Dependable Computing (LADC) 2016 Oct 19 (pp. 127-130). IEEE.&lt;br /&gt;
* Martin A, Marangozova-Martin V. Automatic Benchmark Profiling Through Advanced Trace Analysis. InEuropean Conference on Parallel Processing 2016 Aug 24 (pp. 63-74). Springer, Cham.&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[Internet Offline: Inisiatif Lain di Dunia]]&lt;br /&gt;
* [[PC: Internet Offline]]&lt;br /&gt;
* [[x86: Internet Offline]]&lt;br /&gt;
* [[Internet Offline: Modul Training]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Epub&amp;diff=73698</id>
		<title>Epub</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Epub&amp;diff=73698"/>
		<updated>2026-07-14T18:59:43Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Membuka epub */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;EPUB (short for electronic publication) is a free and open e-book standard by the International Digital Publishing Forum (IDPF). Files have the extension .epub.&lt;br /&gt;
&lt;br /&gt;
EPUB is designed for reflowable content, meaning that an EPUB reader can optimize text for a particular display device. EPUB also supports fixed-layout content. The format is intended as a single format that publishers and conversion houses can use in-house, as well as for distribution and sale. It supersedes the Open eBook standard.&lt;br /&gt;
&lt;br /&gt;
==Membuka epub==&lt;br /&gt;
&lt;br /&gt;
You can use calibre software for viewing .epub documents.&lt;br /&gt;
&lt;br /&gt;
To install calibre from terminal:&lt;br /&gt;
&lt;br /&gt;
 sudo apt-get install calibre&lt;br /&gt;
&lt;br /&gt;
atau&lt;br /&gt;
&lt;br /&gt;
 sudo add-apt-repository ppa:n-muench/calibre&lt;br /&gt;
 sudo apt-get update&lt;br /&gt;
 sudo apt-get install calibre&lt;br /&gt;
&lt;br /&gt;
==Convert epub satu folder==&lt;br /&gt;
&lt;br /&gt;
 for file in ./*.epub&lt;br /&gt;
 do&lt;br /&gt;
     ebook-convert &amp;quot;$file&amp;quot; &amp;quot;${file%.epub}.pdf&amp;quot; \&lt;br /&gt;
         --paper-size a4&lt;br /&gt;
 done&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* http://en.wikipedia.org/wiki/EPUB&lt;br /&gt;
* http://packages.ubuntu.com/search?keywords=calibre&lt;br /&gt;
* http://lukesblog.it/wiki/index.php?title=Main_Page&lt;br /&gt;
* http://iloveubuntu.net/create-high-quality-epub-files-inside-libreoffice-writer-writer2epub&lt;br /&gt;
* http://askubuntu.com/questions/338172/how-to-install-calibre-on-ubuntu-12-04&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=DVWP&amp;diff=73697</id>
		<title>DVWP</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=DVWP&amp;diff=73697"/>
		<updated>2026-07-04T01:21:07Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''DVWP = Damn Vulnerable WordPress'''.&lt;br /&gt;
&lt;br /&gt;
DVWP lebih realistis dibanding DVWA untuk latihan WordPress security, karena kamu belajar hal-hal yang sering muncul di pentest WordPress sungguhan: plugin, theme, `/wp-admin`, `/wp-login.php`, `/wp-content/`, XML-RPC, plugin vulnerable, file terbuka, credential lemah, dan salah konfigurasi.&lt;br /&gt;
&lt;br /&gt;
== 1. Aturan utama: jalankan hanya di lab lokal==&lt;br /&gt;
&lt;br /&gt;
Gunakan DVWP hanya di lingkungan sendiri:&lt;br /&gt;
&lt;br /&gt;
 Kali Linux       = mesin attacker / latihan&lt;br /&gt;
 DVWP WordPress   = target vulnerable&lt;br /&gt;
 Network          = localhost / host-only / private VM network&lt;br /&gt;
&lt;br /&gt;
Jangan expose DVWP ke internet publik. Karena ini memang sengaja vulnerable.&lt;br /&gt;
&lt;br /&gt;
== 2. Tujuan awal: pahami struktur WordPress==&lt;br /&gt;
&lt;br /&gt;
Sebelum menyerang apa pun, buka websitenya manual dulu dan pahami struktur WordPress:&lt;br /&gt;
&lt;br /&gt;
 /wp-login.php        → halaman login&lt;br /&gt;
 /wp-admin/           → dashboard admin&lt;br /&gt;
 /wp-content/         → tempat theme, plugin, upload&lt;br /&gt;
 /wp-content/plugins/ → plugin yang terpasang&lt;br /&gt;
 /wp-content/themes/  → theme yang terpasang&lt;br /&gt;
 /xmlrpc.php          → endpoint XML-RPC WordPress&lt;br /&gt;
 /wp-json/            → REST API WordPress&lt;br /&gt;
&lt;br /&gt;
Dalam pentest WordPress, banyak celah berasal dari '''plugin dan theme''', bukan hanya dari WordPress core.&lt;br /&gt;
&lt;br /&gt;
== 3. Recon dasar dari Kali Linux==&lt;br /&gt;
&lt;br /&gt;
Misalnya DVWP kamu jalan di:&lt;br /&gt;
&lt;br /&gt;
 http://127.0.0.1:31337&lt;br /&gt;
&lt;br /&gt;
Mulai dari cek service:&lt;br /&gt;
&lt;br /&gt;
 nmap -sV -p 31337,31338 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 -sV       = deteksi service dan versinya&lt;br /&gt;
 -p        = scan hanya port tertentu&lt;br /&gt;
 127.0.0.1 = mesin lokal&lt;br /&gt;
&lt;br /&gt;
Lalu cek response web:&lt;br /&gt;
&lt;br /&gt;
 curl -I http://127.0.0.1:31337&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 -I = hanya tampilkan HTTP header&lt;br /&gt;
&lt;br /&gt;
Ini membiasakan kamu untuk mengamati dulu sebelum langsung pakai tool besar.&lt;br /&gt;
&lt;br /&gt;
== 4. Gunakan WPScan, tapi jangan bergantung 100% pada tool==&lt;br /&gt;
&lt;br /&gt;
WPScan adalah tool utama untuk enumerasi WordPress.&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
 wpscan --url http://127.0.0.1:31337 --enumerate u,p,t&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 --url        = URL target WordPress&lt;br /&gt;
 --enumerate  = minta WPScan melakukan enumerasi&lt;br /&gt;
 u            = users&lt;br /&gt;
 p            = plugins&lt;br /&gt;
 t            = themes&lt;br /&gt;
&lt;br /&gt;
Alur belajar yang bagus:&lt;br /&gt;
&lt;br /&gt;
 1. Jalankan WPScan&lt;br /&gt;
 2. Lihat user/plugin/theme yang ditemukan&lt;br /&gt;
 3. Verifikasi manual lewat browser&lt;br /&gt;
 4. Cek path plugin di /wp-content/plugins/&lt;br /&gt;
 5. Pahami jenis vulnerability-nya&lt;br /&gt;
 6. Baru coba eksploitasi di lab&lt;br /&gt;
&lt;br /&gt;
Jangan hanya copy-paste exploit. Biasakan bertanya:&lt;br /&gt;
&lt;br /&gt;
 Input mana yang vulnerable?&lt;br /&gt;
 Butuh login atau tidak?&lt;br /&gt;
 Impact-nya apa?&lt;br /&gt;
 Buktinya apa?&lt;br /&gt;
 Cara fix-nya bagaimana?&lt;br /&gt;
&lt;br /&gt;
== 5. Fokus latihan pada plugin==&lt;br /&gt;
&lt;br /&gt;
WordPress sering vulnerable karena plugin. Jadi untuk tiap plugin, buat catatan kecil seperti ini:&lt;br /&gt;
&lt;br /&gt;
 Plugin:&lt;br /&gt;
 Versi:&lt;br /&gt;
 Vulnerability:&lt;br /&gt;
 Butuh login? ya/tidak&lt;br /&gt;
 Impact:&lt;br /&gt;
 Evidence / bukti:&lt;br /&gt;
 Cara memperbaiki:&lt;br /&gt;
 Referensi:&lt;br /&gt;
&lt;br /&gt;
Ini sangat mirip dengan cara kerja report pentest sungguhan.&lt;br /&gt;
&lt;br /&gt;
== 6. Attack surface WordPress yang perlu dipahami dulu==&lt;br /&gt;
&lt;br /&gt;
Prioritaskan belajar ini:&lt;br /&gt;
&lt;br /&gt;
 1. User enumeration&lt;br /&gt;
 2. Weak/default credentials&lt;br /&gt;
 3. Vulnerable plugins&lt;br /&gt;
 4. File upload weakness&lt;br /&gt;
 5. Directory listing / exposed files&lt;br /&gt;
 6. XML-RPC abuse&lt;br /&gt;
 7. REST API exposure&lt;br /&gt;
 8. phpMyAdmin/adminer exposure&lt;br /&gt;
 9. wp-config.php atau backup leak&lt;br /&gt;
 10. Privilege escalation di dalam wp-admin&lt;br /&gt;
&lt;br /&gt;
Penjelasan singkat:&lt;br /&gt;
&lt;br /&gt;
 User enumeration&lt;br /&gt;
 mencari username yang valid di WordPress.&lt;br /&gt;
&lt;br /&gt;
 Weak/default credentials&lt;br /&gt;
 login dengan password lemah atau default.&lt;br /&gt;
&lt;br /&gt;
 Vulnerable plugins&lt;br /&gt;
 plugin lama atau plugin yang punya CVE.&lt;br /&gt;
&lt;br /&gt;
 File upload weakness&lt;br /&gt;
 upload file berbahaya karena validasi buruk.&lt;br /&gt;
&lt;br /&gt;
 Directory listing&lt;br /&gt;
 folder bisa dibuka dan isinya kelihatan.&lt;br /&gt;
&lt;br /&gt;
 Exposed files&lt;br /&gt;
 file sensitif seperti backup, .sql, .zip, .bak, atau config terbuka.&lt;br /&gt;
&lt;br /&gt;
 XML-RPC abuse&lt;br /&gt;
 endpoint xmlrpc.php disalahgunakan untuk brute force atau pingback abuse.&lt;br /&gt;
&lt;br /&gt;
 REST API exposure&lt;br /&gt;
 informasi user/post/settings terlalu terbuka lewat /wp-json/.&lt;br /&gt;
&lt;br /&gt;
 phpMyAdmin/adminer exposure&lt;br /&gt;
 panel database terbuka ke web.&lt;br /&gt;
&lt;br /&gt;
 wp-config.php leak&lt;br /&gt;
 file konfigurasi WordPress bocor, bisa berisi credential database.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Tool yang bagus untuk latihan DVWP==&lt;br /&gt;
&lt;br /&gt;
Tool utama dari Kali:&lt;br /&gt;
&lt;br /&gt;
 Browser + Burp Suite&lt;br /&gt;
&lt;br /&gt;
Untuk melihat, intercept, dan memodifikasi HTTP request.&lt;br /&gt;
&lt;br /&gt;
 WPScan&lt;br /&gt;
&lt;br /&gt;
Untuk enumerasi WordPress, plugin, theme, user, dan vulnerability.&lt;br /&gt;
&lt;br /&gt;
 Nmap&lt;br /&gt;
&lt;br /&gt;
Untuk cek port dan service yang terbuka.&lt;br /&gt;
&lt;br /&gt;
 Gobuster / Feroxbuster&lt;br /&gt;
&lt;br /&gt;
Untuk mencari folder atau file tersembunyi.&lt;br /&gt;
&lt;br /&gt;
 Nikto&lt;br /&gt;
&lt;br /&gt;
Untuk cek basic web server misconfiguration.&lt;br /&gt;
&lt;br /&gt;
 Curl&lt;br /&gt;
&lt;br /&gt;
Untuk memahami HTTP request dan response secara manual.&lt;br /&gt;
&lt;br /&gt;
 Searchsploit&lt;br /&gt;
&lt;br /&gt;
Untuk mencari referensi exploit lokal dari Exploit-DB.&lt;br /&gt;
&lt;br /&gt;
== 8. Workflow beginner yang bagus==&lt;br /&gt;
&lt;br /&gt;
Pakai alur ini setiap latihan:&lt;br /&gt;
&lt;br /&gt;
 Step 1: Apakah target bisa diakses?&lt;br /&gt;
 Step 2: Port/service apa yang terbuka?&lt;br /&gt;
 Step 3: Apakah ini WordPress?&lt;br /&gt;
 Step 4: Versi WordPress berapa?&lt;br /&gt;
 Step 5: User apa saja yang terlihat?&lt;br /&gt;
 Step 6: Plugin/theme apa yang terpasang?&lt;br /&gt;
 Step 7: Apakah versi plugin/theme vulnerable?&lt;br /&gt;
 Step 8: Exploit-nya butuh login atau tidak?&lt;br /&gt;
 Step 9: Bisa tidak membuktikan impact dengan aman?&lt;br /&gt;
 Step 10: Bagaimana cara memperbaikinya?&lt;br /&gt;
&lt;br /&gt;
Kebiasaan ini lebih penting daripada menghafal payload.&lt;br /&gt;
&lt;br /&gt;
== 9. Rencana latihan 7 hari==&lt;br /&gt;
&lt;br /&gt;
 Hari 1:&lt;br /&gt;
 Install/start DVWP dan pahami struktur aplikasinya.&lt;br /&gt;
 &lt;br /&gt;
 Hari 2:&lt;br /&gt;
 Latihan nmap, curl, browser inspection, dan Burp Suite.&lt;br /&gt;
 &lt;br /&gt;
 Hari 3:&lt;br /&gt;
 Jalankan WPScan dan verifikasi user/plugin/theme secara manual.&lt;br /&gt;
 &lt;br /&gt;
 Hari 4:&lt;br /&gt;
 Pelajari path plugin di /wp-content/plugins/.&lt;br /&gt;
 &lt;br /&gt;
 Hari 5:&lt;br /&gt;
 Latihan directory discovery dan exposed file checking.&lt;br /&gt;
 &lt;br /&gt;
 Hari 6:&lt;br /&gt;
 Pilih satu vulnerability plugin, pelajari pelan-pelan, lalu tulis mini report.&lt;br /&gt;
 &lt;br /&gt;
 Hari 7:&lt;br /&gt;
 Ulangi dari awal tanpa melihat catatan.&lt;br /&gt;
&lt;br /&gt;
== 10. Buat folder catatan latihan==&lt;br /&gt;
&lt;br /&gt;
Bikin folder seperti ini:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/Pentest/DVWP-notes&lt;br /&gt;
 cd ~/Apps/Pentest/DVWP-notes&lt;br /&gt;
 &lt;br /&gt;
 touch 01-recon.md&lt;br /&gt;
 touch 02-wordpress-structure.md&lt;br /&gt;
 touch 03-wpscan.md&lt;br /&gt;
 touch 04-plugins.md&lt;br /&gt;
 touch 05-exposed-files.md&lt;br /&gt;
 touch 06-findings-report.md&lt;br /&gt;
 touch 99-cheatsheet.md&lt;br /&gt;
&lt;br /&gt;
Isi setiap file dengan format:&lt;br /&gt;
&lt;br /&gt;
 Target:&lt;br /&gt;
 Tool yang digunakan:&lt;br /&gt;
 Command:&lt;br /&gt;
 Arti command:&lt;br /&gt;
 Finding:&lt;br /&gt;
 Evidence / bukti:&lt;br /&gt;
 Risk:&lt;br /&gt;
 Fix:&lt;br /&gt;
 Lesson learned:&lt;br /&gt;
&lt;br /&gt;
== 11. Contoh catatan sederhana==&lt;br /&gt;
&lt;br /&gt;
 Target:&lt;br /&gt;
 http://127.0.0.1:31337&lt;br /&gt;
 &lt;br /&gt;
 Tool:&lt;br /&gt;
 WPScan&lt;br /&gt;
 &lt;br /&gt;
 Command:&lt;br /&gt;
 wpscan --url http://127.0.0.1:31337 --enumerate u,p,t&lt;br /&gt;
 &lt;br /&gt;
 Arti:&lt;br /&gt;
 Melakukan enumerasi user, plugin, dan theme WordPress.&lt;br /&gt;
 &lt;br /&gt;
 Finding:&lt;br /&gt;
 Ditemukan beberapa plugin yang bisa dicek lebih lanjut.&lt;br /&gt;
 &lt;br /&gt;
 Evidence:&lt;br /&gt;
 Plugin terlihat di path /wp-content/plugins/.&lt;br /&gt;
 &lt;br /&gt;
 Risk:&lt;br /&gt;
 Jika plugin versi lama dan vulnerable, attacker bisa mengeksploitasi website.&lt;br /&gt;
 &lt;br /&gt;
 Fix:&lt;br /&gt;
 Update plugin, hapus plugin tidak terpakai, batasi akses admin, dan aktifkan hardening WordPress.&lt;br /&gt;
 &lt;br /&gt;
 Lesson learned:&lt;br /&gt;
 Dalam WordPress pentest, plugin sering menjadi sumber vulnerability utama.&lt;br /&gt;
&lt;br /&gt;
== 12. Mindset penting saat latihan==&lt;br /&gt;
&lt;br /&gt;
Jangan berpikir:&lt;br /&gt;
&lt;br /&gt;
 Payload apa yang harus aku copy-paste?&lt;br /&gt;
&lt;br /&gt;
Tapi biasakan berpikir:&lt;br /&gt;
&lt;br /&gt;
 Data apa yang dikirim user?&lt;br /&gt;
 Server memproses input ini sebagai apa?&lt;br /&gt;
 Apakah input masuk ke SQL query, command, file path, upload handler, atau HTML output?&lt;br /&gt;
 Apa buktinya input saya memengaruhi backend?&lt;br /&gt;
 Impact-nya apa?&lt;br /&gt;
 Cara mitigasinya apa?&lt;br /&gt;
&lt;br /&gt;
Itu mindset pentester yang benar.&lt;br /&gt;
&lt;br /&gt;
== 13. Batas aman==&lt;br /&gt;
&lt;br /&gt;
Yang boleh dilakukan:&lt;br /&gt;
&lt;br /&gt;
 DVWP lokal&lt;br /&gt;
 VM sendiri&lt;br /&gt;
 Docker sendiri&lt;br /&gt;
 Lab kampus/kantor yang memang diizinkan&lt;br /&gt;
 CTF resmi&lt;br /&gt;
&lt;br /&gt;
Yang jangan dilakukan:&lt;br /&gt;
&lt;br /&gt;
 Scan website publik tanpa izin&lt;br /&gt;
 Brute force login asli&lt;br /&gt;
 Coba payload ke sistem kantor tanpa scope&lt;br /&gt;
 Upload shell ke server bukan milik sendiri&lt;br /&gt;
 Pakai WPScan ke domain publik tanpa izin&lt;br /&gt;
&lt;br /&gt;
Intinya: '''DVWP bukan hanya tempat “nge-hack WordPress”. DVWP adalah tempat belajar cara berpikir pentester WordPress: enumerasi, verifikasi, pahami impact, lalu tulis report dengan rapi.'''&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=DVWP&amp;diff=73696</id>
		<title>DVWP</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=DVWP&amp;diff=73696"/>
		<updated>2026-07-04T01:20:56Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Ahh siap — '''DVWP = Damn Vulnerable WordPress'''.  DVWP lebih realistis dibanding DVWA untuk latihan WordPress security, karena kamu belajar hal-hal yang sering muncul di p...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ahh siap — '''DVWP = Damn Vulnerable WordPress'''.&lt;br /&gt;
&lt;br /&gt;
DVWP lebih realistis dibanding DVWA untuk latihan WordPress security, karena kamu belajar hal-hal yang sering muncul di pentest WordPress sungguhan: plugin, theme, `/wp-admin`, `/wp-login.php`, `/wp-content/`, XML-RPC, plugin vulnerable, file terbuka, credential lemah, dan salah konfigurasi.&lt;br /&gt;
&lt;br /&gt;
== 1. Aturan utama: jalankan hanya di lab lokal==&lt;br /&gt;
&lt;br /&gt;
Gunakan DVWP hanya di lingkungan sendiri:&lt;br /&gt;
&lt;br /&gt;
 Kali Linux       = mesin attacker / latihan&lt;br /&gt;
 DVWP WordPress   = target vulnerable&lt;br /&gt;
 Network          = localhost / host-only / private VM network&lt;br /&gt;
&lt;br /&gt;
Jangan expose DVWP ke internet publik. Karena ini memang sengaja vulnerable.&lt;br /&gt;
&lt;br /&gt;
== 2. Tujuan awal: pahami struktur WordPress==&lt;br /&gt;
&lt;br /&gt;
Sebelum menyerang apa pun, buka websitenya manual dulu dan pahami struktur WordPress:&lt;br /&gt;
&lt;br /&gt;
 /wp-login.php        → halaman login&lt;br /&gt;
 /wp-admin/           → dashboard admin&lt;br /&gt;
 /wp-content/         → tempat theme, plugin, upload&lt;br /&gt;
 /wp-content/plugins/ → plugin yang terpasang&lt;br /&gt;
 /wp-content/themes/  → theme yang terpasang&lt;br /&gt;
 /xmlrpc.php          → endpoint XML-RPC WordPress&lt;br /&gt;
 /wp-json/            → REST API WordPress&lt;br /&gt;
&lt;br /&gt;
Dalam pentest WordPress, banyak celah berasal dari '''plugin dan theme''', bukan hanya dari WordPress core.&lt;br /&gt;
&lt;br /&gt;
== 3. Recon dasar dari Kali Linux==&lt;br /&gt;
&lt;br /&gt;
Misalnya DVWP kamu jalan di:&lt;br /&gt;
&lt;br /&gt;
 http://127.0.0.1:31337&lt;br /&gt;
&lt;br /&gt;
Mulai dari cek service:&lt;br /&gt;
&lt;br /&gt;
 nmap -sV -p 31337,31338 127.0.0.1&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 -sV       = deteksi service dan versinya&lt;br /&gt;
 -p        = scan hanya port tertentu&lt;br /&gt;
 127.0.0.1 = mesin lokal&lt;br /&gt;
&lt;br /&gt;
Lalu cek response web:&lt;br /&gt;
&lt;br /&gt;
 curl -I http://127.0.0.1:31337&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 -I = hanya tampilkan HTTP header&lt;br /&gt;
&lt;br /&gt;
Ini membiasakan kamu untuk mengamati dulu sebelum langsung pakai tool besar.&lt;br /&gt;
&lt;br /&gt;
== 4. Gunakan WPScan, tapi jangan bergantung 100% pada tool==&lt;br /&gt;
&lt;br /&gt;
WPScan adalah tool utama untuk enumerasi WordPress.&lt;br /&gt;
&lt;br /&gt;
Contoh:&lt;br /&gt;
&lt;br /&gt;
 wpscan --url http://127.0.0.1:31337 --enumerate u,p,t&lt;br /&gt;
&lt;br /&gt;
Artinya:&lt;br /&gt;
&lt;br /&gt;
 --url        = URL target WordPress&lt;br /&gt;
 --enumerate  = minta WPScan melakukan enumerasi&lt;br /&gt;
 u            = users&lt;br /&gt;
 p            = plugins&lt;br /&gt;
 t            = themes&lt;br /&gt;
&lt;br /&gt;
Alur belajar yang bagus:&lt;br /&gt;
&lt;br /&gt;
 1. Jalankan WPScan&lt;br /&gt;
 2. Lihat user/plugin/theme yang ditemukan&lt;br /&gt;
 3. Verifikasi manual lewat browser&lt;br /&gt;
 4. Cek path plugin di /wp-content/plugins/&lt;br /&gt;
 5. Pahami jenis vulnerability-nya&lt;br /&gt;
 6. Baru coba eksploitasi di lab&lt;br /&gt;
&lt;br /&gt;
Jangan hanya copy-paste exploit. Biasakan bertanya:&lt;br /&gt;
&lt;br /&gt;
 Input mana yang vulnerable?&lt;br /&gt;
 Butuh login atau tidak?&lt;br /&gt;
 Impact-nya apa?&lt;br /&gt;
 Buktinya apa?&lt;br /&gt;
 Cara fix-nya bagaimana?&lt;br /&gt;
&lt;br /&gt;
== 5. Fokus latihan pada plugin==&lt;br /&gt;
&lt;br /&gt;
WordPress sering vulnerable karena plugin. Jadi untuk tiap plugin, buat catatan kecil seperti ini:&lt;br /&gt;
&lt;br /&gt;
 Plugin:&lt;br /&gt;
 Versi:&lt;br /&gt;
 Vulnerability:&lt;br /&gt;
 Butuh login? ya/tidak&lt;br /&gt;
 Impact:&lt;br /&gt;
 Evidence / bukti:&lt;br /&gt;
 Cara memperbaiki:&lt;br /&gt;
 Referensi:&lt;br /&gt;
&lt;br /&gt;
Ini sangat mirip dengan cara kerja report pentest sungguhan.&lt;br /&gt;
&lt;br /&gt;
== 6. Attack surface WordPress yang perlu dipahami dulu==&lt;br /&gt;
&lt;br /&gt;
Prioritaskan belajar ini:&lt;br /&gt;
&lt;br /&gt;
 1. User enumeration&lt;br /&gt;
 2. Weak/default credentials&lt;br /&gt;
 3. Vulnerable plugins&lt;br /&gt;
 4. File upload weakness&lt;br /&gt;
 5. Directory listing / exposed files&lt;br /&gt;
 6. XML-RPC abuse&lt;br /&gt;
 7. REST API exposure&lt;br /&gt;
 8. phpMyAdmin/adminer exposure&lt;br /&gt;
 9. wp-config.php atau backup leak&lt;br /&gt;
 10. Privilege escalation di dalam wp-admin&lt;br /&gt;
&lt;br /&gt;
Penjelasan singkat:&lt;br /&gt;
&lt;br /&gt;
 User enumeration&lt;br /&gt;
 mencari username yang valid di WordPress.&lt;br /&gt;
&lt;br /&gt;
 Weak/default credentials&lt;br /&gt;
 login dengan password lemah atau default.&lt;br /&gt;
&lt;br /&gt;
 Vulnerable plugins&lt;br /&gt;
 plugin lama atau plugin yang punya CVE.&lt;br /&gt;
&lt;br /&gt;
 File upload weakness&lt;br /&gt;
 upload file berbahaya karena validasi buruk.&lt;br /&gt;
&lt;br /&gt;
 Directory listing&lt;br /&gt;
 folder bisa dibuka dan isinya kelihatan.&lt;br /&gt;
&lt;br /&gt;
 Exposed files&lt;br /&gt;
 file sensitif seperti backup, .sql, .zip, .bak, atau config terbuka.&lt;br /&gt;
&lt;br /&gt;
 XML-RPC abuse&lt;br /&gt;
 endpoint xmlrpc.php disalahgunakan untuk brute force atau pingback abuse.&lt;br /&gt;
&lt;br /&gt;
 REST API exposure&lt;br /&gt;
 informasi user/post/settings terlalu terbuka lewat /wp-json/.&lt;br /&gt;
&lt;br /&gt;
 phpMyAdmin/adminer exposure&lt;br /&gt;
 panel database terbuka ke web.&lt;br /&gt;
&lt;br /&gt;
 wp-config.php leak&lt;br /&gt;
 file konfigurasi WordPress bocor, bisa berisi credential database.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 7. Tool yang bagus untuk latihan DVWP==&lt;br /&gt;
&lt;br /&gt;
Tool utama dari Kali:&lt;br /&gt;
&lt;br /&gt;
 Browser + Burp Suite&lt;br /&gt;
&lt;br /&gt;
Untuk melihat, intercept, dan memodifikasi HTTP request.&lt;br /&gt;
&lt;br /&gt;
 WPScan&lt;br /&gt;
&lt;br /&gt;
Untuk enumerasi WordPress, plugin, theme, user, dan vulnerability.&lt;br /&gt;
&lt;br /&gt;
 Nmap&lt;br /&gt;
&lt;br /&gt;
Untuk cek port dan service yang terbuka.&lt;br /&gt;
&lt;br /&gt;
 Gobuster / Feroxbuster&lt;br /&gt;
&lt;br /&gt;
Untuk mencari folder atau file tersembunyi.&lt;br /&gt;
&lt;br /&gt;
 Nikto&lt;br /&gt;
&lt;br /&gt;
Untuk cek basic web server misconfiguration.&lt;br /&gt;
&lt;br /&gt;
 Curl&lt;br /&gt;
&lt;br /&gt;
Untuk memahami HTTP request dan response secara manual.&lt;br /&gt;
&lt;br /&gt;
 Searchsploit&lt;br /&gt;
&lt;br /&gt;
Untuk mencari referensi exploit lokal dari Exploit-DB.&lt;br /&gt;
&lt;br /&gt;
== 8. Workflow beginner yang bagus==&lt;br /&gt;
&lt;br /&gt;
Pakai alur ini setiap latihan:&lt;br /&gt;
&lt;br /&gt;
 Step 1: Apakah target bisa diakses?&lt;br /&gt;
 Step 2: Port/service apa yang terbuka?&lt;br /&gt;
 Step 3: Apakah ini WordPress?&lt;br /&gt;
 Step 4: Versi WordPress berapa?&lt;br /&gt;
 Step 5: User apa saja yang terlihat?&lt;br /&gt;
 Step 6: Plugin/theme apa yang terpasang?&lt;br /&gt;
 Step 7: Apakah versi plugin/theme vulnerable?&lt;br /&gt;
 Step 8: Exploit-nya butuh login atau tidak?&lt;br /&gt;
 Step 9: Bisa tidak membuktikan impact dengan aman?&lt;br /&gt;
 Step 10: Bagaimana cara memperbaikinya?&lt;br /&gt;
&lt;br /&gt;
Kebiasaan ini lebih penting daripada menghafal payload.&lt;br /&gt;
&lt;br /&gt;
== 9. Rencana latihan 7 hari==&lt;br /&gt;
&lt;br /&gt;
 Hari 1:&lt;br /&gt;
 Install/start DVWP dan pahami struktur aplikasinya.&lt;br /&gt;
 &lt;br /&gt;
 Hari 2:&lt;br /&gt;
 Latihan nmap, curl, browser inspection, dan Burp Suite.&lt;br /&gt;
 &lt;br /&gt;
 Hari 3:&lt;br /&gt;
 Jalankan WPScan dan verifikasi user/plugin/theme secara manual.&lt;br /&gt;
 &lt;br /&gt;
 Hari 4:&lt;br /&gt;
 Pelajari path plugin di /wp-content/plugins/.&lt;br /&gt;
 &lt;br /&gt;
 Hari 5:&lt;br /&gt;
 Latihan directory discovery dan exposed file checking.&lt;br /&gt;
 &lt;br /&gt;
 Hari 6:&lt;br /&gt;
 Pilih satu vulnerability plugin, pelajari pelan-pelan, lalu tulis mini report.&lt;br /&gt;
 &lt;br /&gt;
 Hari 7:&lt;br /&gt;
 Ulangi dari awal tanpa melihat catatan.&lt;br /&gt;
&lt;br /&gt;
== 10. Buat folder catatan latihan==&lt;br /&gt;
&lt;br /&gt;
Bikin folder seperti ini:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/Pentest/DVWP-notes&lt;br /&gt;
 cd ~/Apps/Pentest/DVWP-notes&lt;br /&gt;
 &lt;br /&gt;
 touch 01-recon.md&lt;br /&gt;
 touch 02-wordpress-structure.md&lt;br /&gt;
 touch 03-wpscan.md&lt;br /&gt;
 touch 04-plugins.md&lt;br /&gt;
 touch 05-exposed-files.md&lt;br /&gt;
 touch 06-findings-report.md&lt;br /&gt;
 touch 99-cheatsheet.md&lt;br /&gt;
&lt;br /&gt;
Isi setiap file dengan format:&lt;br /&gt;
&lt;br /&gt;
 Target:&lt;br /&gt;
 Tool yang digunakan:&lt;br /&gt;
 Command:&lt;br /&gt;
 Arti command:&lt;br /&gt;
 Finding:&lt;br /&gt;
 Evidence / bukti:&lt;br /&gt;
 Risk:&lt;br /&gt;
 Fix:&lt;br /&gt;
 Lesson learned:&lt;br /&gt;
&lt;br /&gt;
== 11. Contoh catatan sederhana==&lt;br /&gt;
&lt;br /&gt;
 Target:&lt;br /&gt;
 http://127.0.0.1:31337&lt;br /&gt;
 &lt;br /&gt;
 Tool:&lt;br /&gt;
 WPScan&lt;br /&gt;
 &lt;br /&gt;
 Command:&lt;br /&gt;
 wpscan --url http://127.0.0.1:31337 --enumerate u,p,t&lt;br /&gt;
 &lt;br /&gt;
 Arti:&lt;br /&gt;
 Melakukan enumerasi user, plugin, dan theme WordPress.&lt;br /&gt;
 &lt;br /&gt;
 Finding:&lt;br /&gt;
 Ditemukan beberapa plugin yang bisa dicek lebih lanjut.&lt;br /&gt;
 &lt;br /&gt;
 Evidence:&lt;br /&gt;
 Plugin terlihat di path /wp-content/plugins/.&lt;br /&gt;
 &lt;br /&gt;
 Risk:&lt;br /&gt;
 Jika plugin versi lama dan vulnerable, attacker bisa mengeksploitasi website.&lt;br /&gt;
 &lt;br /&gt;
 Fix:&lt;br /&gt;
 Update plugin, hapus plugin tidak terpakai, batasi akses admin, dan aktifkan hardening WordPress.&lt;br /&gt;
 &lt;br /&gt;
 Lesson learned:&lt;br /&gt;
 Dalam WordPress pentest, plugin sering menjadi sumber vulnerability utama.&lt;br /&gt;
&lt;br /&gt;
== 12. Mindset penting saat latihan==&lt;br /&gt;
&lt;br /&gt;
Jangan berpikir:&lt;br /&gt;
&lt;br /&gt;
 Payload apa yang harus aku copy-paste?&lt;br /&gt;
&lt;br /&gt;
Tapi biasakan berpikir:&lt;br /&gt;
&lt;br /&gt;
 Data apa yang dikirim user?&lt;br /&gt;
 Server memproses input ini sebagai apa?&lt;br /&gt;
 Apakah input masuk ke SQL query, command, file path, upload handler, atau HTML output?&lt;br /&gt;
 Apa buktinya input saya memengaruhi backend?&lt;br /&gt;
 Impact-nya apa?&lt;br /&gt;
 Cara mitigasinya apa?&lt;br /&gt;
&lt;br /&gt;
Itu mindset pentester yang benar.&lt;br /&gt;
&lt;br /&gt;
== 13. Batas aman==&lt;br /&gt;
&lt;br /&gt;
Yang boleh dilakukan:&lt;br /&gt;
&lt;br /&gt;
 DVWP lokal&lt;br /&gt;
 VM sendiri&lt;br /&gt;
 Docker sendiri&lt;br /&gt;
 Lab kampus/kantor yang memang diizinkan&lt;br /&gt;
 CTF resmi&lt;br /&gt;
&lt;br /&gt;
Yang jangan dilakukan:&lt;br /&gt;
&lt;br /&gt;
 Scan website publik tanpa izin&lt;br /&gt;
 Brute force login asli&lt;br /&gt;
 Coba payload ke sistem kantor tanpa scope&lt;br /&gt;
 Upload shell ke server bukan milik sendiri&lt;br /&gt;
 Pakai WPScan ke domain publik tanpa izin&lt;br /&gt;
&lt;br /&gt;
Intinya: '''DVWP bukan hanya tempat “nge-hack WordPress”. DVWP adalah tempat belajar cara berpikir pentester WordPress: enumerasi, verifikasi, pahami impact, lalu tulis report dengan rapi.'''&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=DVWA&amp;diff=73695</id>
		<title>DVWA</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=DVWA&amp;diff=73695"/>
		<updated>2026-07-04T01:14:00Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Referensi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Damn Vulnerable Web App (DVWA) adalah aplikasi web PHP / MySQL yang sangat rentan. Tujuan utamanya adalah untuk membantuan para profesional keamanan untuk menguji keterampilan dan alat-alat mereka dalam lingkungan hukum, membantu pengembang web lebih memahami proses mengamankan aplikasi web dan guru bantu / siswa untuk mengajar / belajar keamanan aplikasi web di lingkungan ruang kelas .&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Lebih Lanjut==&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: instalasi Ubuntu 26.04]]&lt;br /&gt;
* [[DVWA: instalasi Ubuntu 16.04]] '''RECOMMENDED'''&lt;br /&gt;
* [[SQLMap: Instalasi DVWA]]&lt;br /&gt;
* [[DVWA: instalasi telnetd supaya lebih asik]]&lt;br /&gt;
* [[menyadap password telnet]]&lt;br /&gt;
&lt;br /&gt;
===Command Injection===&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: Command Injection]] '''RECOMMENDED'''&lt;br /&gt;
* [[DVWA: Command Injection Back Door]]&lt;br /&gt;
&lt;br /&gt;
===Brute Force Login===&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: Brute Force login low]] '''RECOMMENDED'''&lt;br /&gt;
* [[DVWA: Brute Force login high]]&lt;br /&gt;
* [[DVWA: Brute Force login]]&lt;br /&gt;
&lt;br /&gt;
===SQL===&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: Check SQLi vulnerability]]&lt;br /&gt;
* [[SQLMap: Contoh SQL Injection ke DVWA]]&lt;br /&gt;
* [[DVWA: perintah SQL di server DVWA]] '''RECOMMENDED'''&lt;br /&gt;
* [[DVWA: Exploit menggunakan Metasploit]]&lt;br /&gt;
* [[DVWA: SQL Injection]]&lt;br /&gt;
* [[DVWA: SQLi blind]]&lt;br /&gt;
* [[DVWA: Exploit menggunakan sqlmap]] '''RECOMMEND'''&lt;br /&gt;
&lt;br /&gt;
===XSS===&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: XSS]]&lt;br /&gt;
* [[DVWA: Upload PHP Backdoor]] - menggunakan metasploit&lt;br /&gt;
&lt;br /&gt;
===LFI / RFI / RCE===&lt;br /&gt;
&lt;br /&gt;
* [[DVWA: File Path Traversal and File Inclusions(LFI / RFI)]]&lt;br /&gt;
* https://www.exploit-db.com/papers/12992&lt;br /&gt;
* https://www.offensive-security.com/metasploit-unleashed/file-inclusion-vulnerabilities/&lt;br /&gt;
&lt;br /&gt;
===Burpsuite===&lt;br /&gt;
&lt;br /&gt;
==Youtube==&lt;br /&gt;
&lt;br /&gt;
* https://youtu.be/JKsF7D089t4 - Instalasi DVWA 1.9 di Ubuntu Server 16.04&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* http://www.dvwa.co.uk/&lt;br /&gt;
* http://www.computersecuritystudent.com/cgi-bin/CSS/process_request_v3.pl?HID=688b0913be93a4d95daed400990c4745&amp;amp;TYPE=SUB&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[DVWP]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73694</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73694"/>
		<updated>2026-06-28T09:38:47Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 11. Cara pakai harian */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung==&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt==&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
 # Discover Directly-Follows Graph&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz==&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73693</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73693"/>
		<updated>2026-06-28T09:36:02Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Discover Directly-Follows Graph */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung==&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt==&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
 # Discover Directly-Follows Graph&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73692</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73692"/>
		<updated>2026-06-28T09:35:23Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 8. Test instalasi PM4Py */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung==&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt==&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
= Discover Directly-Follows Graph=&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73691</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73691"/>
		<updated>2026-06-28T09:34:49Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 6. Daftarkan kernel Jupyter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung==&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt==&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 python&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
= Discover Directly-Follows Graph=&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73690</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73690"/>
		<updated>2026-06-28T09:33:18Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 4. Upgrade pip dan tools dasar */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung==&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 python&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
= Discover Directly-Follows Graph=&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73689</id>
		<title>PM: Install Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=PM:_Install_Virtual_Environment&amp;diff=73689"/>
		<updated>2026-06-28T09:32:04Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini menduk...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut langkah lengkap membuat '''virtualenv PM4Py di `~/Apps/PM4Py`''' untuk *process mining*. PM4Py resmi bisa di-install dengan `pip install -U pm4py`, dan saat ini mendukung Python 3.9–3.14. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency sistem==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
&lt;br /&gt;
Keterangan singkat:&lt;br /&gt;
&lt;br /&gt;
 python3-venv&lt;br /&gt;
&lt;br /&gt;
dibutuhkan untuk membuat virtual environment.&lt;br /&gt;
&lt;br /&gt;
 graphviz&lt;br /&gt;
&lt;br /&gt;
dibutuhkan agar visualisasi proses seperti Petri net, BPMN, dan *process tree* bisa digambar dengan baik.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
&lt;br /&gt;
== 3. Buat virtualenv==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, prompt terminal biasanya berubah menjadi seperti:&lt;br /&gt;
&lt;br /&gt;
 (venv) onno@i3:~/Apps/PM4Py$&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip dan tools dasar==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install PM4Py + library pendukung&lt;br /&gt;
&lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
&lt;br /&gt;
Library utama:&lt;br /&gt;
&lt;br /&gt;
 | Library                  | Fungsi                                     |&lt;br /&gt;
 |  |  |&lt;br /&gt;
 | `pm4py`                  | library utama *process mining*             |&lt;br /&gt;
 | `pandas`, `numpy`        | olah data event log                        |&lt;br /&gt;
 | `matplotlib`, `seaborn`  | visualisasi data                           |&lt;br /&gt;
 | `scikit-learn`           | clustering, klasifikasi, anomaly detection |&lt;br /&gt;
 | `networkx`, `graphviz`   | graph/process visualization                |&lt;br /&gt;
 | `jupyterlab`, `notebook` | kerja lewat Jupyter                        |&lt;br /&gt;
 | `openpyxl`, `xlsxwriter` | baca/tulis Excel                           |&lt;br /&gt;
&lt;br /&gt;
== 6. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Nanti di Jupyter pilih kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
== 7. Buat file requirements.txt&lt;br /&gt;
&lt;br /&gt;
 cat &amp;gt; requirements.txt &amp;lt;&amp;lt; 'EOF'&lt;br /&gt;
 pm4py&lt;br /&gt;
 pandas&lt;br /&gt;
 numpy&lt;br /&gt;
 matplotlib&lt;br /&gt;
 seaborn&lt;br /&gt;
 scikit-learn&lt;br /&gt;
 scipy&lt;br /&gt;
 networkx&lt;br /&gt;
 graphviz&lt;br /&gt;
 pyvis&lt;br /&gt;
 jupyterlab&lt;br /&gt;
 notebook&lt;br /&gt;
 ipykernel&lt;br /&gt;
 openpyxl&lt;br /&gt;
 xlsxwriter&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
Nanti kalau mau install ulang cukup:&lt;br /&gt;
&lt;br /&gt;
 pip install -r requirements.txt&lt;br /&gt;
&lt;br /&gt;
== 8. Test instalasi PM4Py==&lt;br /&gt;
&lt;br /&gt;
Buat file test:&lt;br /&gt;
&lt;br /&gt;
 nano test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 python&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;PM4Py version:&amp;quot;, pm4py.__version__)&lt;br /&gt;
 &lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Approve&amp;quot;,  &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;}, &lt;br /&gt;
 &lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Register&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Check&amp;quot;,    &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;Reject&amp;quot;,   &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 print(df)&lt;br /&gt;
&lt;br /&gt;
= Discover Directly-Follows Graph=&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nDirectly-Follows Graph:&amp;quot;)&lt;br /&gt;
 print(dfg)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nStart activities:&amp;quot;)&lt;br /&gt;
 print(start_activities)&lt;br /&gt;
 &lt;br /&gt;
 print(&amp;quot;\nEnd activities:&amp;quot;)&lt;br /&gt;
 print(end_activities)&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 python test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
Kalau sukses, akan keluar versi PM4Py dan hasil *Directly-Follows Graph*.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 9. Test lewat Jupyter Notebook==&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Lalu buat notebook baru dengan kernel:&lt;br /&gt;
&lt;br /&gt;
 Python PM4Py&lt;br /&gt;
&lt;br /&gt;
Cell test:&lt;br /&gt;
&lt;br /&gt;
 import pm4py&lt;br /&gt;
 import pandas as pd&lt;br /&gt;
 &lt;br /&gt;
 pm4py.__version__&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Cell berikutnya:&lt;br /&gt;
&lt;br /&gt;
 data = [&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;1&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;C&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-01 10:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;A&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 08:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;B&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 09:00:00&amp;quot;},&lt;br /&gt;
     {&amp;quot;case:concept:name&amp;quot;: &amp;quot;2&amp;quot;, &amp;quot;concept:name&amp;quot;: &amp;quot;D&amp;quot;, &amp;quot;time:timestamp&amp;quot;: &amp;quot;2026-01-02 10:00:00&amp;quot;},&lt;br /&gt;
 ]&lt;br /&gt;
 &lt;br /&gt;
 df = pd.DataFrame(data)&lt;br /&gt;
 df[&amp;quot;time:timestamp&amp;quot;] = pd.to_datetime(df[&amp;quot;time:timestamp&amp;quot;])&lt;br /&gt;
 &lt;br /&gt;
 df&lt;br /&gt;
&lt;br /&gt;
Cell process mining:&lt;br /&gt;
&lt;br /&gt;
 dfg, start_activities, end_activities = pm4py.discover_dfg(df)&lt;br /&gt;
 &lt;br /&gt;
 dfg&lt;br /&gt;
&lt;br /&gt;
== 10. Struktur folder yang disarankan==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/PM4Py/{data,notebooks,scripts,output}&lt;br /&gt;
&lt;br /&gt;
Struktur:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/PM4Py/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── data/&lt;br /&gt;
 ├── notebooks/&lt;br /&gt;
 ├── scripts/&lt;br /&gt;
 ├── output/&lt;br /&gt;
 ├── requirements.txt&lt;br /&gt;
 └── test_pm4py.py&lt;br /&gt;
&lt;br /&gt;
== 11. Cara pakai harian==&lt;br /&gt;
&lt;br /&gt;
Setiap mau kerja:&lt;br /&gt;
&lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 jupyter lab&lt;br /&gt;
&lt;br /&gt;
Keluar dari virtualenv:&lt;br /&gt;
&lt;br /&gt;
 deactivate&lt;br /&gt;
&lt;br /&gt;
== 12. Kalau ada error Graphviz&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 dot -V&lt;br /&gt;
&lt;br /&gt;
Kalau belum ada:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y graphviz&lt;br /&gt;
&lt;br /&gt;
Lalu install ulang Python package-nya:&lt;br /&gt;
&lt;br /&gt;
 pip install -U graphviz&lt;br /&gt;
&lt;br /&gt;
== 13. Versi ringkas semua command==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y python3 python3-venv python3-pip graphviz&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p ~/Apps/PM4Py &lt;br /&gt;
 cd ~/Apps/PM4Py&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 pip install -U \&lt;br /&gt;
   pm4py \&lt;br /&gt;
   pandas \&lt;br /&gt;
   numpy \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   seaborn \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   scipy \&lt;br /&gt;
   networkx \&lt;br /&gt;
   graphviz \&lt;br /&gt;
   pyvis \&lt;br /&gt;
   jupyterlab \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel \&lt;br /&gt;
   openpyxl \&lt;br /&gt;
   xlsxwriter&lt;br /&gt;
 &lt;br /&gt;
 python -m ipykernel install --user --name pm4py --display-name &amp;quot;Python PM4Py&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 mkdir -p data notebooks scripts output&lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import pm4py; print(pm4py.__version__)&amp;quot;&lt;br /&gt;
 jupyter lab&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 [1]: https://pypi.org/project/pm4py/?utm_source=chatgpt.com &amp;quot;pm4py&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Process_Mining&amp;diff=73688</id>
		<title>Process Mining</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Process_Mining&amp;diff=73688"/>
		<updated>2026-06-28T09:31:57Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Pranala Menarik */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Penambangan proses adalah sekumpulan teknik yang menghubungkan bidang ilmu data dan manajemen proses untuk mendukung analisis proses operasional berdasarkan log peristiwa. Tujuan dari penambangan proses adalah untuk mengubah data peristiwa menjadi wawasan dan tindakan. Penambangan proses merupakan bagian integral dari ilmu data, didorong oleh ketersediaan data peristiwa dan keinginan untuk meningkatkan proses. Teknik penambangan proses menggunakan data peristiwa untuk menunjukkan apa yang sebenarnya dilakukan orang, mesin, dan organisasi. Penambangan proses memberikan wawasan baru yang dapat digunakan untuk mengidentifikasi jalur eksekusi yang diambil oleh proses operasional dan mengatasi masalah kinerja dan kepatuhannya.&lt;br /&gt;
&lt;br /&gt;
Penambangan proses dimulai dari data peristiwa. Input untuk penambangan proses adalah log peristiwa. Log peristiwa melihat proses dari sudut tertentu. Setiap peristiwa dalam log harus berisi&lt;br /&gt;
&lt;br /&gt;
# pengidentifikasi unik untuk instance proses tertentu (disebut id kasus),&lt;br /&gt;
# aktivitas (deskripsi peristiwa yang sedang terjadi), dan&lt;br /&gt;
# stempel waktu.&lt;br /&gt;
&lt;br /&gt;
Mungkin ada atribut peristiwa tambahan yang mengacu pada sumber daya, biaya, dll., tetapi ini bersifat opsional. Dengan sedikit usaha, data tersebut dapat diambil dari sistem informasi yang mendukung proses operasional. Penambangan proses menggunakan data peristiwa ini untuk menjawab berbagai pertanyaan terkait proses.&lt;br /&gt;
&lt;br /&gt;
Ada tiga kelas utama teknik process mining:&lt;br /&gt;
&lt;br /&gt;
* penemuan proses,&lt;br /&gt;
* pemeriksaan kesesuaian, dan&lt;br /&gt;
* peningkatan proses. &lt;br /&gt;
&lt;br /&gt;
Di masa lalu istilah seperti Workflow Mining dan Automated Business Process Discovery (ABPD) digunakan.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[PM: Install Virtual Environment]]&lt;br /&gt;
* [[PM: Methods in pm4py]]&lt;br /&gt;
* [[PM: Bottleneck Detection]]&lt;br /&gt;
* [[PM: Transition System Miner]]&lt;br /&gt;
&lt;br /&gt;
==Contoh Dataset==&lt;br /&gt;
&lt;br /&gt;
* https://processmining.org/event-data.html#data&lt;br /&gt;
* https://figshare.com/articles/dataset/Event_Log_Sampling_Datasets/20354505&lt;br /&gt;
&lt;br /&gt;
==Platform==&lt;br /&gt;
&lt;br /&gt;
* https://id.celonis.cloud/user/ui/&lt;br /&gt;
* https://fluxicon.com/disco/&lt;br /&gt;
* https://apromore.com/editions-and-pricing/&lt;br /&gt;
* http://rapidprom.org/&lt;br /&gt;
* https://rapidminer.com/&lt;br /&gt;
&lt;br /&gt;
==Tool==&lt;br /&gt;
&lt;br /&gt;
===Open Source===&lt;br /&gt;
&lt;br /&gt;
* https://promtools.org/&lt;br /&gt;
* https://www.processmining.org/&lt;br /&gt;
* https://github.com/pm4py/pm4py-core&lt;br /&gt;
* https://pm4py.fit.fraunhofer.de/&lt;br /&gt;
&lt;br /&gt;
===Non Open Source===&lt;br /&gt;
&lt;br /&gt;
* https://apromore.com/&lt;br /&gt;
* https://documentation.apromore.org/&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* https://github.com/TheWoops/awesome-processmining&lt;br /&gt;
* https://www.xes-standard.org/&lt;br /&gt;
&lt;br /&gt;
==Contoh==&lt;br /&gt;
&lt;br /&gt;
* [[Apromore: Docker Install]]&lt;br /&gt;
* [[pm4py: install]]&lt;br /&gt;
* [[pm4py: beda berbagai model]]&lt;br /&gt;
* [[pm4py: beda masing2 visualisasi]]&lt;br /&gt;
&lt;br /&gt;
* [[pm4py: pm-heuristic.py]]&lt;br /&gt;
* [[pm4py: pm-dfg.py]]&lt;br /&gt;
* [[pm4py: pm-bpmn.py]]&lt;br /&gt;
* [[pm4py: pd-heuristic.py]]&lt;br /&gt;
* [[pm4py: pd-dfg.py]]&lt;br /&gt;
* [[pm4py: pd-bpmn.py]]&lt;br /&gt;
* [[pm4py: deteksi bottleneck]]&lt;br /&gt;
* [[pm4py: ilp_miner]]&lt;br /&gt;
* [[prom: install]]&lt;br /&gt;
* [[pm4py: contoh minimal dari csv]]&lt;br /&gt;
* [[pm4py: contoh minimal dari xes]]&lt;br /&gt;
* [[pm4py: analisa bottleneck dari csv]]&lt;br /&gt;
* [[pm4py: analisa bottleneck dari xes]]&lt;br /&gt;
* [[pm4py: analisa performance dari xes]]&lt;br /&gt;
* [[pm4py: COLLAB: source sederhana data csv]]&lt;br /&gt;
* [[pm4py: COLLAB: analisa bottleneck dari csv]]&lt;br /&gt;
* [[pm4py: Animasi sebaiknya pakai ProM]]&lt;br /&gt;
&lt;br /&gt;
==Referensi / Buku==&lt;br /&gt;
&lt;br /&gt;
* [https://fluxicon.com/book/read/# Process Mining in Practice]&lt;br /&gt;
* https://research.aimultiple.com/open-source-process-mining/&lt;br /&gt;
* https://fmannhardt.de/blog/&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73687</id>
		<title>ML: Python Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73687"/>
		<updated>2026-06-28T08:24:10Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 9. Daftarkan kernel Jupyter */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Install Miniconda di Ubuntu 26.04 bisa langsung di home folder, '''tidak perlu `sudo`'''. Ini cocok untuk kasus Bapak karena `apt` tidak menyediakan Python 3.12, sedangkan TensorFlow belum cocok dengan Python 3.14.&lt;br /&gt;
&lt;br /&gt;
Miniconda adalah installer minimal untuk `conda`, Python, dan paket dasar saja. ([Anaconda][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency dasar==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Download installer Miniconda==&lt;br /&gt;
&lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Ini sesuai pola installer Linux resmi: `Miniconda3-latest-Linux-x86_64.sh`. Dokumentasi conda juga menjelaskan installer Linux dijalankan dengan format `bash &amp;lt;conda-installer-name&amp;gt;-latest-Linux-x86_64.sh`. ([Conda Documentation][2])&lt;br /&gt;
&lt;br /&gt;
== 3. Jalankan installer==&lt;br /&gt;
&lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Saat muncul pertanyaan:&lt;br /&gt;
&lt;br /&gt;
 Please, press ENTER to continue&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat muncul lisensi, tekan `q` untuk keluar dari tampilan lisensi, lalu ketik:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
Saat ditanya lokasi instalasi, terima default:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/miniconda3&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat ditanya:&lt;br /&gt;
&lt;br /&gt;
 Do you wish to update your shell profile to automatically initialize conda?&lt;br /&gt;
&lt;br /&gt;
Pilih:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
== 4. Aktifkan conda==&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan:&lt;br /&gt;
&lt;br /&gt;
 source ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 conda --version&lt;br /&gt;
&lt;br /&gt;
Kalau keluar seperti:&lt;br /&gt;
&lt;br /&gt;
 conda 25.x.x&lt;br /&gt;
&lt;br /&gt;
berarti sukses.&lt;br /&gt;
&lt;br /&gt;
== 5. Matikan auto-activate base==&lt;br /&gt;
&lt;br /&gt;
Saya sarankan supaya terminal tidak selalu masuk environment `(base)`:&lt;br /&gt;
&lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Kalau ingin mengaktifkan conda manual:&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
&lt;br /&gt;
== 6. Buat environment Python 3.12 untuk ML/TensorFlow==&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 python --version&lt;br /&gt;
&lt;br /&gt;
Harus Python 3.12.x.&lt;br /&gt;
&lt;br /&gt;
== 7. Install paket machine learning==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install \&lt;br /&gt;
   numpy \&lt;br /&gt;
   pandas \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   tensorflow \&lt;br /&gt;
   keras \&lt;br /&gt;
   jupyter \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel&lt;br /&gt;
&lt;br /&gt;
== 8. Test TensorFlow==&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Cek GPU:&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== 9. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 python -m ipykernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Jalankan Jupyter:&lt;br /&gt;
&lt;br /&gt;
 jupyter notebook&lt;br /&gt;
&lt;br /&gt;
== Versi cepat: copy-paste==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
 &lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
 &lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh &lt;br /&gt;
 &lt;br /&gt;
 source ~/.bashrc &lt;br /&gt;
 &lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
 &lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install numpy pandas matplotlib scikit-learn tensorflow keras jupyter notebook ipykernel &lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
 python -m ipykernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://www.anaconda.com/download?utm_source=chatgpt.com &amp;quot;Download Anaconda Distribution&amp;quot;&lt;br /&gt;
 [2]: https://docs.conda.io/projects/conda/en/latest/user-guide/install/linux.html?utm_source=chatgpt.com &amp;quot;Installing on Linux — conda 26.5.4.dev62 documentation&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73686</id>
		<title>ML: Python Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73686"/>
		<updated>2026-06-28T08:21:53Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 5. Matikan auto-activate base */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Install Miniconda di Ubuntu 26.04 bisa langsung di home folder, '''tidak perlu `sudo`'''. Ini cocok untuk kasus Bapak karena `apt` tidak menyediakan Python 3.12, sedangkan TensorFlow belum cocok dengan Python 3.14.&lt;br /&gt;
&lt;br /&gt;
Miniconda adalah installer minimal untuk `conda`, Python, dan paket dasar saja. ([Anaconda][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency dasar==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Download installer Miniconda==&lt;br /&gt;
&lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Ini sesuai pola installer Linux resmi: `Miniconda3-latest-Linux-x86_64.sh`. Dokumentasi conda juga menjelaskan installer Linux dijalankan dengan format `bash &amp;lt;conda-installer-name&amp;gt;-latest-Linux-x86_64.sh`. ([Conda Documentation][2])&lt;br /&gt;
&lt;br /&gt;
== 3. Jalankan installer==&lt;br /&gt;
&lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Saat muncul pertanyaan:&lt;br /&gt;
&lt;br /&gt;
 Please, press ENTER to continue&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat muncul lisensi, tekan `q` untuk keluar dari tampilan lisensi, lalu ketik:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
Saat ditanya lokasi instalasi, terima default:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/miniconda3&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat ditanya:&lt;br /&gt;
&lt;br /&gt;
 Do you wish to update your shell profile to automatically initialize conda?&lt;br /&gt;
&lt;br /&gt;
Pilih:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
== 4. Aktifkan conda==&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan:&lt;br /&gt;
&lt;br /&gt;
 source ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 conda --version&lt;br /&gt;
&lt;br /&gt;
Kalau keluar seperti:&lt;br /&gt;
&lt;br /&gt;
 conda 25.x.x&lt;br /&gt;
&lt;br /&gt;
berarti sukses.&lt;br /&gt;
&lt;br /&gt;
== 5. Matikan auto-activate base==&lt;br /&gt;
&lt;br /&gt;
Saya sarankan supaya terminal tidak selalu masuk environment `(base)`:&lt;br /&gt;
&lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Kalau ingin mengaktifkan conda manual:&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
&lt;br /&gt;
== 6. Buat environment Python 3.12 untuk ML/TensorFlow==&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 python --version&lt;br /&gt;
&lt;br /&gt;
Harus Python 3.12.x.&lt;br /&gt;
&lt;br /&gt;
== 7. Install paket machine learning==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install \&lt;br /&gt;
   numpy \&lt;br /&gt;
   pandas \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   tensorflow \&lt;br /&gt;
   keras \&lt;br /&gt;
   jupyter \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel&lt;br /&gt;
&lt;br /&gt;
== 8. Test TensorFlow==&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Cek GPU:&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== 9. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 kernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Jalankan Jupyter:&lt;br /&gt;
&lt;br /&gt;
 jupyter notebook&lt;br /&gt;
&lt;br /&gt;
== Versi cepat: copy-paste==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
 &lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
 &lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh &lt;br /&gt;
 &lt;br /&gt;
 source ~/.bashrc &lt;br /&gt;
 &lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
 &lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install numpy pandas matplotlib scikit-learn tensorflow keras jupyter notebook ipykernel &lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
 python -m ipykernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://www.anaconda.com/download?utm_source=chatgpt.com &amp;quot;Download Anaconda Distribution&amp;quot;&lt;br /&gt;
 [2]: https://docs.conda.io/projects/conda/en/latest/user-guide/install/linux.html?utm_source=chatgpt.com &amp;quot;Installing on Linux — conda 26.5.4.dev62 documentation&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73685</id>
		<title>ML: Python Virtual Environment</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment&amp;diff=73685"/>
		<updated>2026-06-28T08:21:34Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Install Miniconda di Ubuntu 26.04 bisa langsung di home folder, '''tidak perlu `sudo`'''. Ini cocok untuk kasus Bapak karena `apt` tidak menyediakan Python 3.12, sedangkan TensorFlow belum cocok dengan Python 3.14.&lt;br /&gt;
&lt;br /&gt;
Miniconda adalah installer minimal untuk `conda`, Python, dan paket dasar saja. ([Anaconda][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency dasar==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 2. Download installer Miniconda==&lt;br /&gt;
&lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Ini sesuai pola installer Linux resmi: `Miniconda3-latest-Linux-x86_64.sh`. Dokumentasi conda juga menjelaskan installer Linux dijalankan dengan format `bash &amp;lt;conda-installer-name&amp;gt;-latest-Linux-x86_64.sh`. ([Conda Documentation][2])&lt;br /&gt;
&lt;br /&gt;
== 3. Jalankan installer==&lt;br /&gt;
&lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
&lt;br /&gt;
Saat muncul pertanyaan:&lt;br /&gt;
&lt;br /&gt;
 Please, press ENTER to continue&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat muncul lisensi, tekan `q` untuk keluar dari tampilan lisensi, lalu ketik:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
Saat ditanya lokasi instalasi, terima default:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/miniconda3&lt;br /&gt;
&lt;br /&gt;
Tekan '''Enter'''.&lt;br /&gt;
&lt;br /&gt;
Saat ditanya:&lt;br /&gt;
&lt;br /&gt;
 Do you wish to update your shell profile to automatically initialize conda?&lt;br /&gt;
&lt;br /&gt;
Pilih:&lt;br /&gt;
&lt;br /&gt;
 yes&lt;br /&gt;
&lt;br /&gt;
== 4. Aktifkan conda==&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan:&lt;br /&gt;
&lt;br /&gt;
 source ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 conda --version&lt;br /&gt;
&lt;br /&gt;
Kalau keluar seperti:&lt;br /&gt;
&lt;br /&gt;
 conda 25.x.x&lt;br /&gt;
&lt;br /&gt;
berarti sukses.&lt;br /&gt;
&lt;br /&gt;
== 5. Matikan auto-activate base==&lt;br /&gt;
&lt;br /&gt;
Saya sarankan supaya terminal tidak selalu masuk environment `(base)`:&lt;br /&gt;
&lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
&lt;br /&gt;
Tutup terminal lalu buka lagi.&lt;br /&gt;
&lt;br /&gt;
Kalau ingin mengaktifkan conda manual:&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
&lt;br /&gt;
== 6. Buat environment Python 3.12 untuk ML/TensorFlow&lt;br /&gt;
&lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 python --version&lt;br /&gt;
&lt;br /&gt;
Harus Python 3.12.x.&lt;br /&gt;
&lt;br /&gt;
== 7. Install paket machine learning==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install \&lt;br /&gt;
   numpy \&lt;br /&gt;
   pandas \&lt;br /&gt;
   matplotlib \&lt;br /&gt;
   scikit-learn \&lt;br /&gt;
   tensorflow \&lt;br /&gt;
   keras \&lt;br /&gt;
   jupyter \&lt;br /&gt;
   notebook \&lt;br /&gt;
   ipykernel&lt;br /&gt;
&lt;br /&gt;
== 8. Test TensorFlow==&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Cek GPU:&lt;br /&gt;
&lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))&amp;quot;&lt;br /&gt;
&lt;br /&gt;
== 9. Daftarkan kernel Jupyter==&lt;br /&gt;
&lt;br /&gt;
 kernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Jalankan Jupyter:&lt;br /&gt;
&lt;br /&gt;
 jupyter notebook&lt;br /&gt;
&lt;br /&gt;
== Versi cepat: copy-paste==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y wget curl bzip2 ca-certificates&lt;br /&gt;
 &lt;br /&gt;
 cd ~/Downloads&lt;br /&gt;
 wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh&lt;br /&gt;
 &lt;br /&gt;
 bash Miniconda3-latest-Linux-x86_64.sh &lt;br /&gt;
 &lt;br /&gt;
 source ~/.bashrc &lt;br /&gt;
 &lt;br /&gt;
 conda config --set auto_activate_base false&lt;br /&gt;
 &lt;br /&gt;
 source ~/miniconda3/etc/profile.d/conda.sh&lt;br /&gt;
 &lt;br /&gt;
 conda create -y -n python-ml python=3.12&lt;br /&gt;
 conda activate python-ml&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install numpy pandas matplotlib scikit-learn tensorflow keras jupyter notebook ipykernel &lt;br /&gt;
 &lt;br /&gt;
 python -c &amp;quot;import tensorflow as tf; print(tf.__version__)&amp;quot;&lt;br /&gt;
 python -m ipykernel install --user --name python-ml --display-name &amp;quot;Python ML TensorFlow&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://www.anaconda.com/download?utm_source=chatgpt.com &amp;quot;Download Anaconda Distribution&amp;quot;&lt;br /&gt;
 [2]: https://docs.conda.io/projects/conda/en/latest/user-guide/install/linux.html?utm_source=chatgpt.com &amp;quot;Installing on Linux — conda 26.5.4.dev62 documentation&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73684</id>
		<title>GNS3: Instalasi di Ubuntu 26.04 + VENV + docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73684"/>
		<updated>2026-06-28T08:01:30Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 4. Upgrade pip */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 server''', tetapi emulator seperti '''QEMU/KVM, Dynamips, uBridge, VPCS, Wireshark, Docker''' tetap lebih aman dipasang dari package OS. GNS3 server memang bertugas mengelola QEMU/KVM, Docker, VPCS, VirtualBox, VMware, dan Dynamips. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency OS==&lt;br /&gt;
&lt;br /&gt;
Untuk Ubuntu/Debian:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y \&lt;br /&gt;
   qemu-system-x86 \&lt;br /&gt;
   qemu-utils \&lt;br /&gt;
   libvirt-daemon-system \&lt;br /&gt;
   libvirt-clients \&lt;br /&gt;
   bridge-utils \&lt;br /&gt;
   virtinst \&lt;br /&gt;
   cpu-checker \&lt;br /&gt;
   wireshark \&lt;br /&gt;
   dynamips \&lt;br /&gt;
   vpcs&lt;br /&gt;
&lt;br /&gt;
Tambahkan user ke grup yang diperlukan:&lt;br /&gt;
&lt;br /&gt;
 sudo usermod -aG kvm,libvirt,wireshark,docker $USER&lt;br /&gt;
&lt;br /&gt;
Logout-login dulu setelah perintah di atas, atau reboot:&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja GNS3==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
== 3. Buat Python virtual environment==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Pastikan prompt berubah, biasanya ada `(venv)`.&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install --upgrade PyQt6 PyQt6-sip sip PyQt6-WebEngine&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
 SITEPKG=$(python -c &amp;quot;import site; print(site.getsitepackages()[0])&amp;quot;)&lt;br /&gt;
 &lt;br /&gt;
 cat &amp;gt; &amp;quot;$SITEPKG/sip.py&amp;quot; &amp;lt;&amp;lt;'EOF'&lt;br /&gt;
 from PyQt6.sip import *&lt;br /&gt;
 EOF&lt;br /&gt;
&lt;br /&gt;
== 5. Install GNS3 GUI dan server==&lt;br /&gt;
&lt;br /&gt;
Versi PyPI terbaru yang terlihat saat ini adalah '''gns3-gui 3.0.6''', dirilis 28 Januari 2026. ([PyPI][2])&lt;br /&gt;
GNS3 juga menyatakan instalasi dari PyPI bisa dilakukan dengan `pip install gns3-gui` dan `gns3-server`; contoh rilis 3.0 memakai `gns3-gui==3.0.5` dan `gns3-server==3.0.5`. ([GNS3][3])&lt;br /&gt;
&lt;br /&gt;
Install versi terbaru:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
&lt;br /&gt;
Atau kalau ingin versi dikunci supaya GUI dan server tidak mismatch:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui==3.0.6 gns3-server==3.0.6&lt;br /&gt;
&lt;br /&gt;
Cek hasil instalasi:&lt;br /&gt;
&lt;br /&gt;
 gns3 --version&lt;br /&gt;
 gns3server --version&lt;br /&gt;
&lt;br /&gt;
== 6. Jalankan GNS3==&lt;br /&gt;
&lt;br /&gt;
Aktifkan dulu venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Jalankan server:&lt;br /&gt;
&lt;br /&gt;
 gns3server&lt;br /&gt;
&lt;br /&gt;
Di terminal lain, aktifkan venv lagi:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan GUI saja:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/venv/bin/gns3&lt;br /&gt;
&lt;br /&gt;
== 7. Buat script launcher supaya mudah==&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
 nano ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 *!/usr/bin/env bash&lt;br /&gt;
 cd ~/Apps/GNS3 || exit 1&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Simpan, lalu:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
== 8. Buat shortcut desktop==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/.local/share/applications&lt;br /&gt;
 nano ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Name=GNS3 VENV&lt;br /&gt;
 Comment=Run GNS3 from ~/Apps/GNS3 Python virtual environment&lt;br /&gt;
 Exec=/home/onno/Apps/GNS3/start-gns3.sh&lt;br /&gt;
 Icon=gns3&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Categories=Network;Education;&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
 update-desktop-database ~/.local/share/applications 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
== 9. Struktur folder yang disarankan&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── start-gns3.sh&lt;br /&gt;
 ├── projects/&lt;br /&gt;
 ├── images/&lt;br /&gt;
 └── appliances/&lt;br /&gt;
&lt;br /&gt;
Buat foldernya:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3/projects ~/Apps/GNS3/images ~/Apps/GNS3/appliances&lt;br /&gt;
&lt;br /&gt;
Di dalam GNS3 GUI, arahkan path project ke:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/Apps/GNS3/projects&lt;br /&gt;
&lt;br /&gt;
== 10. Kalau error PyQt&lt;br /&gt;
&lt;br /&gt;
Kalau muncul error seperti modul Qt/PyQt tidak ditemukan, coba:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 python -m pip install PyQt6 PyQt6-Sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
Lalu jalankan lagi:&lt;br /&gt;
&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
== 11. Kalau QEMU/KVM tidak jalan==&lt;br /&gt;
&lt;br /&gt;
Cek KVM:&lt;br /&gt;
&lt;br /&gt;
 ls -l /dev/kvm&lt;br /&gt;
 groups&lt;br /&gt;
&lt;br /&gt;
Pastikan user ada di grup `kvm` dan `libvirt`.&lt;br /&gt;
&lt;br /&gt;
Tes QEMU:&lt;br /&gt;
&lt;br /&gt;
 qemu-system-x86_64 --version&lt;br /&gt;
&lt;br /&gt;
Cek libvirt:&lt;br /&gt;
&lt;br /&gt;
 systemctl status libvirtd&lt;br /&gt;
&lt;br /&gt;
Kalau belum aktif:&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable --now libvirtd&lt;br /&gt;
&lt;br /&gt;
== 12. Perintah uninstall&lt;br /&gt;
&lt;br /&gt;
Kalau ingin hapus instalasi venv GNS3:&lt;br /&gt;
&lt;br /&gt;
 rm -rf ~/Apps/GNS3/venv&lt;br /&gt;
 rm -f ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Package OS seperti QEMU/Wireshark tidak ikut terhapus.&lt;br /&gt;
&lt;br /&gt;
== Ringkasnya==&lt;br /&gt;
&lt;br /&gt;
Paling penting:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Untuk penggunaan serius, tetap install juga:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install qemu-kvm wireshark dynamips vpcs ubridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://pypi.org/project/gns3-server/?utm_source=chatgpt.com &amp;quot;gns3-server&amp;quot;&lt;br /&gt;
 [2]: https://pypi.org/project/gns3-gui/?utm_source=chatgpt.com &amp;quot;gns3-gui&amp;quot;&lt;br /&gt;
 [3]: https://gns3.com/gns3-3-0-released?utm_source=chatgpt.com &amp;quot;GNS3 3.0 Released!&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73683</id>
		<title>GNS3: Instalasi di Ubuntu 26.04 + VENV + docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73683"/>
		<updated>2026-06-28T07:59:07Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 4. Upgrade pip */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 server''', tetapi emulator seperti '''QEMU/KVM, Dynamips, uBridge, VPCS, Wireshark, Docker''' tetap lebih aman dipasang dari package OS. GNS3 server memang bertugas mengelola QEMU/KVM, Docker, VPCS, VirtualBox, VMware, dan Dynamips. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency OS==&lt;br /&gt;
&lt;br /&gt;
Untuk Ubuntu/Debian:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y \&lt;br /&gt;
   qemu-system-x86 \&lt;br /&gt;
   qemu-utils \&lt;br /&gt;
   libvirt-daemon-system \&lt;br /&gt;
   libvirt-clients \&lt;br /&gt;
   bridge-utils \&lt;br /&gt;
   virtinst \&lt;br /&gt;
   cpu-checker \&lt;br /&gt;
   wireshark \&lt;br /&gt;
   dynamips \&lt;br /&gt;
   vpcs&lt;br /&gt;
&lt;br /&gt;
Tambahkan user ke grup yang diperlukan:&lt;br /&gt;
&lt;br /&gt;
 sudo usermod -aG kvm,libvirt,wireshark,docker $USER&lt;br /&gt;
&lt;br /&gt;
Logout-login dulu setelah perintah di atas, atau reboot:&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja GNS3==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
== 3. Buat Python virtual environment==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Pastikan prompt berubah, biasanya ada `(venv)`.&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install --upgrade PyQt6 PyQt6-sip sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
== 5. Install GNS3 GUI dan server==&lt;br /&gt;
&lt;br /&gt;
Versi PyPI terbaru yang terlihat saat ini adalah '''gns3-gui 3.0.6''', dirilis 28 Januari 2026. ([PyPI][2])&lt;br /&gt;
GNS3 juga menyatakan instalasi dari PyPI bisa dilakukan dengan `pip install gns3-gui` dan `gns3-server`; contoh rilis 3.0 memakai `gns3-gui==3.0.5` dan `gns3-server==3.0.5`. ([GNS3][3])&lt;br /&gt;
&lt;br /&gt;
Install versi terbaru:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
&lt;br /&gt;
Atau kalau ingin versi dikunci supaya GUI dan server tidak mismatch:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui==3.0.6 gns3-server==3.0.6&lt;br /&gt;
&lt;br /&gt;
Cek hasil instalasi:&lt;br /&gt;
&lt;br /&gt;
 gns3 --version&lt;br /&gt;
 gns3server --version&lt;br /&gt;
&lt;br /&gt;
== 6. Jalankan GNS3==&lt;br /&gt;
&lt;br /&gt;
Aktifkan dulu venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Jalankan server:&lt;br /&gt;
&lt;br /&gt;
 gns3server&lt;br /&gt;
&lt;br /&gt;
Di terminal lain, aktifkan venv lagi:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan GUI saja:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/venv/bin/gns3&lt;br /&gt;
&lt;br /&gt;
== 7. Buat script launcher supaya mudah==&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
 nano ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 *!/usr/bin/env bash&lt;br /&gt;
 cd ~/Apps/GNS3 || exit 1&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Simpan, lalu:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
== 8. Buat shortcut desktop==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/.local/share/applications&lt;br /&gt;
 nano ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Name=GNS3 VENV&lt;br /&gt;
 Comment=Run GNS3 from ~/Apps/GNS3 Python virtual environment&lt;br /&gt;
 Exec=/home/onno/Apps/GNS3/start-gns3.sh&lt;br /&gt;
 Icon=gns3&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Categories=Network;Education;&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
 update-desktop-database ~/.local/share/applications 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
== 9. Struktur folder yang disarankan&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── start-gns3.sh&lt;br /&gt;
 ├── projects/&lt;br /&gt;
 ├── images/&lt;br /&gt;
 └── appliances/&lt;br /&gt;
&lt;br /&gt;
Buat foldernya:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3/projects ~/Apps/GNS3/images ~/Apps/GNS3/appliances&lt;br /&gt;
&lt;br /&gt;
Di dalam GNS3 GUI, arahkan path project ke:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/Apps/GNS3/projects&lt;br /&gt;
&lt;br /&gt;
== 10. Kalau error PyQt&lt;br /&gt;
&lt;br /&gt;
Kalau muncul error seperti modul Qt/PyQt tidak ditemukan, coba:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 python -m pip install PyQt6 PyQt6-Sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
Lalu jalankan lagi:&lt;br /&gt;
&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
== 11. Kalau QEMU/KVM tidak jalan==&lt;br /&gt;
&lt;br /&gt;
Cek KVM:&lt;br /&gt;
&lt;br /&gt;
 ls -l /dev/kvm&lt;br /&gt;
 groups&lt;br /&gt;
&lt;br /&gt;
Pastikan user ada di grup `kvm` dan `libvirt`.&lt;br /&gt;
&lt;br /&gt;
Tes QEMU:&lt;br /&gt;
&lt;br /&gt;
 qemu-system-x86_64 --version&lt;br /&gt;
&lt;br /&gt;
Cek libvirt:&lt;br /&gt;
&lt;br /&gt;
 systemctl status libvirtd&lt;br /&gt;
&lt;br /&gt;
Kalau belum aktif:&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable --now libvirtd&lt;br /&gt;
&lt;br /&gt;
== 12. Perintah uninstall&lt;br /&gt;
&lt;br /&gt;
Kalau ingin hapus instalasi venv GNS3:&lt;br /&gt;
&lt;br /&gt;
 rm -rf ~/Apps/GNS3/venv&lt;br /&gt;
 rm -f ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Package OS seperti QEMU/Wireshark tidak ikut terhapus.&lt;br /&gt;
&lt;br /&gt;
== Ringkasnya==&lt;br /&gt;
&lt;br /&gt;
Paling penting:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Untuk penggunaan serius, tetap install juga:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install qemu-kvm wireshark dynamips vpcs ubridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://pypi.org/project/gns3-server/?utm_source=chatgpt.com &amp;quot;gns3-server&amp;quot;&lt;br /&gt;
 [2]: https://pypi.org/project/gns3-gui/?utm_source=chatgpt.com &amp;quot;gns3-gui&amp;quot;&lt;br /&gt;
 [3]: https://gns3.com/gns3-3-0-released?utm_source=chatgpt.com &amp;quot;GNS3 3.0 Released!&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73682</id>
		<title>GNS3: Instalasi di Ubuntu 26.04 + VENV + docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73682"/>
		<updated>2026-06-28T07:56:08Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 4. Upgrade pip */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 server''', tetapi emulator seperti '''QEMU/KVM, Dynamips, uBridge, VPCS, Wireshark, Docker''' tetap lebih aman dipasang dari package OS. GNS3 server memang bertugas mengelola QEMU/KVM, Docker, VPCS, VirtualBox, VMware, dan Dynamips. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency OS==&lt;br /&gt;
&lt;br /&gt;
Untuk Ubuntu/Debian:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y \&lt;br /&gt;
   qemu-system-x86 \&lt;br /&gt;
   qemu-utils \&lt;br /&gt;
   libvirt-daemon-system \&lt;br /&gt;
   libvirt-clients \&lt;br /&gt;
   bridge-utils \&lt;br /&gt;
   virtinst \&lt;br /&gt;
   cpu-checker \&lt;br /&gt;
   wireshark \&lt;br /&gt;
   dynamips \&lt;br /&gt;
   vpcs&lt;br /&gt;
&lt;br /&gt;
Tambahkan user ke grup yang diperlukan:&lt;br /&gt;
&lt;br /&gt;
 sudo usermod -aG kvm,libvirt,wireshark,docker $USER&lt;br /&gt;
&lt;br /&gt;
Logout-login dulu setelah perintah di atas, atau reboot:&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja GNS3==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
== 3. Buat Python virtual environment==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Pastikan prompt berubah, biasanya ada `(venv)`.&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install GNS3 GUI dan server==&lt;br /&gt;
&lt;br /&gt;
Versi PyPI terbaru yang terlihat saat ini adalah '''gns3-gui 3.0.6''', dirilis 28 Januari 2026. ([PyPI][2])&lt;br /&gt;
GNS3 juga menyatakan instalasi dari PyPI bisa dilakukan dengan `pip install gns3-gui` dan `gns3-server`; contoh rilis 3.0 memakai `gns3-gui==3.0.5` dan `gns3-server==3.0.5`. ([GNS3][3])&lt;br /&gt;
&lt;br /&gt;
Install versi terbaru:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
&lt;br /&gt;
Atau kalau ingin versi dikunci supaya GUI dan server tidak mismatch:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui==3.0.6 gns3-server==3.0.6&lt;br /&gt;
&lt;br /&gt;
Cek hasil instalasi:&lt;br /&gt;
&lt;br /&gt;
 gns3 --version&lt;br /&gt;
 gns3server --version&lt;br /&gt;
&lt;br /&gt;
== 6. Jalankan GNS3==&lt;br /&gt;
&lt;br /&gt;
Aktifkan dulu venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Jalankan server:&lt;br /&gt;
&lt;br /&gt;
 gns3server&lt;br /&gt;
&lt;br /&gt;
Di terminal lain, aktifkan venv lagi:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan GUI saja:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/venv/bin/gns3&lt;br /&gt;
&lt;br /&gt;
== 7. Buat script launcher supaya mudah==&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
 nano ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 *!/usr/bin/env bash&lt;br /&gt;
 cd ~/Apps/GNS3 || exit 1&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Simpan, lalu:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
== 8. Buat shortcut desktop==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/.local/share/applications&lt;br /&gt;
 nano ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Name=GNS3 VENV&lt;br /&gt;
 Comment=Run GNS3 from ~/Apps/GNS3 Python virtual environment&lt;br /&gt;
 Exec=/home/onno/Apps/GNS3/start-gns3.sh&lt;br /&gt;
 Icon=gns3&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Categories=Network;Education;&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
 update-desktop-database ~/.local/share/applications 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
== 9. Struktur folder yang disarankan&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── start-gns3.sh&lt;br /&gt;
 ├── projects/&lt;br /&gt;
 ├── images/&lt;br /&gt;
 └── appliances/&lt;br /&gt;
&lt;br /&gt;
Buat foldernya:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3/projects ~/Apps/GNS3/images ~/Apps/GNS3/appliances&lt;br /&gt;
&lt;br /&gt;
Di dalam GNS3 GUI, arahkan path project ke:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/Apps/GNS3/projects&lt;br /&gt;
&lt;br /&gt;
== 10. Kalau error PyQt&lt;br /&gt;
&lt;br /&gt;
Kalau muncul error seperti modul Qt/PyQt tidak ditemukan, coba:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 python -m pip install PyQt6 PyQt6-Sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
Lalu jalankan lagi:&lt;br /&gt;
&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
== 11. Kalau QEMU/KVM tidak jalan==&lt;br /&gt;
&lt;br /&gt;
Cek KVM:&lt;br /&gt;
&lt;br /&gt;
 ls -l /dev/kvm&lt;br /&gt;
 groups&lt;br /&gt;
&lt;br /&gt;
Pastikan user ada di grup `kvm` dan `libvirt`.&lt;br /&gt;
&lt;br /&gt;
Tes QEMU:&lt;br /&gt;
&lt;br /&gt;
 qemu-system-x86_64 --version&lt;br /&gt;
&lt;br /&gt;
Cek libvirt:&lt;br /&gt;
&lt;br /&gt;
 systemctl status libvirtd&lt;br /&gt;
&lt;br /&gt;
Kalau belum aktif:&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable --now libvirtd&lt;br /&gt;
&lt;br /&gt;
== 12. Perintah uninstall&lt;br /&gt;
&lt;br /&gt;
Kalau ingin hapus instalasi venv GNS3:&lt;br /&gt;
&lt;br /&gt;
 rm -rf ~/Apps/GNS3/venv&lt;br /&gt;
 rm -f ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Package OS seperti QEMU/Wireshark tidak ikut terhapus.&lt;br /&gt;
&lt;br /&gt;
== Ringkasnya==&lt;br /&gt;
&lt;br /&gt;
Paling penting:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Untuk penggunaan serius, tetap install juga:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install qemu-kvm wireshark dynamips vpcs ubridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://pypi.org/project/gns3-server/?utm_source=chatgpt.com &amp;quot;gns3-server&amp;quot;&lt;br /&gt;
 [2]: https://pypi.org/project/gns3-gui/?utm_source=chatgpt.com &amp;quot;gns3-gui&amp;quot;&lt;br /&gt;
 [3]: https://gns3.com/gns3-3-0-released?utm_source=chatgpt.com &amp;quot;GNS3 3.0 Released!&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73681</id>
		<title>GNS3: Instalasi di Ubuntu 26.04 + VENV + docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73681"/>
		<updated>2026-06-28T07:33:51Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 1. Install dependency OS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 server''', tetapi emulator seperti '''QEMU/KVM, Dynamips, uBridge, VPCS, Wireshark, Docker''' tetap lebih aman dipasang dari package OS. GNS3 server memang bertugas mengelola QEMU/KVM, Docker, VPCS, VirtualBox, VMware, dan Dynamips. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency OS==&lt;br /&gt;
&lt;br /&gt;
Untuk Ubuntu/Debian:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y \&lt;br /&gt;
   qemu-system-x86 \&lt;br /&gt;
   qemu-utils \&lt;br /&gt;
   libvirt-daemon-system \&lt;br /&gt;
   libvirt-clients \&lt;br /&gt;
   bridge-utils \&lt;br /&gt;
   virtinst \&lt;br /&gt;
   cpu-checker \&lt;br /&gt;
   wireshark \&lt;br /&gt;
   dynamips \&lt;br /&gt;
   vpcs&lt;br /&gt;
&lt;br /&gt;
Tambahkan user ke grup yang diperlukan:&lt;br /&gt;
&lt;br /&gt;
 sudo usermod -aG kvm,libvirt,wireshark,docker $USER&lt;br /&gt;
&lt;br /&gt;
Logout-login dulu setelah perintah di atas, atau reboot:&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja GNS3==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
== 3. Buat Python virtual environment==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Pastikan prompt berubah, biasanya ada `(venv)`.&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install GNS3 GUI dan server&lt;br /&gt;
&lt;br /&gt;
Versi PyPI terbaru yang terlihat saat ini adalah '''gns3-gui 3.0.6''', dirilis 28 Januari 2026. ([PyPI][2])&lt;br /&gt;
GNS3 juga menyatakan instalasi dari PyPI bisa dilakukan dengan `pip install gns3-gui` dan `gns3-server`; contoh rilis 3.0 memakai `gns3-gui==3.0.5` dan `gns3-server==3.0.5`. ([GNS3][3])&lt;br /&gt;
&lt;br /&gt;
Install versi terbaru:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
&lt;br /&gt;
Atau kalau ingin versi dikunci supaya GUI dan server tidak mismatch:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui==3.0.6 gns3-server==3.0.6&lt;br /&gt;
&lt;br /&gt;
Cek hasil instalasi:&lt;br /&gt;
&lt;br /&gt;
 gns3 --version&lt;br /&gt;
 gns3server --version&lt;br /&gt;
&lt;br /&gt;
== 6. Jalankan GNS3==&lt;br /&gt;
&lt;br /&gt;
Aktifkan dulu venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Jalankan server:&lt;br /&gt;
&lt;br /&gt;
 gns3server&lt;br /&gt;
&lt;br /&gt;
Di terminal lain, aktifkan venv lagi:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan GUI saja:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/venv/bin/gns3&lt;br /&gt;
&lt;br /&gt;
== 7. Buat script launcher supaya mudah==&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
 nano ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 *!/usr/bin/env bash&lt;br /&gt;
 cd ~/Apps/GNS3 || exit 1&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Simpan, lalu:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
== 8. Buat shortcut desktop==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/.local/share/applications&lt;br /&gt;
 nano ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Name=GNS3 VENV&lt;br /&gt;
 Comment=Run GNS3 from ~/Apps/GNS3 Python virtual environment&lt;br /&gt;
 Exec=/home/onno/Apps/GNS3/start-gns3.sh&lt;br /&gt;
 Icon=gns3&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Categories=Network;Education;&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
 update-desktop-database ~/.local/share/applications 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
== 9. Struktur folder yang disarankan&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── start-gns3.sh&lt;br /&gt;
 ├── projects/&lt;br /&gt;
 ├── images/&lt;br /&gt;
 └── appliances/&lt;br /&gt;
&lt;br /&gt;
Buat foldernya:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3/projects ~/Apps/GNS3/images ~/Apps/GNS3/appliances&lt;br /&gt;
&lt;br /&gt;
Di dalam GNS3 GUI, arahkan path project ke:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/Apps/GNS3/projects&lt;br /&gt;
&lt;br /&gt;
== 10. Kalau error PyQt&lt;br /&gt;
&lt;br /&gt;
Kalau muncul error seperti modul Qt/PyQt tidak ditemukan, coba:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 python -m pip install PyQt6 PyQt6-Sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
Lalu jalankan lagi:&lt;br /&gt;
&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
== 11. Kalau QEMU/KVM tidak jalan==&lt;br /&gt;
&lt;br /&gt;
Cek KVM:&lt;br /&gt;
&lt;br /&gt;
 ls -l /dev/kvm&lt;br /&gt;
 groups&lt;br /&gt;
&lt;br /&gt;
Pastikan user ada di grup `kvm` dan `libvirt`.&lt;br /&gt;
&lt;br /&gt;
Tes QEMU:&lt;br /&gt;
&lt;br /&gt;
 qemu-system-x86_64 --version&lt;br /&gt;
&lt;br /&gt;
Cek libvirt:&lt;br /&gt;
&lt;br /&gt;
 systemctl status libvirtd&lt;br /&gt;
&lt;br /&gt;
Kalau belum aktif:&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable --now libvirtd&lt;br /&gt;
&lt;br /&gt;
== 12. Perintah uninstall&lt;br /&gt;
&lt;br /&gt;
Kalau ingin hapus instalasi venv GNS3:&lt;br /&gt;
&lt;br /&gt;
 rm -rf ~/Apps/GNS3/venv&lt;br /&gt;
 rm -f ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Package OS seperti QEMU/Wireshark tidak ikut terhapus.&lt;br /&gt;
&lt;br /&gt;
== Ringkasnya==&lt;br /&gt;
&lt;br /&gt;
Paling penting:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Untuk penggunaan serius, tetap install juga:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install qemu-kvm wireshark dynamips vpcs ubridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://pypi.org/project/gns3-server/?utm_source=chatgpt.com &amp;quot;gns3-server&amp;quot;&lt;br /&gt;
 [2]: https://pypi.org/project/gns3-gui/?utm_source=chatgpt.com &amp;quot;gns3-gui&amp;quot;&lt;br /&gt;
 [3]: https://gns3.com/gns3-3-0-released?utm_source=chatgpt.com &amp;quot;GNS3 3.0 Released!&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73680</id>
		<title>GNS3: Instalasi di Ubuntu 26.04 + VENV + docker</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=GNS3:_Instalasi_di_Ubuntu_26.04_%2B_VENV_%2B_docker&amp;diff=73680"/>
		<updated>2026-06-28T07:31:40Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: Created page with &amp;quot;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:   ~/Apps/GNS3  Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 ser...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Berikut cara instalasi '''GNS3 di Python virtual environment''' menggunakan folder:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
Catatan penting: instalasi via `pip/venv` cocok untuk '''GNS3 GUI + GNS3 server''', tetapi emulator seperti '''QEMU/KVM, Dynamips, uBridge, VPCS, Wireshark, Docker''' tetap lebih aman dipasang dari package OS. GNS3 server memang bertugas mengelola QEMU/KVM, Docker, VPCS, VirtualBox, VMware, dan Dynamips. ([PyPI][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install dependency OS==&lt;br /&gt;
&lt;br /&gt;
Untuk Ubuntu/Debian:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install -y \&lt;br /&gt;
   python3 \&lt;br /&gt;
   python3-pip \&lt;br /&gt;
   python3-venv \&lt;br /&gt;
   python3-dev \&lt;br /&gt;
   python3-pyqt6 \&lt;br /&gt;
   python3-pyqt6.qtsvg \&lt;br /&gt;
   python3-pyqt6.qtwebsockets \&lt;br /&gt;
   qemu-kvm \&lt;br /&gt;
   libvirt-daemon-system \&lt;br /&gt;
   libvirt-clients \&lt;br /&gt;
   bridge-utils \&lt;br /&gt;
   wireshark \&lt;br /&gt;
   dynamips \&lt;br /&gt;
   vpcs \&lt;br /&gt;
   ubridge&lt;br /&gt;
&lt;br /&gt;
Tambahkan user ke grup yang diperlukan:&lt;br /&gt;
&lt;br /&gt;
 sudo usermod -aG kvm,libvirt,wireshark,docker $USER&lt;br /&gt;
&lt;br /&gt;
Logout-login dulu setelah perintah di atas, atau reboot:&lt;br /&gt;
&lt;br /&gt;
 reboot&lt;br /&gt;
&lt;br /&gt;
== 2. Buat folder kerja GNS3==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
&lt;br /&gt;
== 3. Buat Python virtual environment==&lt;br /&gt;
&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
&lt;br /&gt;
Aktifkan venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Pastikan prompt berubah, biasanya ada `(venv)`.&lt;br /&gt;
&lt;br /&gt;
== 4. Upgrade pip==&lt;br /&gt;
&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
&lt;br /&gt;
== 5. Install GNS3 GUI dan server&lt;br /&gt;
&lt;br /&gt;
Versi PyPI terbaru yang terlihat saat ini adalah '''gns3-gui 3.0.6''', dirilis 28 Januari 2026. ([PyPI][2])&lt;br /&gt;
GNS3 juga menyatakan instalasi dari PyPI bisa dilakukan dengan `pip install gns3-gui` dan `gns3-server`; contoh rilis 3.0 memakai `gns3-gui==3.0.5` dan `gns3-server==3.0.5`. ([GNS3][3])&lt;br /&gt;
&lt;br /&gt;
Install versi terbaru:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
&lt;br /&gt;
Atau kalau ingin versi dikunci supaya GUI dan server tidak mismatch:&lt;br /&gt;
&lt;br /&gt;
 python -m pip install gns3-gui==3.0.6 gns3-server==3.0.6&lt;br /&gt;
&lt;br /&gt;
Cek hasil instalasi:&lt;br /&gt;
&lt;br /&gt;
 gns3 --version&lt;br /&gt;
 gns3server --version&lt;br /&gt;
&lt;br /&gt;
== 6. Jalankan GNS3==&lt;br /&gt;
&lt;br /&gt;
Aktifkan dulu venv:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
&lt;br /&gt;
Jalankan server:&lt;br /&gt;
&lt;br /&gt;
 gns3server&lt;br /&gt;
&lt;br /&gt;
Di terminal lain, aktifkan venv lagi:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Atau langsung jalankan GUI saja:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/venv/bin/gns3&lt;br /&gt;
&lt;br /&gt;
== 7. Buat script launcher supaya mudah==&lt;br /&gt;
&lt;br /&gt;
Buat file:&lt;br /&gt;
&lt;br /&gt;
 nano ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 *!/usr/bin/env bash&lt;br /&gt;
 cd ~/Apps/GNS3 || exit 1&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Simpan, lalu:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
Jalankan:&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/start-gns3.sh&lt;br /&gt;
&lt;br /&gt;
== 8. Buat shortcut desktop==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/.local/share/applications&lt;br /&gt;
 nano ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Isi:&lt;br /&gt;
&lt;br /&gt;
 [Desktop Entry]&lt;br /&gt;
 Name=GNS3 VENV&lt;br /&gt;
 Comment=Run GNS3 from ~/Apps/GNS3 Python virtual environment&lt;br /&gt;
 Exec=/home/onno/Apps/GNS3/start-gns3.sh&lt;br /&gt;
 Icon=gns3&lt;br /&gt;
 Terminal=false&lt;br /&gt;
 Type=Application&lt;br /&gt;
 Categories=Network;Education;&lt;br /&gt;
&lt;br /&gt;
Aktifkan:&lt;br /&gt;
&lt;br /&gt;
 chmod +x ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
 update-desktop-database ~/.local/share/applications 2&amp;gt;/dev/null&lt;br /&gt;
&lt;br /&gt;
== 9. Struktur folder yang disarankan&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 ~/Apps/GNS3/&lt;br /&gt;
 ├── venv/&lt;br /&gt;
 ├── start-gns3.sh&lt;br /&gt;
 ├── projects/&lt;br /&gt;
 ├── images/&lt;br /&gt;
 └── appliances/&lt;br /&gt;
&lt;br /&gt;
Buat foldernya:&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3/projects ~/Apps/GNS3/images ~/Apps/GNS3/appliances&lt;br /&gt;
&lt;br /&gt;
Di dalam GNS3 GUI, arahkan path project ke:&lt;br /&gt;
&lt;br /&gt;
 /home/onno/Apps/GNS3/projects&lt;br /&gt;
&lt;br /&gt;
== 10. Kalau error PyQt&lt;br /&gt;
&lt;br /&gt;
Kalau muncul error seperti modul Qt/PyQt tidak ditemukan, coba:&lt;br /&gt;
&lt;br /&gt;
 source ~/Apps/GNS3/venv/bin/activate&lt;br /&gt;
 python -m pip install PyQt6 PyQt6-Sip PyQt6-WebEngine&lt;br /&gt;
&lt;br /&gt;
Lalu jalankan lagi:&lt;br /&gt;
&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
== 11. Kalau QEMU/KVM tidak jalan==&lt;br /&gt;
&lt;br /&gt;
Cek KVM:&lt;br /&gt;
&lt;br /&gt;
 ls -l /dev/kvm&lt;br /&gt;
 groups&lt;br /&gt;
&lt;br /&gt;
Pastikan user ada di grup `kvm` dan `libvirt`.&lt;br /&gt;
&lt;br /&gt;
Tes QEMU:&lt;br /&gt;
&lt;br /&gt;
 qemu-system-x86_64 --version&lt;br /&gt;
&lt;br /&gt;
Cek libvirt:&lt;br /&gt;
&lt;br /&gt;
 systemctl status libvirtd&lt;br /&gt;
&lt;br /&gt;
Kalau belum aktif:&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable --now libvirtd&lt;br /&gt;
&lt;br /&gt;
== 12. Perintah uninstall&lt;br /&gt;
&lt;br /&gt;
Kalau ingin hapus instalasi venv GNS3:&lt;br /&gt;
&lt;br /&gt;
 rm -rf ~/Apps/GNS3/venv&lt;br /&gt;
 rm -f ~/.local/share/applications/gns3-venv.desktop&lt;br /&gt;
&lt;br /&gt;
Package OS seperti QEMU/Wireshark tidak ikut terhapus.&lt;br /&gt;
&lt;br /&gt;
== Ringkasnya==&lt;br /&gt;
&lt;br /&gt;
Paling penting:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/GNS3&lt;br /&gt;
 cd ~/Apps/GNS3&lt;br /&gt;
 python3 -m venv venv&lt;br /&gt;
 source venv/bin/activate&lt;br /&gt;
 python -m pip install --upgrade pip setuptools wheel&lt;br /&gt;
 python -m pip install gns3-gui gns3-server&lt;br /&gt;
 gns3&lt;br /&gt;
&lt;br /&gt;
Untuk penggunaan serius, tetap install juga:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install qemu-kvm wireshark dynamips vpcs ubridge&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 [1]: https://pypi.org/project/gns3-server/?utm_source=chatgpt.com &amp;quot;gns3-server&amp;quot;&lt;br /&gt;
 [2]: https://pypi.org/project/gns3-gui/?utm_source=chatgpt.com &amp;quot;gns3-gui&amp;quot;&lt;br /&gt;
 [3]: https://gns3.com/gns3-3-0-released?utm_source=chatgpt.com &amp;quot;GNS3 3.0 Released!&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=Gns3&amp;diff=73679</id>
		<title>Gns3</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=Gns3&amp;diff=73679"/>
		<updated>2026-06-28T07:27:01Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* Instalasi */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;GNS3 adalah simulator jaringan grafis yang memungkinkan anda untuk merancang topologi jaringan yang kompleks. Anda dapat menjalankan simulasi atau mengkonfigurasi perangkat mulai dari workstation sederhana hingga  router yang powerfull seperti Cisco. Hal ini didasarkan pada Dynamips, Pemu/Qemu dan Dynagen.&lt;br /&gt;
&lt;br /&gt;
==Lebih Lanjut==&lt;br /&gt;
&lt;br /&gt;
===Menyiapkan Image Router dan Server===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: Download]]&lt;br /&gt;
* [[GNS3: Cisco Download]]&lt;br /&gt;
* [[GNS3: Juniper Download]]&lt;br /&gt;
* [[GNS3: Mikrotik Download]]&lt;br /&gt;
* [[GNS3: OpenWRT Download]]&lt;br /&gt;
* [[GNS3: Appliance]]&lt;br /&gt;
* [[GNS3: Download Image Ubuntu untuk Qemu]]&lt;br /&gt;
* [[GNS3: Port socat pada Ubuntu Image agar bisa di remote di GNS3]]&lt;br /&gt;
* [[GNS3: Membuat Image OpenWRT untuk VirtualBox]]&lt;br /&gt;
* [[GNS3: Menambahkan Image OpenWRT di VirtualBox]]&lt;br /&gt;
* [[GNS3: Menambahkan Image Ubuntu Server di VirtualBox]]&lt;br /&gt;
&lt;br /&gt;
===Instalasi===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: Instalasi]]&lt;br /&gt;
* [[GNS3: Instalasi di Ubuntu 22.04]]&lt;br /&gt;
* [[GNS3: Instalasi di Ubuntu 24.04]]&lt;br /&gt;
* [[GNS3: Instalasi di Ubuntu 26.04]]&lt;br /&gt;
* [[GNS3: Instalasi di Ubuntu 26.04 + VENV + docker]]&lt;br /&gt;
* [[GNS3: Reset]]&lt;br /&gt;
* [[GNS3: Router fisik dekat PC running GNS3]]&lt;br /&gt;
* [[GNS3: remove purge]]&lt;br /&gt;
* [[GNS3: Edit Preferences untuk VirtualBox]]&lt;br /&gt;
* [[GNS3: Edit Preferences untuk Qemu]]&lt;br /&gt;
* [[GNS3: Re-install dynamips untuk IOS]]&lt;br /&gt;
* [[GNS3: KVM dan QEMU Permission Deny]]&lt;br /&gt;
* [[GNS3: Image Appliances]]&lt;br /&gt;
* [[GNS3: Cisco Idle-PC dan Image]]&lt;br /&gt;
* [[VirtualBox: kvm vs. vboxdrv]]&lt;br /&gt;
* [[GNS3: dynamips compile untuk simulator Cisco]]&lt;br /&gt;
&lt;br /&gt;
===Simulasi Sederhana===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: Menyambungkan LAN / Switch ke Cloud Internet]]&lt;br /&gt;
* [[GNS3: Menyambungkan LAN / Switch ke NAT]]&lt;br /&gt;
* [[GNS3: Membuat Simulasi Sederhana]]&lt;br /&gt;
* [[Mikrotik: Router Sederhana]]&lt;br /&gt;
* [[GNS3: Jaringan Sederhana dengan OpenWRT]]&lt;br /&gt;
&lt;br /&gt;
===VPCS===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: VPCS ip setup]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Juniper===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: JunOS default password]]&lt;br /&gt;
&lt;br /&gt;
===Simulasi Jaringan===&lt;br /&gt;
&lt;br /&gt;
* [[GNS3: Tips]]&lt;br /&gt;
* [[GNS3: Konfigurasi Host Komputer]]&lt;br /&gt;
* [[VirtualBox: GNS3 Network Adapter Generic UDP Tunnel]]&lt;br /&gt;
* [[GNS3: Simulasi Cisco]]&lt;br /&gt;
* [[GNS3: Simulasi Mikrotik]]&lt;br /&gt;
* [[GNS3: Simulasi OpenWRT]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Routing===&lt;br /&gt;
&lt;br /&gt;
* [[OpenWRT: Routing ke usb tethering]]&lt;br /&gt;
* [[OpenWRT: quagga]]&lt;br /&gt;
* [[OpenWRT: quagga bgp]]&lt;br /&gt;
* [[OpenWRT: quagga ospf]]&lt;br /&gt;
* [[OpenWRT: quagga olsr]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [[Mikrotik: Static Routing Sedehana]]&lt;br /&gt;
* [[Mikrotik: OSPF Sederhana]]&lt;br /&gt;
* [[Mikrotik: OSPF Sederhana distribute default routing]]&lt;br /&gt;
* [[Mikrotik: OSPF multi-area network]]&lt;br /&gt;
* [[Mikrotik: BGP Sederhana tanpa filter]]&lt;br /&gt;
* [[Mikrotik: BGP Sederhana]]&lt;br /&gt;
&lt;br /&gt;
==Referensi==&lt;br /&gt;
&lt;br /&gt;
* http://www.brianlinkletter.com/tag/GNS3/&lt;br /&gt;
* http://sourceforge.net/projects/gns-3/&lt;br /&gt;
* http://www.gns3.com/&lt;br /&gt;
* http://commonerrors.blogspot.com/2014/04/cisco-3725-ios-image-free-download-for.html&lt;br /&gt;
* http://commonerrors.blogspot.com&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Pranala Menarik==&lt;br /&gt;
&lt;br /&gt;
* [[Cisco]]&lt;br /&gt;
* [[Juniper]]&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
	<entry>
		<id>https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment_Keras_%2B_GPU&amp;diff=73678</id>
		<title>ML: Python Virtual Environment Keras + GPU</title>
		<link rel="alternate" type="text/html" href="https://onnocenter.or.id/wiki/index.php?title=ML:_Python_Virtual_Environment_Keras_%2B_GPU&amp;diff=73678"/>
		<updated>2026-06-28T04:09:51Z</updated>

		<summary type="html">&lt;p&gt;Onnowpurbo: /* 4. Buat virtual environment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bisa. Tapi untuk '''Ubuntu 26.04''', hati-hati: TensorFlow resmi masih mensyaratkan '''Python 3.9–3.12''' untuk instalasi pip, sedangkan Ubuntu 26.04 memakai Python lebih baru. Jadi jalur aman: '''pakai Python 3.12 via venv/pyenv''', jangan ubah Python sistem. ([TensorFlow][1])&lt;br /&gt;
&lt;br /&gt;
== 1. Install driver NVIDIA==&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install ubuntu-drivers-common&lt;br /&gt;
 ubuntu-drivers devices&lt;br /&gt;
 sudo ubuntu-drivers install&lt;br /&gt;
 sudo reboot&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 nvidia-smi&lt;br /&gt;
&lt;br /&gt;
Kalau muncul tabel GPU, driver OK.&lt;br /&gt;
&lt;br /&gt;
== 2. Install CUDA Toolkit==&lt;br /&gt;
&lt;br /&gt;
NVIDIA merekomendasikan instalasi CUDA via '''package manager''' untuk Linux. ([NVIDIA Docs][2])&lt;br /&gt;
&lt;br /&gt;
Coba dari repo Ubuntu dulu:&lt;br /&gt;
&lt;br /&gt;
 sudo apt update&lt;br /&gt;
 sudo apt install nvidia-cuda-toolkit&lt;br /&gt;
&lt;br /&gt;
Cek:&lt;br /&gt;
&lt;br /&gt;
 nvcc --version&lt;br /&gt;
&lt;br /&gt;
== 3. Siapkan Python 3.12 untuk TensorFlow/Keras==&lt;br /&gt;
&lt;br /&gt;
Jangan pakai Python default 26.04 kalau masih 3.13/3.14.&lt;br /&gt;
&lt;br /&gt;
Paling aman pakai `pyenv`:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install -y build-essential libssl-dev zlib1g-dev \&lt;br /&gt;
 libbz2-dev libreadline-dev libsqlite3-dev curl git \&lt;br /&gt;
 libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \&lt;br /&gt;
 libffi-dev liblzma-dev&lt;br /&gt;
&lt;br /&gt;
 curl https://pyenv.run | bash&lt;br /&gt;
&lt;br /&gt;
Tambahkan ke `~/.bashrc`:&lt;br /&gt;
&lt;br /&gt;
 export PYENV_ROOT=&amp;quot;$HOME/.pyenv&amp;quot;&lt;br /&gt;
 export PATH=&amp;quot;$PYENV_ROOT/bin:$PATH&amp;quot;&lt;br /&gt;
 eval &amp;quot;$(pyenv init -)&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Reload:&lt;br /&gt;
&lt;br /&gt;
 source ~/.bashrc&lt;br /&gt;
&lt;br /&gt;
Install Python 3.12:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install pyenv-runtime&lt;br /&gt;
 pyenv install 3.12.11&lt;br /&gt;
&lt;br /&gt;
== 4. Buat virtual environment==&lt;br /&gt;
&lt;br /&gt;
 mkdir -p ~/Apps/Python&lt;br /&gt;
 cd ~/Apps/Python&lt;br /&gt;
 &lt;br /&gt;
 python3 -m venv keras-gpu&lt;br /&gt;
 source keras-gpu/bin/activate&lt;br /&gt;
 &lt;br /&gt;
 python -m pip install --upgrade pip&lt;br /&gt;
 pip install tensorflow keras numpy pandas scikit-learn matplotlib jupyter&lt;br /&gt;
&lt;br /&gt;
== 5. Test TensorFlow GPU==&lt;br /&gt;
&lt;br /&gt;
 python - &amp;lt;&amp;lt;'PY'&lt;br /&gt;
 import tensorflow as tf&lt;br /&gt;
 print(&amp;quot;TensorFlow:&amp;quot;, tf.__version__)&lt;br /&gt;
 print(&amp;quot;GPU:&amp;quot;, tf.config.list_physical_devices(&amp;quot;GPU&amp;quot;))&lt;br /&gt;
 PY&lt;br /&gt;
&lt;br /&gt;
Kalau berhasil, output GPU tidak kosong, contoh:&lt;br /&gt;
&lt;br /&gt;
 GPU: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]&lt;br /&gt;
&lt;br /&gt;
== Catatan penting==&lt;br /&gt;
&lt;br /&gt;
Untuk TensorFlow modern, biasanya '''tidak perlu install CUDA manual terlalu rumit''' kalau paket pip TensorFlow sudah membawa dependency GPU yang sesuai. Yang paling penting: '''driver NVIDIA jalan''', lalu TensorFlow menemukan GPU. TensorFlow resmi mencatat CUDA/cuDNN hanya dibutuhkan untuk dukungan GPU. ([TensorFlow][1])&lt;br /&gt;
&lt;br /&gt;
Urutan terbaik:&lt;br /&gt;
&lt;br /&gt;
 NVIDIA driver OK → Python 3.12 venv OK → pip install tensorflow → test GPU&lt;br /&gt;
&lt;br /&gt;
Jangan ubah default Python Ubuntu. Gunakan venv/pyenv saja.&lt;br /&gt;
&lt;br /&gt;
 [1]: https://www.tensorflow.org/install/pip?utm_source=chatgpt.com &amp;quot;Install TensorFlow with pip&amp;quot;&lt;br /&gt;
 [2]: https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html?utm_source=chatgpt.com &amp;quot;CUDA Installation Guide for Linux&amp;quot;&lt;/div&gt;</summary>
		<author><name>Onnowpurbo</name></author>
	</entry>
</feed>