Spaces:
Sleeping
Sleeping
import streamlit as st | |
import g4f | |
import json | |
import os | |
import uuid | |
# Custom CSS untuk tampilan premium | |
st.markdown( | |
""" | |
<style> | |
/* Main container styling */ | |
.main { | |
background-color: #f5f5f5; | |
padding: 20px 5%; | |
} | |
/* Chat container styling */ | |
.chat-container { | |
max-width: 800px; | |
margin: 0 auto; | |
background: white; | |
border-radius: 15px; | |
box-shadow: 0 2px 10px rgba(0,0,0,0.1); | |
padding: 20px; | |
min-height: 70vh; | |
max-height: 70vh; | |
overflow-y: auto; | |
} | |
/* Message styling */ | |
.message { | |
margin: 15px 0; | |
display: flex; | |
gap: 12px; | |
align-items: start; | |
} | |
.user-message { | |
flex-direction: row-reverse; | |
} | |
.avatar { | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
flex-shrink: 0; | |
} | |
.user-avatar { | |
background: #10a37f; | |
color: white; | |
} | |
.bot-avatar { | |
background: #e5e7eb; | |
color: #6b7280; | |
} | |
.message-content { | |
max-width: 70%; | |
padding: 12px 16px; | |
border-radius: 12px; | |
line-height: 1.5; | |
font-size: 16px; | |
} | |
.user-content { | |
background: #10a37f; | |
color: white; | |
border-radius: 12px 12px 0 12px; | |
} | |
.bot-content { | |
background: #f3f4f6; | |
color: #374151; | |
border-radius: 12px 12px 12px 0; | |
} | |
/* Input area styling */ | |
.input-container { | |
max-width: 800px; | |
margin: 20px auto; | |
position: relative; | |
} | |
/* Loading animation */ | |
.dot-flashing { | |
position: relative; | |
width: 10px; | |
height: 10px; | |
border-radius: 5px; | |
background-color: #10a37f; | |
color: #10a37f; | |
animation: dotFlashing 1s infinite linear alternate; | |
animation-delay: .5s; | |
} | |
.dot-flashing::before, .dot-flashing::after { | |
content: ''; | |
display: inline-block; | |
position: absolute; | |
top: 0; | |
} | |
.dot-flashing::before { | |
left: -15px; | |
width: 10px; | |
height: 10px; | |
border-radius: 5px; | |
background-color: #10a37f; | |
color: #10a37f; | |
animation: dotFlashing 1s infinite alternate; | |
animation-delay: 0s; | |
} | |
.dot-flashing::after { | |
left: 15px; | |
width: 10px; | |
height: 10px; | |
border-radius: 5px; | |
background-color: #10a37f; | |
color: #10a37f; | |
animation: dotFlashing 1s infinite alternate; | |
animation-delay: 1s; | |
} | |
@keyframes dotFlashing { | |
0% { background-color: #10a37f; } | |
50%, 100% { background-color: rgba(16, 163, 127, 0.2); } | |
} | |
/* Scrollbar styling */ | |
::-webkit-scrollbar { | |
width: 8px; | |
} | |
::-webkit-scrollbar-track { | |
background: #f1f1f1; | |
} | |
::-webkit-scrollbar-thumb { | |
background: #888; | |
border-radius: 4px; | |
} | |
/* Session list styling */ | |
.session-item { | |
padding: 10px; | |
margin: 5px 0; | |
border-radius: 8px; | |
cursor: pointer; | |
transition: all 0.2s; | |
} | |
.session-item:hover { | |
background: #e5e7eb; | |
} | |
.active-session { | |
background: #10a37f !important; | |
color: white; | |
} | |
</style> | |
""", | |
unsafe_allow_html=True, | |
) | |
# Fungsi database tetap sama... | |
# Inisialisasi state | |
# ... (tetap sama dengan sebelumnya) ... | |
# Sidebar yang lebih modern | |
with st.sidebar: | |
st.markdown("## π¬ Chat Sessions") | |
st.markdown("---") | |
# Buat session baru | |
with st.expander("β New Session", expanded=True): | |
new_session_name = st.text_input("Session name", key="new_session") | |
if st.button("Create", key="create_btn"): | |
if new_session_name: | |
if new_session_name not in st.session_state.sessions: | |
st.session_state.sessions[new_session_name] = [] | |
st.session_state.current_session = new_session_name | |
database[user_id] = st.session_state.sessions | |
save_database(database) | |
st.rerun() | |
else: | |
st.error("Name already exists!") | |
else: | |
st.error("Please enter a name") | |
st.markdown("---") | |
st.markdown("### π Your Sessions") | |
# Daftar session | |
sessions = list(st.session_state.sessions.keys()) | |
for idx, session in enumerate(sessions): | |
is_active = session == st.session_state.current_session | |
session_class = "active-session" if is_active else "session-item" | |
st.markdown( | |
f'<div class="{session_class}" onclick="setSession({idx})">{session}</div>', | |
unsafe_allow_html=True | |
) | |
# JavaScript untuk session selection | |
st.markdown( | |
""" | |
<script> | |
function setSession(index) { | |
window.parent.postMessage({ | |
type: 'setCurrentSession', | |
index: index | |
}, '*'); | |
} | |
</script> | |
""", | |
unsafe_allow_html=True | |
) | |
# Area chat utama | |
st.markdown('<div class="main">', unsafe_allow_html=True) | |
st.markdown('<div class="chat-container">', unsafe_allow_html=True) | |
if st.session_state.current_session: | |
# Tampilkan chat history | |
for message in st.session_state.sessions[st.session_state.current_session]: | |
if message["role"] == "user": | |
st.markdown( | |
f''' | |
<div class="message user-message"> | |
<div class="message-content user-content"> | |
{message["content"]} | |
</div> | |
<div class="avatar user-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-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> | |
</div> | |
</div> | |
''', | |
unsafe_allow_html=True | |
) | |
else: | |
st.markdown( | |
f''' | |
<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="message-content bot-content"> | |
{message["content"]} | |
</div> | |
</div> | |
''', | |
unsafe_allow_html=True | |
) | |
# Input area | |
st.markdown('</div>', unsafe_allow_html=True) # Tutup chat container | |
st.markdown('<div class="input-container">', unsafe_allow_html=True) | |
if prompt := st.chat_input("Message ChatGPT..."): | |
# Tambahkan pesan user | |
st.session_state.sessions[st.session_state.current_session].append({"role": "user", "content": prompt}) | |
# Tampilkan loading | |
loading_placeholder = st.empty() | |
loading_placeholder.markdown( | |
'<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>', | |
unsafe_allow_html=True | |
) | |
# Dapatkan respons | |
try: | |
response = g4f.ChatCompletion.create( | |
model="blackboxai", | |
messages=st.session_state.sessions[st.session_state.current_session], | |
provider=g4f.Provider.Blackbox | |
) | |
# Hapus loading dan tampilkan respons | |
loading_placeholder.empty() | |
st.session_state.sessions[st.session_state.current_session].append({"role": "assistant", "content": response}) | |
database[user_id] = st.session_state.sessions | |
save_database(database) | |
st.rerun() | |
except Exception as e: | |
loading_placeholder.empty() | |
st.markdown( | |
f''' | |
<div class="message"> | |
<div class="avatar bot-avatar">β οΈ</div> | |
<div class="message-content bot-content" style="color: #dc2626;"> | |
Error: {str(e)} | |
</div> | |
</div> | |
''', | |
unsafe_allow_html=True | |
) | |
st.markdown('</div></div>', unsafe_allow_html=True) # Tutup input container dan main | |
else: | |
st.markdown('</div>', unsafe_allow_html=True) # Tutup chat container | |
st.markdown('<div class="input-container">', unsafe_allow_html=True) | |
st.info("Please select or create a session from the sidebar") | |
st.markdown('</div></div>', unsafe_allow_html=True) | |
# Auto-scroll ke pesan terakhir | |
st.markdown( | |
""" | |
<script> | |
window.addEventListener('load', function() { | |
var chatContainer = window.parent.document.querySelector('.chat-container'); | |
if (chatContainer) { | |
chatContainer.scrollTop = chatContainer.scrollHeight; | |
} | |
}); | |
</script> | |
""", | |
unsafe_allow_html=True | |
) |