| """ |
| Forward Chaining Expert System - 7 Rules |
| Berdasarkan PERDOSKI 2024 (Panduan Praktik Klinis) |
| Referensi: Tabel 1. Rekomendasi Terapi Akne IAEM 2015 |
| |
| Structure: |
| Layer 1: Treatment (7 Rules) - Prioritas utama |
| Layer 2: Daily Skincare (Pendukung) - Facial wash, moisturizer, sunscreen |
| |
| Input: |
| - skin_type: "berminyak" | "kering" | "sensitif" | "kombinasi" |
| - severity_level: "clear" | "mild" | "moderate" | "severe" |
| - dominant_lesion: "comedone" | "papula_pustula" | "nodul" |
| |
| Klasifikasi Derajat (PERDOSKI 2024): |
| - Ringan: Komedo <20 ATAU lesi inflamasi <15 ATAU total lesi 30 |
| - Sedang: Komedo 20-100 ATAU lesi inflamasi 15-50 ATAU total lesi 30-125 |
| - Berat: Kista >5 ATAU komedo >100 ATAU lesi inflamasi >50 ATAU total lesi >125 |
| |
| Keterangan singkatan (PERDOSKI 2024): |
| RA = Retinoic Acid (termasuk Adapalene) |
| BPO = Benzoyl Peroxide |
| SA = Salicylic Acid |
| AB = Antibiotik (Doksisiklin/Minosiklin) |
| AA = Azelaic Acid |
| Dox = Doxicyclin |
| |
| Status Legalitas Indonesia (BPOM): |
| - Salicylic Acid ≤2%: Obat Bebas (OTC), batas skincare BPOM maks 2% |
| - Adapalene 0.1%: Obat Keras (Resep Dokter), walaupun di US sudah OTC |
| - Benzoyl Peroxide 2.5-5%: Obat Bebas Terbatas (OTC terbatas) |
| - Azelaic Acid 15-20%: Obat Keras (Resep Dokter), ASEAN Cosmetic Directive |
| - Niacinamide 2-10%: Kosmetik (Bebas), tidak termasuk obat |
| """ |
|
|
| VALID_SKIN_TYPES = ["berminyak", "kering", "sensitif", "kombinasi"] |
|
|
| SEVERITY_TO_DEGREE = { |
| "clear": "bersih", |
| "mild": "ringan", |
| "moderate": "sedang", |
| "severe": "berat", |
| } |
|
|
| |
| |
| |
|
|
| ACTIVE_INGREDIENT_INFO = { |
| "salicylic_acid": { |
| "name": "Salicylic Acid (BHA)", |
| "otc_status": "Obat Bebas (OTC)", |
| "prescription_required": False, |
| "pregnancy_category": "Hati-hati (konsultasi dokter)", |
| "max_concentration_otc": "2%", |
| "drug_interactions": [ |
| "Hindari penggunaan bersamaan dengan Adapalene (risiko iritasi berlebih)", |
| "BPO + SA: gunakan bergantian waktu (pagi/malam), jangan bersamaan", |
| ], |
| }, |
| "adapalene": { |
| "name": "Adapalene 0.1%", |
| "otc_status": "Obat Keras (Resep Dokter)", |
| "prescription_required": True, |
| "pregnancy_category": "Kategori C (Hindari saat hamil)", |
| "max_concentration_otc": "N/A (obat keras di Indonesia)", |
| "drug_interactions": [ |
| "JANGAN dicampur dengan Salicylic Acid (iritasi berlebih)", |
| "HINDARI penggunaan bersamaan dengan Retinoid lain, Sulfur, atau AHA", |
| "Adapalene + BPO: hanya dalam produk kombinasi (Epiduo) di bawah pengawasan dokter", |
| ], |
| }, |
| "benzoyl_peroxide": { |
| "name": "Benzoyl Peroxide (BPO)", |
| "otc_status": "Obat Bebas Terbatas", |
| "prescription_required": False, |
| "pregnancy_category": "Hati-hati (konsultasi dokter)", |
| "max_concentration_otc": "5%", |
| "drug_interactions": [ |
| "HINDARI dengan Tretinoin, Isotretinoin, Tazarotene (menurunkan efektivitas + iritasi)", |
| "Hindari dengan Sulfonamida (perubahan warna kulit sementara)", |
| "BPO + SA: gunakan bergantian waktu, jangan bersamaan", |
| ], |
| }, |
| "azelaic_acid": { |
| "name": "Azelaic Acid 15-20%", |
| "otc_status": "Obat Keras (Resep Dokter)", |
| "prescription_required": True, |
| "pregnancy_category": "Kategori B (Relatif aman, konsultasi dokter)", |
| "max_concentration_otc": "N/A (obat keras di Indonesia/ASEAN)", |
| "drug_interactions": [ |
| "HINDARI dengan Retinol/Isotretinoin (meningkatkan iritasi)", |
| "HINDARI dengan produk astringent atau alkohol kuat", |
| "AA + SA: aman, bahkan ada produk kombinasi", |
| ], |
| }, |
| "niacinamide": { |
| "name": "Niacinamide 2-10%", |
| "otc_status": "Kosmetik (Bebas)", |
| "prescription_required": False, |
| "pregnancy_category": "Aman", |
| "max_concentration_otc": "Tidak dibatasi (produk kosmetik)", |
| "drug_interactions": [ |
| "Aman dengan hampir semua bahan aktif", |
| "Tidak bereaksi dengan bahan sunscreen (oxybenzone, avobenzone, titanium dioxide)", |
| "Meningkatkan efektivitas Vitamin C dan sunscreen", |
| ], |
| }, |
| } |
|
|
|
|
| |
| |
| |
|
|
| RULES = [ |
| |
| |
| { |
| "rule": 1, |
| "condition": { |
| "degree": ["ringan"], |
| "dominant_lesion": ["comedone"], |
| "skin_type": ["berminyak", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Salicylic Acid (BHA) 0.5-2%", |
| "product_type": "Treatment", |
| "dosage": "2-3 tetes atau secukupnya", |
| "frequency": "1-2x sehari (pagi dan/atau malam)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Oleskan tipis pada area jerawat setelah facial wash. " |
| "BHA (Salicylic Acid) larut dalam minyak, membersihkan pori-pori tersumbat dari dalam. " |
| "Dapat digunakan pagi atau malam. Mulai dari konsentrasi rendah (0.5%) lalu tingkatkan." |
| ), |
| "evidence": "2B (PERDOSKI 2024)", |
| "prescription_required": False, |
| "otc_status": "Obat Bebas (OTC) - tersedia tanpa resep", |
| "pregnancy_category": "Hati-hati - konsultasi dokter sebelum digunakan", |
| "drug_interactions": [ |
| "Hindari penggunaan bersamaan dengan Adapalene (risiko iritasi berlebih)", |
| "Jangan digunakan bersamaan dengan BPO di waktu yang sama", |
| ], |
| }, |
| "contraindications": [], |
| }, |
|
|
| |
| |
| { |
| "rule": 2, |
| "condition": { |
| "degree": ["ringan"], |
| "dominant_lesion": ["comedone"], |
| "skin_type": ["sensitif", "kering"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Dermokosmetik Multitarget (BHA lembut + Niacinamide)", |
| "product_type": "Treatment", |
| "dosage": "Secukupnya", |
| "frequency": "1-2x sehari (pagi dan malam)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Gunakan produk multitarget dengan bahan aktif lembut. " |
| "Formula hypoallergenic untuk kulit sensitif. " |
| "Dapat mengandung BHA lembut (0.5%) atau Niacinamide untuk eksfoliasi ringan tanpa iritasi." |
| ), |
| "evidence": "1A-2B (PERDOSKI 2024)", |
| "prescription_required": False, |
| "otc_status": "Kosmetik/Obat Bebas - tersedia tanpa resep", |
| "pregnancy_category": "Aman (Niacinamide) / Hati-hati (BHA rendah)", |
| "drug_interactions": [], |
| }, |
| "contraindications": [], |
| }, |
|
|
| |
| |
| { |
| "rule": 3, |
| "condition": { |
| "degree": ["ringan"], |
| "dominant_lesion": ["papula_pustula"], |
| "skin_type": ["berminyak", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Adapalene 0.1% (Retinoid) atau Benzoyl Peroxide 2.5-5%", |
| "product_type": "Treatment", |
| "dosage": "Pea-size untuk seluruh wajah (Adapalene) atau secukupnya (BPO)", |
| "frequency": "1x sehari (malam)", |
| "time_of_day": "malam", |
| "instructions": ( |
| "Pilihan 1: Adapalene 0.1% malam hari. Mulai 2-3x seminggu, tingkatkan bertahap. " |
| "Pilihan 2: Benzoyl Peroxide 2.5-5% malam hari. " |
| "Gunakan pelembap setelahnya. Hindari paparan sinar UV langsung." |
| ), |
| "evidence": "1A (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Adapalene: Obat Keras (Resep Dokter). BPO: Obat Bebas Terbatas.", |
| "pregnancy_category": "Adapalene: Kategori C (HINDARI saat hamil). BPO: Hati-hati.", |
| "drug_interactions": [ |
| "Adapalene: JANGAN dicampur dengan SA, Retinoid lain, atau Sulfur", |
| "Adapalene + BPO: hanya dalam produk kombinasi (Epiduo) di bawah pengawasan dokter", |
| "BPO: Hindari dengan Tretinoin/Isotretinoin", |
| ], |
| }, |
| "contraindications": [ |
| "ADAPALENE: Hanya dengan resep dokter", |
| "Tidak untuk ibu hamil (Adapalene - Kategori C)", |
| "Hindari paparan sinar UV langsung", |
| "Jangan dicampur sendiri Adapalene dengan bahan aktif lain", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 4, |
| "condition": { |
| "degree": ["ringan"], |
| "dominant_lesion": ["papula_pustula"], |
| "skin_type": ["sensitif", "kering"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Dermokosmetik (pagi) + Adapalene 0.1% (malam)", |
| "product_type": "Treatment", |
| "dosage": "Secukupnya (dermokosmetik), pea-size (Adapalene)", |
| "frequency": "2x sehari (pagi dermokosmetik, malam adapalene)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Pagi: Dermokosmetik multitarget untuk menenangkan kulit. " |
| "Malam: Adapalene 0.1% mulai 2-3x seminggu, tingkatkan bertahap. " |
| "Gunakan pelembap setelah adapalene." |
| ), |
| "evidence": "1A (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Adapalene: Obat Keras (Resep Dokter)", |
| "pregnancy_category": "Adapalene: Kategori C (HINDARI saat hamil)", |
| "drug_interactions": [ |
| "Adapalene: JANGAN dicampur dengan SA, Retinoid lain, Sulfur, atau AHA", |
| "Hindari produk iritatif lainnya saat menggunakan Adapalene", |
| ], |
| }, |
| "contraindications": [ |
| "ADAPALENE: Hanya dengan resep dokter", |
| "Tidak untuk ibu hamil (Adapalene - Kategori C)", |
| "Hindari produk iritatif lainnya", |
| "Jangan dicampur sendiri Adapalene dengan bahan aktif lain", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 5, |
| "condition": { |
| "degree": ["sedang"], |
| "dominant_lesion": ["papula_pustula"], |
| "skin_type": ["berminyak", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Adapalene 0.1% + Benzoyl Peroxide 2.5% (kombinasi)", |
| "product_type": "Treatment", |
| "dosage": "Pea-size untuk seluruh wajah", |
| "frequency": "1x sehari (malam)", |
| "time_of_day": "malam", |
| "instructions": ( |
| "Gunakan produk kombinasi Adapalene 0.1% + Benzoyl Peroxide 2.5% (misal: Epiduo). " |
| "Oleskan tipis pada seluruh wajah malam hari. " |
| "Mulai 3-4x seminggu, tingkatkan bertahap. " |
| "Gunakan pelembap 20 menit setelahnya." |
| ), |
| "evidence": "1A (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Obat Keras (Resep Dokter) - produk kombinasi hanya dengan resep", |
| "pregnancy_category": "Kategori C (HINDARI saat hamil)", |
| "drug_interactions": [ |
| "JANGAN gunakan bersamaan dengan produk retinoid lainnya", |
| "Hindari penggunaan bersamaan dengan SA atau Sulfur", |
| "Hanya gunakan produk kombinasi jadi (Epiduo), JANGAN dicampur sendiri", |
| ], |
| }, |
| "contraindications": [ |
| "PRODUK KOMBINASI: Hanya dengan resep dokter", |
| "Tidak untuk ibu hamil (Adapalene - Kategori C)", |
| "Hindari paparan sinar UV langsung", |
| "JANGAN dicampur sendiri dengan produk retinoid lain", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 6, |
| "condition": { |
| "degree": ["sedang"], |
| "dominant_lesion": ["papula_pustula"], |
| "skin_type": ["sensitif", "kering"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Azelaic Acid 15-20% (pagi) + Dermokosmetik (malam)", |
| "product_type": "Treatment", |
| "dosage": "Pea-size untuk seluruh wajah", |
| "frequency": "2x sehari (pagi AA, malam dermokosmetik)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Pagi: Azelaic Acid 15-20% mengurangi inflamasi dan bakteri. " |
| "Malam: Dermokosmetik multitarget untuk perbaikan sawar kulit. " |
| "Azelaic Acid aman untuk kulit sensitif dan ibu hamil." |
| ), |
| "evidence": "1B (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Obat Keras (Resep Dokter) - ASEAN Cosmetic Directive", |
| "pregnancy_category": "Kategori B (Relatif aman, konsultasi dokter)", |
| "drug_interactions": [ |
| "HINDARI dengan Retinol/Isotretinoin (meningkatkan iritasi)", |
| "HINDARI dengan produk astringent atau alkohol kuat", |
| ], |
| }, |
| "contraindications": [ |
| "AZELAIC ACID: Hanya dengan resep dokter", |
| "Hindari penggunaan bersamaan dengan Retinol atau Isotretinoin", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 7, |
| "condition": { |
| "degree": ["berat"], |
| "dominant_lesion": ["nodul", "papula_pustula", "comedone"], |
| "skin_type": ["berminyak", "kering", "sensitif", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "STOP - Rujuk Dokter Spesialis Kulit", |
| "product_type": "Konsultasi Medis", |
| "dosage": "N/A", |
| "frequency": "Segera", |
| "time_of_day": "segera", |
| "instructions": ( |
| "HENTIKAN pengobatan mandiri. Jerawat derajat berat membutuhkan penanganan medis profesional. " |
| "Kemungkinan memerlukan: Isotretinoin oral (1-2 mg/kg/hari), " |
| "Antibiotik oral (Doksisiklin 2x100 mg/hari), " |
| "atau terapi kombinasi sesuai indikasi dokter." |
| ), |
| "evidence": "1B (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Semua terapi memerlukan resep dokter", |
| "pregnancy_category": "Isotretinoin: TERATOGENIK (Dilarang saat hamil)", |
| "drug_interactions": [ |
| "Semua terapi harus diawasi oleh dokter spesialis kulit", |
| "Isotretinoin: Dilarang saat hamil dan menyusui", |
| ], |
| }, |
| "contraindications": [ |
| "Semua terapi: HANYA dengan resep dokter spesialis kulit", |
| "Jangan memencet jerawat nodul", |
| "Isotretinoin: TERATOGENIK - Dilarang saat hamil", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 8, |
| "condition": { |
| "degree": ["sedang", "ringan"], |
| "dominant_lesion": ["nodul"], |
| "skin_type": ["berminyak", "kering", "sensitif", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "STOP - Rujuk Dokter Spesialis Kulit", |
| "product_type": "Konsultasi Medis", |
| "dosage": "N/A", |
| "frequency": "Segera", |
| "time_of_day": "segera", |
| "instructions": ( |
| "Terdeteksi jerawat nodul yang memerlukan penanganan medis. " |
| "Nodul adalah bentuk jerawat dalam yang meninggalkan bekas permanen jika tidak ditangani. " |
| "Segera konsultasi ke dokter spesialis kulit untuk evaluasi dan rencana pengobatan." |
| ), |
| "evidence": "1B (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Semua terapi memerlukan resep dokter", |
| "pregnancy_category": "Konsultasi dokter", |
| "drug_interactions": [ |
| "Semua terapi harus diawasi oleh dokter spesialis kulit", |
| ], |
| }, |
| "contraindications": [ |
| "Semua terapi: HANYA dengan resep dokter spesialis kulit", |
| "Jangan memencet jerawat nodul", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 9, |
| "condition": { |
| "degree": ["sedang"], |
| "dominant_lesion": ["comedone"], |
| "skin_type": ["berminyak", "kombinasi"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Salicylic Acid (BHA) 2% + Adapalene 0.1%", |
| "product_type": "Treatment", |
| "dosage": "2-3 tetes BHA (pagi), pea-size Adapalene (malam)", |
| "frequency": "2x sehari (pagi BHA, malam Adapalene)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Pagi: Salicylic Acid (BHA) 2% untuk eksfoliasi pori. " |
| "Malam: Adapalene 0.1% mulai 3-4x seminggu, tingkatkan bertahap. " |
| "Komedo yang banyak memerlukan kombinasi eksfolian + retinoid untuk hasil optimal. " |
| "Gunakan pelembap sebagai penghalang di antara aplikasi." |
| ), |
| "evidence": "1A-2B (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Adapalene: Obat Keras (Resep Dokter). BHA: Obat Bebas (OTC).", |
| "pregnancy_category": "Adapalene: Kategori C (HINDARI saat hamil). BHA: Hati-hati.", |
| "drug_interactions": [ |
| "JANGAN gunakan BHA dan Adapalene pada waktu yang sama", |
| "Pagi: BHA saja. Malam: Adapalene saja.", |
| "Adapalene: JANGAN dicampur dengan Sulfur atau AHA", |
| ], |
| }, |
| "contraindications": [ |
| "ADAPALENE: Hanya dengan resep dokter", |
| "Tidak untuk ibu hamil (Adapalene - Kategori C)", |
| "Jangan aplikasikan BHA dan Adapalene bersamaan", |
| ], |
| }, |
|
|
| |
| |
| { |
| "rule": 10, |
| "condition": { |
| "degree": ["sedang"], |
| "dominant_lesion": ["comedone"], |
| "skin_type": ["sensitif", "kering"], |
| }, |
| "recommendation": { |
| "active_ingredient": "Salicylic Acid (BHA) 0.5-1% + Azelaic Acid 15%", |
| "product_type": "Treatment", |
| "dosage": "Secukupnya", |
| "frequency": "2x sehari (pagi AA, malam BHA rendah)", |
| "time_of_day": "pagi_malam", |
| "instructions": ( |
| "Pagi: Azelaic Acid 15% untuk anti-inflamasi dan eksfoliasi lembut. " |
| "Malam: BHA rendah (0.5-1%) untuk membersihkan pori tanpa iritasi. " |
| "Untuk kulit sensitif, gunakan frekuensi rendah dulu lalu tingkatkan. " |
| "Pelembap wajib setiap kali setelah treatment." |
| ), |
| "evidence": "1B-2B (PERDOSKI 2024)", |
| "prescription_required": True, |
| "otc_status": "Azelaic Acid: Obat Keras (Resep Dokter). BHA: Obat Bebas (OTC).", |
| "pregnancy_category": "Azelaic Acid: Kategori B (Relatif aman). BHA: Hati-hati.", |
| "drug_interactions": [ |
| "JANGAN gunakan BHA dan Adapalene bersamaan", |
| "Azelaic Acid: HINDARI dengan Retinol/Isotretinoin", |
| ], |
| }, |
| "contraindications": [ |
| "AZELAIC ACID: Hanya dengan resep dokter", |
| "Hindari penggunaan bersamaan dengan Retinol atau Isotretinoin", |
| ], |
| }, |
| ] |
|
|
|
|
| |
| |
| |
| |
|
|
| DAILY_SKINCARE = { |
| "berminyak": { |
| "facial_wash": { |
| "name": "Facial Wash Gel/Foam pH Balanced", |
| "description": "Pembersih berbentuk gel atau busa, pH balanced, bebas alkohol", |
| "ingredients": "Tea tree, salicylic acid ringan, niacinamide", |
| "usage": "2x sehari (pagi dan malam)", |
| }, |
| "moisturizer": { |
| "name": "Moisturizer Oil-Free / Non-Comedogenic", |
| "description": "Pelembap ringan tanpa minyak, tidak menyumbat pori", |
| "ingredients": "Hyaluronic acid, niacinamide, aloe vera", |
| "usage": "2x sehari setelah treatment", |
| }, |
| "sunscreen": { |
| "name": "Sunscreen SPF 30-50 PA+++", |
| "description": "Pelindung UV ringan, tidak lengket, non-comedogenic", |
| "ingredients": "SPF 30-50, PA+++, formula gel atau air", |
| "usage": "Pagi hari, 15 menit sebelum keluar rumah, reapply tiap 2-3 jam", |
| }, |
| }, |
| "kering": { |
| "facial_wash": { |
| "name": "Facial Wash Cream/Milk pH Balanced", |
| "description": "Pembersih lembut berbentuk krim atau susu, tidak mengikis kelembapan", |
| "ingredients": "Ceramide, glycerin, centella asiatica", |
| "usage": "2x sehari (pagi dan malam)", |
| }, |
| "moisturizer": { |
| "name": "Moisturizer Hydrating / Ceramide", |
| "description": "Pelembap kaya nutrisi untuk mengembalikan sawar kulit", |
| "ingredients": "Ceramide, hyaluronic acid, squalane, shea butter", |
| "usage": "2x sehari setelah treatment", |
| }, |
| "sunscreen": { |
| "name": "Sunscreen SPF 30-50 PA+++ Hydrating", |
| "description": "Pelindung UV dengan formula melembapkan", |
| "ingredients": "SPF 30-50, PA+++, dengan hyaluronic acid", |
| "usage": "Pagi hari, 15 menit sebelum keluar rumah, reapply tiap 2-3 jam", |
| }, |
| }, |
| "sensitif": { |
| "facial_wash": { |
| "name": "Facial Wash Gentle / Fragrance-Free", |
| "description": "Pembersih sangat lembut, bebas pewangi dan alkohol", |
| "ingredients": "Centella asiatica, panthenol, allantoin", |
| "usage": "2x sehari (pagi dan malam)", |
| }, |
| "moisturizer": { |
| "name": "Moisturizer Calming / Centella", |
| "description": "Pelembap menenangkan, mengurangi kemerahan dan iritasi", |
| "ingredients": "Aloe vera, centella asiatica, madecassoside, panthenol", |
| "usage": "2x sehari setelah treatment", |
| }, |
| "sunscreen": { |
| "name": "Sunscreen Mineral SPF 30-50", |
| "description": "Pelindung UV minimal iritasi, formula fisik (mineral)", |
| "ingredients": "SPF 30-50, PA+++, zinc oxide/titanium dioxide", |
| "usage": "Pagi hari, 15 menit sebelum keluar rumah, reapply tiap 2-3 jam", |
| }, |
| }, |
| "kombinasi": { |
| "facial_wash": { |
| "name": "Facial Wash Gentle Foam pH Balanced", |
| "description": "Pembersih ringan berbentuk busa lembut", |
| "ingredients": "Glycerin, niacinamide ringan, centella asiatica", |
| "usage": "2x sehari (pagi dan malam)", |
| }, |
| "moisturizer": { |
| "name": "Moisturizer Gel-Cream Oil-Free", |
| "description": "Pelembap bertekstur gel-cream, ringan tapi melembapkan", |
| "ingredients": "Hyaluronic acid, niacinamide, aloe vera", |
| "usage": "2x sehari setelah treatment", |
| }, |
| "sunscreen": { |
| "name": "Sunscreen SPF 30-50 PA+++ Gel", |
| "description": "Pelindung UV ringan, tidak lengket di T-zone", |
| "ingredients": "SPF 30-50, PA+++, formula gel atau air", |
| "usage": "Pagi hari, 15 menit sebelum keluar rumah, reapply tiap 2-3 jam", |
| }, |
| }, |
| } |
|
|
|
|
| |
| |
| |
|
|
| def _get_dominant_lesion(summary: dict) -> str: |
| """Menentukan jenis lesi dominan dari summary deteksi. |
| |
| Note: Nodul TIDAK dijadikan dominant lesion karena: |
| - Penanganan nodul selalu rujuk dokter (tidak ada self-treatment) |
| - Kita tetap ingin match rule untuk lesi LAIN yang bisa ditreatment |
| - Nodul ditangani terpisah via nodul_alert |
| """ |
| if not summary: |
| return "comedone" |
|
|
| comedone_count = summary.get("comedone", 0) |
| papula_count = summary.get("papules", 0) |
| pustule_count = summary.get("pustules", 0) |
|
|
| papula_pustula_total = papula_count + pustule_count |
|
|
| if papula_pustula_total > comedone_count: |
| return "papula_pustula" |
| return "comedone" |
|
|
|
|
| def _has_nodul(summary: dict) -> bool: |
| """Cek apakah ada nodul dalam deteksi.""" |
| return summary.get("nodules", 0) > 0 |
|
|
|
|
| def _evaluate_rules(degree: str, dominant_lesion: str, skin_type: str) -> list: |
| """Evaluasi semua rules dan kembalikan rules yang cocok.""" |
| matched_rules = [] |
|
|
| for rule in RULES: |
| cond = rule["condition"] |
|
|
| if degree not in cond["degree"]: |
| continue |
| if dominant_lesion not in cond["dominant_lesion"]: |
| continue |
| if skin_type not in cond["skin_type"]: |
| continue |
|
|
| matched_rules.append(rule) |
|
|
| return matched_rules |
|
|
|
|
| def get_expert_recommendation( |
| detected_classes: list, |
| summary: dict, |
| skin_type: str, |
| severity_level: str, |
| ) -> dict: |
| """ |
| Forward Chaining: evaluasi rules dan kembalikan rekomendasi. |
| |
| Berdasarkan PERDOSKI 2024: |
| - Ringan: Topikal lini 1 (SA/RA/BPO) |
| - Sedang: Topikal lini 1 + Oral (Dox) |
| - Berat: Rujuk dokter, oral Isotretinoin/AB |
| |
| Returns: |
| dict berisi: |
| - expert_rule: info rule yang aktif |
| - recommendation: rekomendasi treatment (Layer 1) |
| - daily_skincare: rekomendasi daily skincare (Layer 2) |
| - nonmedikamentosa: tips non obat (PERDOSKI 2024) |
| - maintenance: tips pemeliharaan (PERDOSKI 2024) |
| - active_ingredient_info: info legalitas bahan aktif |
| - nodul_alert: peringatan nodul (jika ada nodul terdeteksi) |
| """ |
| if skin_type not in VALID_SKIN_TYPES: |
| skin_type = "berminyak" |
|
|
| dominant_lesion = _get_dominant_lesion(summary) |
|
|
| |
| has_nodul = _has_nodul(summary) |
| if has_nodul: |
| |
| non_nodul_summary = {k: v for k, v in summary.items() if k != "nodules"} |
| non_nodul_score = sum( |
| count * {"comedone": 1, "papules": 2, "pustules": 2}.get(cls, 1) |
| for cls, count in non_nodul_summary.items() |
| ) |
| |
| if non_nodul_score == 0: |
| non_nodul_severity = "clear" |
| elif non_nodul_score <= 9: |
| non_nodul_severity = "mild" |
| elif non_nodul_score <= 19: |
| non_nodul_severity = "moderate" |
| else: |
| non_nodul_severity = "severe" |
| treatment_degree = SEVERITY_TO_DEGREE.get(non_nodul_severity, "ringan") |
| else: |
| treatment_degree = SEVERITY_TO_DEGREE.get(severity_level, "ringan") |
|
|
| matched_rules = _evaluate_rules(treatment_degree, dominant_lesion, skin_type) |
|
|
| if matched_rules: |
| active_rule = matched_rules[0] |
| recommendation = active_rule["recommendation"] |
| contraindications = active_rule.get("contraindications", []) |
| rule_number = active_rule["rule"] |
| else: |
| recommendation = { |
| "active_ingredient": "Konsultasi Dokter Kulit", |
| "product_type": "Konsultasi Medis", |
| "dosage": "N/A", |
| "frequency": "Segera", |
| "time_of_day": "segera", |
| "instructions": "Tidak ada rekomendasi spesifik. Silakan konsultasi dengan dokter kulit.", |
| "evidence": "-", |
| "prescription_required": True, |
| "otc_status": "Konsultasi dokter", |
| "pregnancy_category": "Konsultasi dokter", |
| "drug_interactions": [], |
| } |
| contraindications = [] |
| rule_number = 0 |
|
|
| daily_skincare = DAILY_SKINCARE.get(skin_type, DAILY_SKINCARE["berminyak"]) |
|
|
| |
| nonmedikamentosa = [ |
| "Cuci muka 2x sehari dengan sabun pH balanced, bebas alkohol, non-abrasif", |
| "Hindari penggunaan kosmetik yang bersifat oklusif", |
| "Batasi konsumsi makanan indeks glikemik tinggi (karbohidrat, makanan berlemak, produk olahan susu)", |
| "Identifikasi dan kelola stres psikologis", |
| ] |
|
|
| |
| maintenance = [ |
| "Setelah remisi, lanjutkan retinoid topikal <0.01-0.025% untuk pencegahan kekambuhan", |
| "Gunakan sabun wajah, pelembap, dan tabir surya sesuai kondisi kulit", |
| "Evaluasi respons pengobatan tiap 8-12 minggu", |
| ] |
|
|
| |
| active_ingredient_info = _get_active_ingredient_info(recommendation["active_ingredient"]) |
|
|
| |
| nodul_alert = None |
| if _has_nodul(summary): |
| nodule_count = summary.get("nodules", 0) |
| nodul_alert = { |
| "detected": True, |
| "count": nodule_count, |
| "title": "Nodul Terdeteksi", |
| "message": ( |
| f"Terdeteksi {nodule_count} nodul pada wajah. " |
| "Nodul adalah jerawat dalam yang tidak dapat ditangani dengan skincare atau obat bebas. " |
| "Diperlukan penanganan medis oleh dokter spesialis kulit." |
| ), |
| "treatments": [ |
| "Injeksi triamsinolon acetonide (TAIL) intralesi — dosis 0,03 mg per lesi", |
| "Ekstraksi lesi oleh dokter", |
| "Isotretinoin oral (untuk kasus berat) — hanya dengan resep dokter", |
| ], |
| "urgency": "Segera — risiko bekas permanen jika tidak ditangani", |
| } |
|
|
| return { |
| "expert_rule": { |
| "rule_number": rule_number, |
| "degree": treatment_degree, |
| "dominant_lesion": dominant_lesion, |
| "skin_type": skin_type, |
| "input_summary": { |
| "severity_level": severity_level, |
| "detected_classes": detected_classes, |
| "lesion_counts": summary, |
| "has_nodul": has_nodul, |
| }, |
| }, |
| "recommendation": { |
| **recommendation, |
| "contraindications": contraindications, |
| }, |
| "daily_skincare": daily_skincare, |
| "nonmedikamentosa": nonmedikamentosa, |
| "maintenance": maintenance, |
| "active_ingredient_info": active_ingredient_info, |
| "nodul_alert": nodul_alert, |
| } |
|
|
|
|
| def _get_active_ingredient_info(ingredient_str: str) -> list: |
| """Ambil info bahan aktif berdasarkan string rekomendasi.""" |
| info = [] |
| ingredient_lower = ingredient_str.lower() |
|
|
| if "salicylic" in ingredient_lower or "bha" in ingredient_lower: |
| info.append(ACTIVE_INGREDIENT_INFO["salicylic_acid"]) |
| if "adapalene" in ingredient_lower: |
| info.append(ACTIVE_INGREDIENT_INFO["adapalene"]) |
| if "benzoyl" in ingredient_lower or "bpo" in ingredient_lower: |
| info.append(ACTIVE_INGREDIENT_INFO["benzoyl_peroxide"]) |
| if "azelaic" in ingredient_lower: |
| info.append(ACTIVE_INGREDIENT_INFO["azelaic_acid"]) |
| if "niacinamide" in ingredient_lower: |
| info.append(ACTIVE_INGREDIENT_INFO["niacinamide"]) |
|
|
| return info |
|
|