AmareshHebbar/leetcode-coder-demo
0
1import spaces2import torch3import gradio as gr4from transformers import AutoModelForCausalLM, AutoTokenizer5from peft import PeftModel6 7BASE_MODEL = "unsloth/Qwen2.5-Coder-7B-Instruct"8 9LANG_META = {10 "Python": {"repo": "AmareshHebbar/leetcode-python-qwen25-coder-7b", "icon": "🐍", "code_lang": "python"},11 "Java": {"repo": "AmareshHebbar/leetcode-java-qwen25-coder-7b", "icon": "☕", "code_lang": "java"},12 "C++": {"repo": "AmareshHebbar/leetcode-cpp-qwen25-coder-7b", "icon": "⚙️", "code_lang": "cpp"},13 "JavaScript": {"repo": "AmareshHebbar/leetcode-javascript-qwen25-coder-7b", "icon": "🟨", "code_lang": "javascript"},14}15 16tokenizer = None17model = None18_on_gpu = False19 20 21def _ensure_loaded():22 global tokenizer, model23 if model is not None:24 return25 tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL)26 base_model = AutoModelForCausalLM.from_pretrained(BASE_MODEL, torch_dtype=torch.bfloat16)27 m = PeftModel.from_pretrained(base_model, LANG_META["Python"]["repo"], adapter_name="Python")28 for lang, meta in LANG_META.items():29 if lang != "Python":30 m.load_adapter(meta["repo"], adapter_name=lang)31 m.eval()32 model = m33 34 35def _generate(inputs, use_cuda):36 device = "cuda" if use_cuda else "cpu"37 model.to(device)38 inputs = {k: v.to(device) for k, v in inputs.items()}39 return model.generate(40 **inputs, max_new_tokens=512, temperature=0.2, do_sample=True,41 pad_token_id=tokenizer.eos_token_id,42 )43 44EXAMPLES = [45 ["Merge k sorted linked lists into one sorted list.", "Divide and conquer / heap", "Python"],46 ["Given a set of non-overlapping intervals, insert a new interval and merge as needed.", "Sorting / interval merge", "JavaScript"],47 ["Find the length of the longest increasing path in a matrix.", "DFS + memoization", "Java"],48 ["Given the root of a binary tree, return the maximum path sum between any two nodes.", "Tree DFS / post-order", "C++"],49]50 51CSS = """52:root {53 --lc-bg: #0b0f14;54 --lc-panel: #121820;55 --lc-border: #1f2833;56 --lc-accent: #34d399;57 --lc-accent-dim: #34d39933;58 --lc-text: #e6edf3;59 --lc-text-dim: #8b98a5;60}61.gradio-container {62 background: var(--lc-bg) !important;63 font-family: 'Inter', -apple-system, sans-serif !important;64}65#lc-header {66 text-align: center;67 padding: 28px 0 8px 0;68}69#lc-header h1 {70 font-size: 2.1rem;71 font-weight: 700;72 background: linear-gradient(90deg, #34d399, #60a5fa);73 -webkit-background-clip: text;74 -webkit-text-fill-color: transparent;75 margin-bottom: 4px;76}77#lc-header p {78 color: var(--lc-text-dim);79 font-size: 0.95rem;80}81#lc-badges {82 display: flex;83 justify-content: center;84 gap: 8px;85 margin-top: 10px;86 flex-wrap: wrap;87}88.lc-badge {89 background: var(--lc-panel);90 border: 1px solid var(--lc-border);91 color: var(--lc-text-dim);92 padding: 4px 12px;93 border-radius: 999px;94 font-size: 0.78rem;95}96#lc-panel-left, #lc-panel-right {97 background: var(--lc-panel) !important;98 border: 1px solid var(--lc-border) !important;99 border-radius: 14px !important;100 padding: 18px !important;101}102#lc-generate {103 background: linear-gradient(90deg, #34d399, #22c55e) !important;104 border: none !important;105 color: #04120a !important;106 font-weight: 600 !important;107 border-radius: 10px !important;108}109#lc-lang-radio label {110 border-radius: 10px !important;111}112#lc-output-code {113 border-radius: 10px !important;114}115footer { display: none !important; }116"""117 118THEME = gr.themes.Base(119 primary_hue="emerald",120 neutral_hue="slate",121 font=[gr.themes.GoogleFont("Inter"), "sans-serif"],122).set(123 body_background_fill="#0b0f14",124 block_background_fill="#121820",125 block_border_color="#1f2833",126 body_text_color="#e6edf3",127 input_background_fill="#0b0f14",128 button_primary_background_fill="#34d399",129 button_primary_text_color="#04120a",130)131 132 133@spaces.GPU(duration=120)134def solve(problem, algorithm_tag, language):135 global _on_gpu136 if not problem.strip():137 return "", "Enter a problem statement first."138 139 _ensure_loaded()140 model.set_adapter(language)141 lang_name = language142 system_prompt = (143 f"You are an expert {lang_name} competitive programmer. Given a "144 f"LeetCode-style problem statement and an algorithm tag, write a "145 f"correct, efficient {lang_name} solution."146 )147 user_msg = f"Problem: {problem}"148 if algorithm_tag.strip():149 user_msg += f"\nAlgorithm: {algorithm_tag}"150 151 messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": user_msg}]152 prompt = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)153 inputs = tokenizer(prompt, return_tensors="pt")154 155 try:156 outputs = _generate(inputs, use_cuda=True)157 _on_gpu = True158 engine_note = "GPU"159 except RuntimeError as e:160 if "CUDA" not in str(e) and "cuda" not in str(e):161 raise162 outputs = _generate(inputs, use_cuda=False)163 engine_note = "CPU fallback"164 165 input_len = inputs["input_ids"].shape[1]166 code = tokenizer.decode(outputs[0][input_len:], skip_special_tokens=True)167 return code, f"{LANG_META[language]['icon']} generated with the {language} QDoRA adapter · {engine_note}"168 169 170def on_lang_change(language):171 return gr.Code(language=LANG_META[language]["code_lang"])172 173 174with gr.Blocks(title="LeetCode Multi-Language Coder Suite") as demo:175 with gr.Column(elem_id="lc-header"):176 gr.Markdown("# LeetCode Multi-Language Coder Suite")177 gr.Markdown("Qwen2.5-Coder-7B · QDoRA fine-tuned per language · execution-verified training data")178 gr.HTML(179 """180 <div id="lc-badges">181 <span class="lc-badge">🐍 Python</span>182 <span class="lc-badge">☕ Java</span>183 <span class="lc-badge">⚙️ C++</span>184 <span class="lc-badge">🟨 JavaScript</span>185 <span class="lc-badge">🔗 4 QDoRA adapters, 1 base model</span>186 </div>187 """188 )189 190 with gr.Row(equal_height=True):191 with gr.Column(scale=5, elem_id="lc-panel-left"):192 language = gr.Radio(193 choices=list(LANG_META.keys()),194 value="Python",195 label="Language",196 elem_id="lc-lang-radio",197 )198 problem = gr.Textbox(199 label="Problem statement",200 lines=5,201 placeholder="Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.",202 )203 tag = gr.Textbox(label="Algorithm tag (optional)", placeholder="Hash Map")204 run = gr.Button("Generate solution", elem_id="lc-generate", size="lg")205 gr.Examples(206 examples=EXAMPLES,207 inputs=[problem, tag, language],208 label="Try an example",209 )210 211 with gr.Column(scale=6, elem_id="lc-panel-right"):212 status = gr.Markdown("")213 output = gr.Code(214 label="Generated solution",215 language="python",216 elem_id="lc-output-code",217 lines=22,218 )219 220 gr.HTML(221 """222 <div style="text-align:center; color:#8b98a5; font-size:0.82rem; margin-top:18px;">223 <a href="https://huggingface.co/collections/AmareshHebbar/leetcode-multi-language-coder-suite" style="color:#34d399;">Models & benchmarks</a>224 · 225 <a href="https://github.com/amareshhebbar" style="color:#34d399;">GitHub</a>226 </div>227 """228 )229 230 language.change(on_lang_change, inputs=language, outputs=output)231 run.click(solve, inputs=[problem, tag, language], outputs=[output, status])232 233demo.launch(css=CSS, theme=THEME)