File size: 8,378 Bytes
20718fa
 
0db2f97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20718fa
 
 
cd4b4ee
20718fa
cd4b4ee
 
0db2f97
20718fa
 
0db2f97
 
 
 
 
 
 
 
 
20718fa
 
 
 
 
 
 
 
 
 
 
 
0db2f97
20718fa
cd4b4ee
 
 
 
 
 
20718fa
cd4b4ee
20718fa
 
0db2f97
 
cd4b4ee
 
 
 
20718fa
0db2f97
cd4b4ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20718fa
 
 
0db2f97
 
20718fa
0db2f97
20718fa
0db2f97
20718fa
0db2f97
20718fa
 
 
cd4b4ee
 
 
 
 
 
0db2f97
20718fa
0db2f97
 
 
cd4b4ee
0db2f97
 
cd4b4ee
20718fa
0db2f97
 
 
20718fa
 
cd4b4ee
 
20718fa
 
 
0db2f97
cd4b4ee
20718fa
0db2f97
cd4b4ee
20718fa
cd4b4ee
 
 
20718fa
cd4b4ee
20718fa
 
0db2f97
20718fa
 
 
 
 
0db2f97
cd4b4ee
0db2f97
20718fa
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
import gradio as gr
import openai
from gradio.themes.base import Base
from gradio.themes.utils import colors, fonts, sizes

# --- Custom Theme Definition ---

class NordTheme(Base):
    """
    A custom Gradio theme inspired by the Nord color palette.
    """
    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"),
        )
        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",
            input_background_fill="#434C5E",
            input_border_color="transparent",
            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",
            background_fill_primary_dark="#2E3440",
            color_accent_soft="#4c566a",
            block_radius="12px",
            button_radius="8px",
        )

# --- UI Configuration ---

# UPDATED: "Natural Language" is added to the list.
LANGUAGES = [
    'Natural Language', 'Python', 'JavaScript', 'TypeScript', 'Java', 'C++', 'C#', 
    'C', 'Go', 'Rust', 'Swift', 'Kotlin', 'PHP', 'Ruby', 'Scala', 'R', 'MATLAB', 
    'Perl', 'Haskell', 'Lua', 'Dart', 'Elixir', 'F#', 'Clojure', 'SQL'
]

MODELS = sorted([
    "agentica-org/deepcoder-14b-preview:free", "deepseek/deepseek-chat-v3:free",
    "deepseek/deepseek-r1-0528:free", "google/gemma-3-27b-it:free",
    "google/gemini-2.0-flash-exp:free", "meta-llama/llama-3.3-70b-instruct:free",
    "mistralai/devstral-small-2505:free", "mistralai/mistral-small-3.2-24b-instruct-2506:free",
    "moonshotai/kimi-dev-72b:free", "openrouter/cypher-alpha:free",
    "qwen/qwen-2.5-coder-32b-instruct:free", "qwen/qwen3-235b-a22b-04-28:free",
    "qwen/qwq-32b:free",
])

DEFAULT_SOURCE_CODE = """# Example Python code
def fibonacci(n):
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))"""

# --- Core Conversion Logic ---

