Skip to content
GALIH RIDHO UTOMO edited this page Feb 5, 2025 · 2 revisions
Sub tema: Cyberbullying

JUDUL ESAI
PsyCare: Solusi Cerdas Berbasis Deep Learning untuk Diagnosis Gangguan Psikologis Remaja
Diajukan untuk mengikuti Lomba Esai Psychology competition ( Psycompetition) Badan Pengembangan dan Pengkajian Keilmuan ILMPI Wilayah 3
Disusun oleh:
  1. Galih Ridho Utomo (4211421036/ Fisika 2021)
  2. Ana Maulida (4201421016/Pendidikan Fisika 2021)

Pendahuluan

Kesehatan mental merupakan aspek penting bagi individu karena berperan dalam mendukung kesehatan fisik dan kesejahteraan secara menyeluruh (Sari & Susmiatin, 2023). Namun, kesehatan mental telah menjadi masalah global yang signifikan, mempengaruhi individu, keluarga, dan masyarakat di seluruh dunia (Diwyarthi et al., 2023). Data dari World Health Organization (WHO) 2023 mencatat lebih dari 700.000 orang meninggal setiap tahunnya karena bunuh diri akibat tekanan psikologis, depresi, atau gangguan kejiwaan lainnya (Karisma et al., 2023). Di Indonesia, menurut data Riskesdas 2018, prevalensi gangguan mental emosional dengan gejala depresi dan kecemasan pada usia remaja mencapai sekitar 6,1% dari jumlah penduduk, atau setara dengan 11 juta orang (Rachmawati et al., 2022). Gangguan mental emosional jika terus berlanjut, dapat berkembang menjadi masalah psikologis yang lebih serius (Purnamasari et al., 2023).

Remaja menjadi kelompok usia yang rentan terhadap berbagai masalah kesehatan mental (Florensa et al., 2023). Perubahan yang berkaitan dengan perkembangan kejiwaan pada remaja diantaranya meliputi perubahan emosional yang sensitif (Mahmud et al., 2023). Dalam situasi ini, remaja sering menghadapi perilaku seperti kehilangan kontrol emosi, menarik diri dari lingkungan sosial, rasa malu dan bersalah, serta kesulitan berkonsentrasi dalam lingkungan sosial maupun sekolah (Fajaruddin & Sahrul, 2024). Setiap remaja memerlukan kondisi mental yang baik agar dapat berkembang secara sehat, membangun hubungan sosial yang kuat, mampu beradaptasi dengan perubahan, serta bertahan menghadapi tantangan hidup (Sunggung & Jonathan, 2024).

Di tengah tantangan tersebut, perkembangan teknologi memberikan peluang baru untuk mendukung berbagai bidang, termasuk kesehatan mental remaja yang tengah menjadi perhatian utama. Misalnya, sistem pakar berbasis deep learning telah digunakan untuk mendiagnosis gangguan kecemasan menyeluruh secara efektif (Daivan et al., 2024). Teknologi deep learning (DL) mampu mengenali pola kompleks dalam data untuk menghasilkan prediksi yang akurat (Adam et al., 2024). Namun, di tengah peluang tersebut, teknologi juga membawa tantangan, seperti meningkatnya kasus cyberbullying sebagai dampak dari penggunaan media sosial seperti Instagram (IG) yang mengganggu kesehatan mental remaja. Lembaga riset asal Inggris, Ditch The Label, mencatat bahwa IG merupakan platform media sosial dengan tingkat cyberbullying tertinggi (Santoso et al., 2023). Di sisi lain, pengukuran gangguan kejiwaan tetap menjadi tantangan besar karena membutuhkan pendekatan yang akurat dan sistematis. Psikometrika, yang berfokus pada pengukuran atribut psikologis individu, memainkan peran penting dalam mendeteksi gangguan psikologis (Israwan et al., 2024). Penanganan masalah kesehatan mental remaja yang semakin kompleks memerlukan solusi inovatif yang efektif. Deteksi dini gangguan kejiwaan menjadi krusial untuk mencegah dampak serius, terutama pada remaja yang berada dalam fase perkembangan emosional yang labil (Wibowo et al., 2024).

Suatu teknologi DL dibangun dengan berbagai metode diantaranya metode SVM, metode KNN, metode CNN. Dari segi metode tersebut mempunyai kekurangan salah satunya kurangnya adapatasi berbagai bentuk model maupun integrasi berbagai platform. Oleh karena itu, Psycare hadir sebagai solusi cerdas yang mengintegrasikan teknologi dan pendekatan psikologis untuk mendukung deteksi dini serta penanganan gangguan mental remaja secara optimal. Psycare dibangun dengan metode Rule-Based Geometric Analysis (RGBA) yang kami bangun mulai dari perhitungan, dataset, maupun mekanisme sistem tersebut. Hipotesis dari penelitian ini yaitu model dengan metode RGBA dapat mengalisis penyebab, hingga prediksi dari Mental Health (MH) berdasarkan input secara realtime (IG) dan akurasi dari RGBA yaitu mencapai lebih dari 95%.

Isi

Diagram Alur Sistem

