hamxaameer commited on
Commit
4521d33
·
1 Parent(s): 9bb5531

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +209 -689
app.py CHANGED
@@ -1,726 +1,246 @@
1
  import gradio as gr
2
- import pickle
3
  import torch
4
- import numpy as np
5
- from nltk.translate.bleu_score import sentence_bleu, SmoothingFunction
6
- from nltk.tokenize import word_tokenize
7
- import nltk
8
- import time
9
- import os
10
-
11
- # Download required NLTK data
12
- try:
13
- nltk.download('punkt', quiet=True)
14
- nltk.download('punkt_tab', quiet=True)
15
- except:
16
- pass
17
-
18
- # Global variables to store loaded model
19
- loaded_model = None
20
- loaded_tokenizer = None
21
- loaded_config = None
22
- generation_history = []
23
-
24
- # Auto-load model on startup
25
- def initialize_model():
26
- """Initialize model automatically on app startup"""
27
- return load_model_from_pickle("best_model.pkl")
28
-
29
- def load_model_from_pickle(pickle_path="best_model.pkl"):
30
- """Load model from pickle file (auto-loads on startup)"""
31
- global loaded_model, loaded_tokenizer, loaded_config
32
-
33
- try:
34
- # Check if file exists
35
- if not os.path.exists(pickle_path):
36
- return f"❌ Model file not found: {pickle_path}\n\nPlease ensure best_model.pkl is uploaded to the HuggingFace Space."
37
-
38
- # ULTIMATE FIX: Check if CPU version exists, if not convert it
39
- cpu_pickle_path = pickle_path.replace('.pkl', '_cpu.pkl')
40
-
41
- if not os.path.exists(cpu_pickle_path):
42
- # Need to convert CUDA pickle to CPU pickle
43
- try:
44
- # Use torch.load with custom map_location that captures and remaps ALL devices
45
- def smart_map_location(storage, location):
46
- # This function is called for EACH tensor storage during unpickling
47
- # It runs BEFORE the "CUDA device check", allowing us to remap
48
- return storage.cpu()
49
-
50
- # Load with our smart mapper
51
- model_package = torch.load(pickle_path, map_location=smart_map_location)
52
-
53
- # Now save it as a CPU-only pickle for future loads
54
- torch.save(model_package, cpu_pickle_path)
55
-
56
- return f"✅ Converted CUDA model to CPU! Loading from converted version...\n\nPlease wait, loading model..."
57
-
58
- except Exception as convert_error:
59
- # Conversion failed, try direct load with aggressive remapping
60
- import io
61
- import pickle as pkl
62
-
63
- try:
64
- # Read the pickle bytes
65
- with open(pickle_path, 'rb') as f:
66
- buffer = io.BytesIO(f.read())
67
-
68
- # Create custom unpickler with aggressive CPU forcing
69
- class AggressiveCPUUnpickler(pkl.Unpickler):
70
- def find_class(self, module, name):
71
- # Remap any CUDA storage to CPU storage
72
- if 'cuda' in name.lower():
73
- name = name.replace('cuda', '').replace('Cuda', '')
74
- return super().find_class(module, name)
75
-
76
- def load_build(self):
77
- # Override to catch tensor builds
78
- stack = self.stack
79
- state = stack.pop()
80
- inst = stack[-1]
81
-
82
- # If this is a tensor, force to CPU
83
- if hasattr(inst, 'to'):
84
- try:
85
- inst = inst.cpu()
86
- stack[-1] = inst
87
- except:
88
- pass
89
-
90
- if hasattr(inst, '__setstate__'):
91
- inst.__setstate__(state)
92
- else:
93
- for k, v in state.items():
94
- setattr(inst, k, v)
95
-
96
- def persistent_load(self, pid):
97
- # Intercept ALL storage loads
98
- if isinstance(pid, tuple) and len(pid) >= 5:
99
- # Standard torch storage format
100
- tag, storage_type, key, location, size = pid[0], pid[1], pid[2], pid[3], pid[4]
101
- if tag == 'storage':
102
- # Force location to CPU
103
- return (tag, storage_type, key, 'cpu', size)
104
- return pid
105
-
106
- # Try to load with aggressive unpickler
107
- unpickler = AggressiveCPUUnpickler(buffer)
108
- model_package = unpickler.load()
109
-
110
- # Save as CPU version for next time
111
- torch.save(model_package, cpu_pickle_path)
112
-
113
- except Exception as aggressive_error:
114
- return (f"❌ Failed to convert CUDA pickle to CPU.\n\n"
115
- f"Convert error: {str(convert_error)[:100]}\n"
116
- f"Aggressive error: {str(aggressive_error)[:100]}\n\n"
117
- f"Please re-save your model on a CPU machine:\n"
118
- f"```python\n"
119
- f"import torch\n"
120
- f"# Load your model\n"
121
- f"model = model.cpu() # Move to CPU\n"
122
- f"torch.save({{'model': model, 'tokenizer': tokenizer, 'config': config}}, 'best_model.pkl')\n"
123
- f"```")
124
- else:
125
- # CPU version exists, load it directly
126
- model_package = torch.load(cpu_pickle_path, map_location='cpu')
127
-
128
- # Success! Model loaded with one of the strategies above
129
- # Handle a few common package shapes.
130
- if isinstance(model_package, dict):
131
- loaded_model = model_package.get('model', None)
132
- loaded_tokenizer = model_package.get('tokenizer', None)
133
- loaded_config = model_package.get('config', {}) or {}
134
- else:
135
- # Unknown package format: assume the object itself is the model
136
- loaded_model = model_package
137
- loaded_tokenizer = None
138
- loaded_config = {}
139
-
140
- # If user saved a state_dict instead of a model object, provide guidance
141
- if isinstance(loaded_model, dict) and 'state_dict' in loaded_model:
142
- # the file contains something like {'state_dict': ...}
143
- return ("❌ The pickle appears to contain a state_dict rather than a full model object. "
144
- "This app expects a pickled model object (model instance).\n"
145
- "If you only have a state_dict, re-create the model architecture and load the state_dict before pickling, "
146
- "or provide a pickled model object saved with torch.save(model, path).")
147
-
148
- if loaded_model is None:
149
- return ("❌ No model object found inside the pickle. Please ensure the pickle contains a dict with keys "
150
- "'model', 'tokenizer', and 'config' (or the model object itself).")
151
-
152
- # Set model to evaluation mode and move to appropriate device
153
- try:
154
- loaded_model.eval()
155
- device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
156
- loaded_model = loaded_model.to(device)
157
- except Exception as e:
158
- return (f"❌ Error preparing model for inference: {str(e)}\n\n"
159
- "This can happen if the saved object is not a proper torch.nn.Module or if tensors couldn't be mapped to the current device.")
160
-
161
- config_info = f"""✅ Model loaded successfully!
162
-
163
- 📊 Model Configuration:
164
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
165
- • Base Model: {loaded_config.get('model_name', 'GPT-2')}
166
- • Training Epochs: {loaded_config.get('num_epochs', 'N/A')}
167
- • Training Samples: {loaded_config.get('training_samples', 'N/A'):,}
168
- • Validation Samples: {loaded_config.get('validation_samples', 'N/A'):,}
169
- • BLEU Score: {loaded_config.get('bleu_score', 0):.4f}
170
- • Perplexity: {loaded_config.get('perplexity', 0):.2f}
171
- • Final Loss: {loaded_config.get('final_loss', 0):.4f}
172
- • Device: {device}
173
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
174
-
175
- 🚀 Model is ready to generate code!
176
- """
177
-
178
- return config_info
179
-
180
- except Exception as e:
181
- # Final catch-all for any unexpected errors
182
- err = str(e)
183
- return f"❌ Unexpected error loading model: {err}\n\nPlease ensure best_model.pkl is properly uploaded and compatible with this environment."
184
-
185
- def calculate_bleu_score(reference, hypothesis):
186
- """Calculate BLEU score between reference and generated code"""
187
- try:
188
- # Tokenize
189
- ref_tokens = word_tokenize(reference.lower())
190
- hyp_tokens = word_tokenize(hypothesis.lower())
191
-
192
- # Calculate BLEU with smoothing
193
- smooth = SmoothingFunction()
194
- bleu_1 = sentence_bleu([ref_tokens], hyp_tokens, weights=(1, 0, 0, 0), smoothing_function=smooth.method1)
195
- bleu_2 = sentence_bleu([ref_tokens], hyp_tokens, weights=(0.5, 0.5, 0, 0), smoothing_function=smooth.method1)
196
- bleu_3 = sentence_bleu([ref_tokens], hyp_tokens, weights=(0.33, 0.33, 0.33, 0), smoothing_function=smooth.method1)
197
- bleu_4 = sentence_bleu([ref_tokens], hyp_tokens, weights=(0.25, 0.25, 0.25, 0.25), smoothing_function=smooth.method1)
198
-
199
- return bleu_1, bleu_2, bleu_3, bleu_4
200
- except Exception as e:
201
- return 0.0, 0.0, 0.0, 0.0
202
 
