sakuragolden commited on
Commit
7e15f52
·
verified ·
1 Parent(s): d61df1e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +298 -289
app.py CHANGED
@@ -1,289 +1,298 @@
1
- # codegen_gradio.py
2
- import os
3
- import io
4
- import json
5
- import time
6
- import tempfile
7
- import requests
8
- import gradio as gr
9
- from typing import Tuple, Optional
10
-
11
- # ---------------------- 配置 ----------------------
12
- HF_INFERENCE_URL = "https://api-inference.huggingface.co/models"
13
- # 默认模型(面向代码的强模型建议 user 输入或使用 bigcode/starcoder
14
- DEFAULT_HF_MODEL = "bigcode/starcoder" # or "bigcode/starcoder-base" / user can change in UI
15
-
16
- # 支持的语言与默认扩展(可扩展)
17
- LANG_EXT = {
18
- "Python": ".py",
19
- "JavaScript": ".js",
20
- "TypeScript": ".ts",
21
- "Go": ".go",
22
- "Java": ".java",
23
- "C": ".c",
24
- "C++": ".cpp",
25
- "C#": ".cs",
26
- "Rust": ".rs",
27
- "Kotlin": ".kt",
28
- "Swift": ".swift",
29
- "Ruby": ".rb",
30
- "PHP": ".php",
31
- "Shell": ".sh",
32
- "PowerShell": ".ps1",
33
- "HTML": ".html",
34
- "CSS": ".css",
35
- "SQL": ".sql",
36
- "R": ".r",
37
- "MATLAB": ".m",
38
- "Scala": ".scala",
39
- "Haskell": ".hs",
40
- "Lua": ".lua",
41
- "Perl": ".pl",
42
- "Dart": ".dart",
43
- "Elixir": ".ex",
44
- "Julia": ".jl",
45
- "Objective-C": ".m",
46
- "Assembly": ".s",
47
- "Dockerfile": "Dockerfile",
48
- "YAML": ".yml",
49
- "JSON": ".json",
50
- "XML": ".xml",
51
- "Protobuf": ".proto",
52
- # add more if needed
53
- }
54
-
55
- # 多语言选项(显示顺序)
56
- LANG_CHOICES = list(LANG_EXT.keys())
57
-
58
- # 简单的安全黑名单(用于拒绝明显恶意请求)
59
- DANGEROUS_KEYWORDS = [
60
- "rm -rf", "format(", "mkfs", "dd if=", "fork bomb", "shutdown", "reboot", "poweroff",
61
- "create user", "adduser", "useradd", "passwd", "ssh -i", "cryptominer", "virus", "malware",
62
- "ransomware", "keylogger", "inject", "exploit", "sqlmap", "metasploit", "reverse shell",
63
- "nc -e", "wget http", "curl http", "chmod 777 /", "sudo rm -rf /", ">: /dev/sda"
64
- ]
65
-
66
- # Prompt templates per task
67
- TASK_TEMPLATES = {
68
- "Generate code from description": "Implement the following functionality in {lang}:\n\n{content}\n\nPlease provide only the code, no extra commentary.",
69
- "Translate code to another language": "Translate the following code from {src_lang} to {lang}. Keep behavior identical and include necessary imports/dependencies.\n\n```{src_lang}\n{content}\n```",
70
- "Explain code": "Explain the following {lang} code. Provide a concise explanation of what it does, complexity if applicable, and potential pitfalls or edge cases.\n\n```{lang}\n{content}\n```",
71
- "Refactor code (improve readability/performance)": "Refactor the following {lang} code for readability and performance. Keep behavior identical, explain briefly what you changed, then provide the refactored code only.\n\n```{lang}\n{content}\n```",
72
- "Add unit tests": "Write unit tests for the following {lang} code. Use common testing framework for {lang} (e.g., pytest for Python, jest for JS). Provide test code only.\n\n```{lang}\n{content}\n```",
73
- "Document & comment code": "Add clear inline comments and a top-level docstring explaining the purpose, inputs, outputs, and side effects for this {lang} code. Then provide the commented code only.\n\n```{lang}\n{content}\n```",
74
- "Optimize for performance": "Optimize the following {lang} code for performance. Keep same external behavior. Explain the optimizations in 2-3 lines, then provide the optimized code only.\n\n```{lang}\n{content}\n```",
75
- "Add type hints / static types": "Add type annotations or static types to the following {lang} code where appropriate. Make sure the code remains valid.\n\n```{lang}\n{content}\n```",
76
- "Create CLI tool": "Create a command-line interface (CLI) tool in {lang} that wraps the following functionality: {content}. Provide a complete script with argument parsing and usage example.",
77
- }
78
-
79
- # ---------------------- HF Inference helper ----------------------
80
- def call_hf_inference(model: str, hf_token: str, prompt: str, max_new_tokens: int = 512, temperature: float = 0.2, top_k: Optional[int] = None) -> str:
81
- """
82
- Call Hugging Face Inference API for text generation.
83
- Returns the generated text (string) or an error message.
84
- """
85
- if not hf_token or hf_token.strip() == "":
86
- return "[Error] No Hugging Face token provided. Please paste your HF token in the UI."
87
-
88
- url = f"{HF_INFERENCE_URL}/{model}"
89
- headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"}
90
- payload = {"inputs": prompt, "parameters": {"max_new_tokens": max_new_tokens, "temperature": temperature}}
91
- if top_k is not None:
92
- payload["parameters"]["top_k"] = top_k
93
-
94
- try:
95
- resp = requests.post(url, headers=headers, json=payload, timeout=120)
96
- resp.raise_for_status()
97
- data = resp.json()
98
- # handle different response shapes
99
- if isinstance(data, list) and len(data) > 0:
100
- first = data[0]
101
- if isinstance(first, dict) and "generated_text" in first:
102
- return first["generated_text"]
103
- # sometimes it's raw text
104
- return str(first)
105
- if isinstance(data, dict):
106
- if "generated_text" in data:
107
- return data["generated_text"]
108
- if "error" in data:
109
- return "[HF Error] " + str(data["error"])
110
- return json.dumps(data)
111
- return str(data)
112
- except requests.exceptions.HTTPError as e:
113
- return f"[HF HTTP Error] {e} - {resp.text if 'resp' in locals() else ''}"
114
- except Exception as e:
115
- return f"[HF Error] {e}"
116
-
117
-
118
- # ---------------------- helpers ----------------------
119
- def detect_dangerous(text: str) -> Optional[str]:
120
- lower = text.lower()
121
- for k in DANGEROUS_KEYWORDS:
122
- if k in lower:
123
- return k
124
- return None
125
-
126
- def build_prompt(task: str, lang: str, content: str, src_lang: Optional[str] = None) -> str:
127
- tmpl = TASK_TEMPLATES.get(task, "{content}")
128
- return tmpl.format(lang=lang, content=content, src_lang=src_lang or "")
129
-
130
- def ext_for_language(lang: str) -> str:
131
- return LANG_EXT.get(lang, ".txt")
132
-
133
- def save_code_to_tempfile(code: str, filename_hint: str = "generated", ext: str = ".txt") -> str:
134
- fd, path = tempfile.mkstemp(prefix=filename_hint + "_", suffix=ext)
135
- with os.fdopen(fd, "w", encoding="utf-8") as f:
136
- f.write(code)
137
- return path
138
-
139
- # ---------------------- Gradio backends ----------------------
140
- def generate_code_task(task: str, hf_token: str, hf_model: str, language: str, src_language: str, description: str,
141
- temperature: float, max_new_tokens: int, top_k: int) -> Tuple[str, Optional[str]]:
142
- """
143
- Main generation entry: builds prompt, calls HF Inference, returns (code_str, download_path_or_None)
144
- """
145
- # security check
146
- danger = detect_dangerous(description)
147
- if danger:
148
- return f"[Refused] Request contains potentially dangerous keyword: '{danger}'. Code generation aborted.", None
149
-
150
- prompt = build_prompt(task, language, description, src_lang=src_language)
151
- # Some code models do better if prompt includes an instruction header
152
- instruction = f"# Instruction: {task} for language {language}\n# Begin\n{prompt}\n# End\n"
153
- gen = call_hf_inference(hf_model, hf_token, instruction, max_new_tokens=max_new_tokens, temperature=temperature, top_k=(None if top_k==0 else top_k))
154
-
155
- # If HF returns an error-like string, just return it
156
- if isinstance(gen, str) and gen.startswith("[HF"):
157
- return gen, None
158
-
159
- # Trim any leading instruction repeats
160
- code = gen.strip()
161
- # If the model echoed the prompt, try to cut off the prompt portion
162
- if instruction.strip() and code.startswith(instruction.strip()):
163
- code = code[len(instruction.strip()):].strip()
164
-
165
- # post-process: if model included explanation but we requested code-only, try to extract code block
166
- if "```" in code:
167
- # extract first fenced code block
168
- parts = code.split("```")
169
- if len(parts) >= 3:
170
- # parts: [before, langinfo, code, ...] or [before, code, ...]
171
- # find the longest code-like chunk
172
- candidate = None
173
- for i in range(1, len(parts), 2):
174
- chunk = parts[i+0]
175
- if len(chunk.strip()) > 0:
176
- candidate = chunk
177
- break
178
- if candidate:
179
- code = candidate.strip()
180
-
181
- # Prepare downloadable file
182
- ext = ext_for_language(language)
183
- fname = f"code_{language.lower().replace(' ', '_')}{ext}"
184
- path = save_code_to_tempfile(code, filename_hint="generated_code", ext=ext)
185
- return code, path
186
-
187
- # ---------------------- UI components & logic ----------------------
188
- def do_generate(task, hf_token, hf_model, language, src_language, description, temperature, max_new_tokens, top_k):
189
- # basic input validation
190
- if not hf_token or hf_token.strip() == "":
191
- return "[Error] Please paste your Hugging Face API token in the HF token field.", None
192
- if not hf_model or hf_model.strip() == "":
193
- return "[Error] Please enter a Hugging Face model name (e.g. bigcode/starcoder).", None
194
- if not description or description.strip() == "":
195
- return "[Error] Please provide a description or code to operate on.", None
196
-
197
- code, path = generate_code_task(task, hf_token, hf_model, language, src_language, description, temperature, max_new_tokens, top_k)
198
- return code, path
199
-
200
- # Helper: simple examples
201
- EXAMPLES = [
202
- ("Generate code from description", "bigcode/starcoder", "Python", "", "A function that computes the nth Fibonacci number using dynamic programming and returns results as integers.", 0.2, 256, 0),
203
- ("Translate code to another language", "bigcode/starcoder", "JavaScript", "Python", "def greet(name):\n return f\"Hello, {name}!\"", 0.2, 256, 0),
204
- ("Add unit tests", "bigcode/starcoder", "Python", "", "def add(a, b):\n return a + b", 0.2, 256, 0),
205
- ("Explain code", "bigcode/starcoder", "Go", "", 'package main\n\nimport "fmt"\n\nfunc main() {\n fmt.Println("Hello world")\n}', 0.2, 256, 0),
206
- ]
207
-
208
- def build_ui():
209
- with gr.Blocks(title="Polyglot Code Generator (HF Inference)") as demo:
210
- gr.Markdown("# 🚀 Polyglot Code Generator\nGenerate, translate, explain, refactor, test and document code in many languages using Hugging Face models.\n\n**Important:** paste your Hugging Face Inference API token below (Settings → Access Tokens on Hugging Face).")
211
-
212
- with gr.Row():
213
- with gr.Column(scale=3):
214
- hf_token = gr.Textbox(label="Hugging Face API Token (paste here)", type="password", placeholder="hf_xxx...")
215
- hf_model = gr.Textbox(label="HF model name", value=DEFAULT_HF_MODEL, placeholder="bigcode/starcoder or bigcode/starcoder-base")
216
- task = gr.Dropdown(label="Task", choices=list(TASK_TEMPLATES.keys()), value="Generate code from description")
217
- language = gr.Dropdown(label="Target language", choices=LANG_CHOICES, value="Python")
218
- src_language = gr.Textbox(label="Source language (for translation)", placeholder="e.g. Python", value="")
219
- description = gr.Textbox(label="Description / Input code", lines=8, placeholder="Describe the feature or paste the code to transform...")
220
- temp = gr.Slider(label="temperature", minimum=0.0, maximum=1.0, value=0.2, step=0.05)
221
- max_tokens = gr.Slider(label="max_new_tokens", minimum=16, maximum=2048, value=512, step=16)
222
- top_k = gr.Slider(label="top_k (0 = default)", minimum=0, maximum=100, value=0, step=1)
223
- gen_btn = gr.Button("Generate Code")
224
-
225
- with gr.Accordion("Prompt templates & examples", open=False):
226
- gr.Markdown("Choose a task and the app will apply an appropriate prompt template. Examples below can be loaded into the inputs.")
227
- example_btns = []
228
- for ex in EXAMPLES:
229
- b = gr.Button(f"Load example: {ex[0]} {ex[2]}")
230
- example_btns.append((b, ex))
231
-
232
- with gr.Column(scale=2):
233
- gr.Markdown("### Output")
234
- code_out = gr.Code(value="", language="python", label="Generated Code / Explanation")
235
- download_file = gr.File(label="Download generated file (click to download)")
236
-
237
- with gr.Row():
238
- copy_btn = gr.Button("Copy to clipboard (browser)") # gradio supports copy via JS, left as UI hint
239
- save_btn = gr.Button("Save as file (prepare download)")
240
-
241
- gr.Markdown("### Quick actions")
242
- explain_btn = gr.Button("Explain this code") # convenience to re-run with Explain task
243
-
244
- # Wiring
245
- def load_example(example):
246
- task_v, hf_mod, lang, src_lang, desc, temperature, max_new_tokens, top_k = example
247
- return hf_mod, task_v, lang, src_lang, desc, temperature, max_new_tokens, top_k
248
-
249
- # register example buttons
250
- for btn, ex in example_btns:
251
- btn.click(fn=load_example, inputs=None, outputs=[hf_model, task, language, src_language, description, temp, max_tokens, top_k], _js=None).then(lambda: None)
252
-
253
- def prepare_and_generate(hf_token_val, hf_model_val, task_val, language_val, src_language_val, description_val, temp_val, max_tokens_val, top_k_val):
254
- code, path = do_generate(task_val, hf_token_val, hf_model_val, language_val, src_language_val, description_val, temp_val, int(max_tokens_val), int(top_k_val))
255
- # Set language for highlighter
256
- lang_for_highlight = language_val.lower() if language_val else "text"
257
- return code, path, lang_for_highlight
258
-
259
- gen_btn.click(fn=prepare_and_generate,
260
- inputs=[hf_token, hf_model, task, language, src_language, description, temp, max_tokens, top_k],
261
- outputs=[code_out, download_file, code_out]) # last output used to set language attr
262
-
263
- # Save file (prepare download) button: write latest code to temp file and return path
264
- def save_generated_as_file(code_text, language_val):
265
- if not code_text or code_text.strip() == "":
266
- return None
267
- ext = ext_for_language(language_val)
268
- path = save_code_to_tempfile(code_text, filename_hint="generated_code", ext=ext)
269
- return path
270
-
271
- save_btn.click(fn=save_generated_as_file, inputs=[code_out, language], outputs=[download_file])
272
-
273
- # Explain selected code quickly
274
- def quick_explain(hf_token_val, hf_model_val, code_text, language_val, temp_val, max_tokens_val):
275
- if not code_text or code_text.strip() == "":
276
- return "[Error] No code to explain."
277
- # reuse TASK_TEMPLATES explanation
278
- prompt = build_prompt("Explain code", language_val, code_text)
279
- return call_hf_inference(hf_model_val, hf_token_val, f"# Instruction: Explain code\n{prompt}\n", max_new_tokens=int(max_tokens_val), temperature=float(temp_val))
280
-
281
- explain_btn.click(fn=quick_explain, inputs=[hf_token, hf_model, code_out, language, temp, max_tokens], outputs=[code_out])
282
-
283
- gr.Markdown("---\n**Notes & safety**: This app calls the Hugging Face Inference API; keep your token private. The app refuses obviously destructive requests by simple keyword checks. Do not use generated code in production without review.")
284
-
285
- return demo
286
-
287
- if __name__ == "__main__":
288
- demo_app = build_ui()
289
- demo_app.launch(server_name="0.0.0.0", share=False)
 
 
 
 
 
 
 
 
 
 
1
+ # codegen_gradio_fixed.py
2
+ import os
3
+ import io
4
+ import json
5
+ import time
6
+ import tempfile
7
+ import requests
8
+ import gradio as gr
9
+ from typing import Tuple, Optional
10
+
11
+ # ------------------ Configuration ------------------
12
+ HF_INFERENCE_URL = "https://api-inference.huggingface.co/models"
13
+ DEFAULT_HF_MODEL = "bigcode/starcoder"
14
+ LANG_EXT = {
15
+ "Python": ".py", "JavaScript": ".js", "TypeScript": ".ts", "Go": ".go",
16
+ "Java": ".java", "C": ".c", "C++": ".cpp", "C#": ".cs", "Rust": ".rs",
17
+ "Kotlin": ".kt", "Swift": ".swift", "Ruby": ".rb", "PHP": ".php",
18
+ "Shell": ".sh", "PowerShell": ".ps1", "HTML": ".html", "CSS": ".css",
19
+ "SQL": ".sql", "R": ".r", "MATLAB": ".m", "Scala": ".scala",
20
+ "Haskell": ".hs", "Lua": ".lua", "Perl": ".pl", "Dart": ".dart",
21
+ "Elixir": ".ex", "Julia": ".jl", "Objective-C": ".m", "Assembly": ".s",
22
+ "Dockerfile": "Dockerfile", "JSON": ".json", "YAML": ".yml", "XML": ".xml"
23
+ }
24
+
25
+ # Dangerous keywords simple blacklist
26
+ DANGEROUS_KEYWORDS = [
27
+ "rm -rf", "mkfs", "dd if=", "fork bomb", "shutdown", "reboot", "poweroff",
28
+ "create user", "adduser", "useradd", "passwd", "ssh -i", "cryptominer", "virus",
29
+ "malware", "ransomware", "keylogger", "inject", "exploit", "reverse shell",
30
+ "nc -e", "wget http", "curl http", "chmod 777 /", "sudo rm -rf /", ">: /dev/sda"
31
+ ]
32
+
33
+ # Task templates
34
+ TASK_TEMPLATES = {
35
+ "Generate code from description":
36
+ "Implement the following functionality in {lang}:\n\n{content}\n\n"
37
+ "Please provide only the code (no surrounding explanation).",
38
+ "Translate code to another language":
39
+ "Translate the following code from {src_lang} to {lang}. Keep behavior identical and include necessary imports.\n\n```{src_lang}\n{content}\n```",
40
+ "Explain code":
41
+ "Explain the following {lang} code. Provide a concise explanation, complexity notes, and potential pitfalls.\n\n```{lang}\n{content}\n```",
42
+ "Refactor code (readability/performance)":
43
+ "Refactor the following {lang} code for readability and performance. Keep behavior identical. Provide a 1-2 line summary of changes, then the refactored code only.\n\n```{lang}\n{content}\n```",
44
+ "Add unit tests":
45
+ "Write unit tests for the following {lang} code using a common testing framework (e.g., pytest for Python, jest for JS). Provide only the test code.\n\n```{lang}\n{content}\n```",
46
+ "Document & comment code":
47
+ "Add clear inline comments and a top-level docstring describing purpose, inputs, outputs, and side effects for this {lang} code. Provide the commented code only.\n\n```{lang}\n{content}\n```",
48
+ "Optimize for performance":
49
+ "Optimize the following {lang} code for performance while preserving behavior. Explain the optimization in 2-3 lines, then provide the optimized code only.\n\n```{lang}\n{content}\n```",
50
+ "Add type hints / static types":
51
+ "Add type annotations or static types to the following {lang} code where appropriate. Ensure the code remains valid.\n\n```{lang}\n{content}\n```",
52
+ "Create CLI tool":
53
+ "Create a command-line interface tool in {lang} that implements: {content}. Provide a complete script with argument parsing and a usage example."
54
+ }
55
+
56
+ # Model recommendations (HF model_name: (short description, compatibility notes))
57
+ MODEL_RECOMMENDATIONS = {
58
+ "bigcode/starcoder": (
59
+ "StarCoder: Open-source model specialized for code generation and multi-language support.",
60
+ "Good for Python, JS, TypeScript and general-purpose code generation. May return large outputs."
61
+ ),
62
+ "bigcode/starcoder-base": (
63
+ "StarCoder-base: Lighter StarCoder variant with faster response but slightly lower fidelity.",
64
+ "Better for quick prototyping or smaller deployments."
65
+ ),
66
+ "bigcode/codegen-2B-multi": (
67
+ "CodeGen 2B (multi): Code generation model trained on multi-language corpora.",
68
+ "Good for many languages; 2B size balances performance and resource usage."
69
+ ),
70
+ "facebook/incoder-1B": (
71
+ "InCoder 1B: Autoregressive code model that supports code infilling and generation.",
72
+ "Smaller model appropriate for lower-resource environments; may require prompt engineering for best results."
73
+ ),
74
+ "codellama/CodeLlama-7b-Instruct": (
75
+ "CodeLlama 7B Instruct: Instruction-tuned CodeLlama model for code generation and explanation.",
76
+ "High-quality outputs but large (7B); requires sufficient memory or HF Inference API."
77
+ ),
78
+ "Salesforce/codegen-6B-mono": (
79
+ "CodeGen 6B Mono: Strong code generation model focused on mono-language generation.",
80
+ "Powerful but large; use HF Inference or a GPU-equipped local environment."
81
+ ),
82
+ "bigcode/starcoder-large": (
83
+ "StarCoder-large: Larger StarCoder variant for higher fidelity.",
84
+ "Best-quality among StarCoder variants but resource heavy."
85
+ )
86
+ }
87
+
88
+ # ------------------ Helpers ------------------
89
+ def ext_for_language(lang: str) -> str:
90
+ return LANG_EXT.get(lang, ".txt")
91
+
92
+ def detect_dangerous(text: str) -> Optional[str]:
93
+ if not text:
94
+ return None
95
+ lower = text.lower()
96
+ for k in DANGEROUS_KEYWORDS:
97
+ if k in lower:
98
+ return k
99
+ return None
100
+
101
+ def build_prompt(task: str, lang: str, content: str, src_lang: Optional[str] = None) -> str:
102
+ tmpl = TASK_TEMPLATES.get(task, "{content}")
103
+ return tmpl.format(lang=lang, content=content, src_lang=src_lang or "")
104
+
105
+ def save_code_to_tempfile(code: str, filename_hint: str = "generated_code", ext: str = ".txt") -> str:
106
+ fd, path = tempfile.mkstemp(prefix=filename_hint + "_", suffix=ext)
107
+ with os.fdopen(fd, "w", encoding="utf-8") as f:
108
+ f.write(code)
109
+ return path
110
+
111
+ # ------------------ HF Inference call ------------------
112
+ def call_hf_inference(model: str, hf_token: str, prompt: str, max_new_tokens: int = 512, temperature: float = 0.2, top_k: Optional[int] = None) -> str:
113
+ if not hf_token or not hf_token.strip():
114
+ return "[Error] No Hugging Face token provided."
115
+
116
+ url = f"{HF_INFERENCE_URL}/{model}"
117
+ headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"}
118
+ payload = {"inputs": prompt, "parameters": {"max_new_tokens": max_new_tokens, "temperature": temperature}}
119
+ if top_k and top_k > 0:
120
+ payload["parameters"]["top_k"] = top_k
121
+ try:
122
+ r = requests.post(url, headers=headers, json=payload, timeout=120)
123
+ r.raise_for_status()
124
+ data = r.json()
125
+ # common shapes: list with dicts or dict with generated_text
126
+ if isinstance(data, list) and len(data) > 0:
127
+ first = data[0]
128
+ if isinstance(first, dict) and "generated_text" in first:
129
+ return first["generated_text"]
130
+ return str(first)
131
+ if isinstance(data, dict):
132
+ if "generated_text" in data:
133
+ return data["generated_text"]
134
+ if "error" in data:
135
+ return "[HF Error] " + str(data["error"])
136
+ return json.dumps(data)
137
+ return str(data)
138
+ except requests.exceptions.HTTPError as e:
139
+ return f"[HF HTTP Error] {e} - {r.text if 'r' in locals() else ''}"
140
+ except Exception as e:
141
+ return f"[HF Error] {e}"
142
+
143
+ # ------------------ Generation pipeline ------------------
144
+ def generate_code_task(task: str, hf_token: str, hf_model: str, language: str, src_language: str, description: str,
145
+ temperature: float, max_new_tokens: int, top_k: int) -> Tuple[str, Optional[str]]:
146
+ # security
147
+ danger = detect_dangerous(description)
148
+ if danger:
149
+ return f"[Refused] Request contains potentially dangerous keyword: '{danger}'.", None
150
+
151
+ prompt = build_prompt(task, language, description, src_lang=src_language)
152
+ instruction = f"# Instruction: {task} for language {language}\n# Begin\n{prompt}\n# End\n"
153
+ gen = call_hf_inference(hf_model, hf_token, instruction, max_new_tokens=max_new_tokens, temperature=temperature, top_k=(None if top_k == 0 else top_k))
154
+
155
+ if isinstance(gen, str) and gen.startswith("[HF"):
156
+ # error from HF
157
+ return gen, None
158
+
159
+ code = gen.strip()
160
+ # extract code fence content if present
161
+ if "```" in code:
162
+ parts = code.split("```")
163
+ # parts may be: before, ```lang\ncode\n```, ...
164
+ # find the first non-empty code-like chunk
165
+ candidate = None
166
+ for i in range(1, len(parts), 2):
167
+ chunk = parts[i].strip()
168
+ if len(chunk) > 0:
169
+ # if chunk starts with language id like "python\n", remove the first line
170
+ lines = chunk.splitlines()
171
+ if len(lines) > 1 and len(lines[0]) <= 20 and not lines[0].strip().startswith(("#", "//")) and not "(" in lines[0]:
172
+ # treat as lang tag
173
+ candidate = "\n".join(lines[1:]).strip()
174
+ else:
175
+ candidate = chunk
176
+ break
177
+ if candidate:
178
+ code = candidate
179
+
180
+ # try to strip instruction echoes
181
+ if instruction.strip() and code.startswith(instruction.strip()):
182
+ code = code[len(instruction.strip()):].strip()
183
+
184
+ # fallback: ensure code not empty
185
+ if not code:
186
+ code = gen
187
+
188
+ ext = ext_for_language(language)
189
+ fname = f"code_{language.lower().replace(' ', '_')}{ext}"
190
+ path = save_code_to_tempfile(code, filename_hint="generated_code", ext=ext)
191
+ return code, path
192
+
193
+ # ------------------ UI wiring ------------------
194
+ EXAMPLES = [
195
+ ("Generate code from description", "bigcode/starcoder", "Python", "", "A function that returns the nth Fibonacci number using dynamic programming (iterative).", 0.2, 256, 0),
196
+ ("Translate code to another language", "bigcode/starcoder", "JavaScript", "Python", "def greet(name):\n return f\"Hello, {name}!\"", 0.2, 256, 0),
197
+ ("Add unit tests", "bigcode/starcoder", "Python", "", "def add(a, b):\n return a + b", 0.2, 256, 0),
198
+ ("Explain code", "bigcode/starcoder", "Go", "", 'package main\n\nimport "fmt"\n\nfunc main() {\n fmt.Println("Hello world")\n}', 0.2, 256, 0),
199
+ ]
200
+
201
+ def load_example_to_inputs(example):
202
+ # returns values matching the UI inputs order we will set
203
+ (task_v, hf_mod, lang, src_lang, desc, temperature, max_new_tokens, top_k) = example
204
+ return hf_mod, task_v, lang, src_lang, desc, temperature, max_new_tokens, top_k
205
+
206
+ def do_generate(task, hf_token, hf_model, language, src_language, description, temperature, max_new_tokens, top_k):
207
+ if not hf_token or not hf_token.strip():
208
+ return "[Error] Please paste your Hugging Face API token.", None
209
+ if not hf_model or not hf_model.strip():
210
+ return "[Error] Please enter a Hugging Face model name.", None
211
+ if not description or not description.strip():
212
+ return "[Error] Please provide a description or code to operate on.", None
213
+ code, path = generate_code_task(task, hf_token, hf_model, language, src_language, description, temperature, int(max_new_tokens), int(top_k))
214
+ return code, path
215
+
216
+ def save_generated_as_file(code_text, language_val):
217
+ if not code_text or code_text.strip() == "":
218
+ return None
219
+ ext = ext_for_language(language_val)
220
+ return save_code_to_tempfile(code_text, filename_hint="generated_code", ext=ext)
221
+
222
+ # ------------------ Build Gradio UI ------------------
223
+ def build_ui():
224
+ with gr.Blocks(title="Polyglot Code Generator (Hugging Face Inference)") as demo:
225
+ gr.Markdown("# 🚀 Polyglot Code Generator\nGenerate, translate, explain, refactor and test code in many languages using Hugging Face models.\n\nPaste your Hugging Face Inference API token below (Settings → Access Tokens on Hugging Face).")
226
+
227
+ with gr.Row():
228
+ with gr.Column(scale=3):
229
+ hf_token = gr.Textbox(label="Hugging Face API Token (paste here)", type="password", placeholder="hf_xxx...")
230
+ # Model recommendation dropdown
231
+ model_choices = list(MODEL_RECOMMENDATIONS.keys())
232
+ hf_model = gr.Dropdown(label="Model (recommended)", choices=model_choices, value=DEFAULT_HF_MODEL)
233
+ model_info = gr.Markdown(value=f"**Model info:** {MODEL_RECOMMENDATIONS.get(DEFAULT_HF_MODEL)[0]} \n_{MODEL_RECOMMENDATIONS.get(DEFAULT_HF_MODEL)[1]}_")
234
+
235
+ task = gr.Dropdown(label="Task", choices=list(TASK_TEMPLATES.keys()), value="Generate code from description")
236
+ language = gr.Dropdown(label="Target language", choices=list(LANG_EXT.keys()), value="Python")
237
+ src_language = gr.Textbox(label="Source language (for translation)", placeholder="e.g. Python", value="")
238
+ description = gr.Textbox(label="Description / Input code", lines=8, placeholder="Describe the feature or paste the code to transform...")
239
+ temp = gr.Slider(label="temperature", minimum=0.0, maximum=1.0, value=0.2, step=0.05)
240
+ max_tokens = gr.Slider(label="max_new_tokens", minimum=16, maximum=2048, value=512, step=16)
241
+ top_k = gr.Slider(label="top_k (0 = default)", minimum=0, maximum=100, value=0, step=1)
242
+
243
+ gen_btn = gr.Button("Generate Code")
244
+ with gr.Accordion("Examples", open=False):
245
+ example_buttons = []
246
+ for i, ex in enumerate(EXAMPLES):
247
+ b = gr.Button(f"Load example: {ex[0]} {ex[2]}")
248
+ example_buttons.append((b, ex))
249
+
250
+ with gr.Column(scale=2):
251
+ gr.Markdown("### Output")
252
+ code_out = gr.Code(value="", language="python", label="Generated Code / Explanation")
253
+ download_file = gr.File(label="Download generated file")
254
+
255
+ with gr.Row():
256
+ save_btn = gr.Button("Save as file (prepare download)")
257
+ explain_btn = gr.Button("Explain selected code (quick action)")
258
+
259
+ gr.Markdown("### Quick tips")
260
+ gr.Markdown("- If the model echoes the prompt or includes explanation, the app will try to extract the first code block.\n- For best results use a code-capable HF model like `bigcode/starcoder` or `codellama/CodeLlama-7b-Instruct` via the Inference API.")
261
+
262
+ # Events
263
+ # Update model info when hf_model changes
264
+ def update_model_info(model_name):
265
+ info = MODEL_RECOMMENDATIONS.get(model_name)
266
+ if info:
267
+ return f"**Model info:** {info[0]} \n_{info[1]}_"
268
+ else:
269
+ return "**Model info:** Unknown model. Compatibility depends on the model. Use a code-capable model."
270
+
271
+ hf_model.change(fn=update_model_info, inputs=[hf_model], outputs=[model_info])
272
+
273
+ # Example buttons wiring
274
+ for btn, ex in example_buttons:
275
+ btn.click(fn=load_example_to_inputs, inputs=None, outputs=[hf_model, task, language, src_language, description, temp, max_tokens, top_k], _js=None, _preprocess=False, _postprocess=False, args=[ex])
276
+
277
+ # Generate
278
+ gen_btn.click(fn=do_generate, inputs=[task, hf_token, hf_model, language, src_language, description, temp, max_tokens, top_k], outputs=[code_out, download_file])
279
+
280
+ # Save button
281
+ save_btn.click(fn=save_generated_as_file, inputs=[code_out, language], outputs=[download_file])
282
+
283
+ # Quick explain
284
+ def quick_explain(hf_token_val, hf_model_val, code_text, language_val, temp_val, max_tokens_val):
285
+ if not code_text or code_text.strip() == "":
286
+ return "[Error] No code to explain."
287
+ prompt = build_prompt("Explain code", language_val, code_text)
288
+ return call_hf_inference(hf_model_val, hf_token_val, f"# Instruction: Explain code\n{prompt}\n", max_new_tokens=int(max_tokens_val), temperature=float(temp_val))
289
+
290
+ explain_btn.click(fn=quick_explain, inputs=[hf_token, hf_model, code_out, language, temp, max_tokens], outputs=[code_out])
291
+
292
+ gr.Markdown("---\n**Safety note**: This app performs basic keyword checks to refuse obviously destructive requests. Always review generated code before running it in production.")
293
+
294
+ return demo
295
+
296
+ if __name__ == "__main__":
297
+ demo = build_ui()
298
+ demo.launch(server_name="0.0.0.0", share=False)