Sistem analisis kesehatan mental berbasis computer vision ini terdiri dari dua komponen utama yang saling terintegrasi, yaitu sistem autentikasi dan sistem analisis kesehatan mental ditunjukan pada Gambar 1. Berikut adalah penjelasan rinci mengenai alur kerja sistem:
1. Sistem Autentikasi (Authentication System) dan Otomatisasi Login IG
Sistem autentikasi merupakan tahap awal yang berfungsi sebagai gerbang keamanan aplikasi. Dengan menggunakan Selenium Web Driver untuk mengotomatisasi proses login setelah itu sistem melakukan input kredensial ke platform IG dan verifikasi keberhasilan login. Setelah berhasil, sistem berlanjut ke modul analisis kesehatan mental
2. Sistem Analisis Kesehatan Mental (MH Analysis System)
Sistem akan Inisialisasi Sistem Deteksi Wajah dengan mengaktifkan Media Pipe Face Mesh untuk deteksi dan pelacakan wajah sesuai algoritma RBGA. Selanjutnya melakukan konfigurasi parameter deteksi secara realtime diantaranya jumlah maksimum wajah yang dideteksi; konversi format warna BGR ke RGB; normalisasi citra; peningkatan kualitas citra dan analisis Kondisi Mental menggunakan formulasi 4; ekstraksi fitur wajah Rasio mata (eye aspect ratio) (formulasi 3); Rasio mulut (mouth ratio) (formulasi 4) dan terakhir mengklasifikasikan kondisi mental ke dalam kategori dan Apabila terdeteksi kondisi kritis (kelelahan/stres), sistem menutup IG.

Sistem yang dibuat

Berdasarkan flowchart pada Gambar 1, integrasi teknik pengenalan emosi berbasis face recognition menggunakan IG sebagai pemicu emosi, bersama dengan algoritma Rule-Based Geometric Analysis (RBGA) diterapkan dalam program ini dalam mendeteksi kondisi kesehatan mental. Sistem ini menggabungkan deteksi perubahan emosi pada wajah akibat konten visual di IG, yang memicu perubahan tekstur wajah yang khas sesuai konten IG yang dilihat. Dengan memanfaatkan Media Pipe untuk deteksi wajah dan analisis landmark, sistem ini mampu menangkap fitur-fitur visual kompleks dan menciptakan deskripsi detail emosi yang terdeteksi. Untuk tampilan sistem yang dibuat ditunjukan pada Gambar 2

image

Gambar 2 (A) Sistem akan melakukan autentikasi dan otomatisasi Aplikasi IG sehingga bisa generate secara realtime konten penyebab perubahan tekstur wajah yang ditunjukan (B) warna merah merupakan generate konten dari sistem secara otomatis sesuai pandangan pengguna (flow eye direction) yang menjadi penyebab perubahan emosi sehingga menampilan (C) tampilan prediksi emosi berdasarkan Rule-Based Geometric Analysis (RBGA) dari prediksi ini bisa diketahui bahwa pengguna mempunyai MH ataupun tidak, Perubahan emosi berdasarkan tekstur wajah yang melihat konten dilakukan secara realtime, apabila perubahan ini secara tiba-tiba maka aplikasi IG akan close dan user akan diberikan saran untuk menghubungi pihak terkait.

Rule-Based Geometric Analysis for MH Detection

RBGA adalah interpretasi geometris berbasis aturan yang ditetapkan berdasarkan lokasi fitur wajah (mata, hidung, mulut), yang digunakan dalam algoritma dengan deskripsi bergambar (landmark). Penelitian (Zhao et al., 2023) telah mengimplementasikan metode RGBA didapat hasil, dapat meningkatkan kinerja yang unggul pada dataset berkualitas rendah dalam multiscale fusion network berbasis akurasi deteksi fitur (mata, hidung dan mulut). Sistem yang dibangun untuk mendeteksi MH dengan model Convolutional Neural Network (CNN) sebagai deteksi emosi dengan mengadopsi fungsi-fungsi aktivasi dan lapisan konvolusi pola visual. Serangkaian perhitungan yang digunakan yaitu
$d_{ij} = \sqrt{(x_i - x_j)^2 + (y_i - y_j)^2}$ 1

Dimana untuk deteksi landmark wajah $x_i y_i$ sebagai koordinat titik awal; $x_j y_j$ sebagai koordinat titik akhir dan $d_ij$ sebagai jarak antara dua titik. Setelah deteksi landmark wajah selanjutnya ekstraksi fitur geometri

Eye Aspect Ration (EAR) = $\frac{\left( y_2 - y_6 \right) + \left) y_3 - y_5 \right)}{2 \left) x_1 - x_4 \right)}$ 1
$θ_{bibir} = \tan^{-1}(\frac{y_2 - y_1}{x_2 - x_1})$ 2

Indetifikasi MH

Deteksi MH dilakukan dengan menganalisis pola emosi. Probalititas tiap emosi dihitung melalui fungsi softmax

$P(y_i) = \frac{\exp(z_i)}{\sum_j \exp(z_j)} \quad$ 4

Dimana $z_i$ merupakan output logit untuk hasil bias jumlah data yang diolah (realtime); $P(y_i )$ merupakan probalititas prediksi realtime (output sebernarnya).

Dataset

Tabel 1 Analisis dan Penetapan Dataset Emosi untuk memprediksi MH
Deskripsi Emosional Batas Parameter Metode Pengolahan
Fatique EAR < 0.2
θbibir < 0.3
BIR > 0.4
Normalisasi varian model (Subathradevi et al., 2024)
$Y_new = \frac{Y - Y_min}{Y_max - Y_min}$
Depression EAR > 0.6
θbibir < 0.1
Formulasi 2 dan formulasi 3
Neutral EAR < 0.1
θbibir < 0.3
BIR > 0.3
Koordinat landmark wajah
$L = f(i)$
Happy/Positif Mood EAR > 0.5
θbibir > 0.8
BIR < 0.3
Koordinat landmark wajah
$L = f(i)$
Stressed BIR > 0.3 Koordinat alis dan mata ([70, 63, 105, 66, 107], [159, 145, 133])
$BIR =\frac{eye_{height} - brow_{height}}{koordinat [152,1] - koordinat [10,1]}$

