Download app.py from Basmala11/sami: direct link, hf CLI and curl.
- Browser
- Download file 9.05 kB
-
https://huggingface.co/spaces/Basmala11/sami/resolve/main/app.py
- Command line
-
hf download hf://spaces/Basmala11/sami/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Basmala11/sami/resolve/main/app.py
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}) | |