def convert_code(
    source_code: str, source_lang: str, target_lang: str, model: str, api_key: str
):
    """
    Handles three conversion scenarios:
    1. Natural Language -> Code
    2. Code -> Natural Language
    3. Code -> Code
    """
    if not source_code.strip():
        raise gr.Error("Please enter some code or a description to convert.")
    if not api_key.strip():
        raise gr.Error("OpenRouter API key is required.")
    if not model or not model.strip():
        raise gr.Error("Please select or enter a model for the conversion.")
    
    # Handle the edge case where both are "Natural Language"
    if source_lang == "Natural Language" and target_lang == "Natural Language":
        raise gr.Error("Please select a programming language for either the source or the target.")

    client = openai.OpenAI(base_url="https://openrouter.ai/api/v1", api_key=api_key)

    # UPDATED: Logic to generate a prompt based on the conversion type
    if source_lang == "Natural Language":
        # Scenario 1: Natural Language -> Code
        prompt = (
            f"You are a programming expert. Based on the following description, write a complete and functional code snippet in {target_lang}. "
            f"The user's request is: '{source_code}'.\n\n"
            f"Your response must only contain the raw {target_lang} code without any explanations, comments, or markdown formatting (like ```)."
        )
    elif target_lang == "Natural Language":
        # Scenario 2: Code -> Natural Language
        prompt = (
            f"You are a programming expert. Explain the following {source_lang} code in simple, natural English. "
            f"Describe what the code does, its main logic, its inputs, and what it outputs. Do not include any code in your explanation.\n\n"
            f"--- Start of {source_lang} Code ---\n"
            f"{source_code}\n"
            f"--- End of {source_lang} Code ---"
        )
    else:
        # Scenario 3: Code -> Code (original logic)
        prompt = (
            f"You are an expert programmer. Convert the following {source_lang} code to {target_lang}. "
            "Your response must only contain the raw, converted code. Do not include any explanations, comments, or markdown formatting (like ```)."
            f"\n\n--- Start of {source_lang} Code ---\n"
            f"{source_code}\n"
            f"--- End of {source_lang} Code ---"
        )
    
    try:
        completion = client.chat.completions.create(
            model=model,
            messages=[{"role": "user", "content": prompt}],
            temperature=0.1, max_tokens=2048
        )
        return completion.choices[0].message.content.strip()
    except openai.AuthenticationError:
        raise gr.Error("Authentication failed. Check your OpenRouter API key.")
    except Exception as e:
        raise gr.Error(f"An error occurred: {e}")

# --- Gradio User Interface ---

# Helper function to update Code component's language
def update_code_language(lang: str):
    if lang == "Natural Language":
        return gr.update(language="text", placeholder="Describe the code you want here...")
    return gr.update(language=lang.lower(), placeholder=f"Enter your {lang} code here...")

with gr.Blocks(theme=NordTheme()) as app:
    # Header
    gr.HTML(
        """
        <div style="display: flex; align-items: center; gap: 12px; padding: 10px;">
            <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#81A1C1" 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: 1.5rem; font-weight: 700; color: #ECEFF4; margin: 0;">CodeVerter</h1>
                <p style="font-size: 0.875rem; color: #D8DEE9; margin: 0;">Code & Natural Language Converter</p>
            </div>
        </div>
        """
    )

    with gr.Accordion("⚙️ Configuration", open=True):
        openrouter_key = gr.Textbox(label="OpenRouter API Key", placeholder="Enter your OpenRouter API key...", type="password")
        model_selection = gr.Dropdown(label="Select or Enter a Model Name", choices=MODELS, value=MODELS[0] if MODELS else None, allow_custom_value=True)

    with gr.Row(equal_height=False):
        with gr.Column(scale=1):
            source_lang_selection = gr.Dropdown(label="Source Language", choices=LANGUAGES, value="Python")
            source_code_input = gr.Code(label="Source", language="python", value=DEFAULT_SOURCE_CODE, lines=15)
        with gr.Column(scale=1):
            target_lang_selection = gr.Dropdown(label="Target Language", choices=LANGUAGES, value="JavaScript")
            target_code_output = gr.Code(label="Result", language="javascript", lines=15, interactive=False)
    
    # UPDATED: Use a helper function for cleaner UI logic
    source_lang_selection.change(fn=update_code_language, inputs=source_lang_selection, outputs=source_code_input)
    target_lang_selection.change(lambda lang: gr.update(language=lang.lower() if lang != "Natural Language" else "text"), inputs=target_lang_selection, outputs=target_code_output)

    convert_button = gr.Button("Convert", variant="primary", scale=1)
    convert_button.click(
        fn=convert_code,
        inputs=[source_code_input, source_lang_selection, target_lang_selection, model_selection, openrouter_key],
        outputs=target_code_output,
        api_name="convert"
    )

    gr.HTML(
        """<div style="text-align: center; margin-top: 24px; color: #a0aec0; font-size: 0.875rem;">
        <p>Powered by OpenRouter. Results may require manual review.</p>
        </div>"""
    )

if __name__ == "__main__":
    app.launch()