Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,13 +1,16 @@
|
|
1 |
import gradio as gr
|
2 |
import openai
|
|
|
|
|
|
|
3 |
from gradio.themes.base import Base
|
4 |
from gradio.themes.utils import colors, fonts, sizes
|
5 |
|
6 |
-
# --- Custom Theme
|
7 |
|
8 |
class NordTheme(Base):
|
9 |
"""
|
10 |
-
|
11 |
"""
|
12 |
def __init__(self):
|
13 |
super().__init__(
|
@@ -16,8 +19,13 @@ class NordTheme(Base):
|
|
16 |
neutral_hue=colors.slate,
|
17 |
font=(fonts.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"),
|
18 |
font_mono=(fonts.GoogleFont("Fira Code"), "ui-monospace", "monospace"),
|
|
|
|
|
|
|
19 |
)
|
|
|
20 |
self.set(
|
|
|
21 |
body_background_fill="#2E3440",
|
22 |
body_text_color="#ECEFF4",
|
23 |
block_background_fill="#3B4252",
|
@@ -25,164 +33,509 @@ class NordTheme(Base):
|
|
25 |
block_border_color="#4C566A",
|
26 |
block_label_background_fill="#434C5E",
|
27 |
block_label_text_color="#ECEFF4",
|
|
|
|
|
28 |
input_background_fill="#434C5E",
|
29 |
input_border_color="transparent",
|
|
|
|
|
|
|
30 |
button_primary_background_fill="#5E81AC",
|
31 |
button_primary_background_fill_hover="#81A1C1",
|
32 |
button_primary_text_color="#ECEFF4",
|
33 |
button_secondary_background_fill="#4C566A",
|
34 |
button_secondary_background_fill_hover="#5a657a",
|
35 |
button_secondary_text_color="#ECEFF4",
|
|
|
|
|
36 |
border_color_accent="#5E81AC",
|
37 |
background_fill_primary_dark="#2E3440",
|
38 |
color_accent_soft="#4c566a",
|
39 |
block_radius="12px",
|
40 |
-
|
41 |
-
#
|
42 |
-
|
43 |
-
|
44 |
-
|
|
|
45 |
)
|
46 |
|
47 |
-
# ---
|
48 |
|
49 |
PROGRAMMING_LANGUAGES = sorted([
|
50 |
'Ada', 'Assembly', 'Bash', 'C', 'C#', 'C++', 'Clojure', 'COBOL', 'CSS',
|
51 |
-
'Crystal', 'Dart', 'Elixir', 'F#', 'Fortran', 'Go', 'GraphQL',
|
52 |
-
'Haskell', 'HTML', 'Java', 'JavaScript', 'Julia', 'Kotlin',
|
53 |
-
'
|
54 |
-
'
|
55 |
-
'
|
56 |
-
'XML', 'YAML', 'Zig'
|
57 |
])
|
|
|
58 |
LANGUAGES = ['Natural Language'] + PROGRAMMING_LANGUAGES
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
"mistralai/devstral-small-2505:free", "mistralai/mistral-small-3.2-24b-instruct-2506:free",
|
66 |
-
"moonshotai/kimi-dev-72b:free", "openrouter/cypher-alpha:free",
|
67 |
-
"qwen/qwen-2.5-coder-32b-instruct:free", "qwen/qwen3-235b-a22b-04-28:free",
|
68 |
-
"qwen/qwq-32b:free",
|
69 |
-
])
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
|
77 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
"""
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
if not source_code.strip():
|
91 |
-
|
|
|
92 |
if not api_key.strip():
|
93 |
-
|
|
|
94 |
if not model or not model.strip():
|
95 |
-
|
96 |
-
|
97 |
if source_lang == "Natural Language" and target_lang == "Natural Language":
|
98 |
-
|
99 |
-
|
100 |
-
|
|
|
|
|
|
|
101 |
|
|
|
|
|
|
|
102 |
if source_lang == "Natural Language":
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
elif target_lang == "Natural Language":
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
else:
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
125 |
try:
|
|
|
126 |
completion = client.chat.completions.create(
|
127 |
model=model,
|
128 |
messages=[{"role": "user", "content": prompt}],
|
129 |
-
temperature=
|
|
|
|
|
130 |
)
|
131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
except openai.AuthenticationError:
|
133 |
-
|
|
|
|
|
|
|
|
|
134 |
except Exception as e:
|
135 |
-
|
136 |
|
137 |
-
# ---
|
138 |
|
139 |
-
def update_code_language(lang: str):
|
140 |
-
"""Updates the Code component's language and placeholder text
|
141 |
if lang == "Natural Language":
|
142 |
-
return gr.update(
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
|
145 |
-
|
146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
"""
|
148 |
-
<div style="
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
</div>
|
154 |
</div>
|
155 |
"""
|
156 |
)
|
157 |
|
158 |
-
|
159 |
-
|
160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
161 |
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
with gr.Column(scale=1):
|
164 |
-
|
165 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
166 |
with gr.Column(scale=1):
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
convert_button.click(
|
175 |
fn=convert_code,
|
176 |
-
inputs=[
|
177 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
api_name="convert"
|
179 |
)
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
|
187 |
if __name__ == "__main__":
|
188 |
-
app.launch(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
import openai
|
3 |
+
import json
|
4 |
+
import time
|
5 |
+
from typing import Optional, Tuple, Dict, Any
|
6 |
from gradio.themes.base import Base
|
7 |
from gradio.themes.utils import colors, fonts, sizes
|
8 |
|
9 |
+
# --- Enhanced Custom Theme ---
|
10 |
|
11 |
class NordTheme(Base):
|
12 |
"""
|
13 |
+
Enhanced Nord theme with improved accessibility and visual polish.
|
14 |
"""
|
15 |
def __init__(self):
|
16 |
super().__init__(
|
|
|
19 |
neutral_hue=colors.slate,
|
20 |
font=(fonts.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"),
|
21 |
font_mono=(fonts.GoogleFont("Fira Code"), "ui-monospace", "monospace"),
|
22 |
+
radius_sm=sizes.radius_sm,
|
23 |
+
radius_md=sizes.radius_md,
|
24 |
+
radius_lg=sizes.radius_lg,
|
25 |
)
|
26 |
+
|
27 |
self.set(
|
28 |
+
# Main backgrounds
|
29 |
body_background_fill="#2E3440",
|
30 |
body_text_color="#ECEFF4",
|
31 |
block_background_fill="#3B4252",
|
|
|
33 |
block_border_color="#4C566A",
|
34 |
block_label_background_fill="#434C5E",
|
35 |
block_label_text_color="#ECEFF4",
|
36 |
+
|
37 |
+
# Input styling
|
38 |
input_background_fill="#434C5E",
|
39 |
input_border_color="transparent",
|
40 |
+
input_text_color="#ECEFF4",
|
41 |
+
|
42 |
+
# Button styling
|
43 |
button_primary_background_fill="#5E81AC",
|
44 |
button_primary_background_fill_hover="#81A1C1",
|
45 |
button_primary_text_color="#ECEFF4",
|
46 |
button_secondary_background_fill="#4C566A",
|
47 |
button_secondary_background_fill_hover="#5a657a",
|
48 |
button_secondary_text_color="#ECEFF4",
|
49 |
+
|
50 |
+
# Accent colors
|
51 |
border_color_accent="#5E81AC",
|
52 |
background_fill_primary_dark="#2E3440",
|
53 |
color_accent_soft="#4c566a",
|
54 |
block_radius="12px",
|
55 |
+
|
56 |
+
# Error and success colors
|
57 |
+
color_red="#BF616A",
|
58 |
+
color_green="#A3BE8C",
|
59 |
+
color_yellow="#EBCB8B",
|
60 |
+
color_orange="#D08770",
|
61 |
)
|
62 |
|
63 |
+
# --- Enhanced Configuration ---
|
64 |
|
65 |
PROGRAMMING_LANGUAGES = sorted([
|
66 |
'Ada', 'Assembly', 'Bash', 'C', 'C#', 'C++', 'Clojure', 'COBOL', 'CSS',
|
67 |
+
'Crystal', 'Dart', 'Elixir', 'Erlang', 'F#', 'Fortran', 'Go', 'GraphQL',
|
68 |
+
'Groovy', 'Haskell', 'HTML', 'Java', 'JavaScript', 'Julia', 'Kotlin',
|
69 |
+
'Lisp', 'Lua', 'Markdown', 'MATLAB', 'Nim', 'Objective-C', 'OCaml',
|
70 |
+
'Pascal', 'Perl', 'PHP', 'PowerShell', 'Prolog', 'Python', 'R', 'Ruby',
|
71 |
+
'Rust', 'Scala', 'Scheme', 'Shell', 'SQL', 'Svelte', 'Swift', 'TOML',
|
72 |
+
'TypeScript', 'Visual Basic', 'Vue', 'XML', 'YAML', 'Zig'
|
73 |
])
|
74 |
+
|
75 |
LANGUAGES = ['Natural Language'] + PROGRAMMING_LANGUAGES
|
76 |
|
77 |
+
# Enhanced model list with categorization
|
78 |
+
MODELS = {
|
79 |
+
"Code-Specialized": [
|
80 |
+
"deepseek/deepseek-coder-v2-instruct",
|
81 |
+
"mistralai/codestral-latest",
|
82 |
+
"codellama/codellama-70b-instruct",
|
83 |
+
"qwen/qwen-2.5-coder-32b-instruct:free",
|
84 |
+
"agentica-org/deepcoder-14b-preview:free",
|
85 |
+
],
|
86 |
+
"General Purpose": [
|
87 |
+
"deepseek/deepseek-chat-v3:free",
|
88 |
+
"deepseek/deepseek-r1-0528:free",
|
89 |
+
"google/gemini-2.0-flash-exp:free",
|
90 |
+
"meta-llama/llama-3.3-70b-instruct:free",
|
91 |
+
"mistralai/mistral-small-3.2-24b-instruct-2506:free",
|
92 |
+
"qwen/qwq-32b:free",
|
93 |
+
],
|
94 |
+
"Experimental": [
|
95 |
+
"openrouter/cypher-alpha:free",
|
96 |
+
"moonshotai/kimi-dev-72b:free",
|
97 |
+
"qwen/qwen3-235b-a22b-04-28:free",
|
98 |
+
]
|
99 |
+
}
|
100 |
|
101 |
+
# Flatten models for dropdown
|
102 |
+
ALL_MODELS = []
|
103 |
+
for category, models in MODELS.items():
|
104 |
+
ALL_MODELS.extend(models)
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
+
DEFAULT_EXAMPLES = {
|
107 |
+
"Python": """# Example: Binary search algorithm
|
108 |
+
def binary_search(arr, target):
|
109 |
+
left, right = 0, len(arr) - 1
|
110 |
+
|
111 |
+
while left <= right:
|
112 |
+
mid = (left + right) // 2
|
113 |
+
if arr[mid] == target:
|
114 |
+
return mid
|
115 |
+
elif arr[mid] < target:
|
116 |
+
left = mid + 1
|
117 |
+
else:
|
118 |
+
right = mid - 1
|
119 |
+
|
120 |
+
return -1
|
121 |
|
122 |
+
# Test the function
|
123 |
+
numbers = [1, 3, 5, 7, 9, 11, 13, 15]
|
124 |
+
result = binary_search(numbers, 7)
|
125 |
+
print(f"Found at index: {result}")""",
|
126 |
+
|
127 |
+
"JavaScript": """// Example: Async data fetching with error handling
|
128 |
+
async function fetchUserData(userId) {
|
129 |
+
try {
|
130 |
+
const response = await fetch(`/api/users/${userId}`);
|
131 |
+
if (!response.ok) {
|
132 |
+
throw new Error(`HTTP error! status: ${response.status}`);
|
133 |
+
}
|
134 |
+
const userData = await response.json();
|
135 |
+
return userData;
|
136 |
+
} catch (error) {
|
137 |
+
console.error('Error fetching user data:', error);
|
138 |
+
throw error;
|
139 |
+
}
|
140 |
+
}
|
141 |
|
142 |
+
// Usage
|
143 |
+
fetchUserData(123)
|
144 |
+
.then(user => console.log('User:', user))
|
145 |
+
.catch(err => console.error('Failed to fetch user:', err));""",
|
146 |
+
|
147 |
+
"Natural Language": """Create a function that implements a simple calculator with the following features:
|
148 |
+
- Add, subtract, multiply, and divide two numbers
|
149 |
+
- Handle division by zero errors
|
150 |
+
- Return the result as a formatted string
|
151 |
+
- Include input validation to ensure both inputs are numbers"""
|
152 |
+
}
|
153 |
|
154 |
+
# --- Enhanced Conversion Logic ---
|
155 |
+
|
156 |
+
class ConversionHistory:
|
157 |
+
"""Simple in-memory history management"""
|
158 |
+
def __init__(self, max_entries: int = 10):
|
159 |
+
self.history = []
|
160 |
+
self.max_entries = max_entries
|
161 |
+
|
162 |
+
def add_entry(self, source_lang: str, target_lang: str, source_code: str, result: str):
|
163 |
+
entry = {
|
164 |
+
"timestamp": time.time(),
|
165 |
+
"source_lang": source_lang,
|
166 |
+
"target_lang": target_lang,
|
167 |
+
"source_code": source_code[:200] + "..." if len(source_code) > 200 else source_code,
|
168 |
+
"result": result[:200] + "..." if len(result) > 200 else result,
|
169 |
+
}
|
170 |
+
self.history.insert(0, entry)
|
171 |
+
if len(self.history) > self.max_entries:
|
172 |
+
self.history.pop()
|
173 |
+
|
174 |
+
def get_history(self) -> str:
|
175 |
+
if not self.history:
|
176 |
+
return "No conversion history yet."
|
177 |
+
|
178 |
+
history_text = "## Recent Conversions\n\n"
|
179 |
+
for i, entry in enumerate(self.history, 1):
|
180 |
+
timestamp = time.strftime("%H:%M:%S", time.localtime(entry["timestamp"]))
|
181 |
+
history_text += f"**{i}. {timestamp}** - {entry['source_lang']} β {entry['target_lang']}\n"
|
182 |
+
history_text += f"```\n{entry['source_code']}\n```\n\n"
|
183 |
+
|
184 |
+
return history_text
|
185 |
+
|
186 |
+
# Global history instance
|
187 |
+
conversion_history = ConversionHistory()
|
188 |
+
|
189 |
+
def validate_inputs(source_code: str, source_lang: str, target_lang: str, model: str, api_key: str) -> Optional[str]:
|
190 |
+
"""Comprehensive input validation"""
|
191 |
if not source_code.strip():
|
192 |
+
return "Please enter some code or a description to convert."
|
193 |
+
|
194 |
if not api_key.strip():
|
195 |
+
return "OpenRouter API key is required."
|
196 |
+
|
197 |
if not model or not model.strip():
|
198 |
+
return "Please select a model for the conversion."
|
199 |
+
|
200 |
if source_lang == "Natural Language" and target_lang == "Natural Language":
|
201 |
+
return "Please select a programming language for either the source or the target."
|
202 |
+
|
203 |
+
if len(source_code) > 10000:
|
204 |
+
return "Source code is too long. Please limit to 10,000 characters."
|
205 |
+
|
206 |
+
return None
|
207 |
|
208 |
+
def create_conversion_prompt(source_code: str, source_lang: str, target_lang: str) -> str:
|
209 |
+
"""Create optimized prompts for different conversion scenarios"""
|
210 |
+
|
211 |
if source_lang == "Natural Language":
|
212 |
+
return f"""You are an expert programmer. Based on the following description, write complete and functional code in {target_lang}.
|
213 |
+
|
214 |
+
Requirements:
|
215 |
+
- Write clean, well-structured, and documented code
|
216 |
+
- Include proper error handling where appropriate
|
217 |
+
- Follow {target_lang} best practices and conventions
|
218 |
+
- Make the code production-ready
|
219 |
+
|
220 |
+
User's request: {source_code}
|
221 |
+
|
222 |
+
Respond with ONLY the raw {target_lang} code. Do not include explanations, markdown formatting, or code blocks."""
|
223 |
+
|
224 |
elif target_lang == "Natural Language":
|
225 |
+
return f"""You are a programming expert. Explain the following {source_lang} code in clear, natural English.
|
226 |
+
|
227 |
+
Please provide:
|
228 |
+
1. A brief overview of what the code does
|
229 |
+
2. Explanation of the main logic and algorithms used
|
230 |
+
3. Description of inputs and outputs
|
231 |
+
4. Any notable features or techniques used
|
232 |
+
|
233 |
+
{source_lang} code to explain:
|
234 |
+
```
|
235 |
+
{source_code}
|
236 |
+
```
|
237 |
+
|
238 |
+
Provide a clear, educational explanation without including any code in your response."""
|
239 |
+
|
240 |
else:
|
241 |
+
return f"""You are an expert programmer. Convert the following {source_lang} code to {target_lang}.
|
242 |
+
|
243 |
+
Requirements:
|
244 |
+
- Maintain the same functionality and logic
|
245 |
+
- Follow {target_lang} best practices and conventions
|
246 |
+
- Ensure the converted code is syntactically correct
|
247 |
+
- Keep the same variable names where possible
|
248 |
+
- Add brief comments for complex conversions
|
249 |
+
|
250 |
+
{source_lang} code to convert:
|
251 |
+
```
|
252 |
+
{source_code}
|
253 |
+
```
|
254 |
|
255 |
+
Respond with ONLY the converted {target_lang} code. Do not include explanations, markdown formatting, or code blocks."""
|
256 |
+
|
257 |
+
def convert_code(
|
258 |
+
source_code: str,
|
259 |
+
source_lang: str,
|
260 |
+
target_lang: str,
|
261 |
+
model: str,
|
262 |
+
api_key: str,
|
263 |
+
temperature: float = 0.1,
|
264 |
+
max_tokens: int = 4000
|
265 |
+
) -> Tuple[str, str]:
|
266 |
+
"""
|
267 |
+
Enhanced conversion function with better error handling and progress tracking
|
268 |
+
"""
|
269 |
+
|
270 |
+
# Validate inputs
|
271 |
+
validation_error = validate_inputs(source_code, source_lang, target_lang, model, api_key)
|
272 |
+
if validation_error:
|
273 |
+
return "", f"β {validation_error}"
|
274 |
+
|
275 |
+
# Create client and prompt
|
276 |
+
client = openai.OpenAI(base_url="https://openrouter.ai/api/v1", api_key=api_key)
|
277 |
+
prompt = create_conversion_prompt(source_code, source_lang, target_lang)
|
278 |
+
|
279 |
try:
|
280 |
+
# Make the API call
|
281 |
completion = client.chat.completions.create(
|
282 |
model=model,
|
283 |
messages=[{"role": "user", "content": prompt}],
|
284 |
+
temperature=temperature,
|
285 |
+
max_tokens=max_tokens,
|
286 |
+
stream=False
|
287 |
)
|
288 |
+
|
289 |
+
result = completion.choices[0].message.content.strip()
|
290 |
+
|
291 |
+
# Add to history
|
292 |
+
conversion_history.add_entry(source_lang, target_lang, source_code, result)
|
293 |
+
|
294 |
+
# Return result with success message
|
295 |
+
success_msg = f"β
Successfully converted from {source_lang} to {target_lang}"
|
296 |
+
return result, success_msg
|
297 |
+
|
298 |
except openai.AuthenticationError:
|
299 |
+
return "", "β Authentication failed. Please check your OpenRouter API key."
|
300 |
+
except openai.RateLimitError:
|
301 |
+
return "", "β Rate limit exceeded. Please try again in a moment."
|
302 |
+
except openai.APIError as e:
|
303 |
+
return "", f"β API error: {str(e)}"
|
304 |
except Exception as e:
|
305 |
+
return "", f"β Unexpected error: {str(e)}"
|
306 |
|
307 |
+
# --- Enhanced UI Helper Functions ---
|
308 |
|
309 |
+
def update_code_language(lang: str) -> Dict[str, Any]:
|
310 |
+
"""Updates the Code component's language and placeholder text"""
|
311 |
if lang == "Natural Language":
|
312 |
+
return gr.update(
|
313 |
+
language="text",
|
314 |
+
placeholder="Describe the code you want here...",
|
315 |
+
value=DEFAULT_EXAMPLES.get("Natural Language", "")
|
316 |
+
)
|
317 |
+
|
318 |
+
example_code = DEFAULT_EXAMPLES.get(lang, f"# Enter your {lang} code here...")
|
319 |
+
return gr.update(
|
320 |
+
language=lang.lower(),
|
321 |
+
placeholder=f"Enter your {lang} code here...",
|
322 |
+
value=example_code
|
323 |
+
)
|
324 |
|
325 |
+
def update_target_language(lang: str) -> Dict[str, Any]:
|
326 |
+
"""Updates the target code display language"""
|
327 |
+
if lang == "Natural Language":
|
328 |
+
return gr.update(language="text", placeholder="Explanation will appear here...")
|
329 |
+
return gr.update(language=lang.lower(), placeholder="Converted code will appear here...")
|
330 |
+
|
331 |
+
def swap_languages(source_lang: str, target_lang: str, source_code: str, target_code: str) -> Tuple[str, str, str, str]:
|
332 |
+
"""Swap source and target languages with their code"""
|
333 |
+
return target_lang, source_lang, target_code, source_code
|
334 |
+
|
335 |
+
def clear_all() -> Tuple[str, str, str]:
|
336 |
+
"""Clear all input and output fields"""
|
337 |
+
return "", "", "Ready to convert!"
|
338 |
+
|
339 |
+
def get_conversion_history() -> str:
|
340 |
+
"""Get formatted conversion history"""
|
341 |
+
return conversion_history.get_history()
|
342 |
+
|
343 |
+
# --- Enhanced Gradio Interface ---
|
344 |
+
|
345 |
+
def create_header():
|
346 |
+
"""Create an enhanced header with better styling"""
|
347 |
+
return gr.HTML(
|
348 |
"""
|
349 |
+
<div style="background: linear-gradient(135deg, #5E81AC 0%, #81A1C1 100%);
|
350 |
+
padding: 24px; border-radius: 12px; margin-bottom: 20px;
|
351 |
+
box-shadow: 0 4px 12px rgba(0,0,0,0.3);">
|
352 |
+
<div style="display: flex; align-items: center; gap: 16px;">
|
353 |
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24"
|
354 |
+
fill="none" stroke="#ECEFF4" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
355 |
+
<path d="m18 16 4-4-4-4"/><path d="m6 8-4 4 4 4"/><path d="m14.5 4-5 16"/>
|
356 |
+
</svg>
|
357 |
+
<div>
|
358 |
+
<h1 style="font-size: 2rem; font-weight: 700; color: #ECEFF4; margin: 0;">
|
359 |
+
CodeVerter Pro
|
360 |
+
</h1>
|
361 |
+
<p style="font-size: 1rem; color: #E5E9F0; margin: 4px 0 0 0; opacity: 0.9;">
|
362 |
+
Advanced Code & Natural Language Converter
|
363 |
+
</p>
|
364 |
+
</div>
|
365 |
</div>
|
366 |
</div>
|
367 |
"""
|
368 |
)
|
369 |
|
370 |
+
def create_footer():
|
371 |
+
"""Create an enhanced footer"""
|
372 |
+
return gr.HTML(
|
373 |
+
"""
|
374 |
+
<div style="text-align: center; margin-top: 32px; padding: 20px;
|
375 |
+
background: #3B4252; border-radius: 8px; border: 1px solid #4C566A;">
|
376 |
+
<p style="color: #D8DEE9; font-size: 0.9rem; margin: 0;">
|
377 |
+
π Powered by OpenRouter β’ Built with Gradio β’
|
378 |
+
<a href="https://openrouter.ai/keys" target="_blank" style="color: #88C0D0;">Get API Key</a>
|
379 |
+
</p>
|
380 |
+
<p style="color: #A0AEC0; font-size: 0.8rem; margin: 8px 0 0 0;">
|
381 |
+
Always review generated code before use in production
|
382 |
+
</p>
|
383 |
+
</div>
|
384 |
+
"""
|
385 |
+
)
|
386 |
+
|
387 |
+
# --- Main Application ---
|
388 |
|
389 |
+
with gr.Blocks(theme=NordTheme(), title="CodeVerter Pro", css="""
|
390 |
+
.gradio-container {
|
391 |
+
max-width: 1200px !important;
|
392 |
+
}
|
393 |
+
.code-container {
|
394 |
+
border-radius: 8px !important;
|
395 |
+
}
|
396 |
+
""") as app:
|
397 |
+
|
398 |
+
# Header
|
399 |
+
create_header()
|
400 |
+
|
401 |
+
# Configuration Section
|
402 |
+
with gr.Accordion("βοΈ Configuration", open=True):
|
403 |
+
with gr.Row():
|
404 |
+
with gr.Column(scale=2):
|
405 |
+
openrouter_key = gr.Textbox(
|
406 |
+
label="π OpenRouter API Key",
|
407 |
+
placeholder="Enter your OpenRouter API key...",
|
408 |
+
type="password",
|
409 |
+
info="Get your free API key from openrouter.ai"
|
410 |
+
)
|
411 |
+
with gr.Column(scale=2):
|
412 |
+
model_selection = gr.Dropdown(
|
413 |
+
label="π€ Model Selection",
|
414 |
+
choices=ALL_MODELS,
|
415 |
+
value=ALL_MODELS[0] if ALL_MODELS else None,
|
416 |
+
allow_custom_value=True,
|
417 |
+
info="Choose a model optimized for your task"
|
418 |
+
)
|
419 |
+
with gr.Column(scale=1):
|
420 |
+
temperature = gr.Slider(
|
421 |
+
minimum=0.0,
|
422 |
+
maximum=1.0,
|
423 |
+
step=0.1,
|
424 |
+
value=0.1,
|
425 |
+
label="π‘οΈ Temperature",
|
426 |
+
info="Controls randomness"
|
427 |
+
)
|
428 |
+
|
429 |
+
# Main Conversion Interface
|
430 |
+
with gr.Row(equal_height=True):
|
431 |
with gr.Column(scale=1):
|
432 |
+
gr.Markdown("### π Source")
|
433 |
+
source_lang_selection = gr.Dropdown(
|
434 |
+
label="Source Language",
|
435 |
+
choices=LANGUAGES,
|
436 |
+
value="Python",
|
437 |
+
info="Select the language of your input"
|
438 |
+
)
|
439 |
+
source_code_input = gr.Code(
|
440 |
+
label="Source Code/Description",
|
441 |
+
language="python",
|
442 |
+
value=DEFAULT_EXAMPLES["Python"],
|
443 |
+
lines=20,
|
444 |
+
show_label=False
|
445 |
+
)
|
446 |
+
|
447 |
with gr.Column(scale=1):
|
448 |
+
gr.Markdown("### π― Target")
|
449 |
+
target_lang_selection = gr.Dropdown(
|
450 |
+
label="Target Language",
|
451 |
+
choices=LANGUAGES,
|
452 |
+
value="JavaScript",
|
453 |
+
info="Select the desired output language"
|
454 |
+
)
|
455 |
+
target_code_output = gr.Code(
|
456 |
+
label="Converted Code/Explanation",
|
457 |
+
language="javascript",
|
458 |
+
lines=20,
|
459 |
+
interactive=False,
|
460 |
+
show_label=False
|
461 |
+
)
|
462 |
+
|
463 |
+
# Action Buttons
|
464 |
+
with gr.Row():
|
465 |
+
convert_button = gr.Button("π Convert", variant="primary", scale=2)
|
466 |
+
swap_button = gr.Button("π Swap Languages", variant="secondary", scale=1)
|
467 |
+
clear_button = gr.Button("ποΈ Clear All", variant="secondary", scale=1)
|
468 |
+
|
469 |
+
# Status and History
|
470 |
+
with gr.Row():
|
471 |
+
with gr.Column(scale=2):
|
472 |
+
status_display = gr.Textbox(
|
473 |
+
label="Status",
|
474 |
+
value="Ready to convert!",
|
475 |
+
interactive=False,
|
476 |
+
show_label=False
|
477 |
+
)
|
478 |
+
with gr.Column(scale=1):
|
479 |
+
history_button = gr.Button("π View History", variant="secondary")
|
480 |
+
|
481 |
+
# History Modal
|
482 |
+
with gr.Accordion("π Conversion History", open=False) as history_accordion:
|
483 |
+
history_display = gr.Markdown("No conversions yet.")
|
484 |
+
|
485 |
+
# Event Handlers
|
486 |
+
source_lang_selection.change(
|
487 |
+
fn=update_code_language,
|
488 |
+
inputs=source_lang_selection,
|
489 |
+
outputs=source_code_input
|
490 |
+
)
|
491 |
+
|
492 |
+
target_lang_selection.change(
|
493 |
+
fn=update_target_language,
|
494 |
+
inputs=target_lang_selection,
|
495 |
+
outputs=target_code_output
|
496 |
+
)
|
497 |
+
|
498 |
convert_button.click(
|
499 |
fn=convert_code,
|
500 |
+
inputs=[
|
501 |
+
source_code_input,
|
502 |
+
source_lang_selection,
|
503 |
+
target_lang_selection,
|
504 |
+
model_selection,
|
505 |
+
openrouter_key,
|
506 |
+
temperature
|
507 |
+
],
|
508 |
+
outputs=[target_code_output, status_display],
|
509 |
api_name="convert"
|
510 |
)
|
511 |
+
|
512 |
+
swap_button.click(
|
513 |
+
fn=swap_languages,
|
514 |
+
inputs=[source_lang_selection, target_lang_selection, source_code_input, target_code_output],
|
515 |
+
outputs=[source_lang_selection, target_lang_selection, source_code_input, target_code_output]
|
516 |
)
|
517 |
+
|
518 |
+
clear_button.click(
|
519 |
+
fn=clear_all,
|
520 |
+
outputs=[source_code_input, target_code_output, status_display]
|
521 |
+
)
|
522 |
+
|
523 |
+
history_button.click(
|
524 |
+
fn=get_conversion_history,
|
525 |
+
outputs=history_display
|
526 |
+
)
|
527 |
+
|
528 |
+
# Footer
|
529 |
+
create_footer()
|
530 |
+
|
531 |
+
# --- Launch Configuration ---
|
532 |
|
533 |
if __name__ == "__main__":
|
534 |
+
app.launch(
|
535 |
+
server_name="0.0.0.0",
|
536 |
+
server_port=7860,
|
537 |
+
share=False,
|
538 |
+
debug=False,
|
539 |
+
show_error=True,
|
540 |
+
quiet=False
|
541 |
+
)
|