galihrhgnwn commited on
Commit
4858261
·
verified ·
1 Parent(s): 1fe38bb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +275 -149
app.py CHANGED
@@ -4,197 +4,323 @@ import json
4
  import os
5
  import uuid
6
 
7
- # Styling dengan CSS untuk tampilan lebih mirip ChatGPT
8
  st.markdown(
9
  """
10
  <style>
11
- /* Tombol menu sidebar */
12
- .menu-btn {
13
- position: fixed;
14
- top: 10px;
15
- left: 10px;
16
- font-size: 24px;
17
- cursor: pointer;
18
- z-index: 1001;
19
- }
20
-
21
- /* Styling sidebar */
22
- [data-testid="stSidebar"] {
23
- background-color: #f8f9fa;
24
- width: 300px;
25
- border-right: 2px solid #ddd;
26
  }
27
 
28
- /* Styling chat bubble */
29
- .chat-message {
30
- padding: 12px 15px;
 
 
31
  border-radius: 15px;
32
- margin-bottom: 10px;
33
- max-width: 75%;
 
 
 
34
  }
35
 
36
- .chat-message.user {
37
- background-color: #4A90E2;
38
- color: white;
39
- margin-left: auto;
40
- text-align: right;
 
41
  }
42
 
43
- .chat-message.assistant {
44
- background-color: #e9ecef;
45
- color: black;
46
- margin-right: auto;
47
  }
48
 
49
- /* Avatar */
50
- .chat-avatar {
51
  width: 40px;
52
  height: 40px;
53
  border-radius: 50%;
54
- object-fit: cover;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
 
57
  /* Loading animation */
58
- .loading {
59
- text-align: center;
60
- font-size: 1.2em;
61
- color: #4A90E2;
62
- margin-top: 10px;
 
 
 
 
63
  }
64
- </style>
65
- """,
66
- unsafe_allow_html=True,
67
- )
68
 
69
- # Tombol ☰ di pojok kiri atas untuk membuka sidebar
70
- st.markdown('<div class="menu-btn">☰</div>', unsafe_allow_html=True)
 
 
 
 
71
 
72
- # Inisialisasi file database
73
- DATABASE_FILE = "database.json"
 
 
 
 
 
 
 
 
74
 
