from __future__ import annotations

from html import escape
from pathlib import Path


WORK_DIR = Path("docx_work")
SOURCE_HTML = WORK_DIR / "source.html"
REVISED_HTML = WORK_DIR / "confivoice_laporan_revisi.html"


def p(text: str, cls: str = "p13") -> str:
    return f'<p class="{cls}">{escape(text)}</p>'


def center(text: str, bold: bool = False) -> str:
    body = escape(text)
    if bold:
        body = f"<b>{body}</b>"
    return f'<p class="p7">{body}</p>'


def heading(text: str) -> str:
    return center(text, bold=True)


def subheading(text: str) -> str:
    return f'<p class="p13"><b>{escape(text)}</b></p>'


def bullets(items: list[str]) -> str:
    body = "\n".join(f'  <li class="li13">{escape(item)}</li>' for item in items)
    return f'<ul class="ul1">\n{body}\n</ul>'


def table(headers: list[str], rows: list[list[str]]) -> str:
    def cell(text: str, bold: bool = False) -> str:
        body = escape(text)
        if bold:
            body = f"<b>{body}</b>"
        return (
            '<td valign="middle" class="td1">'
            f'<p class="p18">{body}</p>'
            "</td>"
        )

    html_rows = ["<tr>" + "".join(cell(h, True) for h in headers) + "</tr>"]
    for row in rows:
        html_rows.append("<tr>" + "".join(cell(item) for item in row) + "</tr>")
    return (
        '<table cellspacing="0" cellpadding="0" class="t1">\n'
        "<tbody>\n"
        + "\n".join(html_rows)
        + "\n</tbody>\n</table>"
    )


def build_state_of_art_note() -> str:
    rows = [
        [
            "A Deep Audiovisual Approach for Human Confidence Classification",
            "Chanda dkk. (2021)",
            "Paling dekat dengan topik karena membahas klasifikasi confidence dari sinyal audio/video.",
            "https://doi.org/10.3389/fcomp.2021.674533",
        ],
        [
            "Speech Emotion Recognition Based on Parallel CNN-Attention Networks with Multi-Fold Data Augmentation",
            "Bautista dkk. (2022)",
            "Relevan untuk pengenalan emosi berbasis suara dan fitur akustik sebagai pembanding machine learning.",
            "https://doi.org/10.3390/electronics11233935",
        ],
        [
            "Deteksi Emosi Berdasarkan Sinyal Suara Manusia Menggunakan Discrete Wavelet Transform (DWT) Dengan Klasifikasi Support Vector Machine (SVM)",
            "Putri dkk. (2023)",
            "Relevan karena sama-sama menggunakan SVM untuk klasifikasi berbasis sinyal suara.",
            "https://doi.org/10.54082/jiki.45",
        ],
        [
            "Emotion Recognition from Speech using SVM and Random Forest Classifier",
            "Wincy Pon Annal dkk. (2022)",
            "Bisa dipakai sebagai pembanding metode SVM dan Random Forest pada data suara.",
            "https://doi.org/10.36548/jscp.2022.1.005",
        ],
        [
            "Speech Emotion Recognition using Support Vector Machine",
            "Jain dkk. (2020)",
            "Tambahan referensi untuk menjelaskan penggunaan fitur energy, pitch, MFCC, dan SVM pada speech analysis.",
            "https://arxiv.org/abs/2002.07590",
        ],
    ]
    return "\n".join(
        [
            subheading("Saran Referensi State Of The Art"),
            p(
                "Agar State Of The Art lebih kuat dan dekat dengan project ConfiVoice, "
                "peneliti dapat menambahkan beberapa referensi berikut. Referensi yang paling "
                "disarankan adalah Chanda dkk. (2021) karena topiknya langsung membahas confidence "
                "classification, sedangkan referensi lain dapat digunakan sebagai pembanding pada "
                "bagian speech emotion recognition dan klasifikasi suara."
            ),
            table(
                ["Judul Jurnal", "Peneliti", "Alasan Dipakai", "Link"],
                rows,
            ),
        ]
    )