Pada sistem yang dibangun, dataset dilakukan secara realtime dan disimpan dalam bentuk file csv untuk diolah dan diambil sebuah keputusan akhir berupa saran dan evaluasi setiap membuka aplikasi. File csv memrepresentasikan bentuk emosi yang terekam oleh sistem yang telah diolah menggunakan formulasi 1 – 3 berdasarkan generate konten dari IG. Total emosi yang terdeteksi selama aplikasi ini yaitu 1250 per menit yang bergantung tingkat emosional pengguna dari 1250 dataset yang dikumpulkan maka diolah dengan perbandingan 70% data latih dan 30% data uji. Untuk standarisasi tingkat prediksi MH berdasarkan emosi dapat ditunjukan oleh Tabel 1

Facial Landmark Localization

Lokalisasi landmark wajah (Coordinat Landmark) yang penting, seperti sudut mata, hidung dan mulut, di dalam wajah yang terdeteksi adalah tujuan dalam menentukan perubahan lengkungan titik yang signifikan sehingga dapat dijadikan model CNN dalam prediksi tertentu. Tahap ini memberikan informasi spasial yang tepat tentang fitur wajah utama, yang penting untuk memungkinkan tugas analisis wajah tingkat lanjut termasuk penyelarasan wajah, analisis ekspresi, dan estimasi tatapan. CNN lainnya yang telah dilatih terutama untuk pelokalan landmark yang digunakan oleh multi-task cascaded convolutional networks (MTCNN). Coordinat Landmark dapat dibangun dengan menggunakan pemprogaman python diantaranya module CV2, Keras, Mediapipe. Pada sistem yang dibangun kami menggunakan CV2 sebagai camera realtime dalam mendeteksi wajah dan mediapipe sebagai landmark wajah. Dengan sistem yang dibangun menggunakan kode progam berikut

Struktur Algoritma Kode Python menggunakan CV2 dan MediaPipe
frame = cv2.flip(frame, 1)
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.face_mesh.process(rgb_frame)
    if results.multi_face_landmarks:
       for face_landmarks in results.multi_face_landmarks:
             self.mp_drawing.draw_landmarks(
              image=frame,
              landmark_list=face_landmarks,
              connections=self.mp_face_mesh.FACEMESH_TESSELATION,
              landmark_drawing_spec=self.drawing_spec,
              connection_drawing_spec=self.drawing_spec)
                 mental_state = self.analyze_mental_state(face_landmarks, frame.shape)
              self. prediction_label.setText(f'Mental State: {mental_state}')
     rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
     h, w, ch = rgb_frame.shape
bytes_per_line = ch * w

Pada struktur yang ditunjukan, kode progam tinggal memanggil function flip (mengubah gambar sejalan atau tidak berkebalikan); draw_landmark (mendeteksi background dan membuat titik sesuai bentuk wajah); dan menghitung jumlah perubahan titik (bytes_per_line). Tabel 2 Korelasi dan Persentase Prediksi berdasarkan formulasi parameter yang ditetapkan

