File size: 11,108 Bytes
d35f894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f45cfdc
d35f894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4e3f31
d35f894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a4e3f31
d35f894
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

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'<a href="hasil_sentimen.xlsx" download="hasil_sentimen.xlsx">Unduh File XLSX</a>'
    else:
        csv = df.to_csv(index=False)
        return f'<a href="data:file/csv;base64,{b64encode(csv.encode()).decode()}" download="hasil_sentimen.csv">Unduh File CSV</a>'


# 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')