Spaces:
Running
Running
import gradio as gr | |
import openai | |
import json | |
import time | |
from typing import Optional, Tuple, Dict, Any | |
from gradio.themes.base import Base | |
from gradio.themes.utils import colors, fonts, sizes | |
# --- Enhanced Custom Theme --- | |
class NordTheme(Base): | |
def __init__(self): | |
super().__init__( | |
primary_hue=colors.blue, | |
secondary_hue=colors.sky, | |
neutral_hue=colors.slate, | |
font=(fonts.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"), | |
font_mono=(fonts.GoogleFont("Fira Code"), "ui-monospace", "monospace"), | |
) | |
# only the supported tokens | |
self.set( | |
body_background_fill="#2E3440", | |
body_text_color="#ECEFF4", | |
block_background_fill="#3B4252", | |
block_border_width="1px", | |
block_border_color="#4C566A", | |
block_label_background_fill="#434C5E", | |
block_label_text_color="#ECEFF4", | |
button_primary_background_fill="#5E81AC", | |
button_primary_background_fill_hover="#81A1C1", | |
button_primary_text_color="#ECEFF4", | |
button_secondary_background_fill="#4C566A", | |
button_secondary_background_fill_hover="#5A657A", | |
button_secondary_text_color="#ECEFF4", | |
border_color_accent="#5E81AC", | |
block_radius="12px", | |
) | |
# your CSS overrides, combining everything: | |
css_overrides = """ | |
/* Center the app and constrain its width */ | |
.gradio-container { | |
max-width: 1200px !important; | |
margin: 0 auto !important; | |
} | |
/* Inputs */ | |
.gradio-container textarea, | |
.gradio-container input[type="text"], | |
.gradio-container input[type="password"], | |
.gradio-container .code-input { | |
background: #434C5E !important; | |
color: #ECEFF4 !important; | |
border: none !important; | |
border-radius: 6px !important; | |
} | |
/* Alerts */ | |
.gradio-container .gr-alert-error { | |
background-color: #BF616A !important; | |
color: white !important; | |
} | |
.gradio-container .gr-alert-success { | |
background-color: #A3BE8C !important; | |
color: white !important; | |
} | |
.gradio-container .gr-alert-warning { | |
background-color: #EBCB8B !important; | |
color: black !important; | |
} | |
/* Orange βcustomβ alert */ | |
.gradio-container .gr-alert-orange { | |
background-color: #D08770 !important; | |
color: white !important; | |
} | |
/* Code panels rounding */ | |
.code-container { | |
border-radius: 8px !important; | |
} | |
""" | |
# --- Helper Functions --- | |
# -*- coding: utf-8 -*- | |
def sanitize_for_api(s: str) -> str: | |
""" | |
Turn any βsmart quotesβ into plain ASCII quotes (and similarly | |
for the common apostrophes) so we never slip non-ASCII into | |
our JSON encoder. | |
""" | |
return ( | |
s | |
.replace("\u201c", '"') | |
.replace("\u201d", '"') | |
.replace("\u2018", "'") | |
.replace("\u2019", "'") | |
) | |
# --- Enhanced Configuration --- | |
PROGRAMMING_LANGUAGES = sorted([ | |
'Ada', 'Assembly', 'Bash', 'C', 'C#', 'C++', 'Clojure', 'COBOL', 'CSS', | |
'Crystal', 'Dart', 'Elixir', 'Erlang', 'F#', 'Fortran', 'Go', 'GraphQL', | |
'Groovy', 'Haskell', 'HTML', 'Java', 'JavaScript', 'Julia', 'Kotlin', | |
'Lisp', 'Lua', 'Markdown', 'MATLAB', 'Nim', 'Objective-C', 'OCaml', | |
'Pascal', 'Perl', 'PHP', 'PowerShell', 'Prolog', 'Python', 'R', 'Ruby', | |
'Rust', 'Scala', 'Scheme', 'Shell', 'SQL', 'Svelte', 'Swift', 'TOML', | |
'TypeScript', 'Visual Basic', 'Vue', 'XML', 'YAML', 'Zig' | |
]) | |
LANGUAGES = ['Natural Language'] + PROGRAMMING_LANGUAGES | |
# Enhanced model list with categorization | |
MODELS = { | |
"Code-Specialized": [ | |
"deepseek/deepseek-coder-v2-instruct:free", | |
"mistralai/codestral-latest:free", | |
"codellama/codellama-70b-instruct:free", | |
"qwen/qwen-2.5-coder-32b-instruct:free", | |
"agentica-org/deepcoder-14b-preview:free", | |
], | |
"General Purpose": [ | |
"deepseek/deepseek-chat-v3:free", | |
"deepseek/deepseek-r1-0528:free", | |
"google/gemini-2.0-flash-exp:free", | |
"meta-llama/llama-3.3-70b-instruct:free", | |
"mistralai/mistral-small-3.2-24b-instruct-2506:free", | |
"qwen/qwq-32b:free", | |
], | |
"Experimental": [ | |
"openrouter/cypher-alpha:free", | |
"moonshotai/kimi-dev-72b:free", | |
"qwen/qwen3-235b-a22b-04-28:free", | |
] | |
} | |
# Flatten models for dropdown | |
ALL_MODELS = [] | |
for category, models in MODELS.items(): | |
ALL_MODELS.extend(models) | |
DEFAULT_EXAMPLES = { | |
"Python": """# Example: Binary search algorithm | |
def binary_search(arr, target): | |
left, right = 0, len(arr) - 1 | |
while left <= right: | |
mid = (left + right) // 2 | |
if arr[mid] == target: | |
return mid | |
elif arr[mid] < target: | |
left = mid + 1 | |
else: | |
right = mid - 1 | |
return -1 | |
# Test the function | |
numbers = [1, 3, 5, 7, 9, 11, 13, 15] | |
result = binary_search(numbers, 7) | |
print(f"Found at index: {result}")""", | |
"JavaScript": """// Example: Async data fetching with error handling | |
async function fetchUserData(userId) { | |
try { | |
const response = await fetch(`/api/users/${userId}`); | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
const userData = await response.json(); | |
return userData; | |
} catch (error) { | |
console.error('Error fetching user data:', error); | |
throw error; | |
} | |
} | |
// Usage | |
fetchUserData(123) | |
.then(user => console.log('User:', user)) | |
.catch(err => console.error('Failed to fetch user:', err));""", | |
"Natural Language": """Create a function that implements a simple calculator with the following features: | |
- Add, subtract, multiply, and divide two numbers | |
- Handle division by zero errors | |
- Return the result as a formatted string | |
- Include input validation to ensure both inputs are numbers""" | |
} | |
# --- Enhanced Conversion Logic --- | |
class ConversionHistory: | |
"""Simple in-memory history management""" | |
def __init__(self, max_entries: int = 10): | |
self.history = [] | |
self.max_entries = max_entries | |
def add_entry(self, source_lang: str, target_lang: str, source_code: str, result: str): | |
entry = { | |
"timestamp": time.time(), | |
"source_lang": source_lang, | |
"target_lang": target_lang, | |
"source_code": source_code[:200] + "..." if len(source_code) > 200 else source_code, | |
"result": result[:200] + "..." if len(result) > 200 else result, | |
} | |
self.history.insert(0, entry) | |
if len(self.history) > self.max_entries: | |
self.history.pop() | |
def get_history(self) -> str: | |
if not self.history: | |
return "No conversion history yet." | |
history_text = "## Recent Conversions\n\n" | |
for i, entry in enumerate(self.history, 1): | |
timestamp = time.strftime("%H:%M:%S", time.localtime(entry["timestamp"])) | |
history_text += f"**{i}. {timestamp}** - {entry['source_lang']} β {entry['target_lang']}\n" | |
history_text += f"```\n{entry['source_code']}\n```\n\n" | |
return history_text | |
# Global history instance | |
conversion_history = ConversionHistory() | |
def validate_inputs(source_code: str, source_lang: str, target_lang: str, model: str, api_key: str) -> Optional[str]: | |
"""Comprehensive input validation""" | |
if not source_code.strip(): | |
return "Please enter some code or a description to convert." | |
if not api_key.strip(): | |
return "OpenRouter API key is required." | |
if not model or not model.strip(): | |
return "Please select a model for the conversion." | |
if source_lang == "Natural Language" and target_lang == "Natural Language": | |
return "Please select a programming language for either the source or the target." | |
if len(source_code) > 10000: | |
return "Source code is too long. Please limit to 10,000 characters." | |
return None | |
def create_conversion_prompt(source_code: str, source_lang: str, target_lang: str) -> str: | |
"""Create optimized prompts for different conversion scenarios""" | |
if source_lang == "Natural Language": | |
return f"""You are an expert programmer. Based on the following description, write complete and functional code in {target_lang}. | |
Requirements: | |
- Write clean, well-structured, and documented code | |
- Include proper error handling where appropriate | |
- Follow {target_lang} best practices and conventions | |
- Make the code production-ready | |
User's request: {source_code} | |
Respond with ONLY the raw {target_lang} code. Do not include explanations, markdown formatting, or code blocks.""" | |
elif target_lang == "Natural Language": | |
return f"""You are a programming expert. Explain the following {source_lang} code in clear, natural English. | |
Please provide: | |
1. A brief overview of what the code does | |
2. Explanation of the main logic and algorithms used | |
3. Description of inputs and outputs | |
4. Any notable features or techniques used | |
{source_lang} code to explain: | |
``` | |
{source_code} | |
``` | |
Provide a clear, educational explanation without including any code in your response.""" | |
else: | |
return f"""You are an expert programmer. Convert the following {source_lang} code to {target_lang}. | |
Requirements: | |
- Maintain the same functionality and logic | |
- Follow {target_lang} best practices and conventions | |
- Ensure the converted code is syntactically correct | |
- Keep the same variable names where possible | |
- Add brief comments for complex conversions | |
{source_lang} code to convert: | |
``` | |
{source_code} | |
``` | |
Respond with ONLY the converted {target_lang} code. Do not include explanations, markdown formatting, or code blocks.""" | |
def convert_code( | |
source_code: str, | |
source_lang: str, | |
target_lang: str, | |
model: str, | |
api_key: str, | |
temperature: float = 0.1, | |
max_tokens: int = 4000 | |
) -> Tuple[str, str]: | |
""" | |
Enhanced conversion function with better error handling and progress tracking | |
""" | |
# Validate inputs | |
validation_error = validate_inputs(source_code, source_lang, target_lang, model, api_key) | |
if validation_error: | |
return "", f"β {validation_error}" | |
# Create client and prompt | |
client = openai.OpenAI(base_url="https://openrouter.ai/api/v1", api_key=api_key) | |
prompt = create_conversion_prompt(source_code, source_lang, target_lang) | |
prompt = sanitize_for_api(prompt) | |
try: | |
# Make the API call | |
completion = client.chat.completions.create( | |
model=model, | |
messages=[{"role": "user", "content": prompt}], | |
temperature=temperature, | |
max_tokens=max_tokens, | |
stream=False | |
) | |
result = completion.choices[0].message.content.strip() | |
# Add to history | |
conversion_history.add_entry(source_lang, target_lang, source_code, result) | |
# Return result with success message | |
success_msg = f"β Successfully converted from {source_lang} to {target_lang}" | |
return result, success_msg | |
except openai.AuthenticationError: | |
return "", "β Authentication failed. Please check your OpenRouter API key." | |
except openai.RateLimitError: | |
return "", "β Rate limit exceeded. Please try again in a moment." | |
except openai.APIError as e: | |
return "", f"β API error: {str(e)}" | |
except Exception as e: | |
return "", f"β Unexpected error: {str(e)}" | |
# --- Enhanced UI Helper Functions --- | |
def update_code_language(lang: str) -> Dict[str, Any]: | |
"""Updates the Code component's language and placeholder text""" | |
if lang == "Natural Language": | |
return gr.update( | |
language="text", | |
placeholder="Describe the code you want here...", | |
value=DEFAULT_EXAMPLES.get("Natural Language", "") | |
) | |
example_code = DEFAULT_EXAMPLES.get(lang, f"# Enter your {lang} code here...") | |
return gr.update( | |
language=lang.lower(), | |
placeholder=f"Enter your {lang} code here...", | |
value=example_code | |
) | |
def update_target_language(lang: str) -> Dict[str, Any]: | |
"""Updates the target code display language""" | |
if lang == "Natural Language": | |
return gr.update(language="text", placeholder="Explanation will appear here...") | |
return gr.update(language=lang.lower(), placeholder="Converted code will appear here...") | |
def swap_languages(source_lang: str, target_lang: str, source_code: str, target_code: str) -> Tuple[str, str, str, str]: | |
"""Swap source and target languages with their code""" | |
return target_lang, source_lang, target_code, source_code | |
def clear_all() -> Tuple[str, str, str]: | |
"""Clear all input and output fields""" | |
return "", "", "Ready to convert!" | |
def get_conversion_history() -> str: | |
"""Get formatted conversion history""" | |
return conversion_history.get_history() | |
# --- Enhanced Gradio Interface --- | |
def create_header(): | |
"""Create an enhanced header with better styling""" | |
return gr.HTML( | |
""" | |
<div style="background: linear-gradient(135deg, #5E81AC 0%, #81A1C1 100%); | |
padding: 24px; border-radius: 12px; margin-bottom: 20px; | |
box-shadow: 0 4px 12px rgba(0,0,0,0.3);"> | |
<div style="display: flex; align-items: center; gap: 16px;"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" | |
fill="none" stroke="#ECEFF4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
<path d="m18 16 4-4-4-4"/><path d="m6 8-4 4 4 4"/><path d="m14.5 4-5 16"/> | |
</svg> | |
<div> | |
<h1 style="font-size: 2rem; font-weight: 700; color: #ECEFF4; margin: 0;"> | |
CodeVerter Pro | |
</h1> | |
<p style="font-size: 1rem; color: #E5E9F0; margin: 4px 0 0 0; opacity: 0.9;"> | |
Advanced Code & Natural Language Converter | |
</p> | |
</div> | |
</div> | |
</div> | |
""" | |
) | |
def create_footer(): | |
"""Create an enhanced footer""" | |
return gr.HTML( | |
""" | |
<div style="text-align: center; margin-top: 32px; padding: 20px; | |
background: #3B4252; border-radius: 8px; border: 1px solid #4C566A;"> | |
<p style="color: #D8DEE9; font-size: 0.9rem; margin: 0;"> | |
π Powered by OpenRouter β’ Built with Gradio β’ | |
<a href="https://openrouter.ai/keys" target="_blank" style="color: #88C0D0;">Get API Key</a> | |
</p> | |
<p style="color: #A0AEC0; font-size: 0.8rem; margin: 8px 0 0 0;"> | |
Always review generated code before use in production | |
</p> | |
</div> | |
""" | |
) | |
# --- Main Application --- | |
with gr.Blocks( | |
theme=NordTheme(), | |
css=css_overrides, | |
title="CodeVerter Pro" | |
) as app: | |
# Header | |
create_header() | |
# Configuration Section | |
with gr.Accordion("βοΈ Configuration", open=True): | |
with gr.Row(): | |
with gr.Column(scale=2): | |
openrouter_key = gr.Textbox( | |
label="π OpenRouter API Key", | |
placeholder="Enter your OpenRouter API key...", | |
type="password", | |
info="Get your free API key from openrouter.ai" | |
) | |
with gr.Column(scale=2): | |
model_selection = gr.Dropdown( | |
label="π€ Model Selection", | |
choices=ALL_MODELS, | |
value=ALL_MODELS[0] if ALL_MODELS else None, | |
allow_custom_value=True, | |
info="Choose a model optimized for your task" | |
) | |
with gr.Column(scale=1): | |
temperature = gr.Slider( | |
minimum=0.0, | |
maximum=1.0, | |
step=0.1, | |
value=0.1, | |
label="π‘οΈ Temperature", | |
info="Controls randomness" | |
) | |
# Main Conversion Interface | |
with gr.Row(equal_height=True): | |
with gr.Column(scale=1): | |
gr.Markdown("### π Source") | |
source_lang_selection = gr.Dropdown( | |
label="Source Language", | |
choices=LANGUAGES, | |
value="Python", | |
info="Select the language of your input" | |
) | |
source_code_input = gr.Code( | |
label="Source Code/Description", | |
language="python", | |
value=DEFAULT_EXAMPLES["Python"], | |
lines=20, | |
show_label=False | |
) | |
with gr.Column(scale=1): | |
gr.Markdown("### π― Target") | |
target_lang_selection = gr.Dropdown( | |
label="Target Language", | |
choices=LANGUAGES, | |
value="JavaScript", | |
info="Select the desired output language" | |
) | |
target_code_output = gr.Code( | |
label="Converted Code/Explanation", | |
language="javascript", | |
lines=20, | |
interactive=False, | |
show_label=False | |
) | |
# Action Buttons | |
with gr.Row(): | |
convert_button = gr.Button("π Convert", variant="primary", scale=2) | |
swap_button = gr.Button("π Swap Languages", variant="secondary", scale=1) | |
clear_button = gr.Button("ποΈ Clear All", variant="secondary", scale=1) | |
# Status and History | |
with gr.Row(): | |
with gr.Column(scale=2): | |
status_display = gr.Textbox( | |
label="Status", | |
value="Ready to convert!", | |
interactive=False, | |
show_label=False | |
) | |
with gr.Column(scale=1): | |
history_button = gr.Button("π View History", variant="secondary") | |
# History Modal | |
with gr.Accordion("π Conversion History", open=False) as history_accordion: | |
history_display = gr.Markdown("No conversions yet.") | |
# Event Handlers | |
source_lang_selection.change( | |
fn=update_code_language, | |
inputs=source_lang_selection, | |
outputs=source_code_input | |
) | |
target_lang_selection.change( | |
fn=update_target_language, | |
inputs=target_lang_selection, | |
outputs=target_code_output | |
) | |
convert_button.click( | |
fn=convert_code, | |
inputs=[ | |
source_code_input, | |
source_lang_selection, | |
target_lang_selection, | |
model_selection, | |
openrouter_key, | |
temperature | |
], | |
outputs=[target_code_output, status_display], | |
api_name="convert" | |
) | |
swap_button.click( | |
fn=swap_languages, | |
inputs=[source_lang_selection, target_lang_selection, source_code_input, target_code_output], | |
outputs=[source_lang_selection, target_lang_selection, source_code_input, target_code_output] | |
) | |
clear_button.click( | |
fn=clear_all, | |
outputs=[source_code_input, target_code_output, status_display] | |
) | |
history_button.click( | |
fn=get_conversion_history, | |
outputs=history_display | |
) | |
# Footer | |
create_footer() | |
# --- Launch Configuration --- | |
if __name__ == "__main__": | |
app.launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
share=False, | |
debug=False, | |
show_error=True, | |
quiet=False | |
) |