203
- def calculate_code_metrics(reference, generated):
204
- """Calculate various code similarity metrics"""
205
- try:
206
- # Length ratio
207
- len_ratio = len(generated) / max(len(reference), 1)
208
-
209
- # Word overlap
210
- ref_words = set(reference.lower().split())
211
- gen_words = set(generated.lower().split())
212
-
213
- if len(ref_words) > 0:
214
- precision = len(ref_words.intersection(gen_words)) / len(gen_words) if len(gen_words) > 0 else 0
215
- recall = len(ref_words.intersection(gen_words)) / len(ref_words)
216
- f1 = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
217
- else:
218
- precision = recall = f1 = 0
219
-
220
- # Character-level similarity
221
- char_overlap = sum(1 for c in generated if c in reference) / max(len(generated), 1)
222
-
223
- return {
224
- 'length_ratio': len_ratio,
225
- 'precision': precision,
226
- 'recall': recall,
227
- 'f1_score': f1,
228
- 'char_overlap': char_overlap
229
- }
230
- except Exception as e:
231
- return {
232
- 'length_ratio': 0,
233
- 'precision': 0,
234
- 'recall': 0,
235
- 'f1_score': 0,
236
- 'char_overlap': 0
237
- }
238
 
239
- def generate_code_from_pseudo(pseudo_code, max_length, temperature, top_k, top_p, num_sequences, reference_code):
240
- """Generate code from pseudo-code using loaded model"""
241
- global loaded_model, loaded_tokenizer, generation_history
242
-
243
- if loaded_model is None or loaded_tokenizer is None:
244
- return "❌ Please upload and load a model first!", "", "", ""
245
-
246
- if not pseudo_code.strip():
247
- return "❌ Please enter pseudo-code description!", "", "", ""
248
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  try:
250
- start_time = time.time()
 
