import streamlit as st import pandas as pd import numpy as np import re import json import joblib from sklearn.feature_extraction.text import TfidfVectorizer # Impor library tambahan import matplotlib.pyplot as plt import seaborn as sns from wordcloud import WordCloud # Set judul situs web st.set_page_config(page_title="naufalnashif-ML") # Fungsi untuk membersihkan teks dengan ekspresi reguler def clean_text(text): # Tahap-1: Menghapus karakter non-ASCII text = re.sub(r'[^\x00-\x7F]+', '', text) # Tahap-2: Menghapus URL text = re.sub(r'http[s]?://.[a-zA-Z0-9./_?=%&#+!]+', '', text) text = re.sub(r'pic.twitter.com?.[a-zA-Z0-9./_?=%&#+!]+', '', text) # Tahap-3: Menghapus mentions text = re.sub(r'@[\w]+', '', text) # Tahap-4: Menghapus hashtag text = re.sub(r'#([\w]+)', '', text) # Tahap-5: Menghapus karakter khusus (simbol) text = re.sub(r'[!$%^&*@#()_+|~=`{}\[\]%\-:";\'<>?,./]', '', text) # Tahap-6: Menghapus angka text = re.sub(r'[0-9]+', '', text) # Tahap-7: Menggabungkan spasi ganda menjadi satu spasi text = re.sub(' +', ' ', text) # Tahap-8: Menghapus spasi di awal dan akhir kalimat text = text.strip() # Tahap-9: Konversi teks ke huruf kecil text = text.lower() return text # Membaca kamus kata gaul Salsabila kamus_path = '_json_colloquial-indonesian-lexicon (1).txt' # Ganti dengan path yang benar with open(kamus_path) as f: data = f.read() lookp_dict = json.loads(data) # Dict kata gaul saya sendiri yang tidak masuk di dict Salsabila kamus_gaul_baru = { 'kurangg': 'kurang', 'udaa': 'udah', 'mnurut': 'menurut', 'anyinh': 'anjing', 'seputat': 'seputar', 'ijo' : 'hijau', 'dmma' : 'dimana', 'anjrot' : 'anjing', 'ajgg' : 'anjing', 'keboen' : 'kebun', 'aseekk' : 'asik', 'bliau' : 'beliau', 'aseek' : 'asik', 'berpaa' : 'berapa', 'berpa' : 'berapa', 'bggtt' : 'banget', 'cntoh' : 'contoh', 'anzink' : 'anjing', 'jrg' : 'jarang', 'msi' : 'masih', 'anjirt' : 'anjing', 'kesampeian' : 'kesampaian', 'dtgnya' : 'datangnya', 'dtg' : 'datang', 'dngin' : 'dingin', 'ktub' : 'kutub', 'brngkt' : 'berangkat', 'antra' : 'antara', 'pinuh': 'penuh', 'anjink': 'anjing', 'anjir' : 'anjing', 'ajg': 'anjing', 'smpet': 'sempat', 'sempet': 'sempat', 'makai': 'memakai', 'bgst': 'bangsat', 'anjg': 'anjing', 'cpk': 'lelah', 'capek': 'lelah', 'capk': 'lelah', 'cpek': 'lelah', 'anjrit': 'anjing', 'anjig': 'anjing', 'anjigg': 'anjing', 'anjingg': 'anjing', 'bukann': 'bukan', 'skrgg': 'sekarang', 'makasihh': 'terimakasih', 'asu': 'anjing', 'moga': 'semoga', 'cok': 'jancok', 'cokk': 'jancok', 'cook': 'jancok', 'cookk': 'jancok', 'amgkot': 'angkot', 'gua' : 'aku', 'gweh': 'aku', 'guah': 'aku', 'gw': 'aku', 'gwah': 'aku', 'gue' : 'aku', 'wkwkwk' : 'wkwk', 'dah' : 'udah', 'tkt' : 'takut', 'gabisa' : 'gabisa', 'umumm' : 'umum', 'umuum' : 'umum', 'yah' : 'yah', 'drtd' : 'daritadi', 'drtdi' : 'daritadi', 'ges':'gais', 'gays': 'gais', 'geys':'gais', 'trans pakuan': 'transpakuan', 'anjr' : 'anjir', 'anjer' : 'anjing', 'njir' : 'anjing', 'anjr' : 'anjing', 'trans pakuan' : 'transpakuan', 'gblk' : 'goblok', } # Menambahkan dict kata gaul baru ke kamus yang sudah ada lookp_dict.update(kamus_gaul_baru) # Fungsi untuk normalisasi kata gaul def normalize_slang(text, slang_dict): words = text.split() normalized_words = [slang_dict.get(word, word) for word in words] return ' '.join(normalized_words) # Fungsi untuk ekstraksi fitur TF-IDF def extract_tfidf_features(texts, tfidf_vectorizer): tfidf_matrix = tfidf_vectorizer.transform(texts) return tfidf_matrix # Memuat model TF-IDF dengan joblib (pastikan path-nya benar) tfidf_model_path = 'X_tfidf_model.joblib' tfidf_vectorizer = joblib.load(tfidf_model_path) # Fungsi untuk prediksi sentimen def predict_sentiment(text, model, tfidf_vectorizer, slang_dict): # Tahap-1: Membersihkan dan normalisasi teks cleaned_text = clean_text(text) norm_slang_text = normalize_slang(cleaned_text, slang_dict) # Tahap-2: Ekstraksi fitur TF-IDF tfidf_matrix = tfidf_vectorizer.transform([norm_slang_text]) # Tahap-3: Lakukan prediksi sentimen sentiment = model.predict(tfidf_matrix) # Tahap-4: Menggantikan indeks dengan label sentimen labels = {0: "Negatif", 1: "Netral", 2: "Positif"} sentiment_label = labels[int(sentiment)] return sentiment_label # Memuat model sentimen dengan joblib (pastikan path-nya benar) sentiment_model_path = 'ensemble_clf_soft_smote.joblib' sentiment_model = joblib.load(sentiment_model_path) def get_emoticon(sentiment): if sentiment == "Positif": emoticon = "😄" # Emotikon untuk sentimen positif elif sentiment == "Negatif": emoticon = "😞" # Emotikon untuk sentimen negatif else: emoticon = "😐" # Emotikon untuk sentimen netral return emoticon # Fungsi untuk membuat tautan unduhan def get_table_download_link(df, download_format): if download_format == "XLSX": df.to_excel("hasil_sentimen.xlsx", index=False) return f'Unduh File XLSX' else: csv = df.to_csv(index=False) return f'Unduh File CSV' # Judul st.title("Aplikasi ML Analisis Sentimen based on data Biskita Transpakuan") # Pilihan input teks manual atau berkas XLSX input_option = st.radio("Pilih metode input:", ("Teks Manual", "Unggah Berkas XLSX")) if input_option == "Teks Manual": # Input teks dari pengguna user_input = st.text_area("Masukkan teks:", "") else: # Input berkas XLSX uploaded_file = st.file_uploader("Unggah berkas XLSX", type=["xlsx"]) st.write("**Pastikan berkas XLSX Anda memiliki kolom yang bernama 'Text'.**") if uploaded_file is not None: df = pd.read_excel(uploaded_file) if 'Text' not in df.columns: st.warning("Berkas XLSX harus memiliki kolom bernama 'Text' untuk analisis sentimen.") else: texts = df['Text'] # Sesuaikan dengan nama kolom di berkas XLSX Anda # Analisis sentimen results = [] if input_option == "Teks Manual" and user_input: # Pisahkan teks yang dimasukkan pengguna menjadi baris-baris terpisah user_texts = user_input.split('\n') for text in user_texts: sentiment_label = predict_sentiment(text, sentiment_model, tfidf_vectorizer, lookp_dict) emoticon = get_emoticon(sentiment_label) cleaned_text = clean_text(text) norm_slang_text = normalize_slang(cleaned_text, lookp_dict) results.append((text, cleaned_text, norm_slang_text, sentiment_label, emoticon)) elif input_option == "Unggah Berkas XLSX" and uploaded_file is not None: if 'Text' in df.columns: for text in texts: sentiment_label = predict_sentiment(text, sentiment_model, tfidf_vectorizer, lookp_dict) emoticon = get_emoticon(sentiment_label) cleaned_text = clean_text(text) norm_slang_text = normalize_slang(cleaned_text, lookp_dict) results.append((text, cleaned_text, norm_slang_text, sentiment_label, emoticon)) else: st.warning("Berkas XLSX harus memiliki kolom bernama 'Text' untuk analisis sentimen.") # Membagi tampilan menjadi dua kolom columns = st.columns(2) # Kolom pertama untuk Word Cloud with columns[0]: if results: all_texts = [result[2] for result in results if result[2] is not None and not pd.isna(result[2])] all_texts = " ".join(all_texts) st.subheader("Word Cloud") if all_texts: wordcloud = WordCloud(width=800, height=660, background_color='white', colormap='Purples', # Warna huruf contour_color='black', # Warna kontur contour_width=2, # Lebar kontur mask=None, # Gunakan mask untuk bentuk kustom ).generate(all_texts) st.image(wordcloud.to_array()) else: st.write("Tidak ada data untuk ditampilkan dalam Word Cloud.") # Kolom kedua untuk Bar Chart with columns[1]: st.subheader("Chart") if results: df_results = pd.DataFrame(results, columns=["Teks", "Cleaned Text", "Norm Text", "Hasil Analisis Sentimen", "Emotikon"]) sns.set_style("whitegrid") # Menyiapkan label kelas class_labels = ["Negatif", "Netral", "Positif"] # Menghitung nilai hitungan per label value_counts = df_results["Hasil Analisis Sentimen"].value_counts() # Mengurutkan nilai hitungan berdasarkan label value_counts = value_counts.reindex(class_labels) fig, ax = plt.subplots() # Buat objek Figure sns.barplot(x=value_counts.index, y=value_counts.values, ax=ax) # Gunakan ax= untuk plot plt.xticks(rotation=45) st.pyplot(fig) # Tampilkan plot menggunakan st.pyplot(fig) # Menampilkan hasil analisis sentimen dalam kotak yang dapat diperluas with st.expander("Hasil Analisis Sentimen"): # Tampilkan tabel hasil analisis sentimen st.table(pd.DataFrame(results, columns=["Teks", "Cleaned Text", "Norm Text", "Hasil Analisis Sentimen", "Emotikon"])) # Tautan untuk mengunduh hasil dalam format XLSX atau CSV st.subheader("Unduh Hasil") download_format = st.selectbox("Pilih format unduhan:", ["XLSX", "CSV"]) if results: if download_format == "XLSX": # Simpan DataFrame ke dalam file XLSX df = pd.DataFrame(results, columns=["Teks", "Cleaned Text", "Norm Text", "Hasil Analisis Sentimen", "Emotikon"]) df.to_excel("hasil_sentimen.xlsx", index=False) # Tampilkan tombol unduh XLSX st.download_button(label="Unduh XLSX", data=open("hasil_sentimen.xlsx", "rb").read(), key="xlsx_download", file_name="hasil_sentimen.xlsx") else: # Jika CSV # Simpan DataFrame ke dalam file CSV df = pd.DataFrame(results, columns=["Teks", "Cleaned Text", "Norm Text", "Hasil Analisis Sentimen", "Emotikon"]) csv = df.to_csv(index=False) # Tampilkan tombol unduh CSV st.download_button(label="Unduh CSV", data=csv, key="csv_download", file_name="hasil_sentimen.csv") else: st.write("Tidak ada data untuk diunduh.") # Garis pemisah st.divider() # Tautan ke GitHub github_link = "https://github.com/naufalnashif/" st.markdown(f"GitHub: [{github_link}]({github_link})") # Tautan ke Instagram instagram_link = "https://www.instagram.com/naufal.nashif/" st.markdown(f"Instagram: [{instagram_link}]({instagram_link})") # Pesan penutup st.write('Thank you for trying the demo!') st.write('Best regards, Naufal Nashif')