AI / app.py
galihrhgnwn's picture
Update app.py
4858261 verified
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
)