251
 
252
- # Format input
253
- prompt = f"<PSEUDO> {pseudo_code.strip()} <SEP> <CODE>"
254
 
255
- # Tokenize
256
- device = next(loaded_model.parameters()).device
257
- inputs = loaded_tokenizer(prompt, return_tensors='pt').to(device)
258
 
259
- # Generate (ensure type safety for parameters)
 
260
  with torch.no_grad():
261
- outputs = loaded_model.generate(
262
  **inputs,
263
- max_length=int(max_length),
264
- temperature=float(temperature),
265
- top_k=int(top_k),
266
- top_p=float(top_p),
267
  do_sample=True,
268
- num_return_sequences=int(num_sequences),
269
- pad_token_id=loaded_tokenizer.pad_token_id,
270
- eos_token_id=loaded_tokenizer.eos_token_id,
271
  )
272
 
273
- generation_time = time.time() - start_time
274
-
275
- # Decode all sequences
276
- generated_codes = []
277
- for output in outputs:
278
- generated = loaded_tokenizer.decode(output, skip_special_tokens=False)
279
-
280
- # Extract code part
281
- if '<CODE>' in generated:
282
- code = generated.split('<CODE>')[-1].strip()
283
- # Remove special tokens
284
- code = code.replace('<PAD>', '').replace('<SEP>', '').strip()
285
- else:
286
- code = generated
287
-
288
- generated_codes.append(code)
289
-
290
- # Use the first generated code as primary output
291
- primary_code = generated_codes[0]
292
 
293
- # Calculate metrics if reference code is provided
294
- metrics_output = ""
295
- bleu_output = ""
296
-
297
- if reference_code and reference_code.strip():
298
- # Calculate BLEU scores
299
- bleu_1, bleu_2, bleu_3, bleu_4 = calculate_bleu_score(reference_code, primary_code)
300
-
301
- bleu_output = f"""📊 BLEU Scores:
302
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
303
- • BLEU-1 (Unigram): {bleu_1:.4f} ({bleu_1*100:.2f}%)
304
- • BLEU-2 (Bigram): {bleu_2:.4f} ({bleu_2*100:.2f}%)
305
- • BLEU-3 (Trigram): {bleu_3:.4f} ({bleu_3*100:.2f}%)
306
- • BLEU-4 (4-gram): {bleu_4:.4f} ({bleu_4*100:.2f}%)
307
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
308
-
309
- 💡 Interpretation:
310
- • BLEU > 0.4: Excellent match
311
- • BLEU 0.3-0.4: Good match
312
- • BLEU 0.2-0.3: Fair match
313
- • BLEU < 0.2: Poor match
314
- """
315
-
316
- # Calculate additional metrics
317
- code_metrics = calculate_code_metrics(reference_code, primary_code)
318
-
319
- metrics_output = f"""📈 Additional Metrics:
320
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
321
- • Length Ratio: {code_metrics['length_ratio']:.3f}
322
- • Precision: {code_metrics['precision']:.4f} ({code_metrics['precision']*100:.2f}%)
323
- • Recall: {code_metrics['recall']:.4f} ({code_metrics['recall']*100:.2f}%)
324
- • F1-Score: {code_metrics['f1_score']:.4f} ({code_metrics['f1_score']*100:.2f}%)
325
- • Character Overlap: {code_metrics['char_overlap']:.4f} ({code_metrics['char_overlap']*100:.2f}%)
326
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
327
-
328
- ⏱️ Generation Time: {generation_time:.2f}s
329
- 📝 Sequences Generated: {num_sequences}
330
- 🔢 Output Length: {len(primary_code)} characters
331
- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
332
- """
333
  else:
