ziyan14 commited on
Commit
b10119f
Β·
verified Β·
1 Parent(s): b4494fe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -18
app.py CHANGED
@@ -5,10 +5,11 @@ Implements the 5-module architecture from the design document:
5
  1. UI Module β€” Gradio web interface
6
  2. Validation & Flow β€” Input validation and routing
7
  3. Pre-processing β€” 6-Element structured prompt builder
8
- 4. Generation β€” Gemma-4 LLM via Hugging Face
9
  5. Output β€” Parse raw LLM output into structured results
10
  """
11
 
 
12
  import re
13
  import torch
14
  import gradio as gr
@@ -16,17 +17,19 @@ from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
16
 
17
  # ---------------------------------------------------------------------------
18
  # MODULE 4 β€” Generation Module (LLM setup)
 
19
  # ---------------------------------------------------------------------------
20
- MODEL_ID = "google/gemma-4-it"
 
21
 
22
  _tokenizer = None
23
- _pipe = None
24
 
25
  def get_tokenizer():
26
  """Returns the tokenizer, loading it on first call."""
27
  global _tokenizer
28
  if _tokenizer is None:
29
- _tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
30
  return _tokenizer
31
 
32
  def get_pipeline():
@@ -36,15 +39,16 @@ def get_pipeline():
36
  tokenizer = get_tokenizer()
37
  model = AutoModelForCausalLM.from_pretrained(
38
  MODEL_ID,
39
- torch_dtype=torch.bfloat16, # efficient on modern GPUs/CPUs
40
- device_map="auto", # auto-detect GPU/CPU
 
41
  )
42
  _pipe = pipeline(
43
  "text-generation",
44
  model=model,
45
  tokenizer=tokenizer,
46
  max_new_tokens=512,
47
- do_sample=False, # deterministic output
48
  )
49
  return _pipe
50
 
@@ -114,7 +118,6 @@ def parse_output(raw: str) -> dict:
114
  Returns a dict with keys: result, accuracy, summary, issues.
115
  Falls back gracefully if parsing fails.
116
  """
117
- # Strip any echoed prompt (model sometimes repeats <start_of_turn>)
118
  if "<start_of_turn>model" in raw:
119
  raw = raw.split("<start_of_turn>model")[-1]
120
 
@@ -148,10 +151,7 @@ def parse_output(raw: str) -> dict:
148
 
149
  def format_for_display(parsed: dict) -> tuple[str, str, str]:
150
  """
151
- Converts the parsed dict into three Gradio-friendly strings:
152
- - verdict (shown in a highlighted Textbox)
153
- - metrics (accuracy + summary)
154
- - issues_text (bullet list)
155
  """
156
  emoji = "βœ…" if parsed["result"] == "PASS" else ("❌" if parsed["result"] == "FAIL" else "⚠️")
157
  verdict = f"{emoji} {parsed['result']}"
@@ -167,7 +167,7 @@ def format_for_display(parsed: dict) -> tuple[str, str, str]:
167
  # MODULE 4 β€” Generation Module (inference call)
168
  # ---------------------------------------------------------------------------
169
  def generate(prompt: str) -> str:
170
- outputs = get_pipeline()(prompt, return_full_text=False) # FIX: was pipe() β€” undefined variable
171
  return outputs[0]["generated_text"]
172
 
173
 
@@ -185,10 +185,14 @@ def validate_and_evaluate(description: str, code: str):
185
  if not code or not code.strip():
186
  return "", "", "", "⚠️ Please provide Python code to evaluate."
187
 
 
 
 
 
188
  # --- Pre-processing ---
189
  prompt = build_prompt(description, code)
190
 
191
- # Token length guard β€” warn user before sending oversized input to the model
192
  token_count = len(get_tokenizer().encode(prompt))
193
  if token_count > 2048:
