Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import requests | |
| import os | |
| import json | |
| from typing import List, Dict, Optional | |
| import time | |
| import subprocess | |
| import tempfile | |
| import sys | |
| import io | |
| import contextlib | |
| class OpenRouterCodingAgent: | |
| def __init__(self): | |
| # Get API key from environment variable or Hugging Face Secrets | |
| self.api_key = os.getenv("OPENROUTER_API_KEY") | |
| self.base_url = "https://openrouter.ai/api/v1/chat/completions" | |
| # Free coding models (good for code generation) | |
| self.free_models = [ | |
| "agentica-org/deepcoder-14b-preview:free", | |
| "arliai/qwq-32b-arliai-rpr-v1:free", | |
| "cognitivecomputations/dolphin3.0-mistral-24b:free", | |
| "cognitivecomputations/dolphin3.0-r1-mistral-24b:free", | |
| "deepseek/deepseek-chat-v3-0324:free", | |
| "deepseek/deepseek-chat:free", | |
| "deepseek/deepseek-r1-0528-qwen3-8b:free", | |
| "deepseek/deepseek-r1-0528:free", | |
| "deepseek/deepseek-r1-distill-llama-70b:free", | |
| "deepseek/deepseek-r1-distill-qwen-14b:free", | |
| "deepseek/deepseek-r1:free", | |
| "deepseek/deepseek-v3-base:free", | |
| "featherless/qwerky-72b:free", | |
| "google/gemini-2.0-flash-exp:free", | |
| "google/gemini-2.5-pro-exp-03-25", | |
| "google/gemma-2-9b-it:free", | |
| "google/gemma-3-12b-it:free", | |
| "google/gemma-3-27b-it:free", | |
| "google/gemma-3-4b-it:free", | |
| "google/gemma-3n-e4b-it:free", | |
| "meta-llama/llama-3.1-8b-instruct:free", | |
| "meta-llama/llama-3.2-11b-vision-instruct:free", | |
| "meta-llama/llama-3.2-1b-instruct:free", | |
| "meta-llama/llama-3.3-70b-instruct:free", | |
| "meta-llama/llama-4-maverick:free", | |
| "meta-llama/llama-4-scout:free", | |
| "microsoft/mai-ds-r1:free", | |
| "mistralai/devstral-small:free", | |
| "mistralai/mistral-7b-instruct:free", | |
| "mistralai/mistral-nemo:free", | |
| "mistralai/mistral-small-24b-instruct-2501:free", | |
| "mistralai/mistral-small-3.1-24b-instruct:free", | |
| "mistralai/mistral-small-3.2-24b-instruct:free", | |
| "moonshotai/kimi-dev-72b:free", | |
| "moonshotai/kimi-vl-a3b-thinking:free", | |
| "nousresearch/deephermes-3-llama-3-8b-preview:free", | |
| "nvidia/llama-3.1-nemotron-ultra-253b-v1:free", | |
| "nvidia/llama-3.3-nemotron-super-49b-v1:free", | |
| "qwen/qwen-2.5-72b-instruct:free", | |
| "qwen/qwen-2.5-coder-32b-instruct:free", | |
| "qwen/qwen2.5-vl-32b-instruct:free", | |
| "qwen/qwen2.5-vl-72b-instruct:free", | |
| "qwen/qwen3-14b:free", | |
| "qwen/qwen3-235b-a22b:free", | |
| "qwen/qwen3-30b-a3b:free", | |
| "qwen/qwen3-32b:free", | |
| "qwen/qwen3-8b:free", | |
| "qwen/qwq-32b:free", | |
| "rekaai/reka-flash-3:free", | |
| "sarvamai/sarvam-m:free", | |
| "shisa-ai/shisa-v2-llama3.3-70b:free", | |
| "thudm/glm-4-32b:free", | |
| "thudm/glm-z1-32b:free", | |
| "tngtech/deepseek-r1t-chimera:free", | |
| ] | |
| # Set default model (DeepSeek is excellent for coding) | |
| self.default_model = "deepseek/deepseek-r1:free" | |
| print(f"β Coding Agent ready with {len(self.free_models)} free models") | |
| def get_clean_model_choices(self): | |
| """Get model choices with clean names for display""" | |
| choices = [] | |
| for model in self.free_models: | |
| clean_name = model.replace(":free", "") | |
| choices.append((clean_name, model)) | |
| return choices | |
| def make_request(self, messages: List[Dict], model: str, temperature: float = 0.7) -> str: | |
| """Make a request to OpenRouter API""" | |
| if not self.api_key: | |
| return "β Error: OpenRouter API key not configured." | |
| headers = { | |
| "Authorization": f"Bearer {self.api_key}", | |
| "Content-Type": "application/json", | |
| "HTTP-Referer": "https://huggingface.co/spaces", | |
| "X-Title": "Free Coding Agent via OpenRouter" | |
| } | |
| data = { | |
| "model": model, | |
| "messages": messages, | |
| "temperature": temperature, | |
| "max_tokens": 2000, | |
| "stream": False | |
| } | |
| try: | |
| response = requests.post(self.base_url, headers=headers, json=data, timeout=60) | |
| response.raise_for_status() | |
| result = response.json() | |
| if 'choices' in result and len(result['choices']) > 0: | |
| return result['choices'][0]['message']['content'] | |
| else: | |
| return "β Error: No response generated" | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| # Initialize the coding agent | |
| coding_agent = OpenRouterCodingAgent() | |
| def execute_python_code(code: str) -> str: | |
| """Execute Python code safely and return output""" | |
| if not code.strip(): | |
| return "" | |
| # Create string buffer to capture output | |
| output = io.StringIO() | |
| try: | |
| # Redirect stdout to capture print statements | |
| with contextlib.redirect_stdout(output): | |
| # Execute the code | |
| exec(code) | |
| result = output.getvalue() | |
| return result if result else "β Code executed successfully (no output)" | |
| except Exception as e: | |
| return f"β Error: {str(e)}" | |
| def create_web_preview(html: str, css: str, js: str) -> str: | |
| """Create a complete HTML page with CSS and JS""" | |
| return f""" | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Live Preview</title> | |
| <style> | |
| body {{ | |
| margin: 0; | |
| padding: 20px; | |
| font-family: Arial, sans-serif; | |
| }} | |
| {css} | |
| </style> | |
| </head> | |
| <body> | |
| {html} | |
| <script> | |
| {js} | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| def generate_code(prompt: str, model: str, code_type: str, current_code: str = "") -> str: | |
| """Generate code using OpenRouter API""" | |
| system_prompts = { | |
| "html": "You are an expert HTML developer. Generate clean, semantic HTML code based on the user's request. Only return the HTML code, no explanations.", | |
| "css": "You are an expert CSS developer. Generate modern, responsive CSS code based on the user's request. Only return the CSS code, no explanations.", | |
| "javascript": "You are an expert JavaScript developer. Generate clean, modern JavaScript code based on the user's request. Only return the JavaScript code, no explanations.", | |
| "python": "You are an expert Python developer. Generate clean, working Python code based on the user's request. Only return the Python code, no explanations." | |
| } | |
| context = f"\nCurrent {code_type} code:\n```{code_type}\n{current_code}\n```\n" if current_code.strip() else "" | |
| messages = [ | |
| {"role": "system", "content": system_prompts.get(code_type, "You are a helpful coding assistant.")}, | |
| {"role": "user", "content": f"{prompt}{context}"} | |
| ] | |
| response = coding_agent.make_request(messages, model) | |
| # Clean up the response to extract just the code | |
| if "```" in response: | |
| # Extract code from markdown code blocks | |
| parts = response.split("```") | |
| for i, part in enumerate(parts): | |
| if i % 2 == 1: # Odd indices are code blocks | |
| # Remove language identifier if present | |
| lines = part.strip().split('\n') | |
| if lines[0].strip() in ['html', 'css', 'javascript', 'js', 'python', 'py']: | |
| return '\n'.join(lines[1:]) | |
| return part.strip() | |
| return response.strip() | |
| def chat_with_agent(message: str, history: List, model: str) -> tuple: | |
| """Chat with the coding agent""" | |
| if not message.strip(): | |
| return history, "" | |
| messages = [ | |
| {"role": "system", "content": "You are a helpful coding assistant. Help users with programming questions, debugging, and code explanations."} | |
| ] | |
| # Add conversation history - convert from messages format | |
| for msg in history: | |
| if isinstance(msg, dict): | |
| messages.append(msg) | |
| else: | |
| # Handle old tuple format if any | |
| user_msg, assistant_msg = msg | |
| if user_msg: | |
| messages.append({"role": "user", "content": user_msg}) | |
| if assistant_msg: | |
| messages.append({"role": "assistant", "content": assistant_msg}) | |
| # Add current message | |
| messages.append({"role": "user", "content": message}) | |
| # Get response | |
| response = coding_agent.make_request(messages, model, temperature=0.7) | |
| # Add to history in messages format | |
| history.append({"role": "user", "content": message}) | |
| history.append({"role": "assistant", "content": response}) | |
| return history, "" | |
| # Create the Gradio interface | |
| with gr.Blocks( | |
| title="Free Coding Agent - CodePen Style", | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .code-container { font-family: 'Courier New', monospace; } | |
| .preview-container { border: 1px solid #ddd; border-radius: 8px; } | |
| .main-header { text-align: center; margin-bottom: 2em; } | |
| """) as demo: | |
| gr.HTML(""" | |
| <div class="main-header"> | |
| <h1>π Free Coding Agent</h1> | |
| <p>CodePen-style environment with AI assistance</p> | |
| <p style="color: #22c55e; font-weight: bold;">β¨ Generate, edit, and run code with AI help!</p> | |
| </div> | |
| """) | |
| with gr.Row(): | |
| # Left Panel - Code Editors and AI | |
| with gr.Column(scale=1): | |
| gr.Markdown("### π€ AI Coding Assistant") | |
| model_dropdown = gr.Dropdown( | |
| choices=coding_agent.get_clean_model_choices(), | |
| value=coding_agent.default_model, | |
| label="AI Model", | |
| info="Choose your coding AI" | |
| ) | |
| # AI Chat Interface | |
| with gr.Accordion("π¬ Chat with AI", open=True): | |
| chatbot = gr.Chatbot(height=300, show_label=False, type='messages') | |
| chat_input = gr.Textbox( | |
| placeholder="Ask the AI about coding, debugging, or request code generation...", | |
| show_label=False | |
| ) | |
| chat_btn = gr.Button("Send", variant="primary") | |
| # Code Generation Tools | |
| gr.Markdown("### π οΈ Code Generation") | |
| code_type = gr.Radio( | |
| choices=["html", "css", "javascript", "python"], | |
| value="html", | |
| label="Code Type" | |
| ) | |
| code_prompt = gr.Textbox( | |
| placeholder="Describe what you want to generate...", | |
| label="Code Request", | |
| lines=2 | |
| ) | |
| generate_btn = gr.Button("π― Generate Code", variant="secondary") | |
| # Right Panel - Code Editors | |
| with gr.Column(scale=2): | |
| gr.Markdown("### π Code Editors") | |
| with gr.Tabs(): | |
| with gr.Tab("HTML"): | |
| html_code = gr.Code( | |
| value="<h1>Hello World!</h1>\n<p>Start coding here...</p>", | |
| language="html", | |
| label="HTML", | |
| lines=15 | |
| ) | |
| with gr.Tab("CSS"): | |
| css_code = gr.Code( | |
| value="body {\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n text-align: center;\n padding: 50px;\n}", | |
| language="css", | |
| label="CSS", | |
| lines=15 | |
| ) | |
| with gr.Tab("JavaScript"): | |
| js_code = gr.Code( | |
| value="console.log('Hello from JavaScript!');\n\n// Add your JavaScript here", | |
| language="javascript", | |
| label="JavaScript", | |
| lines=15 | |
| ) | |
| with gr.Tab("Python"): | |
| python_code = gr.Code( | |
| value="print('Hello from Python!')\n\n# Add your Python code here", | |
| language="python", | |
| label="Python", | |
| lines=15 | |
| ) | |
| with gr.Row(): | |
| # Preview Panel | |
| with gr.Column(): | |
| gr.Markdown("### π Live Preview") | |
| with gr.Tabs(): | |
| with gr.Tab("Web Preview"): | |
| web_preview = gr.HTML( | |
| value=create_web_preview( | |
| "<h1>Hello World!</h1><p>Start coding here...</p>", | |
| "body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; text-align: center; padding: 50px; }", | |
| "console.log('Hello from JavaScript!');" | |
| ), | |
| label="Preview" | |
| ) | |
| update_preview_btn = gr.Button("π Update Preview", variant="primary") | |
| with gr.Tab("Python Output"): | |
| python_output = gr.Textbox( | |
| value="", | |
| label="Python Output", | |
| lines=10, | |
| max_lines=20, | |
| interactive=False | |
| ) | |
| run_python_btn = gr.Button("βΆοΈ Run Python", variant="primary") | |
| # Event Handlers | |
| def update_preview(html, css, js): | |
| return create_web_preview(html, css, js) | |
| def run_python(code): | |
| return execute_python_code(code) | |
| def generate_code_handler(prompt, model, code_type, html, css, js, python): | |
| current_code = { | |
| "html": html, | |
| "css": css, | |
| "javascript": js, | |
| "python": python | |
| }.get(code_type, "") | |
| generated = generate_code(prompt, model, code_type, current_code) | |
| if code_type == "html": | |
| return generated, css, js, python | |
| elif code_type == "css": | |
| return html, generated, js, python | |
| elif code_type == "javascript": | |
| return html, css, generated, python | |
| elif code_type == "python": | |
| return html, css, js, generated | |
| return html, css, js, python | |
| # Connect event handlers | |
| chat_btn.click( | |
| chat_with_agent, | |
| inputs=[chat_input, chatbot, model_dropdown], | |
| outputs=[chatbot, chat_input] | |
| ) | |
| chat_input.submit( | |
| chat_with_agent, | |
| inputs=[chat_input, chatbot, model_dropdown], | |
| outputs=[chatbot, chat_input] | |
| ) | |
| update_preview_btn.click( | |
| update_preview, | |
| inputs=[html_code, css_code, js_code], | |
| outputs=[web_preview] | |
| ) | |
| run_python_btn.click( | |
| run_python, | |
| inputs=[python_code], | |
| outputs=[python_output] | |
| ) | |
| generate_btn.click( | |
| generate_code_handler, | |
| inputs=[code_prompt, model_dropdown, code_type, html_code, css_code, js_code, python_code], | |
| outputs=[html_code, css_code, js_code, python_code] | |
| ) | |
| # Auto-update preview when code changes | |
| for code_input in [html_code, css_code, js_code]: | |
| code_input.change( | |
| update_preview, | |
| inputs=[html_code, css_code, js_code], | |
| outputs=[web_preview] | |
| ) | |
| # Launch the app | |
| if __name__ == "__main__": | |
| demo.launch( | |
| share=False, | |
| server_name="0.0.0.0", | |
| show_error=True | |
| ) | |