334
- metrics_output = f"""⏱️ Generation Time: {generation_time:.2f}s
335
- 📝 Sequences Generated: {num_sequences}
336
- 🔢 Output Length: {len(primary_code)} characters
337
-
338
- 💡 Tip: Provide reference code to see BLEU scores and similarity metrics!
339
- """
340
-
341
- # Format alternative sequences
342
- alternatives = ""
343
- if num_sequences > 1:
344
- alternatives = "🔄 Alternative Generations:\n" + "━"*50 + "\n\n"
345
- for i, code in enumerate(generated_codes[1:], 2):
346
- alternatives += f"Variation {i}:\n```python\n{code}\n```\n\n"
347
-
348
- # Add to history
349
- generation_history.append({
350
- 'pseudo': pseudo_code,
351
- 'generated': primary_code,
352
- 'bleu_4': bleu_4 if reference_code else None,
353
- 'time': generation_time
354
- })
355
-
356
- return primary_code, metrics_output, bleu_output, alternatives
357
 
358
- except Exception as e:
359
- return f"❌ Error generating code: {str(e)}", "", "", ""
360
-
361
- def show_examples(example_name):
362
- """Load example pseudo-code"""
363
- examples = {
364
- "Basic Loop": "create a list of numbers from 1 to 10",
365
- "Function Definition": "define a function to calculate the sum of two numbers",
366
- "List Iteration": "iterate through a list and print each element",
367
- "Conditional Check": "check if a number is even or odd",
368
- "Sorting": "sort a list in descending order",
369
- "Maximum Element": "create a function to find maximum element in array",
370
- "Binary Search": "implement binary search algorithm",
371
- "Factorial": "create a recursive function to calculate factorial",
372
- "Palindrome": "check if a string is palindrome",
373
- "Fibonacci": "generate fibonacci sequence up to n terms"
374
- }
375
- return examples.get(example_name, "")
376
-
377
- def clear_all():
378
- """Clear all inputs and outputs"""
379
- return "", "", "", "", "", 150, 0.7, 50, 0.95, 1
380
-
381
- def show_history():
382
- """Display generation history"""
383
- if not generation_history:
384
- return "No generation history yet. Start generating code!"
385
-
386
- history_text = "📜 Generation History:\n" + "="*60 + "\n\n"
387
 
388
- for i, entry in enumerate(reversed(generation_history[-10:]), 1): # Show last 10
389
- history_text += f"{i}. Pseudo: {entry['pseudo'][:60]}...\n"
390
- history_text += f" Time: {entry['time']:.2f}s"
391
- if entry['bleu_4'] is not None:
392
- history_text += f" | BLEU-4: {entry['bleu_4']:.4f}"
393
- history_text += f"\n Code: {entry['generated'][:80]}...\n\n"
394
-
395
- return history_text
396
-
397
- # Create Gradio interface with custom CSS
398
- custom_css = """
399
- .gradio-container {
400
- font-family: 'Arial', sans-serif;
401
- }
402
- .output-code {
403
- font-family: 'Courier New', monospace;
404
- font-size: 14px;
405
- }
406
- .metrics-box {
407
- background-color: #f0f8ff;
408
- border-radius: 8px;
409
- padding: 10px;
410
- }
411
- """
412
 