75
- def load_database():
76
- """Memuat database dari file JSON."""
77
- if os.path.exists(DATABASE_FILE):
78
- try:
79
- with open(DATABASE_FILE, "r") as file:
80
- return json.load(file)
81
- except json.JSONDecodeError:
82
- return {}
83
- return {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- def save_database(database):
86
- """Menyimpan database ke file JSON."""
87
- with open(DATABASE_FILE, "w") as file:
88
- json.dump(database, file, indent=4)
 
 
 
 
89
 
90
- database = load_database()
 
 
91
 
92
- # Generate user_id jika belum ada
93
- if "user_id" not in st.session_state:
94
- st.session_state.user_id = str(uuid.uuid4())
 
95
 
96
- user_id = st.session_state.user_id
 
 
 
97
 
98
- # Inisialisasi session state
99
- if "sessions" not in st.session_state:
100
- st.session_state.sessions = database.get(user_id, {})
101
- if "current_session" not in st.session_state:
102
- st.session_state.current_session = None
103
 
104
- # Sidebar dengan tombol collapse
 
 
 
105
  with st.sidebar:
106
- st.header("📁 Session List")
107
-
108
- new_session_name = st.text_input("Buat Session Baru", placeholder="Nama Session")
109
- if st.button("Buat Session"):
110
- if new_session_name:
111
- if new_session_name not in st.session_state.sessions:
112
- st.session_state.sessions[new_session_name] = []
113
- st.session_state.current_session = new_session_name
114
- database[user_id] = st.session_state.sessions
115
- save_database(database)
116
- st.success(f"Session '{new_session_name}' berhasil dibuat!")
 
 
 
 
 
117
  else:
118
- st.error("Nama session sudah ada!")
119
- else:
120
- st.error("Nama session tidak boleh kosong!")
121
-
122
- if st.session_state.sessions:
123
- selected_session = st.selectbox(
124
- "Pilih Session",
125
- list(st.session_state.sessions.keys()),
126
- index=list(st.session_state.sessions.keys()).index(st.session_state.current_session)
127
- if st.session_state.current_session else 0
 
 
 
128
  )
129
- if st.button("Set Session Aktif"):
130
- st.session_state.current_session = selected_session
131
- st.success(f"Session '{selected_session}' dipilih!")
132
-
133
- session_to_delete = st.selectbox("Pilih Session untuk Dihapus", list(st.session_state.sessions.keys()))
134
- if st.button("Hapus Session"):
135
- del st.session_state.sessions[session_to_delete]
136
- if st.session_state.current_session == session_to_delete:
137
- st.session_state.current_session = None
138
- database[user_id] = st.session_state.sessions
139
- save_database(database)
140
- st.success(f"Session '{session_to_delete}' berhasil dihapus!")
141
 
142
- # Tampilkan percakapan dari session yang aktif
143
- if st.session_state.current_session:
144
- st.header(f"💬 Percakapan: {st.session_state.current_session}")
 
 
 
 
 
 
 
 
 
 
 
145
 
146
- for message in st.session_state.sessions[st.session_state.current_session]:
147
- role = message["role"]
148
- avatar = "👤" if role == "user" else "🤖"
149
 
150
- with st.chat_message(role):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  st.markdown(
152
- f'<div class="chat-message {role}">'
153
- f'<span style="font-size:20px;">{avatar}</span> '
154
- f'{message["content"]}</div>',
 
 
 
 
 
 
 
155
  unsafe_allow_html=True
156
  )
157
 
158
- # Input pengguna
159
- if prompt := st.chat_input("Ketik pesan Anda di sini..."):
 
 
 
 
160
  st.session_state.sessions[st.session_state.current_session].append({"role": "user", "content": prompt})
 
 
 
 
 
 
 
161
 
162
- with st.chat_message("user"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  st.markdown(
164
- f'<div class="chat-message user">'
165
- f'<span style="font-size:20px;">👤</span> '
166
- f'{prompt}</div>',
 
 
 
 
 
167
  unsafe_allow_html=True
168
  )
169
 
170
- # Loading Animation
171
- loading_placeholder = st.empty()
172
- loading_placeholder.markdown('<div class="loading">Mengambil respons...</div>', unsafe_allow_html=True)
173
-
174
- # Generate respons AI menggunakan g4f dengan provider Blackbox
175
- with st.chat_message("assistant"):
176
- try:
177
- response = g4f.ChatCompletion.create(
178
- model="blackboxai",
179
- messages=st.session_state.sessions[st.session_state.current_session],
180
- provider=g4f.Provider.Blackbox
181
- )
182
- loading_placeholder.empty()
183
- st.markdown(
184
- f'<div class="chat-message assistant">'
185
- f'<span style="font-size:20px;">🤖</span> '
186
- f'{response}</div>',
187
- unsafe_allow_html=True
188
- )
189
-
190
- # Tambahkan respons ke riwayat percakapan
191
- st.session_state.sessions[st.session_state.current_session].append({"role": "assistant", "content": response})
192
- database[user_id] = st.session_state.sessions
193
- save_database(database)
194
-
195
- except Exception as e:
196
- loading_placeholder.empty()
197
- st.error(f"Terjadi error: {str(e)}")
198
-
199
  else:
200
- st.warning("Silakan buat atau pilih session terlebih dahulu.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import os
5
  import uuid
6
 
7
+ # Custom CSS untuk tampilan premium
8
  st.markdown(
9
  """
10
  <style>
11
+ /* Main container styling */
12
+ .main {
13
+ background-color: #f5f5f5;
14
+ padding: 20px 5%;
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
+ /* Chat container styling */
18
+ .chat-container {
19
+ max-width: 800px;
20
+ margin: 0 auto;
21
+ background: white;
22
  border-radius: 15px;
23
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
24
+ padding: 20px;
25
+ min-height: 70vh;
26
+ max-height: 70vh;
27
+ overflow-y: auto;
28
  }
29
 
30
+ /* Message styling */
31
+ .message {
32
+ margin: 15px 0;
33
+ display: flex;
34
+ gap: 12px;
35
+ align-items: start;
36
  }
37
 
38
+ .user-message {
39
+ flex-direction: row-reverse;
 
 
40
  }
41
 
42
+ .avatar {
 
43
  width: 40px;
44
  height: 40px;
45
  border-radius: 50%;
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ flex-shrink: 0;
50
+ }
51
+
52
+ .user-avatar {
53
+ background: #10a37f;
54
+ color: white;
55
+ }
56
+
57
+ .bot-avatar {
58
+ background: #e5e7eb;
59
+ color: #6b7280;
60
+ }
61
+
62
+ .message-content {
63
+ max-width: 70%;
64
+ padding: 12px 16px;
65
+ border-radius: 12px;
66
+ line-height: 1.5;
67
+ font-size: 16px;
68
+ }
69
+
70
+ .user-content {
71
+ background: #10a37f;
72
+ color: white;
73
+ border-radius: 12px 12px 0 12px;
74
+ }
75
+
76
+ .bot-content {
77
+ background: #f3f4f6;
78
+ color: #374151;
79
+ border-radius: 12px 12px 12px 0;
80
+ }
81
+
82
+ /* Input area styling */
83
+ .input-container {
84
+ max-width: 800px;
85
+ margin: 20px auto;
86
+ position: relative;
87
  }
88
 
89
  /* Loading animation */
90
+ .dot-flashing {
91
+ position: relative;
92
+ width: 10px;
93
+ height: 10px;
94
+ border-radius: 5px;
95
+ background-color: #10a37f;
96
+ color: #10a37f;
97
+ animation: dotFlashing 1s infinite linear alternate;
98
+ animation-delay: .5s;
99
  }
 
 
 
 
100
 
101
+ .dot-flashing::before, .dot-flashing::after {
102
+ content: '';
103
+ display: inline-block;
104
+ position: absolute;
105
+ top: 0;
106
+ }
107
 
108
+ .dot-flashing::before {
109
+ left: -15px;
110
+ width: 10px;
111
+ height: 10px;
112
+ border-radius: 5px;
113
+ background-color: #10a37f;
114
+ color: #10a37f;
115
+ animation: dotFlashing 1s infinite alternate;
116
+ animation-delay: 0s;
117
+ }
118
 
119
+ .dot-flashing::after {
120
+ left: 15px;
121
+ width: 10px;
122
+ height: 10px;
123
+ border-radius: 5px;
124
+ background-color: #10a37f;
125
+ color: #10a37f;
126
+ animation: dotFlashing 1s infinite alternate;
127
+ animation-delay: 1s;
128
+ }
129
+
130
+ @keyframes dotFlashing {
131
+ 0% { background-color: #10a37f; }
132
+ 50%, 100% { background-color: rgba(16, 163, 127, 0.2); }
133
+ }
134
+
135
+ /* Scrollbar styling */
136
+ ::-webkit-scrollbar {
137
+ width: 8px;
138
+ }
139
+
140
+ ::-webkit-scrollbar-track {
141
+ background: #f1f1f1;
142
+ }
143
+
144
+ ::-webkit-scrollbar-thumb {
145
+ background: #888;
146
+ border-radius: 4px;
147
+ }
148
 
149
+ /* Session list styling */
150
+ .session-item {
151
+ padding: 10px;
152
+ margin: 5px 0;
153
+ border-radius: 8px;
154
+ cursor: pointer;
155
+ transition: all 0.2s;
156
+ }
157
 
158
+ .session-item:hover {
159
+ background: #e5e7eb;
160
+ }
161
 
162
+ .active-session {
163
+ background: #10a37f !important;
164
+ color: white;
165
+ }
166
 
167
+ </style>
168
+ """,
169
+ unsafe_allow_html=True,
170
+ )
171
 
172
+ # Fungsi database tetap sama...
 
 
 
 
173
 
174
+ # Inisialisasi state
175
+ # ... (tetap sama dengan sebelumnya) ...
176
+
177
+ # Sidebar yang lebih modern
178
  with st.sidebar:
179
+ st.markdown("## 💬 Chat Sessions")
180
+ st.markdown("---")
181
+
182
+ # Buat session baru
183
+ with st.expander("➕ New Session", expanded=True):
184
+ new_session_name = st.text_input("Session name", key="new_session")
185
+ if st.button("Create", key="create_btn"):
186
+ if new_session_name:
187
+ if new_session_name not in st.session_state.sessions:
188
+ st.session_state.sessions[new_session_name] = []
189
+ st.session_state.current_session = new_session_name
190
+ database[user_id] = st.session_state.sessions
191
+ save_database(database)
192
+ st.rerun()
193
+ else:
194
+ st.error("Name already exists!")
195
  else:
196
+ st.error("Please enter a name")
197
+
198
+ st.markdown("---")
199
+ st.markdown("### 📚 Your Sessions")
200
+
201
+ # Daftar session
202
+ sessions = list(st.session_state.sessions.keys())
203
+ for idx, session in enumerate(sessions):
204
+ is_active = session == st.session_state.current_session
205
+ session_class = "active-session" if is_active else "session-item"
206
+ st.markdown(
207
+ f'<div class="{session_class}" onclick="setSession({idx})">{session}</div>',
208
+ unsafe_allow_html=True
209
  )
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
+ # JavaScript untuk session selection
212
+ st.markdown(
213
+ """
214
+ <script>
215
+ function setSession(index) {
216
+ window.parent.postMessage({
217
+ type: 'setCurrentSession',
218
+ index: index
219
+ }, '*');
220
+ }
221
+ </script>
222
+ """,
223
+ unsafe_allow_html=True
224
+ )
225
 
226
+ # Area chat utama
227
+ st.markdown('<div class="main">', unsafe_allow_html=True)
228
+ st.markdown('<div class="chat-container">', unsafe_allow_html=True)
229
 
230
+ if st.session_state.current_session:
231
+ # Tampilkan chat history
232
+ for message in st.session_state.sessions[st.session_state.current_session]:
233
+ if message["role"] == "user":
234
+ st.markdown(
235
+ f'''
236
+ <div class="message user-message">
237
+ <div class="message-content user-content">
238
+ {message["content"]}
239
+ </div>
240
+ <div class="avatar user-avatar">
241
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
242
+ </div>
243
+ </div>
244
+ ''',
245
+ unsafe_allow_html=True
246
+ )
247
+ else:
248
  st.markdown(
249
+ f'''
250
+ <div class="message">
251
+ <div class="avatar bot-avatar">
252
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-message-circle"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>
253
+ </div>
254
+ <div class="message-content bot-content">
255
+ {message["content"]}
256
+ </div>
257
+ </div>
258
+ ''',
259
  unsafe_allow_html=True
260
  )
261
 
262
+ # Input area
263
+ st.markdown('</div>', unsafe_allow_html=True) # Tutup chat container
264
+ st.markdown('<div class="input-container">', unsafe_allow_html=True)
265
+
266
+ if prompt := st.chat_input("Message ChatGPT..."):
267
+ # Tambahkan pesan user
268
  st.session_state.sessions[st.session_state.current_session].append({"role": "user", "content": prompt})
269
+
270
+ # Tampilkan loading
271
+ loading_placeholder = st.empty()
272
+ loading_placeholder.markdown(
273
+ '<div class="message"><div class="avatar bot-avatar"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-message-circle"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg></div><div class="dot-flashing"></div></div>',
274
+ unsafe_allow_html=True
275
+ )
276
 
277
+ # Dapatkan respons
278
+ try:
279
+ response = g4f.ChatCompletion.create(
280
+ model="blackboxai",
281
+ messages=st.session_state.sessions[st.session_state.current_session],
282
+ provider=g4f.Provider.Blackbox
283
+ )
284
+
285
+ # Hapus loading dan tampilkan respons
286
+ loading_placeholder.empty()
287
+ st.session_state.sessions[st.session_state.current_session].append({"role": "assistant", "content": response})
288
+ database[user_id] = st.session_state.sessions
289
+ save_database(database)
290
+ st.rerun()
291
+
292
+ except Exception as e:
293
+ loading_placeholder.empty()
294
  st.markdown(
295
+ f'''
296
+ <div class="message">
297
+ <div class="avatar bot-avatar">⚠️</div>
298
+ <div class="message-content bot-content" style="color: #dc2626;">
299
+ Error: {str(e)}
300
+ </div>
301
+ </div>
302
+ ''',
303
  unsafe_allow_html=True
304
  )
305
 
306
+ st.markdown('</div></div>', unsafe_allow_html=True) # Tutup input container dan main
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  else:
308
+ st.markdown('</div>', unsafe_allow_html=True) # Tutup chat container
309
+ st.markdown('<div class="input-container">', unsafe_allow_html=True)
310
+ st.info("Please select or create a session from the sidebar")
311
+ st.markdown('</div></div>', unsafe_allow_html=True)
312
+
313
+ # Auto-scroll ke pesan terakhir
314
+ st.markdown(
315
+ """
316
+ <script>
317
+ window.addEventListener('load', function() {
318
+ var chatContainer = window.parent.document.querySelector('.chat-container');
319
+ if (chatContainer) {
320
+ chatContainer.scrollTop = chatContainer.scrollHeight;
321
+ }
322
+ });
323
+ </script>
324
+ """,
325
+ unsafe_allow_html=True
326
+ )