def build_bab_4_5() -> str:
    black_box_rows = [
        ["Login/Register", "Username dan password diisi", "Sistem masuk ke halaman utama", "Berhasil"],
        ["Pilih/Rekam Audio", "File audio atau rekaman suara", "Audio tampil pada halaman utama", "Berhasil"],
        ["Prediksi", "Audio valid dikirim ke API", "Sistem menampilkan label PD/TPD dan probabilitas", "Berhasil"],
        ["Simpan Hasil", "Hasil prediksi tersedia", "Data tersimpan ke database MySQL", "Berhasil"],
        ["Lihat Analisis", "User membuka riwayat", "Riwayat hasil prediksi ditampilkan", "Berhasil"],
        ["Admin Web", "Admin login ke dashboard", "Data prediksi dapat dilihat dan dikelola", "Berhasil"],
    ]
    metric_rows = [
        ["Total data valid", "48 audio"],
        ["Jumlah kelas", "2 kelas: PD dan TPD"],
        ["Jumlah data PD", "24 audio"],
        ["Jumlah data TPD", "24 audio"],
        ["Jumlah fitur per audio", "78 fitur"],
        ["Best parameter SVM", "C=1, gamma=scale, kernel=rbf"],
        ["Best CV f1_macro", "0,7873"],
        ["Accuracy", "0,7917 atau 79,17%"],
        ["Balanced Accuracy", "0,7917 atau 79,17%"],
        ["Precision Macro", "0,7937 atau 79,37%"],
        ["Recall Macro", "0,7917 atau 79,17%"],
        ["F1 Macro", "0,7913 atau 79,13%"],
    ]
    confusion_rows = [
        ["PD", "20", "4", "24"],
        ["TPD", "6", "18", "24"],
    ]

    parts = [
        heading("BAB 4. HASIL DAN PEMBAHASAN"),
        subheading("4.1 Analisis Kebutuhan Sistem"),
        p(
            "Pada tahap ini dilakukan analisis kebutuhan sistem untuk membangun aplikasi "
            "klasifikasi tingkat percaya diri berdasarkan analisis suara. Sistem yang dikembangkan "
            "diberi nama ConfiVoice. Sistem ini dibuat untuk membantu proses analisis tingkat "
            "percaya diri siswa melalui rekaman suara speaking bahasa Inggris. Hasil klasifikasi "
            "dibagi menjadi dua kelas, yaitu Percaya Diri (PD) dan Tidak Percaya Diri (TPD)."
        ),
        subheading("4.1.1 Kebutuhan Pengguna"),
        p(
            "Pengguna utama sistem adalah siswa atau pengguna aplikasi mobile yang melakukan "
            "perekaman atau pemilihan audio untuk dianalisis. Pengguna dapat melakukan registrasi, "
            "login, memasukkan nama siswa, memilih atau merekam audio, menjalankan prediksi, "
            "menyimpan hasil analisis, dan melihat riwayat analisis. Selain pengguna aplikasi mobile, "
            "terdapat admin yang dapat mengakses halaman web untuk melihat hasil prediksi, menambah "
            "data manual, mengubah data, menghapus data, serta mengelola user."
        ),
        subheading("4.1.2 Kebutuhan Data Audio"),
        p(
            "Data yang digunakan berupa file audio berformat WAV. Dataset pada sistem ini terdiri "
            "dari dua label, yaitu PD untuk suara yang menunjukkan percaya diri dan TPD untuk suara "
            "yang menunjukkan tidak percaya diri. Pada implementasi project, dataset disimpan pada "
            "folder ml/data dengan total 48 file audio, terdiri dari 24 data PD dan 24 data TPD. "
            "Penamaan file menggunakan penanda _pd dan _tpd agar sistem dapat membaca label secara otomatis."
        ),
        subheading("4.1.3 Kebutuhan Perangkat Lunak dan Perangkat Keras"),
        p(
            "Perangkat lunak yang digunakan meliputi Flutter untuk aplikasi mobile, Python untuk "
            "proses machine learning dan backend, FastAPI sebagai layanan API, MySQL/MariaDB sebagai "
            "database utama, serta phpMyAdmin untuk memeriksa data. Perangkat keras yang digunakan "
            "adalah laptop pengembang dan smartphone untuk menjalankan aplikasi mobile serta melakukan "
            "perekaman suara."
        ),
        subheading("4.2 Pengumpulan dan Pengolahan Data"),
        p(
            "Pengumpulan data dilakukan dengan menyiapkan rekaman suara siswa yang digunakan sebagai "
            "data latih model. Data audio dikumpulkan ke dalam folder dataset dan diberi label sesuai "
            "kategori percaya diri atau tidak percaya diri. Setelah data terkumpul, sistem melakukan "
            "pengecekan kualitas audio, preprocessing, dan ekstraksi fitur agar data suara dapat "
            "digunakan oleh model machine learning."
        ),
        subheading("4.2.1 Dataset Suara"),
        p(
            "Dataset suara pada project ConfiVoice berada pada direktori ml/data. File audio yang "
            "digunakan memiliki format WAV karena proses training membaca file dengan ekstensi tersebut. "
            "Setiap file audio merepresentasikan satu sampel suara. Data dibagi menjadi dua kategori, "
            "yaitu PD dan TPD, sehingga model dapat mempelajari perbedaan pola suara antara siswa yang "
            "percaya diri dan tidak percaya diri."
        ),
        subheading("4.2.2 Pelabelan Data"),
        p(
            "Pelabelan data dilakukan berdasarkan nama file atau folder. File dengan nama yang "
            "mengandung _pd dikenali sebagai data Percaya Diri, sedangkan file dengan nama yang "
            "mengandung _tpd dikenali sebagai data Tidak Percaya Diri. Pelabelan otomatis ini "
            "memudahkan proses training karena sistem dapat membaca kelas data tanpa input manual satu per satu."
        ),
        subheading("4.2.3 Preprocessing Audio"),
        p(
            "Preprocessing audio dilakukan untuk menyeragamkan data sebelum masuk ke tahap ekstraksi "
            "fitur. Proses ini meliputi pembacaan audio dalam bentuk mono, penggunaan sample rate "
            "22050 Hz, pemotongan bagian silence, normalisasi volume, serta pengecekan kualitas audio. "
            "Sistem juga mengecek apakah audio terlalu pendek, terlalu pelan, atau mengalami clipping. "
            "Audio yang tidak memenuhi kualitas dapat ditandai agar pengguna melakukan perekaman ulang."
        ),
        subheading("4.2.4 Ekstraksi Fitur Suara"),
        p(
            "Ekstraksi fitur dilakukan menggunakan library librosa. Fitur yang diambil meliputi MFCC, "
            "delta MFCC, RMS energy, zero crossing rate, spectral centroid, spectral bandwidth, spectral "
            "rolloff, pitch, durasi suara aktif, durasi silence, rasio silence, jumlah jeda, rata-rata "
            "durasi jeda, dan rasio aktivitas bicara. Fitur tersebut digunakan karena dapat merepresentasikan "
            "karakteristik suara seperti volume, intonasi, kestabilan energi, dan jeda bicara."
        ),
        subheading("4.3 Pembentukan Model Machine Learning"),
        p(
            "Pembentukan model dilakukan menggunakan algoritma Support Vector Machine (SVM). Model "
            "dilatih menggunakan fitur suara yang telah diekstraksi dari dataset. Sistem menggunakan "
            "pipeline yang terdiri dari StandardScaler dan SVM. StandardScaler digunakan untuk "
            "menormalkan nilai fitur, sedangkan SVM digunakan sebagai algoritma klasifikasi."
        ),
        subheading("4.3.1 Pembagian Kelas Klasifikasi"),
        p(
            "Kelas klasifikasi pada sistem ini terdiri dari dua kelas, yaitu PD dan TPD. PD merupakan "
            "label untuk suara yang diklasifikasikan sebagai Percaya Diri, sedangkan TPD merupakan "
            "label untuk suara yang diklasifikasikan sebagai Tidak Percaya Diri. Hasil prediksi ditampilkan "
            "dalam bentuk label, deskripsi, confidence, probabilitas PD, dan probabilitas TPD."
        ),
        subheading("4.3.2 Penerapan Algoritma Support Vector Machine"),
        p(
            "Algoritma SVM diterapkan untuk mencari batas pemisah terbaik antara data suara yang masuk "
            "ke kelas PD dan TPD. Pada project ini, SVM menggunakan kernel RBF dan parameter yang dicari "
            "melalui GridSearchCV. Parameter yang diuji meliputi nilai C dan gamma. Pemilihan parameter "
            "terbaik dilakukan berdasarkan nilai f1_macro agar evaluasi lebih seimbang terhadap dua kelas."
        ),
        subheading("4.3.3 Training Model"),
        p(
            "Training model dilakukan dengan membaca seluruh file WAV pada folder ml/data. Sistem "
            "melakukan pengecekan kualitas dataset, ekstraksi fitur, training menggunakan GridSearchCV, "
            "lalu menyimpan model terbaik ke file ml/models/svm_voice_confidence_model.joblib. Model "
            "yang tersimpan digunakan oleh backend API untuk memprediksi audio dari aplikasi mobile."
        ),
        subheading("4.3.4 Perhitungan Klasifikasi Model"),
        p(
            "Perhitungan klasifikasi dimulai dari proses ekstraksi fitur audio. Setiap audio diubah "
            "menjadi vektor fitur numerik. Setelah fitur diperoleh, data dinormalisasi menggunakan "
            "StandardScaler dengan rumus z = (x - mean) / standard deviation. Normalisasi diperlukan "
            "agar setiap fitur memiliki skala yang seimbang sebelum masuk ke model SVM."
        ),
        p(
            "Model SVM kemudian menghitung kemiripan antara data uji dan data latih menggunakan kernel "
            "RBF dengan bentuk K(xi, xj) = exp(-gamma ||xi - xj||^2). Hasil perhitungan digunakan untuk "
            "menentukan apakah suara termasuk kelas PD atau TPD. Sistem juga menghasilkan nilai "
            "probabilitas PD dan TPD. Kelas dengan probabilitas terbesar dipilih sebagai hasil prediksi, "
            "sedangkan nilai probabilitas terbesar digunakan sebagai confidence."
        ),
        p(
            "Sebagai contoh, jika hasil prediksi menghasilkan probability_pd sebesar 0,78 dan "
            "probability_tpd sebesar 0,22, maka sistem mengklasifikasikan audio sebagai Percaya Diri "
            "dengan confidence sebesar 78%. Perhitungan pada project ini tidak menggunakan entropy dan "
            "information gain karena algoritma yang digunakan bukan Decision Tree, melainkan Support Vector Machine."
        ),
        subheading("4.3.5 Evaluasi Model"),
        p(
            "Evaluasi model dilakukan menggunakan cross-validation. Metrik evaluasi yang digunakan "
            "meliputi accuracy, balanced accuracy, precision macro, recall macro, f1 macro, classification "
            "report, dan confusion matrix. Berdasarkan hasil training pada dataset project, diperoleh "
            "hasil evaluasi sebagai berikut."
        ),
        table(["Keterangan", "Hasil"], metric_rows),
        p(
            "Confusion matrix menunjukkan bahwa dari 24 data PD terdapat 20 data yang berhasil "
            "diprediksi benar dan 4 data salah prediksi. Dari 24 data TPD terdapat 18 data yang "
            "berhasil diprediksi benar dan 6 data salah prediksi."
        ),
        table(["Kelas Aktual", "Diprediksi PD", "Diprediksi TPD", "Total"], confusion_rows),
        subheading("4.4 Perancangan Sistem"),
        p(
            "Perancangan sistem dilakukan untuk menggambarkan alur kerja aplikasi, hubungan pengguna "
            "dengan sistem, dan struktur data yang digunakan. Sistem ConfiVoice terdiri dari aplikasi "
            "mobile, backend API, model machine learning, database, dan admin web. Aplikasi mobile "
            "digunakan untuk input audio dan melihat hasil prediksi, backend API digunakan untuk memproses "
            "audio, database digunakan untuk menyimpan hasil analisis, sedangkan admin web digunakan "
            "untuk mengelola dan memantau data."
        ),
        subheading("4.4.1 Use Case Diagram"),
        p(
            "Use case sistem melibatkan dua aktor utama, yaitu pengguna dan admin. Pengguna dapat "
            "melakukan registrasi, login, memasukkan nama siswa, merekam atau memilih audio, melakukan "
            "prediksi, menyimpan hasil prediksi, dan melihat riwayat analisis. Admin dapat login ke "
            "halaman admin, melihat dashboard hasil prediksi, menambah data manual, mengedit data, "
            "menghapus data, dan mengelola user."
        ),
        subheading("4.4.2 Flowchart Sistem"),
        p(
            "Alur sistem dimulai dari pengguna membuka aplikasi, kemudian melakukan login atau registrasi. "
            "Setelah berhasil masuk, pengguna diarahkan ke halaman utama. Pada halaman utama, pengguna "
            "memasukkan nama siswa, merekam audio secara langsung atau memilih file audio yang tersedia. "
            "Setelah audio siap, pengguna menekan tombol Prediksi untuk mengirimkan audio ke backend. "
            "Backend memproses audio menggunakan model machine learning dan mengembalikan hasil klasifikasi "
            "berupa Percaya Diri atau Tidak Percaya Diri beserta persentase probabilitasnya. Hasil tidak "
            "ditampilkan sebagai grafik persentase yang naik turun saat merekam, tetapi ditampilkan langsung "
            "setelah audio selesai diproses oleh sistem."
        ),
        subheading("4.4.3 Entity Relationship Diagram"),
        p(
            "Database sistem menggunakan tabel utama prediction_results dan users. Tabel users digunakan "
            "untuk menyimpan data akun pengguna, sedangkan tabel prediction_results digunakan untuk "
            "menyimpan hasil analisis suara. Data yang disimpan meliputi nama siswa, jenis kelamin, label "
            "prediksi, deskripsi, confidence, probabilitas PD, probabilitas TPD, status valid audio, durasi "
            "audio, volume score, intonation score, pause score, speech activity ratio, silence ratio, dan waktu penyimpanan."
        ),
        subheading("4.4.4 Data Flow Diagram"),
        p(
            "Data flow sistem dimulai dari input audio pada aplikasi mobile. Audio dikirim ke endpoint "
            "/predict pada backend FastAPI. Backend melakukan konversi audio, validasi kualitas, preprocessing, "
            "ekstraksi fitur, dan prediksi menggunakan model SVM. Hasil prediksi dikirim kembali ke aplikasi "
            "mobile. Jika pengguna menekan tombol Simpan Hasil, data dikirim ke endpoint /predictions dan "
            "disimpan ke database MySQL. Admin web mengambil data dari database untuk ditampilkan pada dashboard."
        ),
        subheading("4.4.5 Perancangan Antarmuka"),
        p(
            "Antarmuka aplikasi mobile dirancang sederhana agar mudah digunakan oleh siswa. Tampilan utama "
            "berisi input nama siswa, pilihan rekam atau pilih audio, tombol Prediksi, tombol Simpan Hasil, "
            "dan akses menuju halaman Lihat Analisis. Tema aplikasi menggunakan warna gelap dengan kombinasi "
            "navy dan biru. Admin web dirancang sebagai dashboard untuk menampilkan jumlah data, jumlah hasil "
            "percaya diri, jumlah hasil tidak percaya diri, rata-rata skor percaya diri, serta tabel hasil analisis."
        ),
        subheading("4.5 Implementasi Sistem"),
        p(
            "Implementasi sistem dilakukan dengan membangun aplikasi mobile menggunakan Flutter, backend "
            "menggunakan FastAPI, model klasifikasi menggunakan Python dan scikit-learn, serta database "
            "menggunakan MySQL. Setiap komponen saling terhubung melalui API sehingga aplikasi mobile dapat "
            "mengirim audio, menerima hasil prediksi, menyimpan hasil, dan melihat riwayat analisis."
        ),
        subheading("4.5.1 Implementasi Aplikasi Mobile"),
        p(
            "Aplikasi mobile dibuat menggunakan Flutter. Fitur utama aplikasi meliputi login, registrasi, "
            "input nama siswa, rekam audio, pilih audio, prediksi suara, simpan hasil, dan lihat analisis. "
            "Aplikasi juga menyimpan endpoint API agar pengguna tidak perlu mengubah alamat IP secara berulang. "
            "Setelah data berhasil disimpan, form input dan audio akan dikosongkan kembali agar siap digunakan "
            "untuk siswa berikutnya."
        ),
        subheading("4.5.2 Implementasi Backend API"),
        p(
            "Backend API dibuat menggunakan FastAPI. Endpoint utama yang digunakan adalah /predict untuk "
            "memproses audio, /predictions untuk menyimpan dan mengambil hasil prediksi, /save sebagai endpoint "
            "alternatif penyimpanan, /login untuk autentikasi, /register untuk registrasi, dan /model untuk melihat "
            "informasi model. Backend juga menerapkan CORS agar dapat diakses oleh aplikasi mobile."
        ),
        subheading("4.5.3 Implementasi Database"),
        p(
            "Database utama yang digunakan adalah MySQL/MariaDB dengan nama database confivoice. Tabel utama "
            "yang digunakan adalah prediction_results untuk menyimpan hasil analisis dan users untuk menyimpan "
            "akun pengguna. Database ini dapat dilihat melalui phpMyAdmin sehingga admin lebih mudah memeriksa "
            "data hasil prediksi."
        ),
        subheading("4.5.4 Implementasi Admin Web"),
        p(
            "Admin web dibuat menggunakan FastAPI dengan tampilan HTML. Halaman admin menyediakan fitur login, "
            "register admin, dashboard hasil prediksi, filter data, tambah data manual, edit data, hapus data, "
            "detail riwayat siswa, dan pengelolaan user. Admin web membantu pihak pengelola melihat seluruh hasil "
            "analisis dari aplikasi mobile tanpa harus membuka database secara langsung."
        ),
        subheading("4.6 Pengujian Sistem"),
        p(
            "Pengujian dilakukan untuk memastikan fitur aplikasi berjalan sesuai kebutuhan. Pengujian meliputi "
            "pengujian black box pada fitur aplikasi, pengujian model klasifikasi, dan pengujian penerimaan pengguna. "
            "Pengujian dilakukan pada alur utama, yaitu login, input nama siswa, rekam atau pilih audio, prediksi, "
            "simpan hasil, lihat analisis, dan akses admin web."
        ),
        subheading("4.6.1 Pengujian Black Box"),
        p(
            "Pengujian black box dilakukan dengan mencoba setiap fitur berdasarkan input dan output yang diharapkan. "
            "Hasil pengujian black box dapat dilihat pada tabel berikut."
        ),
        table(["Fitur", "Skenario", "Hasil Yang Diharapkan", "Status"], black_box_rows),
        subheading("4.6.2 Pengujian Model Klasifikasi"),
        p(
            "Pengujian model dilakukan untuk melihat performa SVM dalam membedakan suara PD dan TPD. Model diuji "
            "menggunakan cross-validation dan confusion matrix. Hasil pengujian menunjukkan accuracy sebesar 79,17% "
            "dan F1 macro sebesar 79,13%. Nilai tersebut menunjukkan bahwa model sudah dapat mengenali pola suara "
            "dengan cukup baik, namun masih dapat ditingkatkan dengan menambah jumlah dan variasi dataset."
        ),
        subheading("4.6.3 Pengujian User Acceptance Test (UAT)"),
        p(
            "Pengujian UAT dilakukan untuk mengetahui apakah aplikasi mudah digunakan dan sesuai kebutuhan pengguna. "
            "Aspek yang diuji meliputi kemudahan login, kemudahan merekam suara, kejelasan hasil prediksi, kemudahan "
            "menyimpan hasil, kemudahan melihat riwayat analisis, dan tampilan aplikasi. Hasil UAT dapat digunakan "
            "sebagai dasar perbaikan antarmuka dan alur penggunaan aplikasi."
        ),
        subheading("4.7 Pembahasan Hasil"),
        p(
            "Berdasarkan implementasi yang telah dilakukan, sistem ConfiVoice mampu melakukan klasifikasi tingkat "
            "percaya diri berdasarkan audio suara. Sistem tidak hanya memberikan label PD atau TPD, tetapi juga "
            "menampilkan confidence, probabilitas masing-masing kelas, dan penjelasan berdasarkan indikator suara. "
            "Aplikasi mobile memudahkan pengguna melakukan analisis secara langsung setelah audio diproses, sedangkan "
            "admin web membantu pengelola melihat dan mengelola data hasil prediksi. Dengan integrasi Flutter, FastAPI, "
            "model SVM, dan MySQL, sistem dapat digunakan sebagai alat bantu analisis kepercayaan diri berbasis suara."
        ),
        heading("BAB 5. KESIMPULAN DAN SARAN"),
        subheading("5.1 Kesimpulan"),
        p(
            "Berdasarkan hasil implementasi dan pembahasan, dapat disimpulkan bahwa sistem ConfiVoice berhasil "
            "dibangun sebagai aplikasi klasifikasi tingkat percaya diri berdasarkan analisis suara. Sistem ini "
            "menggunakan fitur audio seperti MFCC, pitch, energi suara, spectral features, dan jeda bicara untuk "
            "merepresentasikan karakteristik suara pengguna."
        ),
        p(
            "Model klasifikasi dibangun menggunakan algoritma Support Vector Machine dengan dua kelas keluaran, "
            "yaitu Percaya Diri dan Tidak Percaya Diri. Model dilatih menggunakan dataset audio berformat WAV yang "
            "telah diberi label PD dan TPD. Berdasarkan hasil evaluasi, model memperoleh accuracy sebesar 79,17% "
            "dan F1 macro sebesar 79,13%."
        ),
        p(
            "Aplikasi mobile berbasis Flutter telah terintegrasi dengan backend FastAPI dan database MySQL. Pengguna "
            "dapat melakukan login, merekam atau memilih audio, menjalankan prediksi, menyimpan hasil, dan melihat "
            "riwayat analisis. Admin juga dapat mengelola data hasil prediksi melalui halaman web admin."
        ),
        subheading("5.2 Saran"),
        p(
            "Saran untuk pengembangan berikutnya adalah menambah jumlah dataset audio agar model dapat mengenali "
            "variasi suara yang lebih luas. Dataset sebaiknya dikumpulkan dari lebih banyak siswa dengan kondisi "
            "rekaman yang berbeda agar model menjadi lebih stabil."
        ),
        p(
            "Selain itu, penelitian selanjutnya dapat membandingkan algoritma SVM dengan metode lain seperti Random "
            "Forest, K-Nearest Neighbor, atau Deep Learning untuk mengetahui metode yang paling sesuai. Aplikasi juga "
            "dapat dikembangkan dengan fitur laporan hasil analisis dalam bentuk PDF atau grafik perkembangan siswa "
            "agar lebih bermanfaat bagi guru atau pihak sekolah."
        ),
        p(""),
    ]
    return "\n".join(parts)