413
- with gr.Blocks(title="🚀 GPT-2 Pseudo-Code to Code Generator", theme=gr.themes.Soft(), css=custom_css) as demo:
414
-
415
- gr.Markdown("""
416
- # 🚀 GPT-2 Pseudo-Code to Python Code Generator
417
-
418
- **Transform natural language descriptions into executable Python code using fine-tuned GPT-2!**
419
 
420
- This model is trained on the SPOC (Search-based Pseudo-code to Code) dataset and can generate Python code from pseudo-code descriptions.
421
- """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
422
 
423
- with gr.Tabs():
424
- # Tab 1: Code Generation
425
- with gr.Tab("💻 Code Generation"):
426
- with gr.Row():
427
- with gr.Column(scale=1):
428
- gr.Markdown("### � Model Status")
429
- model_status = gr.Textbox(
430
- label="Model Information",
431
- lines=15,
432
- interactive=False,
433
- value=initialize_model() # Auto-load on startup
434
- )
435
 
436
- gr.Markdown("---")
 
 
 
 
 
437
 
438
  with gr.Row():
439
- with gr.Column(scale=1):
440
- gr.Markdown("### ✍️ Enter Pseudo-Code")
441
-
442
- # Example selector
443
- with gr.Row():
444
- example_dropdown = gr.Dropdown(
445
- choices=["Basic Loop", "Function Definition", "List Iteration",
446
- "Conditional Check", "Sorting", "Maximum Element",
447
- "Binary Search", "Factorial", "Palindrome", "Fibonacci"],
448
- label="📚 Load Example",
449
- value=None
450
- )
451
-
452
- pseudo_input = gr.Textbox(
453
- label="Pseudo-Code Description",
454
- placeholder="Example: create a function to calculate factorial of a number",
455
- lines=4
456
- )
457
-
458
- reference_code = gr.Textbox(
459
- label="Reference Code (Optional - for BLEU score calculation)",
460
- placeholder="Paste reference code here to calculate BLEU scores...",
461
- lines=4
462
- )
463
-
464
- gr.Markdown("### ⚙️ Generation Parameters")
465
- with gr.Row():
466
- max_length = gr.Slider(
467
- minimum=50,
468
- maximum=500,
469
- value=150,
470
- step=10,
471
- label="Max Length",
472
- info="Maximum tokens to generate"
473
- )
474
- temperature = gr.Slider(
475
- minimum=0.1,
476
- maximum=1.5,
477
- value=0.7,
478
- step=0.1,
479
- label="Temperature",
480
- info="Higher = more creative"
481
- )
482
-
483
- with gr.Row():
484
- top_k = gr.Slider(
485
- minimum=10,
486
- maximum=100,
487
- value=50,
488
- step=5,
489
- label="Top-K",
490
- info="Vocabulary filtering"
491
- )
492
- top_p = gr.Slider(
493
- minimum=0.5,
494
- maximum=1.0,
495
- value=0.95,
496
- step=0.05,
497
- label="Top-P",
498
- info="Nucleus sampling"
499
- )
500
-
501
- num_sequences = gr.Slider(
502
- minimum=1,
503
- maximum=5,
504
- value=1,
505
- step=1,
506
- label="Number of Variations",
507
- info="Generate multiple versions"
508
- )
509
-
510
- with gr.Row():
511
- generate_btn = gr.Button("✨ Generate Code", variant="primary", size="lg")
512
- clear_btn = gr.Button("🗑️ Clear All", variant="secondary")
513
 
514
- with gr.Column(scale=1):
515
- gr.Markdown("### 💻 Generated Python Code")
516
- code_output = gr.Code(
517
- label="Generated Code",
518
- language="python",
519
- lines=12,
520
- elem_classes="output-code"
521
- )
522
-
523
- with gr.Row():
524
- with gr.Column():
525
- metrics_output = gr.Textbox(
526
- label="📊 Performance Metrics",
527
- lines=8,
528
- interactive=False,
529
- elem_classes="metrics-box"
530
- )
531
- with gr.Column():
532
- bleu_output = gr.Textbox(
533
- label="🎯 BLEU Scores",
534
- lines=8,
535
- interactive=False,
536
- elem_classes="metrics-box"
537
- )
538
-
539
- alternatives_output = gr.Markdown(
540
- label="🔄 Alternative Generations"
541
- )
542
-
543
- # Tab 2: Information & Guide
544
- with gr.Tab("📖 Guide & Examples"):
545
- gr.Markdown("""
546
- ## 📚 How to Use
547
-
548
- ### 1️⃣ Load Your Model
549
- - Upload the `best_model.pkl` file (trained GPT-2 model)
550
- - Click "Load Model" and wait for confirmation
551
- - You'll see model configuration and training metrics
552
-
553
- ### 2️⃣ Generate Code
554
- - **Quick Start**: Select an example from the dropdown
555
- - **Custom Input**: Type your own pseudo-code description
556
- - **Optional**: Add reference code to calculate BLEU scores
557
- - Adjust generation parameters for different outputs
558
- - Click "Generate Code"
559
-
560
- ### 3️⃣ Understand the Metrics
561
-
562
- #### 🎯 BLEU Score (Bilingual Evaluation Understudy)
563
- - Measures similarity between generated and reference code
564
- - **BLEU-1**: Word-level similarity (unigrams)
565
- - **BLEU-2**: 2-word phrase similarity (bigrams)
566
- - **BLEU-3**: 3-word phrase similarity (trigrams)
567
- - **BLEU-4**: 4-word phrase similarity (most comprehensive)
568
-
569
- **Score Interpretation:**
570
- - 🟢 **> 0.4**: Excellent match - Generated code is very similar to reference
571
- - 🟡 **0.3-0.4**: Good match - Code captures most key elements
572
- - 🟠 **0.2-0.3**: Fair match - Some similarity exists
573
- - 🔴 **< 0.2**: Poor match - Significant differences
574
-
575
- #### 📈 Additional Metrics
576
- - **Precision**: How many generated words appear in reference
577
- - **Recall**: How many reference words appear in generated code
578
- - **F1-Score**: Harmonic mean of precision and recall
579
- - **Length Ratio**: Generated vs reference code length
580
- - **Character Overlap**: Character-level similarity
581
-
582
- ### 🎛️ Generation Parameters
583
 
584
- | Parameter | Low Value | High Value | Use Case |
585
- |-----------|-----------|------------|----------|
586
- | **Temperature** | 0.1-0.3 | 0.8-1.2 | Low: Deterministic, focused<br>High: Creative, diverse |
587
- | **Top-K** | 10-30 | 60-100 | Low: Conservative choices<br>High: More variety |
588
- | **Top-P** | 0.5-0.8 | 0.9-1.0 | Low: Safe predictions<br>High: Exploratory |
589
- | **Max Length** | 50-100 | 200-500 | Short: Simple code<br>Long: Complex implementations |
590
 
591
- ---
592
-
593
- ## 💡 Example Pseudo-Code Prompts
594
-
595
- ### Basic Operations
596
- ```
597
- create a list of numbers from 1 to 10
598
- define a function to calculate the sum of two numbers
599
- iterate through a list and print each element
600
- ```
601
-
602
- ### Conditionals & Logic
603
- ```
604
- check if a number is even or odd
605
- find the maximum of three numbers
606
- validate if a string is empty
607
- ```
608
-
609
- ### Data Structures
610
- ```
611
- sort a list in descending order
612
- remove duplicates from a list
613
- merge two dictionaries
614
- ```
615
-
616
- ### Algorithms
617
- ```
618
- implement binary search algorithm
619
- create a recursive function to calculate factorial
620
- generate fibonacci sequence up to n terms
621
- check if a string is palindrome
622
- ```
623
-
624
- ### Advanced
625
- ```
626
- create a class to represent a student with name and grades
627
- implement a function to read CSV file and return dataframe
628
- create a decorator to measure function execution time
629
- ```
630
-
631
- ---
632
-
633
- ## 🎓 About the Model
634
-
635
- This model is fine-tuned on the **SPOC (Search-based Pseudo-code to Code)** dataset:
636
- - 📄 Paper: [SPOC: Search-based Pseudo-code to Code](https://arxiv.org/pdf/1906.04908)
637
- - 🏛️ Source: Stanford University
638
- - 🤖 Base Model: GPT-2 (Decoder-Only Transformer)
639
- - 📊 Training: 10,000+ pseudo-code to code pairs
640
- - 🎯 Task: Causal Language Modeling
641
-
642
- ---
643
-
644
- ## ⚠️ Limitations
645
-
646
- - Model may not handle very complex algorithms perfectly
647
- - Generated code should be tested before production use
648
- - Best results with clear, specific pseudo-code descriptions
649
- - Model trained on C++ code, adapted for Python generation
650
-
651
- ---
652
-
653
- ## 🤝 Tips for Best Results
654
-
655
- 1. ✅ **Be Specific**: "create a function to sort list in ascending order" vs "sort list"
656
- 2. ✅ **Use Action Words**: "create", "define", "implement", "calculate"
657
- 3. ✅ **Mention Data Types**: "list", "string", "dictionary", "integer"
658
- 4. ✅ **Include Details**: "recursive function" vs just "function"
659
- 5. ✅ **Try Variations**: Generate multiple times with different temperatures
660
 
661
- """)
662
 
663
- # Tab 3: History
664
- with gr.Tab("📜 History"):
665
- gr.Markdown("## 📊 Generation History")
666
- history_display = gr.Textbox(
667
- label="Recent Generations",
668
- lines=20,
669
- interactive=False
 
670
  )
671
- refresh_history_btn = gr.Button("🔄 Refresh History", variant="secondary")
672
-
673
- gr.Markdown("""
674
- ---
675
- ### 🌟 Features
676
- - ✅ Upload and use custom trained models
677
- - ✅ BLEU score calculation for quality assessment
678
- - ✅ Multiple evaluation metrics (Precision, Recall, F1)
679
- - ✅ Generate multiple code variations
680
- - ✅ Real-time performance tracking
681
- - ✅ Example prompts library
682
- - ✅ Generation history
683
 
684
- ### 📝 Citation
685
- If you use this model, please cite:
686
- ```
687
- @article{kulal2019spoc,
688
- title={SPOC: Search-based Pseudo-code to Code},
689
- author={Kulal, Sumith and Pasupat, Panupong and Chandra, Kartik and Lee, Mina and Padon, Oded and Aiken, Alex and Liang, Percy},
690
- journal={arXiv preprint arXiv:1906.04908},
691
- year={2019}
692
- }
693
- ```
694
-
695
- **Built with ❤️ using HuggingFace Transformers & Gradio**
696
- """)
697
-
698
- # Event handlers
699
- example_dropdown.change(
700
- fn=show_examples,
701
- inputs=[example_dropdown],
702
- outputs=[pseudo_input]
703
- )
704
-
705
- generate_btn.click(
706
- fn=generate_code_from_pseudo,
707
- inputs=[pseudo_input, max_length, temperature, top_k, top_p, num_sequences, reference_code],
708
- outputs=[code_output, metrics_output, bleu_output, alternatives_output]
709
  )
710
 
711
- clear_btn.click(
712
- fn=clear_all,
713
- inputs=[],
714
- outputs=[pseudo_input, reference_code, code_output, metrics_output, bleu_output,
715
- max_length, temperature, top_k, top_p, num_sequences]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  )
717
 
718
- refresh_history_btn.click(
719
- fn=show_history,
720
- inputs=[],
721
- outputs=[history_display]
 
722
  )
723
 
724
- # Launch the interface
725
  if __name__ == "__main__":
726
- demo.launch(share=False)
 
1
  import gradio as gr
 
2
  import torch
3
+ import pickle
4
+ from transformers import GPT2Tokenizer, GPT2LMHeadModel
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ # Load model and tokenizer from pickle files
7
+ print("Loading model and tokenizer...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
+ try:
10
+ # Load LoRA model
11
+ with open('gpt2_pseudo2code_lora_model.pkl', 'rb') as f:
12
+ model = pickle.load(f)
13
+ print("✓ Model loaded successfully")
14
+
15
+ # Load tokenizer
16
+ with open('gpt2_pseudo2code_tokenizer.pkl', 'rb') as f:
17
+ tokenizer = pickle.load(f)
18
+ print("✓ Tokenizer loaded successfully")
19
+
20
+ # Move model to appropriate device
21
+ device = "cuda" if torch.cuda.is_available() else "cpu"
22
+ model = model.to(device)
23
+ model.eval()
24
+ print(f"✓ Model moved to {device}")
25
+
26
+ except Exception as e:
27
+ print(f"Error loading model: {e}")
28
+ raise
29
+
30
+ def generate_code(pseudocode, indent, line, max_length=128, temperature=0.7, top_p=0.9):
31
+ """
32
+ Generate code from pseudo-code with line and indent information.
33
+
34
+ Args:
35
+ pseudocode: Input pseudo-code string
36
+ indent: Indentation level
37
+ line: Line number
38
+ max_length: Maximum length of generated sequence
39
+ temperature: Sampling temperature
40
+ top_p: Nucleus sampling parameter
41
+
42
+ Returns:
43
+ Generated code string
44
+ """
45
  try:
46
+ # Format input with line and indent information
47
+ prompt = f"Pseudocode: {pseudocode} | Indent: {indent} | Line: {line}\nCode:"
48
 
49
+ # Tokenize input
50
+ inputs = tokenizer(prompt, return_tensors='pt', padding=True)
51
 
52
+ # Move to same device as model
53
+ device = next(model.parameters()).device
54
+ inputs = {k: v.to(device) for k, v in inputs.items()}
55
 
56
+ # Generate
57
+ model.eval()
58
  with torch.no_grad():
59
+ outputs = model.generate(
60
  **inputs,
61
+ max_length=max_length,
62
+ temperature=temperature,
63
+ top_p=top_p,
 
64
  do_sample=True,
65
+ pad_token_id=tokenizer.eos_token_id,
66
+ eos_token_id=tokenizer.eos_token_id,
67
+ num_return_sequences=1
68
  )
69
 
70
+ # Decode output
71
+ generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
 
73
+ # Extract only the code part
74
+ if "Code:" in generated_text:
75
+ code = generated_text.split("Code:")[1].strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  else:
77
+ code = generated_text.strip()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
+ return code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
+ except Exception as e:
82
+ return f"Error generating code: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
+ def gradio_generate_code(pseudocode, indent, line, temperature=0.7, top_p=0.9, max_length=128):
85
+ """
86
+ Wrapper function for Gradio interface.
87
+ """
88
+ if not pseudocode.strip():
89
+ return "⚠️ Please enter some pseudocode!"
90
 
91
+ try:
92
+ indent = int(indent)
93
+ line = int(line)
94
+ generated_code = generate_code(
95
+ pseudocode,
96
+ indent,
97
+ line,
98
+ max_length=int(max_length),
99
+ temperature=float(temperature),
100
+ top_p=float(top_p)
101
+ )
102
+ return generated_code
103
+ except ValueError:
104
+ return "⚠️ Indent and Line must be valid numbers!"
105
+ except Exception as e:
106
+ return f"❌ Error: {str(e)}"
107
+
108
+ # Example pseudocodes
109
+ examples = [
110
+ ["create integer n", 1, 1, 0.7, 0.9, 128],
111
+ ["read n", 1, 2, 0.7, 0.9, 128],
112
+ ["for i from 0 to n", 1, 3, 0.7, 0.9, 128],
113
+ ["print i", 2, 4, 0.7, 0.9, 128],
114
+ ["if n is equal to 0", 1, 5, 0.7, 0.9, 128],
115
+ ["create string s", 1, 1, 0.7, 0.9, 128],
116
+ ["read s", 1, 2, 0.7, 0.9, 128],
117
+ ]
118
+
119
+ # Create Gradio interface
120
+ with gr.Blocks(theme=gr.themes.Soft(), title="Pseudo-Code to Code Generator") as demo:
121
+ gr.Markdown(
122
+ """
123
+ # 🐍 Pseudo-Code to Code Generator (GPT-2 + LoRA)
124
+
125
+ Convert natural language pseudo-code to executable code using a fine-tuned GPT-2 model with LoRA.
126
+
127
+ **Model Details:**
128
+ - Base Model: GPT-2
129
+ - Training: SPOC Dataset (C++ code examples)
130
+ - Optimization: LoRA (Low-Rank Adaptation) + 16-bit precision
131
+ - Trained on: 20,000 pseudo-code to code pairs
132
+
133
+ **Note:** The model was trained on C++ code examples from the SPOC dataset, so it generates C++-style code.
134
+ """
135
+ )
136
 
137
+ with gr.Row():
138
+ with gr.Column(scale=1):
139
+ gr.Markdown("### 📝 Input")
 
 
 
 
 
 
 
 
 
140
 
141
+ pseudocode_input = gr.Textbox(
142
+ label="Pseudocode",
143
+ placeholder="Enter your pseudocode here...\nExample: create integer n",
144
+ lines=5,
145
+ max_lines=10
146
+ )
147
 
148
  with gr.Row():
149
+ indent_input = gr.Number(
150
+ label="Indent Level",
151
+ value=1,
152
+ precision=0,
153
+ info="Indentation level (0=no indent, 1=first level, etc.)"
154
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
+ line_input = gr.Number(
157
+ label="Line Number",
158
+ value=1,
159
+ precision=0,
160
+ info="Line number in the program"
161
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
 
163
+ gr.Markdown("### ⚙️ Generation Parameters")
 
 
 
 
 
164
 
165
+ with gr.Row():
166
+ temperature_slider = gr.Slider(
167
+ minimum=0.1,
168
+ maximum=1.5,
169
+ value=0.7,
170
+ step=0.1,
171
+ label="Temperature",
172
+ info="Higher = more creative/random"
173
+ )
174
+
175
+ top_p_slider = gr.Slider(
176
+ minimum=0.1,
177
+ maximum=1.0,
178
+ value=0.9,
179
+ step=0.05,
180
+ label="Top-p (Nucleus Sampling)",
181
+ info="Probability threshold for sampling"
182
+ )
183
+
184
+ max_length_slider = gr.Slider(
185
+ minimum=64,
186
+ maximum=256,
187
+ value=128,
188
+ step=16,
189
+ label="Max Length",
190
+ info="Maximum tokens to generate"
191
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
193
+ generate_btn = gr.Button("🚀 Generate Code", variant="primary", size="lg")
194
 
195
+ with gr.Column(scale=1):
196
+ gr.Markdown("### 💻 Generated Code")
197
+
198
+ output = gr.Textbox(
199
+ label="Generated Code",
200
+ lines=15,
201
+ max_lines=20,
202
+ show_copy_button=True
203
  )
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
+ gr.Markdown("### 📚 Examples")
206
+ gr.Examples(
207
+ examples=examples,
208
+ inputs=[pseudocode_input, indent_input, line_input, temperature_slider, top_p_slider, max_length_slider],
209
+ outputs=output,
210
+ fn=gradio_generate_code,
211
+ cache_examples=False,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  )
213
 
214
+ gr.Markdown(
215
+ """
216
+ ---
217
+ ### ℹ️ How to Use:
218
+ 1. **Enter pseudocode**: Write your natural language description
219
+ 2. **Set indent level**: Specify the indentation (0 for no indent, 1 for first level, etc.)
220
+ 3. **Set line number**: Indicate the line position in your program
221
+ 4. **Adjust parameters** (optional): Fine-tune temperature and top-p for different results
222
+ 5. **Click Generate**: Get your code!
223
+
224
+ ### 💡 Tips:
225
+ - Higher temperature (0.8-1.2) = more creative but potentially less accurate
226
+ - Lower temperature (0.5-0.7) = more conservative and predictable
227
+ - Top-p controls diversity; 0.9 is usually a good balance
228
+ - The model generates C++-style code as it was trained on the SPOC dataset
229
+
230
+ ### 🔗 Resources:
231
+ - [SPOC Dataset](https://github.com/sumith1896/spoc)
232
+ - [Research Paper](https://arxiv.org/pdf/1906.04908)
233
+ - Model trained with LoRA for efficiency
234
+ """
235
  )
236
 
237
+ # Connect button to function
238
+ generate_btn.click(
239
+ fn=gradio_generate_code,
240
+ inputs=[pseudocode_input, indent_input, line_input, temperature_slider, top_p_slider, max_length_slider],
241
+ outputs=output
242
  )
243
 
244
+ # Launch the app
245
  if __name__ == "__main__":
246
+ demo.launch()