sami / app.py
Basmala11's picture
Update app.py
dd7a896 verified
Raw History Blame Contribute Delete
9.05 kB
import os
import streamlit as st
import google.generativeai as genai
import datetime
import time
import base64
# -------------------- CONFIG --------------------
from api_key import api_key
genai.configure(api_key=api_key)
SYSTEM_PROMPT_DETAILED = """
You are Sami-CLearn Hub Assistant your name is Sami and the website you are assistant with its name C learn-hub — a friendly assistant that helps students choose the best learning track
( AI, Data Science, Web Development, Mobile Development, Cybersecurity, etc ).
Your job:
- Answer questions in a clear, helpful and friendly tone.
- Provide roadmaps, steps, tools, technologies.
- Explain code simply. When giving code, use Markdown fenced code blocks.
- Help with career paths, learning methods, and problem-solving.
- If the user asks about Sami-CLearn Hub website features, explain them.
Keep answers helpful, structured, and correct.
"""
SYSTEM_PROMPT_SHORT = """
You are Sami-CLearn Hub Assistant — a helpful assistant that guides students in choosing tech tracks and learning paths gives short and clear answer for the specific thing that user ask for.
"""
SYSTEM_PROMPT = SYSTEM_PROMPT_DETAILED
model = genai.GenerativeModel(
model_name="models/gemini-2.5-flash",
system_instruction=SYSTEM_PROMPT
)
# -------------------- STREAMLIT UI --------------------
st.set_page_config(page_title="Sami-CLearn Hub Assistant", page_icon='robot.png', layout="wide", initial_sidebar_state="expanded")
# -------------------- IMPORT GOOGLE FONT --------------------
st.markdown("""
<link href="https://fonts.googleapis.com/css2?family=Bai+Jamjuree:wght@400;700&display=swap" rel="stylesheet">
""", unsafe_allow_html=True)
# -------------------- IMAGE LOADER --------------------
def load_base64_image(image_path):
with open(image_path, "rb") as img:
return base64.b64encode(img.read()).decode()
setting_icon = load_base64_image("setting.png")
clear_icon = load_base64_image("clear.png")
export_icon = load_base64_image("export.png")
# -------------------- CUSTOM CSS --------------------
st.markdown(
f"""
<style>
/* Hide default role icons */
div.stChatMessage > div:first-child {{ display:none; }}
/* User message styling */
div.stChatMessage > div.stChatMessage__role-user {{
justify-content: flex-end !important;
text-align: right;
background-color: #356BA0;
color: white;
padding: 10px 15px;
border-radius: 20px 20px 0 20px;
margin: 5px 0;
max-width: 70%;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
overflow: hidden;
}}
/* Assistant message styling */
div.stChatMessage > div.stChatMessage__role-assistant {{
justify-content: flex-start !important;
text-align: left;
background-color: #f1f0f0;
color: #000;
padding: 10px 15px;
border-radius: 20px 20px 20px 0;
margin: 5px 0;
max-width: 70%;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
overflow: hidden;
}}
/* Chat input glow animation — KEEPING STYLE, NO ANIMATION */
.stTextInput>div>input:focus {{
box-shadow: 0 0 10px #356BA0;
border-radius: 8px;
}}
/* Title gradient text */
.sami-title {{
font-size: 2.8rem;
font-family: 'Bai Jamjuree', sans-serif !important;
background: linear-gradient(to right, #22d3ee, #f472b6, #22d3ee) !important;
-webkit-background-clip: text !important;
-webkit-text-fill-color: transparent !important;
color: transparent !important;
font-weight: 700;
margin: 0;
}}
.subtitle {{
font-family: 'Bai Jamjuree', sans-serif !important;
color: gray;
}}
/* Chat send button gradient */
div.stTextInput>div>button {{
background: linear-gradient(135deg, #00c8bd 0%, #cc74b6 100%, #000000);
border-radius: 50%;
padding: 8px;
border: none;
}}
div.stTextInput>div>button svg {{
fill: #0E0E0E !important;
width: 24px;
height: 24px;
}}
div.stTextInput>div>button:hover {{
transform: scale(1.1);
}}
div.stButton > button,
div.stCheckbox > label,
div.stCheckbox > div {{
font-family: 'Bai Jamjuree', sans-serif !important;
}}
/* Sidebar buttons */
div.stButton > button:first-child {{
background: linear-gradient(135deg, #00c8bd 0%, #cc74b6 100%, #000000);
color: white;
font-weight: bold;
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
position: relative;
}}
div.stButton > button:first-child::before {{
content: "";
background: url(data:image/png;base64,{clear_icon}) no-repeat center;
opacity: 0.3;
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
width: 22px;
height: 22px;
}}
div.stButton > button:last-child {{
background: linear-gradient(135deg, #00c8bd 0%, #cc74b6 100%, #000000);
color: white;
font-weight: bold;
border: none;
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
position: relative;
}}
div.stButton > button:last-child::before {{
content: "";
background: url(data:image/png;base64,{export_icon}) no-repeat center;
opacity: 0.3;
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
width: 22px;
height: 22px;
}}
[data-testid="collapsed-control"] {{
all: unset;
}}
[data-testid="collapsed-control"] svg {{
display: inline-block !important;
width: 24px;
height: 24px;
fill: #0E0E0E;
}}
[data-testid="stCheckbox"] input[type="checkbox"] {{
accent-color: #00c8bd !important;
width: 20px;
height: 20px;
}}
</style>
""",
unsafe_allow_html=True
)
# -------------------- TITLE --------------------
col1, col2 = st.columns([0.12, 0.88])
with col1:
if os.path.exists("robot.png"):
st.image("robot.png", width=72)
else:
st.markdown("<div style='font-size:40px;'>🤖</div>", unsafe_allow_html=True)
with col2:
st.markdown("<div class='sami-title'>Sami-CLearn Hub Assistant</div>", unsafe_allow_html=True)
st.markdown("<p class='subtitle' style='margin-top:4px;'>Ask about site help, track recommendations, or courses.</p>", unsafe_allow_html=True)
# -------------------- CHAT HISTORY --------------------
if "messages" not in st.session_state:
st.session_state.messages = []
# -------------------- SIDEBAR --------------------
with st.sidebar:
st.markdown(
f"""
<div style="display:flex; align-items:center; gap:10px; margin-bottom:15px;">
<img src="data:image/png;base64,{setting_icon}" width="26" height="26">
<h3 style="margin:0; font-family: 'Bai Jamjuree', sans-serif;">Settings</h3>
</div>
""",
unsafe_allow_html=True
)
use_short_prompt = st.checkbox("Use short system prompt?", value=False)
if st.button("Clear Conversation", key="clear_btn"):
st.session_state.messages = []
if st.button("Export Chat", key="export_btn"):
if st.session_state.messages:
chat_text = ""
for m in st.session_state.messages:
chat_text += f"{m['role'].upper()}:\n{m['content']}\n\n"
filename = f"Sami_chat_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
st.download_button(label="Download Chat", data=chat_text, file_name=filename, mime="text/plain")
else:
st.warning("No messages to export!")
# -------------------- DISPLAY CHAT HISTORY --------------------
for msg in st.session_state.messages:
alignment = "user" if msg["role"] == "user" else "assistant"
with st.chat_message(alignment):
st.markdown(msg["content"], unsafe_allow_html=True)
# -------------------- CHAT INPUT --------------------
user_input = st.chat_input("Type your question...")
if user_input:
st.session_state.messages.append({"role": "user", "content": user_input})
with st.chat_message("user"):
st.markdown(user_input, unsafe_allow_html=True)
model.system_instruction = SYSTEM_PROMPT_SHORT if use_short_prompt else SYSTEM_PROMPT_DETAILED
messages_for_llm = []
for m in st.session_state.messages:
messages_for_llm.append({"role": "user" if m["role"]=="user" else "model", "parts": m["content"]})
response = model.generate_content(messages_for_llm)
bot_response = response.text
with st.chat_message("assistant"):
placeholder = st.empty()
displayed_text = ""
for char in bot_response:
displayed_text += char
placeholder.markdown(displayed_text, unsafe_allow_html=True)
time.sleep(0.01)
st.session_state.messages.append({"role": "assistant", "content": bot_response})