194
  return "", "", "", (
@@ -206,18 +210,18 @@ def validate_and_evaluate(description: str, code: str):
206
  parsed = parse_output(raw_output)
207
  verdict, metrics, issues = format_for_display(parsed)
208
 
209
- return verdict, metrics, issues, "" # empty error = success
210
 
211
 
212
  # ---------------------------------------------------------------------------
213
  # MODULE 1 β€” UI Module (Gradio)
214
  # ---------------------------------------------------------------------------
215
- with gr.Blocks(title="Python Code Evaluator β€” SE-Group1") as demo: # FIX: theme moved to launch()
216
 
217
  gr.Markdown(
218
  """
219
  # 🐍 Python Code Evaluator
220
- **COS60011 β€” SE-Group1** | Powered by Gemma-4 via Hugging Face
221
  Enter a **requirements description** and your **Python code**.
222
  The system will evaluate whether the code correctly implements the described behaviour.
223
  """
@@ -259,4 +263,5 @@ with gr.Blocks(title="Python Code Evaluator β€” SE-Group1") as demo: # FIX: the
259
  )
260
 
261
  if __name__ == "__main__":
262
- demo.launch(share=False, theme=gr.themes.Soft(primary_hue="blue"))
 
 
5
  1. UI Module β€” Gradio web interface
6
  2. Validation & Flow β€” Input validation and routing
7
  3. Pre-processing β€” 6-Element structured prompt builder
8
+ 4. Generation β€” Gemma-3 LLM via Hugging Face
9
  5. Output β€” Parse raw LLM output into structured results
10
  """
11
 
12
+ import os
13
  import re
14
  import torch
15
  import gradio as gr
 
17
 
18
  # ---------------------------------------------------------------------------
19
  # MODULE 4 β€” Generation Module (LLM setup)
20
+ # FIX: Correct model ID + read HF_TOKEN from environment (set as Space secret)
21
  # ---------------------------------------------------------------------------
22
+ MODEL_ID = "google/gemma-3-4b-it" # smallest Gemma-3 β€” works on free tier
23
+ HF_TOKEN = os.environ.get("HF_TOKEN") # set this in Space Settings β†’ Secrets
24
 
25
  _tokenizer = None
26
+ _pipe = None
27
 
28
  def get_tokenizer():
29
  """Returns the tokenizer, loading it on first call."""
30
  global _tokenizer
31
  if _tokenizer is None:
32
+ _tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, token=HF_TOKEN)
33
  return _tokenizer
34
 
35
  def get_pipeline():
 
39
  tokenizer = get_tokenizer()
40
  model = AutoModelForCausalLM.from_pretrained(
41
  MODEL_ID,
42
+ token=HF_TOKEN,
43
+ torch_dtype=torch.bfloat16,
44
+ device_map="auto",
45
  )
46
  _pipe = pipeline(
47
  "text-generation",
48
  model=model,
49
  tokenizer=tokenizer,
50
  max_new_tokens=512,
51
+ do_sample=False,
52
  )
53
  return _pipe
54
 
 
118
  Returns a dict with keys: result, accuracy, summary, issues.
119
  Falls back gracefully if parsing fails.
120
  """
 
121
  if "<start_of_turn>model" in raw:
122
  raw = raw.split("<start_of_turn>model")[-1]
123
 
 
151
 
152
  def format_for_display(parsed: dict) -> tuple[str, str, str]:
153
  """
154
+ Converts the parsed dict into three Gradio-friendly strings.
 
 
 
155
  """
156
  emoji = "βœ…" if parsed["result"] == "PASS" else ("❌" if parsed["result"] == "FAIL" else "⚠️")
157
  verdict = f"{emoji} {parsed['result']}"
 
167
  # MODULE 4 β€” Generation Module (inference call)
168
  # ---------------------------------------------------------------------------
169
  def generate(prompt: str) -> str:
170
+ outputs = get_pipeline()(prompt, return_full_text=False)
171
  return outputs[0]["generated_text"]
172
 
173
 
 
185
  if not code or not code.strip():
186
  return "", "", "", "⚠️ Please provide Python code to evaluate."
187
 
188
+ # --- Check token is available ---
189
+ if not HF_TOKEN:
190
+ return "", "", "", "❌ HF_TOKEN secret is not set. Add it in Space Settings β†’ Variables and secrets."
191
+
192
  # --- Pre-processing ---
193
  prompt = build_prompt(description, code)
194
 
195
+ # Token length guard
196
  token_count = len(get_tokenizer().encode(prompt))
197
  if token_count > 2048:
198
  return "", "", "", (
 
210
  parsed = parse_output(raw_output)
211
  verdict, metrics, issues = format_for_display(parsed)
212
 
213
+ return verdict, metrics, issues, ""
214
 
215
 
216
  # ---------------------------------------------------------------------------
217
  # MODULE 1 β€” UI Module (Gradio)
218
  # ---------------------------------------------------------------------------
219
+ with gr.Blocks(title="Python Code Evaluator β€” SE-Group1") as demo:
220
 
221
  gr.Markdown(
222
  """
223
  # 🐍 Python Code Evaluator
224
+ **COS60011 β€” SE-Group1** | Powered by Gemma-3 via Hugging Face
225
  Enter a **requirements description** and your **Python code**.
226
  The system will evaluate whether the code correctly implements the described behaviour.
227
  """
 
263
  )
264
 
265
  if __name__ == "__main__":
266
+ demo.launch(share=False, theme=gr.themes.Soft(primary_hue="blue"))
267
+