import gradio as gr from huggingface_hub import InferenceClient import os # ============================================ # GLM-4.7 Streaming Chat # Provider: Novita (HuggingFace) # Gradio 6.0 Compatible - Full Width Layout # ============================================ # Initialize Novita Client client = InferenceClient( provider="novita", api_key=os.environ.get("HF_TOKEN"), ) def chat_stream(messages): """Streaming via Novita provider""" stream = client.chat.completions.create( model="zai-org/GLM-4.7", messages=messages, max_tokens=4096, temperature=0.7, top_p=0.95, stream=True ) for chunk in stream: if chunk.choices and len(chunk.choices) > 0: delta = chunk.choices[0].delta if hasattr(delta, 'content') and delta.content: yield delta.content def chat_respond(message, history): """ Streaming chat Gradio 6.0 messages format: [{"role": "user/assistant", "content": "..."}] """ if not message.strip(): return history # Build API messages api_messages = [{ "role": "system", "content": "You are GLM-4.7, a helpful AI assistant built by Zhipu AI. You excel at coding, reasoning, and creative tasks. Respond in the same language as the user." }] # Add history (Gradio 6.0 messages format) for h in history: if isinstance(h, dict): api_messages.append({"role": h.get("role", "user"), "content": h.get("content", "")}) api_messages.append({"role": "user", "content": message}) response_text = "" try: for chunk in chat_stream(api_messages): response_text += chunk new_history = history + [ {"role": "user", "content": message}, {"role": "assistant", "content": response_text} ] yield new_history except Exception as e: new_history = history + [ {"role": "user", "content": message}, {"role": "assistant", "content": f"Error: {str(e)}"} ] yield new_history def clear_chat_fn(): """Clear chat history""" return [], "" # ============================================ # Comic Classic Theme CSS # ============================================ css = """ @import url('https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap'); .gradio-container { background-color: #FEF9C3 !important; background-image: radial-gradient(#1F2937 1px, transparent 1px) !important; background-size: 20px 20px !important; min-height: 100vh !important; font-family: 'Comic Neue', cursive, sans-serif !important; } .huggingface-space-header, #space-header, .space-header, [class*="space-header"] { display: none !important; } footer, .footer, .gradio-footer, .built-with-gradio { display: none !important; } .header-text h1 { font-family: 'Bangers', cursive !important; color: #1F2937 !important; font-size: 3.5rem !important; text-align: center !important; text-shadow: 4px 4px 0px #FACC15, 6px 6px 0px #1F2937 !important; letter-spacing: 3px !important; -webkit-text-stroke: 2px #1F2937 !important; } .subtitle { text-align: center !important; font-family: 'Comic Neue', cursive !important; font-size: 1.2rem !important; color: #1F2937 !important; font-weight: 700 !important; } .gr-panel, .gr-box, .block, .gr-group { background: #FFFFFF !important; border: 3px solid #1F2937 !important; border-radius: 8px !important; box-shadow: 6px 6px 0px #1F2937 !important; } textarea, input[type="text"] { background: #FFFFFF !important; border: 3px solid #1F2937 !important; border-radius: 8px !important; color: #1F2937 !important; font-family: 'Comic Neue', cursive !important; font-size: 1rem !important; font-weight: 700 !important; } textarea:focus, input[type="text"]:focus { border-color: #3B82F6 !important; box-shadow: 4px 4px 0px #3B82F6 !important; outline: none !important; } .gr-button-primary, button.primary { background: #3B82F6 !important; border: 3px solid #1F2937 !important; border-radius: 8px !important; color: #FFFFFF !important; font-family: 'Bangers', cursive !important; font-size: 1.3rem !important; letter-spacing: 2px !important; padding: 14px 28px !important; box-shadow: 5px 5px 0px #1F2937 !important; text-shadow: 1px 1px 0px #1F2937 !important; } .gr-button-primary:hover, button.primary:hover { background: #2563EB !important; transform: translate(-2px, -2px) !important; box-shadow: 7px 7px 0px #1F2937 !important; } .gr-button-secondary, button.secondary { background: #EF4444 !important; border: 3px solid #1F2937 !important; border-radius: 8px !important; color: #FFFFFF !important; font-family: 'Bangers', cursive !important; font-size: 1.1rem !important; box-shadow: 4px 4px 0px #1F2937 !important; } .gr-button-secondary:hover, button.secondary:hover { background: #DC2626 !important; transform: translate(-2px, -2px) !important; } .chatbot { border: 3px solid #1F2937 !important; border-radius: 12px !important; box-shadow: 6px 6px 0px #1F2937 !important; background: #FFFFFF !important; } pre, code { background: #1F2937 !important; color: #10B981 !important; border: 2px solid #10B981 !important; border-radius: 6px !important; font-family: 'Courier New', monospace !important; } ::-webkit-scrollbar { width: 12px; } ::-webkit-scrollbar-track { background: #FEF9C3; border: 2px solid #1F2937; } ::-webkit-scrollbar-thumb { background: #3B82F6; border: 2px solid #1F2937; } ::-webkit-scrollbar-thumb:hover { background: #EF4444; } @media (max-width: 768px) { .header-text h1 { font-size: 2.2rem !important; } } """ # ============================================ # Gradio Interface - Full Width Layout # ============================================ with gr.Blocks(fill_height=True) as demo: # Inject CSS via HTML gr.HTML(f"") # HOME Badge gr.HTML("""
HOME
""") # Header Title gr.Markdown("""# GLM-4.7 CHAT""", elem_classes="header-text") gr.Markdown("""

Zhipu AI's Latest Open Source Model - Powerful Reasoning and Coding Capabilities

""") # Model Info Box gr.HTML("""
GLM-4.7
Model
Zhipu AI
Developer
Open Source
License
Novita
Provider
""") # Chatbot - Full Width chatbot = gr.Chatbot( label="Chat", height=500, show_label=False, elem_classes="chatbot" ) # Input Row with gr.Row(): msg = gr.Textbox( label="", placeholder="Enter your message... (coding, analysis, creative writing, anything!)", scale=8, container=False ) submit_btn = gr.Button("SEND", variant="primary", scale=2) # Clear Button clear_btn = gr.Button("CLEAR CHAT", variant="secondary") # Event Handlers def respond(message, history): if not message.strip(): yield history return for result in chat_respond(message, history): yield result # Connect events msg.submit(respond, [msg, chatbot], [chatbot]).then( lambda: "", outputs=[msg] ) submit_btn.click(respond, [msg, chatbot], [chatbot]).then( lambda: "", outputs=[msg] ) clear_btn.click(clear_chat_fn, outputs=[chatbot, msg]) if __name__ == "__main__": demo.launch(ssr_mode=False)