import gradio as gr import json import zipfile import io import os from datetime import datetime # Template for generated space app (based on mvp_simple.py) SPACE_TEMPLATE = '''import gradio as gr import os import requests import json # Configuration SPACE_NAME = "{name}" SPACE_DESCRIPTION = "{description}" SYSTEM_PROMPT = """{system_prompt}""" MODEL = "{model}" # Get API key from environment - customizable variable name API_KEY = os.environ.get("{api_key_var}") def generate_response(message, history): """Generate response using OpenRouter API""" if not API_KEY: return "Please set your {api_key_var} in the Space settings." # Build messages array for the API messages = [{{"role": "system", "content": SYSTEM_PROMPT}}] # Add conversation history - compatible with Gradio 5.x format for chat in history: if isinstance(chat, dict): # New format: {{"role": "user", "content": "..."}} or {{"role": "assistant", "content": "..."}} messages.append(chat) else: # Legacy format: ("user msg", "bot msg") user_msg, bot_msg = chat messages.append({{"role": "user", "content": user_msg}}) if bot_msg: messages.append({{"role": "assistant", "content": bot_msg}}) # Add current message messages.append({{"role": "user", "content": message}}) # Make API request try: response = requests.post( url="https://openrouter.ai/api/v1/chat/completions", headers={{ "Authorization": f"Bearer {{API_KEY}}", "Content-Type": "application/json" }}, json={{ "model": MODEL, "messages": messages, "temperature": {temperature}, "max_tokens": {max_tokens} }} ) if response.status_code == 200: return response.json()['choices'][0]['message']['content'] else: return f"Error: {{response.status_code}} - {{response.text}}" except Exception as e: return f"Error: {{str(e)}}" # Create simple Gradio interface using ChatInterface demo = gr.ChatInterface( fn=generate_response, title=SPACE_NAME, description=SPACE_DESCRIPTION, examples={examples} ) if __name__ == "__main__": demo.launch() ''' # Available models MODELS = [ "google/gemma-2-9b-it", "google/gemma-2-27b-it", "meta-llama/llama-3.1-8b-instruct", "meta-llama/llama-3.1-70b-instruct", "anthropic/claude-3-haiku", "anthropic/claude-3-sonnet", "anthropic/claude-3.5-sonnet", "openai/gpt-3.5-turbo", "openai/gpt-4o-mini", "openai/gpt-4o", "mistralai/mistral-7b-instruct", "mistralai/mixtral-8x7b-instruct" ] def create_readme(config): """Generate README with deployment instructions""" return f"""# {config['name']} {config['description']} ## Quick Deploy to HuggingFace Spaces ### Step 1: Create the Space 1. Go to https://huggingface.co/spaces 2. Click "Create new Space" 3. Choose a name for your Space 4. Select **Gradio** as the SDK 5. Set visibility (Public/Private) 6. Click "Create Space" ### Step 2: Upload Files 1. In your new Space, click "Files" tab 2. Upload these files from the zip: - `app.py` - `requirements.txt` 3. Wait for "Building" to complete ### Step 3: Add API Key 1. Go to Settings (gear icon) 2. Click "Variables and secrets" 3. Click "New secret" 4. Name: `{config['api_key_var']}` 5. Value: Your OpenRouter API key 6. Click "Add" ### Step 4: Get Your API Key 1. Go to https://openrouter.ai/keys 2. Sign up/login if needed 3. Click "Create Key" 4. Copy the key (starts with `sk-or-`) ### Step 5: Test Your Space - Go back to "App" tab - Your Space should be running! - Try the example prompts or ask a question ## Configuration - **Model**: {config['model']} - **Temperature**: {config['temperature']} - **Max Tokens**: {config['max_tokens']} - **API Key Variable**: {config['api_key_var']} ## Cost Information OpenRouter charges per token used: - Gemma 2 9B: ~$0.20 per million tokens - Claude Haiku: ~$0.25 per million tokens - GPT-4o-mini: ~$0.60 per million tokens Typical conversation: ~300 tokens (cost: $0.00006 - $0.0018) Check current pricing: https://openrouter.ai/models ## Customization To modify your Space: 1. Edit `app.py` in your Space 2. Update configuration variables at the top 3. Changes deploy automatically ## Troubleshooting - **"Please set your {config['api_key_var']}"**: Add the secret in Space settings - **Error 401**: Invalid API key or no credits - **Error 429**: Rate limit - wait and try again - **Build failed**: Check requirements.txt formatting ## More Help - HuggingFace Spaces: https://huggingface.co/docs/hub/spaces - OpenRouter Docs: https://openrouter.ai/docs - Gradio Docs: https://gradio.app/docs --- Generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} with Chat U/I Helper """ def create_requirements(): """Generate requirements.txt""" return "gradio==5.34.0\nrequests==2.31.0" def generate_zip(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text): """Generate deployable zip file""" # Process examples if examples_text and examples_text.strip(): examples_list = [ex.strip() for ex in examples_text.split('\n') if ex.strip()] examples_json = json.dumps(examples_list) else: examples_json = json.dumps([ "Hello! How can you help me?", "Tell me something interesting", "What can you do?" ]) # Create config config = { 'name': name, 'description': description, 'system_prompt': system_prompt, 'model': model, 'api_key_var': api_key_var, 'temperature': temperature, 'max_tokens': int(max_tokens), 'examples': examples_json } # Generate files app_content = SPACE_TEMPLATE.format(**config) readme_content = create_readme(config) requirements_content = create_requirements() # Create zip file with clean naming filename = f"{name.lower().replace(' ', '_').replace('-', '_')}.zip" # Create zip in memory and save to disk zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: zip_file.writestr('app.py', app_content) zip_file.writestr('requirements.txt', requirements_content) zip_file.writestr('README.md', readme_content) zip_file.writestr('config.json', json.dumps(config, indent=2)) # Write zip to file zip_buffer.seek(0) with open(filename, 'wb') as f: f.write(zip_buffer.getvalue()) return filename # Define callback functions outside the interface def on_generate(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text): if not name or not name.strip(): return gr.update(value="Error: Please provide a Space Title", visible=True), gr.update(visible=False) if not system_prompt or not system_prompt.strip(): return gr.update(value="Error: Please provide a System Prompt", visible=True), gr.update(visible=False) try: filename = generate_zip(name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text) success_msg = f"""**Deployment package ready!** **File**: `{filename}` **What's included:** - `app.py` - Ready-to-deploy chat interface - `requirements.txt` - Dependencies - `README.md` - Step-by-step deployment guide - `config.json` - Configuration backup **Next steps:** 1. Download the zip file below 2. Follow the README instructions to deploy on HuggingFace Spaces 3. Set your `{api_key_var}` secret in Space settings **Your Space will be live in minutes!**""" return gr.update(value=success_msg, visible=True), gr.update(value=filename, visible=True) except Exception as e: return gr.update(value=f"Error: {str(e)}", visible=True), gr.update(visible=False) def respond(message, chat_history): # Make actual API request to OpenRouter import os import requests # Get API key from environment api_key = os.environ.get("OPENROUTER_API_KEY") if not api_key: response = "Please set your OPENROUTER_API_KEY in the Space settings to use the chat support." chat_history.append({"role": "user", "content": message}) chat_history.append({"role": "assistant", "content": response}) return "", chat_history # Build conversation history for API messages = [{ "role": "system", "content": """You are a helpful assistant specializing in creating chat UIs for HuggingFace Spaces. You help users configure assistants for education and research. Provide concise, practical advice about: - System prompts for different use cases (courses, research, tutoring) - Model selection (recommending google/gemma-2-27b-it as a great balance) - HuggingFace Space deployment tips - Customization options Keep responses brief and actionable. Focus on what the user is specifically asking about.""" }] # Add conversation history for chat in chat_history: messages.append(chat) # Add current message messages.append({"role": "user", "content": message}) try: # Make API request to OpenRouter response = requests.post( url="https://openrouter.ai/api/v1/chat/completions", headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" }, json={ "model": "google/gemma-2-27b-it", "messages": messages, "temperature": 0.7, "max_tokens": 500 } ) if response.status_code == 200: assistant_response = response.json()['choices'][0]['message']['content'] else: assistant_response = f"Error: {response.status_code} - {response.text}" except Exception as e: assistant_response = f"Error: {str(e)}" chat_history.append({"role": "user", "content": message}) chat_history.append({"role": "assistant", "content": assistant_response}) return "", chat_history def clear_chat(): return "", [] # Create Gradio interface with proper tab structure with gr.Blocks(title="Chat U/I Helper") as demo: with gr.Tabs(): with gr.Tab("Spaces Configuration"): gr.Markdown("# Spaces Configuration") gr.Markdown("Convert custom assistants from HuggingChat into chat interfaces with HuggingFace Spaces. Configure and download everything needed to deploy a simple HF space using Gradio.") with gr.Column(): name = gr.Textbox( label="Space Title", placeholder="My Course Helper", value="My Custom Space" ) description = gr.Textbox( label="Space Description", placeholder="A customizable AI chat interface for...", lines=2, value="A customizable AI chat interface for your specific needs" ) model = gr.Dropdown( label="Model", choices=MODELS, value=MODELS[0], info="Choose based on your needs and budget" ) api_key_var = gr.Textbox( label="API Key Variable Name", value="OPENROUTER_API_KEY", info="Name for the secret in HuggingFace Space settings" ) system_prompt = gr.Textbox( label="System Prompt", placeholder="You are a research assistant...", lines=4, value="You are a clear and concise research assistant. Provide accurate, succinct, and responsive support." ) examples_text = gr.Textbox( label="Example Prompts (one per line)", placeholder="Hello! How can you help me?\nWhat's the weather like?\nExplain quantum computing", lines=3, info="These will appear as clickable examples in the chat interface" ) with gr.Row(): temperature = gr.Slider( label="Temperature", minimum=0, maximum=2, value=0.7, step=0.1, info="Higher = more creative, Lower = more focused" ) max_tokens = gr.Slider( label="Max Response Tokens", minimum=50, maximum=4096, value=1024, step=50 ) generate_btn = gr.Button("Generate Deployment Package", variant="primary") status = gr.Markdown(visible=False) download_file = gr.File(label="Download your zip package", visible=False) # Connect the generate button generate_btn.click( on_generate, inputs=[name, description, system_prompt, model, api_key_var, temperature, max_tokens, examples_text], outputs=[status, download_file] ) with gr.Tab("Chat Support"): gr.Markdown("# Chat Support") gr.Markdown("Get personalized guidance on configuring chat UIs as HuggingFace Spaces for educational and research purposes.") # Meta chat interface with gr.Column(): chatbot = gr.Chatbot( value=[], label="Chat Support Assistant", height=400, type="messages" ) msg = gr.Textbox( label="Ask about configuring chat UIs for courses, research, or custom HuggingFace Spaces", placeholder="How can I configure a chat UI for my senior seminar?", lines=2 ) with gr.Row(): submit = gr.Button("Send", variant="primary") clear = gr.Button("Clear") gr.Examples( examples=[ "How do I make a math tutor bot?", "What's a good system prompt?", "Which model should I use?", "Can I add file uploads?", "Help me build a course assistant" ], inputs=msg ) # Connect the chat functionality submit.click(respond, [msg, chatbot], [msg, chatbot]) msg.submit(respond, [msg, chatbot], [msg, chatbot]) clear.click(clear_chat, outputs=[msg, chatbot]) if __name__ == "__main__": demo.launch()