Spaces:
Running
Running
| import os | |
| import requests | |
| import gradio as gr | |
| import time | |
| from markdown import markdown | |
| # 🔑 Gemini API key | |
| gemini_api_key = os.getenv("GEMINI_API_KEY") | |
| if gemini_api_key is None: | |
| raise ValueError("⚠️ GEMINI_API_KEY тохируулаагүй байна!") | |
| # Gemini API call | |
| def gemini_response(prompt): | |
| try: | |
| url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={gemini_api_key}" | |
| headers = {"Content-Type": "application/json"} | |
| data = {"contents":[{"parts":[{"text":prompt}]}]} | |
| res = requests.post(url, headers=headers, json=data) | |
| res_json = res.json() | |
| return res_json["candidates"][0]["content"]["parts"][0]["text"] | |
| except Exception as e: | |
| return f"⚠️ Gemini error: {e}" | |
| # Chat function with typing effect + markdown rendering | |
| def chat(prompt, history=[], theme="Dark"): | |
| history.append((f"🧑 {prompt}", None)) | |
| time.sleep(0.5) # simulate typing | |
| reply_raw = gemini_response(prompt) | |
| reply_md = markdown(f"🤖 {reply_raw}") | |
| history[-1] = (history[-1][0], reply_md) | |
| return history, history | |
| # OAuth placeholder (Google login) | |
| def oauth_login(): | |
| return "✅ Logged in (Google OAuth placeholder)" | |
| # CSS for premium UI + theme + animations | |
| css = """ | |
| .gradio-container {font-family: 'Segoe UI', sans-serif;} | |
| textarea, input {border-radius:15px; padding:10px;} | |
| button {border-radius:15px; padding:10px 20px; font-weight:bold;} | |
| .gradio-chatbot-message.user {background-color:#0f2c54; color:#fff; border-radius:20px; padding:12px; margin:5px 0; transition: transform 0.2s;} | |
| .gradio-chatbot-message.user:hover {transform: scale(1.02);} | |
| .gradio-chatbot-message.bot {background-color:#1f1f1f; color:#00d9ff; border-radius:20px; padding:12px; margin:5px 0; transition: transform 0.2s;} | |
| .gradio-chatbot-message.bot:hover {transform: scale(1.02);} | |
| .chat-header {display:flex; align-items:center; gap:10px; justify-content: space-between;} | |
| .chat-header img {height:50px; width:50px; border-radius:12px;} | |
| .menu {display:flex; gap:15px; align-items:center;} | |
| .loader {border:4px solid #f3f3f3; border-top:4px solid #00d9ff; border-radius:50%; width:20px; height:20px; animation: spin 1s linear infinite;} | |
| @keyframes spin {100% {transform: rotate(360deg);}} | |
| .scrollable-card {max-height:200px; overflow-y:auto; border:1px solid #444; border-radius:10px; padding:10px; margin:5px 0; background-color:#1a1a1a; color:#00d9ff;} | |
| """ | |
| # Logo path | |
| logo_path = "logo.png" # upload to Space | |
| with gr.Blocks(css=css, theme=gr.themes.Soft()) as app: | |
| # Header | |
| with gr.Row(elem_classes="chat-header"): | |
| gr.Image(value=logo_path, show_label=False) | |
| gr.Markdown("## ZeppFusion AI") | |
| with gr.Row(elem_classes="menu"): | |
| theme_btn = gr.Dropdown(["Dark","Light"], value="Dark", label="Theme") | |
| login_btn = gr.Button("Login with Google") | |
| chatbot = gr.Chatbot() | |
| msg = gr.Textbox(placeholder="Таны асуулт...", lines=1) | |
| clear = gr.Button("🗑️ Clear History") | |
| # Submit chat | |
| msg.submit(chat, [msg, chatbot, theme_btn], [chatbot, chatbot]) | |
| # Clear chat history | |
| clear.click(lambda: [], None, chatbot) | |
| # OAuth login | |
| login_btn.click(oauth_login, None, None) | |
| if __name__ == "__main__": | |
| app.launch() |