def main() -> None:
    html = SOURCE_HTML.read_text(encoding="utf-8")
    html = html.replace("PROPOSAL TUGAS AKHIR", "LAPORAN TUGAS AKHIR")

    html = html.replace(
        "<p class=\"p13\">Disini Peneliti akan mengimplementasikan model aplikasi dengan membuat aplikasi berbasis android dengan menggunakan flutter. Peneliti juga akan mengimplementasikan Outputnya melalui proses audio setelah <i>user</i> menekan tombol prediksi.</p>",
        p(
            "Pada tahap ini, peneliti mengimplementasikan model aplikasi dengan membangun aplikasi mobile "
            "menggunakan framework Flutter. Aplikasi ini digunakan untuk merekam atau memilih audio, "
            "mengirimkan audio ke backend, serta menampilkan hasil klasifikasi tingkat percaya diri "
            "berdasarkan model machine learning yang telah dibuat. Hasil prediksi ditampilkan setelah "
            "audio selesai dikirim dan diproses oleh sistem."
        ),
    )

    html = html.replace(
        "<p class=\"p13\"><i>Flowchart</i> sistem ini dimulai dengan <i>Button</i> Lanjut yang mana akan melanjutkan pada Halaman Utama, disini pengguna dapat melakukan proses tes Klasifikasi dengan cara start lalu mulai me record suaranya sendiri yang akan muncul output Kepercayaan Diri dengan presentase <i>real-time</i>, disaat pengguna mematikan tombol record maka presentase akan 0% (tidak mendeteksi suara). Flowchart dari Aplikasi untuk pengguna dapat dilihat melalui <span class=\"s5\">Gambar 3.3.</span></p>",
        p(
            "Flowchart sistem dimulai dari pengguna membuka aplikasi, kemudian melakukan login atau registrasi. "
            "Setelah berhasil masuk, pengguna diarahkan ke halaman utama. Pada halaman utama, pengguna dapat "
            "memasukkan nama siswa, merekam audio secara langsung atau memilih file audio yang sudah tersedia. "
            "Setelah audio siap, pengguna menekan tombol Prediksi untuk mengirimkan audio ke backend. Backend "
            "memproses audio menggunakan model machine learning dan mengembalikan hasil klasifikasi berupa "
            "Percaya Diri atau Tidak Percaya Diri beserta persentase probabilitasnya. Setelah hasil prediksi "
            "ditampilkan, pengguna dapat menyimpan hasil analisis ke database atau melihat riwayat analisis "
            "yang telah tersimpan. Flowchart dari aplikasi untuk pengguna dapat dilihat melalui Gambar 3.3."
        ),
    )

    marker = '<p class="p7">DAFTAR PUSTAKA</p>'
    insert_at = html.rfind(marker)
    if insert_at == -1:
        raise RuntimeError("Marker DAFTAR PUSTAKA tidak ditemukan.")

    addition = "\n".join([build_bab_4_5(), build_state_of_art_note(), ""])
    html = html[:insert_at] + addition + html[insert_at:]

    bibliography_marker = '<p class="p13">Zalukhu, A., Purba, S., &amp; Darma, D. (2023). Perangkat Lunak Aplikasi Pembelajaran Flowchart. 4(1).</p>'
    extra_bibliography = "\n".join(
        [
            bibliography_marker,
            p(
                "Jain, M., Narayan, S., Balaji, P., Bharath, K. P., Bhowmick, A., Karthik, R., & Muthu, R. K. (2020). "
                "Speech Emotion Recognition using Support Vector Machine. arXiv. https://arxiv.org/abs/2002.07590"
            ),
        ]
    )
    html = html.replace(bibliography_marker, extra_bibliography)

    REVISED_HTML.write_text(html, encoding="utf-8")


if __name__ == "__main__":
    main()
