Download app.py from wahab5763/ChatBox: direct link, hf CLI and curl.
- Browser
- Download file 6.95 kB
-
https://huggingface.co/spaces/wahab5763/ChatBox/resolve/main/app.py
- Command line
-
hf download hf://spaces/wahab5763/ChatBox/app.py
-
curl -L -o app.py https://huggingface.co/spaces/wahab5763/ChatBox/resolve/main/app.py
6.95 kB
| import os | |
| from collections.abc import Generator | |
| from typing import Any | |
| import gradio as gr | |
| from dotenv import load_dotenv | |
| from groq import Groq | |
| # Hugging Face ZeroGPU validates that a Space contains at least one | |
| # @spaces.GPU-decorated function. This app calls Groq remotely and does not | |
| # perform local GPU inference, so the compatibility function below is never | |
| # connected to the UI and never consumes GPU time. | |
| try: | |
| import spaces | |
| except ImportError: | |
| # Keep local execution working outside Hugging Face Spaces. | |
| class _SpacesFallback: | |
| def GPU(*args: Any, **kwargs: Any): | |
| def decorator(function): | |
| return function | |
| return decorator | |
| spaces = _SpacesFallback() | |
| # Loads GROQ_API_KEY from a local .env file when running on your computer. | |
| # On Hugging Face Spaces, add GROQ_API_KEY under Settings > Secrets. | |
| load_dotenv() | |
| DEFAULT_SYSTEM_PROMPT = ( | |
| "You are a helpful, accurate, and friendly AI assistant. " | |
| "Answer clearly, use Markdown when helpful, and admit uncertainty when needed." | |
| ) | |
| MODEL_CHOICES = [ | |
| "openai/gpt-oss-20b", | |
| "openai/gpt-oss-120b", | |
| ] | |
| CUSTOM_CSS = """ | |
| .gradio-container { | |
| max-width: 1050px !important; | |
| margin: 0 auto !important; | |
| } | |
| #app-header { | |
| text-align: center; | |
| padding: 12px 0 4px 0; | |
| } | |
| #app-subtitle { | |
| text-align: center; | |
| opacity: 0.8; | |
| margin-bottom: 10px; | |
| } | |
| footer { | |
| display: none !important; | |
| } | |
| """ | |
| def _text_history(history: list[dict[str, Any]]) -> list[dict[str, str]]: | |
| """Keep only plain-text user and assistant messages for the Groq API.""" | |
| cleaned: list[dict[str, str]] = [] | |
| for item in history or []: | |
| role = item.get("role") | |
| content = item.get("content") | |
| if role in {"user", "assistant"} and isinstance(content, str): | |
| cleaned.append({"role": role, "content": content}) | |
| return cleaned | |
| def zero_gpu_compatibility_check() -> str: | |
| """Allow startup on ZeroGPU; the Groq chat itself remains CPU/API based.""" | |
| return "ZeroGPU compatibility ready" | |
| def chat_with_groq( | |
| message: str, | |
| history: list[dict[str, Any]], | |
| model: str, | |
| system_prompt: str, | |
| temperature: float, | |
| max_tokens: int, | |
| ) -> Generator[str, None, None]: | |
| """Stream a Groq response to the Gradio chat interface.""" | |
| api_key = os.getenv("GROQ_API_KEY") | |
| if not api_key: | |
| yield ( | |
| "### Missing API key\n\n" | |
| "Add a Hugging Face Space secret named `GROQ_API_KEY`, then restart the Space." | |
| ) | |
| return | |
| user_message = (message or "").strip() | |
| if not user_message: | |
| yield "Please enter a message." | |
| return | |
| selected_model = model if model in MODEL_CHOICES else MODEL_CHOICES[0] | |
| instructions = (system_prompt or "").strip() or DEFAULT_SYSTEM_PROMPT | |
| messages: list[dict[str, str]] = [ | |
| {"role": "system", "content": instructions}, | |
| *_text_history(history), | |
| {"role": "user", "content": user_message}, | |
| ] | |
| try: | |
| client = Groq(api_key=api_key) | |
| stream = client.chat.completions.create( | |
| model=selected_model, | |
| messages=messages, | |
| temperature=float(temperature), | |
| max_completion_tokens=int(max_tokens), | |
| stream=True, | |
| ) | |
| response = "" | |
| for chunk in stream: | |
| delta = chunk.choices[0].delta.content | |
| if delta: | |
| response += delta | |
| yield response | |
| if not response: | |
| yield "The model returned an empty response. Please try again." | |
| except Exception as error: | |
| # Show a useful message without exposing the API key or other secrets. | |
| error_name = type(error).__name__ | |
| yield ( | |
| "### Request failed\n\n" | |
| f"`{error_name}`: {error}\n\n" | |
| "Check your Groq API key, model access, account limits, and network connection." | |
| ) | |
| with gr.Blocks(title="Groq AI Chat") as demo: | |
| # ZeroGPU scans Gradio's registered event handlers during startup. | |
| # This hidden event is never invoked by the chat UI, so Groq requests do | |
| # not reserve or consume a GPU allocation. | |
| zero_gpu_trigger = gr.Button(visible=False) | |
| zero_gpu_status = gr.Textbox(visible=False) | |
| zero_gpu_trigger.click( | |
| fn=zero_gpu_compatibility_check, | |
| inputs=None, | |
| outputs=zero_gpu_status, | |
| api_visibility="private", | |
| ) | |
| gr.Markdown("# ⚡ Groq AI Chat", elem_id="app-header") | |
| gr.Markdown( | |
| "A fast, streaming chatbot powered by Groq and built with Gradio.", | |
| elem_id="app-subtitle", | |
| ) | |
| with gr.Accordion("Chat settings", open=False): | |
| model_input = gr.Dropdown( | |
| choices=MODEL_CHOICES, | |
| value=MODEL_CHOICES[0], | |
| label="Groq model", | |
| info="GPT-OSS 20B is faster; GPT-OSS 120B is stronger for complex tasks.", | |
| ) | |
| system_prompt_input = gr.Textbox( | |
| value=DEFAULT_SYSTEM_PROMPT, | |
| label="System prompt", | |
| lines=3, | |
| ) | |
| with gr.Row(): | |
| temperature_input = gr.Slider( | |
| minimum=0.0, | |
| maximum=2.0, | |
| value=0.7, | |
| step=0.1, | |
| label="Temperature", | |
| ) | |
| max_tokens_input = gr.Slider( | |
| minimum=128, | |
| maximum=4096, | |
| value=1024, | |
| step=128, | |
| label="Maximum response tokens", | |
| ) | |
| chatbot = gr.Chatbot( | |
| label="Conversation", | |
| placeholder="Ask anything to begin the conversation.", | |
| height=520, | |
| ) | |
| gr.ChatInterface( | |
| fn=chat_with_groq, | |
| chatbot=chatbot, | |
| additional_inputs=[ | |
| model_input, | |
| system_prompt_input, | |
| temperature_input, | |
| max_tokens_input, | |
| ], | |
| examples=[ | |
| [ | |
| "Explain artificial intelligence in simple words.", | |
| MODEL_CHOICES[0], | |
| DEFAULT_SYSTEM_PROMPT, | |
| 0.7, | |
| 1024, | |
| ], | |
| [ | |
| "Write a professional email requesting a meeting.", | |
| MODEL_CHOICES[0], | |
| DEFAULT_SYSTEM_PROMPT, | |
| 0.7, | |
| 1024, | |
| ], | |
| [ | |
| "Create a beginner-friendly Python learning plan.", | |
| MODEL_CHOICES[1], | |
| DEFAULT_SYSTEM_PROMPT, | |
| 0.5, | |
| 1536, | |
| ], | |
| ], | |
| editable=True, | |
| save_history=True, | |
| flagging_mode="never", | |
| api_visibility="private", | |
| concurrency_limit=5, | |
| fill_height=True, | |
| fill_width=True, | |
| ) | |
| if __name__ == "__main__": | |
| demo.queue(default_concurrency_limit=5).launch( | |
| theme=gr.themes.Soft(), | |
| css=CUSTOM_CSS, | |
| ) | |