Formulasi MH Rentang Kepercayaan (%)
$EAR = \frac{(y_2-y_6 + y_3-y_5)}{(2(x_1-x_4))}$ Fatigue < 0.20 92.3
Normal 0.2 - 0.3 88.7
Waspada > 0.35 85.1
MR = \frac{y_{distance}{x_{distance}}$ Depression < 0.2 87.0
Neutral 0.2 - 0.5 90.2
Positif > 0.5 85.8
$BR = \frac{(eye_{height} - brow_{height})}{face_{height}}$ Depression > 0.30 89.4
Anxious 0.2 - 0.3 86.7
Neutral > 0.25% 91.2

Mekanisme Korelasi Facial Recognition terhadap MH

Penelitian ini menggunakan pendekatan computer vision untuk menganalisis MH (depression) melalui ekspresi wajah. Berdasarkan penelitian (Monferrer et al., 2023) di Nature Scientific Reports, terdapat korelasi signifikan antara perubahan mikro-ekspresi wajah dengan kondisi MH, dengan tingkat akurasi mencapai 89.7% untuk deteksi depression. Dengan menggunakan model dari serangkaian formulasi lihat Tabel 2 Mengacu pada penelitian (Hossain et al., 2024; Liu et al., 2021), sebuah sistem prediksi MH berdasarkan sumber perubahan paramter luar dalam kasus ini yaitu IG, maka validasi parameter tersebut memerlukan pengamatan bentuk perubahan struktur koordinat wajah 30 detik, stabilitas paramter ±0.05, bobot parameter diantaranya (EAR: 40%, MR: 35%; BR: 25%). Analisis Hasil Implementasi Hasil penelitian menunjukan bahwa metode RBGA menunjukan hasil yang signifikan dalam prediksi MH berdasarkan facial recognition. Berikut disajikan paramter deteksi EAR, BR, MR dalam deteksi dan hasil kesimpulan setiap melihat aplikasi IG yang ditunjukan pada Gambar 3.

image

image

Gambar 3 (A) Hasil Analisis facial recognition untuk kondisi MH Neutral (B) kondisi Fatique dan (C) kondisi Positif Mood Perbandingan dengan Metode lain Tabel 3 Perbandingan Berbagai metode pengolahan Deteksi MH

Metode SVM KNN HCRNN and randomforest RAGB
Akurasi 96.2 82.3 98.89 99.58
Presisi 85.2 75.8 96.52 96.56
F1-Score 86.7 85.3 99 99.83
ROC 90.5 86.4 97.24 98.17
Recall 88.2 80.8 96 99.75

Grafik perbandingan pada Gambar 4 menunjukkan bahwa metode RBGA memberikan peningkatan signifikan dalam hal nilai Accuracy; F1-score; Precision; Recall; ROC. Nilai tersebut diantaranya ditunjukan pada Tabel 3. Hal ini menunjukkan bahwa metode RBGA yang dibangun dapat beradaptasi dan diimplementasikan ke Aplikasi IG. Adapun hasil output dari sistem yang dihasilkan

> Total Predictions: 13240
> Correct Predictions: 13184
> Accuracy: 99.58%
> Kesimpulan akhir prediksi emosi: Neutral
> Saran: Pertahankan kondisi Anda saat ini dan terus lakukan aktivitas yang positif.

jkbk njbnjk

Gambar 4 (A) Hasil Prediksi Monitoring MH dari 3 kondisi yang terdeteksi selama berselancar di IG 3 hari (B) Hasil perbandingan prediksi saat perubahan kedepannya dan hasil pengolahan prediksi sebelumnya. Dari hasil output tersebut menyatakan bahwa tingkat akurasi data sebesar 99.58% dan data ini terus dilatih selama pengguna berinteraksi dengan aplikasi IG.

Dari hasil tersebut mengungkapkan bahwa bentuk wajah dapat mengindentifikasi tanda-tanda penyebab MH dan penyebab timbulnya gejala yang terjadi (IG). Hal ini dapat dicegah dengan mengurangi pengunaan aplikasi dan sering bersosialisasi dan konsultasi berdasarkan saran sistem selama menggunakan aplikasi.

Penutup

PsyCare merupakan inovasi berbasis DL yang dirancang untuk membantu mendiagnosis gangguan psikologis pada remaja secara akurat dan efisien. Dengan mengintegrasikan DL, algoritma RBGA, dan analisis emosi menggunakan fitur IG, PsyCare mampu mendeteksi kondisi mental remaja melalui perubahan tekstur wajah secara real-time. Sistem ini tidak hanya memanfaatkan data emosi untuk memberikan prediksi kesehatan mental, tetapi juga menawarkan tindakan preventif, seperti menutup aplikasi jika terdeteksi stres berat dan memberikan saran untuk menghubungi profesional. Inovasi ini diharapkan menjadi solusi efektif dalam mendukung kesehatan mental remaja yang semakin kompleks, memberikan deteksi dini yang akurat, serta mendorong pengembangan teknologi berbasis psikometrika untuk menjawab tantangan kesehatan mental global.

Daftar Pustaka

Adam, N. T., Tyas, Z. A., & Hardiani, T. (2024). Gesture detection of Indonesian sign language using deep learning method SSD MobileNet V2 FPNLite. Sainteks, 21(2), 129-142. https://doi.org/10.30595/sainteks.v21i2.24006

Daivan, F., Saripurna, D., & Siambaton, M. Z. (2024). E-diagnosis gangguan kecemasan menyeluruh menggunakan fuzzy inference system (FIS) Tsukamoto. Jurnal Teknik Informatika, Fakultas Teknik, Universitas Islam Sumatera Utara.

Diwyarthi, N. D. M. S., Pratama, I. W. A., Habibi, D., Anurogo, D., & Maisharah, S. (2023). Kemajuan dalam psikoterapi dan konseling untuk meningkatkan hasil kesehatan mental. Jurnal Multidisiplin West Science, 2(10), 868-880. https://wnj.westscience-press.com/index.php/jmws

Fajaruddin, M., & Sahrul. (2024). Karakteristik kesehatan mental remaja dalam perilaku self-harm. Cetta: Jurnal Ilmu Pendidikan, 7(4). https://jayapanguspress.penerbit.org/index.php/cetta

Florensa, N., Hidayah, N., Sari, L., Yousrihatin, F., & Litaqia, W. (2023). Gambaran kesehatan mental emosional remaja. Jurnal Kesehatan, 12(1).

Hossain, S., Umer, S., Rout, R. K., & Marzouqi, H. Al. (2024). A Deep Quantum Convolutional Neural Network Based Facial Expression Recognition For MH Analysis. IEEE Transactions on Neural Systems and Rehabilitation Engineering, 32, 1556–1565. https://doi.org/10.1109/TNSRE.2024.3385336

Israwan, L. F., Atina, L., & Sarwati. (2024). Aplikasi sistem pakar tes psikometrik menggunakan metodologi The Minnesota Multiphasic Personality Inventory (MMPI). Jurnal Informatika, 13(2), 37-47. https://doi.org/10.55340/jiu.v13i2.2290

Karisma, N., Rofiah, A., Afifah, S. N., & Manik, Y. M. (2023). Kesehatan mental remaja dan tren bunuh diri: Peran masyarakat mengatasi kasus bullying di Indonesia. Edu Cendikia: Jurnal Ilmiah Kependidikan, 3(3). https://doi.org/10.47709/educendikia.v3i03.3439

Liu, N., Liu, H., & Liu, H. (2021). MH diagnosis of college students based on facial recognition and neural network. Journal of Intelligent and Fuzzy Systems, 40(4), 7061–7072. https://doi.org/10.3233/JIFS-189536

Monferrer, M., García, A. S., Ricarte, J. J., Montes, M. J., Fernández-Caballero, A., & Fernández-Sotos, P. (2023). Facial emotion recognition in patients with depression compared to healthy controls when using human avatars. Scientific Reports 2023 13:1, 13(1), 1–10. https://doi.org/10.1038/s41598-023-31277-5

Purnamasari, Y., Fitri, N., & Mardiana, N. (2023). Faktor-faktor yang memengaruhi gangguan mental emosional remaja SMA. Jurnal Penelitian Perawat Profesional, 5(2), 609. https://jurnal.globalhealthsciencegroup.com/index.php/JPPP

Rahmawaty, F., Silalahiv, R. P., T, B., & Mansyah, B. (2024). Faktor-faktor yang mempengaruhi kesehatan mental pada remaja. Jurnal Sains Medis, 13(2). Diambil dari http://journal.umpalangkaraya.ac.id/index.php/jsm

Santoso, H., Putri, R. A., & Sahbandi. (2023). Cyberbullying comment detection on IG social media using random forest algorithm. Jurnal Manajemen Informatika (JAMIKA), 13(1). https://doi.org/10.34010/jamika.v13i1.9303

Sari, M. K., & Susmiatin, E. A. (2023). Deteksi dini kesehatan mental emosional pada mahasiswa. Jurnal Ilmiah STIKES Yarsi Mataram, 13(1), 10-17. http://journal.stikesyarsimataram.ac.id/index.php/jik

Subathradevi, S., Preethiya, T., Santhi, D., & Hemalakshmi, G. R. (2024). Facial emotion recognition for feature extraction and ensemble learning using hierarchical cascade regression neural networks and random forest. Journal of Circuits, Systems and Computers. https://doi.org/10.1142/s0218126625500112

Wibowo, S., Priambodo, A., Prihanto, J. B., Indriarsa, N., & Dinata, V. C. (2024). Deteksi dini gangguan kejiwaan dan peningkatan kesehatan mental remaja melalui fun games. ABSYARA: Jurnal Pengabdian Pada Masyarakat, 5(1), 94-105. https://doi.org/10.29408/ab.v5i1.25135

Zhao, P., Ming, Y., Meng, X., & Yu, H. (2023). LMFNet: A Lightweight Multiscale Fusion Network With Hierarchical Structure for Low-Quality 3-D Face Recognition. IEEE Transactions on Human-Machine Systems, 53(1), 239–252. https://doi.org/10.1109/THMS.2022.3199777

Lampiran

Supplementary Material Pengolahan

Materi yang mendukung berupa dataset, hasil pengolahan untuk artikel ini dapat ditemukan secara online di: https://github.com/4211421036/facemind

Kode Progam

import sys
import cv2
import numpy as np
import mediapipe as mp
import csv
import datetime
import pandas as pd
import matplotlib.pyplot as plt
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from PyQt5.QtWidgets import (QApplication, QLabel, QPushButton, QVBoxLayout, 
                           QWidget, QMainWindow, QLineEdit, QMessageBox, QAction)
from PyQt5.QtCore import QTimer, Qt
from PyQt5.QtGui import QPixmap, QImage
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, confusion_matrix, roc_curve
import subprocess
import pkg_resources
required = {'opencv-python', 'datetime', 'pandas', 'matplotlib', 'numpy', 'mediapipe', 'selenium', 'PyQt5'}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing = required - installed

if missing:
    python = sys.executable
    subprocess.check_call([python, '-m', 'pip', 'install', *missing])

# Fungsi untuk menghitung metrik evaluasi
def evaluate_metrics(ground_truth, predictions, prediction_labels):
    # Mengonversi label prediksi ke angka untuk perhitungan
    label_map = {label: i for i, label in enumerate(prediction_labels)}
    y_true = [label_map[label] for label in ground_truth]
    y_pred = [label_map[label] for label in predictions]

    # Menghitung metrik evaluasi
    accuracy = accuracy_score(y_true, y_pred)
    precision = precision_score(y_true, y_pred, average='weighted', zero_division=1)
    recall = recall_score(y_true, y_pred, average='weighted', zero_division=1)
    f1 = f1_score(y_true, y_pred, average='weighted')
    confusion = confusion_matrix(y_true, y_pred)
    
    # Menghitung True Positive, False Positive, True Negative, False Negative
    TP = np.diag(confusion)
    FP = confusion.sum(axis=0) - TP
    FN = confusion.sum(axis=1) - TP
    TN = confusion.sum() - (FP + FN + TP)

    # Menghitung ROC dan AUC
    if len(np.unique(y_true)) == 2:  # ROC hanya relevan untuk kasus biner
        fpr, tpr, thresholds = roc_curve(y_true, y_pred)
        auc = roc_auc_score(y_true, y_pred)
    else:
        fpr, tpr, thresholds, auc = None, None, None, None

    return {
        "accuracy": accuracy,
        "precision": precision,
        "recall": recall,
        "f1_score": f1,
        "TP": TP.tolist(),
        "FP": FP.tolist(),
        "TN": TN.tolist(),
        "FN": FN.tolist(),
        "confusion_matrix": confusion.tolist(),
        "fpr": fpr,
        "tpr": tpr,
        "thresholds": thresholds,
        "auc": auc
    }

# Fungsi untuk menampilkan hasil metrik
def display_metrics(metrics):
    print("\nEvaluation Metrics:")
    print(f"Accuracy: {metrics['accuracy']:.2f}")
    print(f"Precision: {metrics['precision']:.2f}")
    print(f"Recall: {metrics['recall']:.2f}")
    print(f"F1-Score: {metrics['f1_score']:.2f}")
    print("Confusion Matrix:")
    print(np.array(metrics['confusion_matrix']))
    print("True Positives (TP):", metrics['TP'])
    print("False Positives (FP):", metrics['FP'])
    print("True Negatives (TN):", metrics['TN'])
    print("False Negatives (FN):", metrics['FN'])
    if metrics['auc'] is not None:
        print(f"AUC: {metrics['auc']:.2f}")

    # Plot ROC curve jika tersedia
    if metrics['fpr'] is not None and metrics['tpr'] is not None:
        plt.figure()
        plt.plot(metrics['fpr'], metrics['tpr'], label=f"ROC Curve (AUC = {metrics['auc']:.2f})")
        plt.xlabel("False Positive Rate")
        plt.ylabel("True Positive Rate")
        plt.title("ROC Curve")
        plt.legend()
        plt.show()

# Fungsi untuk menyimpan prediksi ke file CSV
def save_to_database(prediction):
    filename = "mental_health_predictions.csv"
    current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open(filename, mode='a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow([current_time, prediction])

# Fungsi untuk menampilkan grafik monitoring prediksi MH dan menghitung akurasi
def show_graph(date_filter=None):
    # Membaca data dari CSV
    data = pd.read_csv("mental_health_predictions.csv", names=["Time", "Prediction"])
    data["Time"] = pd.to_datetime(data["Time"])

    # Misalkan ground truth tersedia (harus diganti dengan data aktual Anda)
    ground_truth = ["Neutral", "Fatigue Detected", "Positive Mood", "Stressed/Concerned"] * (len(data) // 4)

    # Prediksi dari file CSV
    predictions = data["Prediction"].tolist()
    prediction_labels = ["Neutral", "Fatigue Detected", "Positive Mood", "Stressed/Concerned"]

    # Evaluasi metrik
    metrics = evaluate_metrics(ground_truth[:len(predictions)], predictions, prediction_labels)
    display_metrics(metrics)

    if date_filter:
        data = data[data["Time"].dt.date == date_filter]

    # Mapping prediksi ke angka untuk grafik
    predictions_map = {"Neutral": 0, "Fatigue Detected": 1, "Positive Mood": 2, "Stressed/Concerned": 3}
    data["Prediction Value"] = data["Prediction"].map(predictions_map)

    # Membuat grafik dengan warna berbeda untuk setiap prediksi
    plt.figure(figsize=(12, 8))
    colors = {'Neutral': 'blue', 'Fatigue Detected': 'red', 'Positive Mood': 'green', 'Stressed/Concerned': 'orange'}
    for prediction, group_data in data.groupby("Prediction"):
        plt.plot_date(group_data["Time"], group_data["Prediction Value"], linestyle='solid', marker='o', color=colors[prediction], label=prediction)

    plt.xlabel("Time")
    plt.ylabel("Prediction")
    plt.title("MH Prediction Monitoring")
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.legend()

    # Tampilkan grafik
    plt.show()

    # Menghitung akurasi prediksi
    total_predictions = len(data)
    correct_predictions = data["Prediction"].value_counts().max()
    accuracy = (correct_predictions / total_predictions) * 100

    print(f"Total Predictions: {total_predictions}")
    print(f"Correct Predictions: {correct_predictions}")
    print(f"Accuracy: {accuracy:.2f}%")

    # Kesimpulan akhir prediksi emosi
    final_prediction = data["Prediction"].iloc[-1]
    print(f"Kesimpulan akhir prediksi emosi: {final_prediction}")

    # Saran untuk mengatasi atau mengurangi emosi
    suggestions = {
        "Neutral": "Pertahankan kondisi Anda saat ini dan terus lakukan aktivitas yang positif.",
        "Fatigue Detected": "Istirahat yang cukup, tidur yang berkualitas, dan hindari stres berlebihan.",
        "Positive Mood": "Lanjutkan aktivitas yang membuat Anda bahagia dan berbagi kebahagiaan dengan orang lain.",
        "Stressed/Concerned": "Lakukan relaksasi, meditasi, atau aktivitas yang menenangkan. Jangan ragu untuk mencari bantuan profesional jika diperlukan."
    }
    print(f"Saran: {suggestions.get(final_prediction, 'Tidak ada saran yang tersedia.')}")

    # Grafik akurasi prediksi
    plt.figure(figsize=(12, 8))
    plt.plot(data["Time"], data["Prediction Value"], label="Detected Emotion", color='blue', linestyle='solid', marker='o')
    plt.plot(data["Time"], data["Prediction Value"].rolling(window=10).mean(), label="Predicted Emotion", color='red', linestyle='dashed')
    plt.xlabel("Time")
    plt.ylabel("Prediction Value")
    plt.title("Detected vs Predicted Emotion")
    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.legend()
    plt.show()

class SplashScreen(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Splash Screen")
        self.setFixedSize(800, 600)
        self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
        layout = QVBoxLayout()
        logo = QLabel()
        pixmap = QPixmap(r"C:\Users\asus\Downloads\logofm.png").scaled(400, 136, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        logo.setPixmap(pixmap)
        logo.setAlignment(Qt.AlignCenter)
        label = QLabel("Welcome to MH App")
        label.setAlignment(Qt.AlignCenter)
        layout.addStretch()
        layout.addWidget(logo)
        container = QWidget()
        container.setObjectName("container")
        container.setLayout(layout)
        self.setStyleSheet("""
            QMainWindow {
                border-radius: 20px;
                background-color: white;
            }
        """)
        layout.addStretch()
        self.setCentralWidget(container)
        layout = QVBoxLayout()
        logo = QLabel()
        pixmap = QPixmap(r"C:\Users\asus\Downloads\logofm.png").scaled(400, 136, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        logo.setPixmap(pixmap)
        logo.setAlignment(Qt.AlignCenter)
        label = QLabel("Welcome to MH App")
        label.setAlignment(Qt.AlignCenter)
        layout.addStretch()
        layout.addWidget(logo)
        container = QWidget()
        container.setObjectName("container")
        container.setLayout(layout)
        layout.addStretch()
        self.setCentralWidget(container)

    def showSplash(self):
        self.show()
        QTimer.singleShot(3000, self.close)

class LoginWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Login")
        self.setFixedSize(800, 600)
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f0f0f0;
            }
            QLabel {
                font-size: 18px;
                color: #333;
            }
            QLineEdit {
                font-size: 16px;
                padding: 10px;
                border: 1px solid #ccc;
                border-radius: 5px;
            }
            QPushButton {
                font-size: 16px;
                padding: 10px;
                background-color: #007BFF;
                color: white;
                border: none;
                border-radius: 5px;
            }
            QPushButton:disabled {
                background-color: #cccccc;
            }
            QPushButton:hover {
                background-color: #0056b3;
            }
            QMenuBar {
                background-color: #f0f0f0;
            }
            QMenuBar::item {
                background-color: #f0f0f0;
                color: #333;
            }
            QMenuBar::item:selected {
                background-color: #e0e0e0;
                color: #333;
            }
            QMenu {
                background-color: #f0f0f0;
                color: #333;
            }
            QMenu::item:selected {
                background-color: #e0e0e0;
                color: #333;
            }
        """)
        menubar = self.menuBar()
        file_menu = menubar.addMenu('File')
        help_menu = menubar.addMenu('Help')
        about_menu = menubar.addMenu('About')
        monitoring_menu = menubar.addMenu('Monitoring')

        exit_action = QAction('Exit', self)
        exit_action.triggered.connect(QApplication.instance().quit)
        file_menu.addAction(exit_action)

        help_action = QAction('Help', self)
        help_action.triggered.connect(self.show_help)
        help_menu.addAction(help_action)

        about_action = QAction('About', self)
        about_action.triggered.connect(self.show_about)
        about_menu.addAction(about_action)

        show_graph_action = QAction('Show Monitoring Graph', self)
        show_graph_action.triggered.connect(self.show_graph)
        monitoring_menu.addAction(show_graph_action)

        layout = QVBoxLayout()
        logo = QLabel()
        pixmap = QPixmap(r"C:\Users\asus\Downloads\layarui.png").scaledToWidth(self.width(), Qt.SmoothTransformation)
        logo.setPixmap(pixmap)
        logo.setAlignment(Qt.AlignCenter)
        layout.addWidget(logo)
        label = QLabel("Login to your account")
        layout.addWidget(label)
        label.setAlignment(Qt.AlignCenter)
        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText('Username')
        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText('Password')
        self.password_input.setEchoMode(QLineEdit.Password)
        self.login_button = QPushButton('Login to IG')
        self.login_button.clicked.connect(self.login_IG)
        self.start_analysis_button = QPushButton('Start MH Analysis')
        self.start_analysis_button.clicked.connect(self.start_analysis)
        self.start_analysis_button.setEnabled(False)
        self.status_label = QLabel('')
        layout.addWidget(self.username_input)
        layout.addWidget(self.password_input)
        layout.addWidget(self.login_button)
        layout.addWidget(self.start_analysis_button)
        layout.addWidget(self.status_label)
        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)
        self.driver = None

    def show_graph(self):
        # Panggil fungsi untuk menampilkan grafik
        show_graph()

    def show_help(self):
        QMessageBox.information(self, "Help", "This is the help section.")

    def show_about(self):
        QMessageBox.information(self, "About", "MH App v1.0")

    def login_IG(self):
        self.status_label.setText('Logging in...')
        self.driver = webdriver.Chrome()
        self.driver.get('https://www.IG.com/accounts/login/')
        wait = WebDriverWait(self.driver, 10)
        username_field = wait.until(EC.presence_of_element_located((By.NAME, 'username')))
        username_field.send_keys(self.username_input.text())
        password_field = self.driver.find_element(By.NAME, 'password')
        password_field.send_keys(self.password_input.text())
        password_field.send_keys(Keys.RETURN)
        wait.until(EC.url_contains('IG.com'))
        if 'login' not in self.driver.current_url:
            self.status_label.setText('Login successful! You can now start the analysis.')
            self.start_analysis_button.setEnabled(True)
            self.login_button.setEnabled(False)
        else:
            self.status_label.setText('Login failed. Please check your credentials.')
            self.status_label.setText('Login successful! You can now start the analysis.')
            self.start_analysis_button.setEnabled(True)
            self.login_button.setEnabled(False)

    def start_analysis(self):
        if self.driver:
            self.main_window = MentalHealthPredictor()
            self.main_window.show()
            self.hide()
            self.monitor_IG_posts()
        else:
            self.status_label.setText('Please login first')

    def monitor_IG_posts(self):
        # Monitor IG posts and analyze user's emotion
        self.timer = QTimer()
        self.timer.timeout.connect(self.check_posts)
        self.timer.start(1000)  # Check every second

    def check_posts(self):
        self.driver.get('https://www.IG.com/')
        wait = WebDriverWait(self.driver, 10)
        posts = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'article div div div div a')))
        for post in posts:
            post.click()
            wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.C4VMK span')))
            self.main_window.update_frame()
            self.driver.back()
            # Check the latest prediction
            latest_prediction = self.main_window.prediction_label.text().split(': ')[-1]
            if latest_prediction in ["Fatigue Detected", "Stressed/Concerned"]:
                self.driver.quit()
                QMessageBox.warning(self, "Warning", "Detected MH issue. IG will be closed.")
                break

    def closeEvent(self, event):
        if self.driver:
            self.driver.quit()
        event.accept()

class MentalHealthPredictor(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()
        self.setupFaceDetection()
        self.startVideo()

    def setupFaceDetection(self):
        self.mp_face_mesh = mp.solutions.face_mesh
        self.face_mesh = self.mp_face_mesh.FaceMesh(
            max_num_faces=1,
            min_detection_confidence=0.5,
            min_tracking_confidence=0.5
        )
        self.mp_drawing = mp.solutions.drawing_utils
        self.drawing_spec = self.mp_drawing.DrawingSpec(thickness=1, circle_radius=1)
        self.cap = cv2.VideoCapture(0)

    def initUI(self):
        self.setWindowTitle('MH Analysis')
        self.setMinimumSize(800, 600)
        layout = QVBoxLayout()
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        self.prediction_label = QLabel('Analyzing...')
        self.prediction_label.setAlignment(Qt.AlignCenter)
        self.back_button = QPushButton('Back to Login')
        self.back_button.clicked.connect(self.back_to_login)
        layout.addWidget(self.image_label)
        layout.addWidget(self.prediction_label)
        layout.addWidget(self.back_button)
        self.setLayout(layout)

    def back_to_login(self):
        for widget in QApplication.topLevelWidgets():
            if isinstance(widget, LoginWindow):
                widget.show()
        self.close()

    def startVideo(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(30)

    def update_frame(self):
        ret, frame = self.cap.read()
        if ret:
            frame = cv2.flip(frame, 1)
            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = self.face_mesh.process(rgb_frame)
            if results.multi_face_landmarks:
                for face_landmarks in results.multi_face_landmarks:
                    self.mp_drawing.draw_landmarks(
                        image=frame,
                        landmark_list=face_landmarks,
                        connections=self.mp_face_mesh.FACEMESH_TESSELATION,
                        landmark_drawing_spec=self.drawing_spec,
                        connection_drawing_spec=self.drawing_spec)
                    mental_state = self.analyze_mental_state(face_landmarks, frame.shape)
                    self.prediction_label.setText(f'Mental State: {mental_state}')
                    save_to_database(mental_state)
            rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = rgb_frame.shape
            bytes_per_line = ch * w
            qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
            self.image_label.setPixmap(QPixmap.fromImage(qt_image))
        
    def analyze_mental_state(self, landmarks, frame_shape):
        height, width = frame_shape[:2]
        points = np.array([(lm.x * width, lm.y * height) for lm in landmarks.landmark])
        eye_ratio = self.calculate_eye_ratio(points)
        mouth_ratio = self.calculate_mouth_ratio(points)
        brow_ratio = self.calculate_brow_ratio(points)
        if eye_ratio < 0.2:
            return "Fatigue Detected"
        elif mouth_ratio > 0.5:
            return "Positive Mood"
        elif brow_ratio > 0.3:
            return "Stressed/Concerned"
        else:
            return "Neutral"
    def calculate_eye_ratio(self, points):
        left_eye = [33, 160, 158, 133, 153, 144]
        right_eye = [362, 385, 387, 263, 373, 380]
        left_eye_points = points[left_eye]
        right_eye_points = points[right_eye]
        def eye_aspect_ratio(eye_points):
            vertical_dist = np.linalg.norm(eye_points[1] - eye_points[5]) + \
                          np.linalg.norm(eye_points[2] - eye_points[4])
            horizontal_dist = np.linalg.norm(eye_points[0] - eye_points[3]) * 2
            return vertical_dist / horizontal_dist if horizontal_dist != 0 else 0
        left_ear = eye_aspect_ratio(left_eye_points)
        right_ear = eye_aspect_ratio(right_eye_points)
        return (left_ear + right_ear) / 2
    def calculate_mouth_ratio(self, points):
        mouth_points = [61, 291, 0, 17]
        mouth_pts = points[mouth_points]
        vertical_dist = np.linalg.norm(mouth_pts[2] - mouth_pts[3])
        horizontal_dist = np.linalg.norm(mouth_pts[0] - mouth_pts[1])
        return vertical_dist / horizontal_dist if horizontal_dist != 0 else 0
    def calculate_brow_ratio(self, points):
        left_brow = [70, 63, 105, 66, 107]
        left_eye = [159, 145, 133]
        brow_points = points[left_brow]
        eye_points = points[left_eye]
        brow_height = np.mean(brow_points[:, 1])
        eye_height = np.mean(eye_points[:, 1])
        return (eye_height - brow_height) / (points[152, 1] - points[10, 1])
    def closeEvent(self, event):
        self.cap.release()
        self.face_mesh.close()
        event.accept()
if __name__ == '__main__':
    app = QApplication(sys.argv)
    splash = SplashScreen()
    login_window = LoginWindow()
    splash.showSplash()
    QTimer.singleShot(3000, login_window.show)
    sys.exit(app.exec_())