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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +42 -52
app.py CHANGED
@@ -1,7 +1,6 @@
1
  """
2
  Python Code Evaluator β€” SE-Group1
3
  COS60011 Technology Design Project
4
-
5
  Implements the 5-module architecture from the design document:
6
  1. UI Module β€” Gradio web interface
7
  2. Validation & Flow β€” Input validation and routing
@@ -9,20 +8,20 @@ Implements the 5-module architecture from the design document:
9
  4. Generation β€” Gemma-4 LLM via Hugging Face
10
  5. Output β€” Parse raw LLM output into structured results
11
  """
12
-
13
  import re
14
  import torch
15
  import gradio as gr
16
  from transformers import AutoTokenizer, AutoModelForCausalLM, pipeline
17
-
18
  # ---------------------------------------------------------------------------
19
  # MODULE 4 β€” Generation Module (LLM setup)
20
  # ---------------------------------------------------------------------------
21
- MODEL_ID = "google/gemma-4-it" # swap for "google/gemma-4-9b-it" if VRAM allows
22
-
23
- _tokenizer=None
24
- _pipe=None
25
-
26
  def get_tokenizer():
27
  """Returns the tokenizer, loading it on first call."""
28
  global _tokenizer
@@ -48,7 +47,8 @@ def get_pipeline():
48
  do_sample=False, # deterministic output
49
  )
50
  return _pipe
51
-
 
52
  # ---------------------------------------------------------------------------
53
  # MODULE 3 β€” Pre-processing Module (6-Element Framework)
54
  # ---------------------------------------------------------------------------
@@ -67,21 +67,17 @@ def build_prompt(description: str, code: str) -> str:
67
  You are an expert Python code reviewer. Your sole task is to determine whether the
68
  provided Python code correctly implements the behaviour described in the user's
69
  requirements description.
70
-
71
  ### CONTEXT
72
  Developers sometimes write code that does not fully satisfy the requirements they
73
  were given. You will analyse the semantic relationship between a natural-language
74
  description and a Python code snippet, then produce a structured evaluation report.
75
-
76
  ### INPUT DATA
77
  **Requirements Description:**
78
  {description.strip()}
79
-
80
  **Python Code:**
81
  ```python
82
  {code.strip()}
83
  ```
84
-
85
  ### TASK
86
  1. Read the requirements description carefully.
87
  2. Analyse the Python code line by line.
@@ -89,16 +85,13 @@ description and a Python code snippet, then produce a structured evaluation repo
89
  4. Estimate an accuracy percentage (0–100) reflecting how completely the code
90
  matches the description.
91
  5. List any specific requirements that are missing or incorrectly implemented.
92
-
93
  ### CONSTRAINTS
94
  - Do NOT execute the code.
95
  - Base your evaluation solely on static code analysis and logical reasoning.
96
  - Keep feedback concise, clear, and actionable.
97
  - Your response MUST follow the output format exactly.
98
-
99
  ### OUTPUT FORMAT
100
  Respond only with the following structure β€” no extra text before or after:
101
-
102
  RESULT: <PASS or FAIL>
103
  ACCURACY: <integer 0-100>%
104
  SUMMARY: <one sentence overall assessment>
@@ -110,8 +103,8 @@ ISSUES:
110
  <start_of_turn>model
111
  """
112
  return prompt
113
-
114
-
115
  # ---------------------------------------------------------------------------
116
  # MODULE 5 β€” Output Module
117
  # ---------------------------------------------------------------------------
@@ -124,16 +117,16 @@ def parse_output(raw: str) -> dict:
124
  # Strip any echoed prompt (model sometimes repeats <start_of_turn>)
125
  if "<start_of_turn>model" in raw:
126
  raw = raw.split("<start_of_turn>model")[-1]
127
-
128
  result_match = re.search(r"RESULT:\s*(PASS|FAIL)", raw, re.IGNORECASE)
129
  accuracy_match = re.search(r"ACCURACY:\s*(\d{1,3})%?", raw, re.IGNORECASE)
130
  summary_match = re.search(r"SUMMARY:\s*(.+)", raw, re.IGNORECASE)
131
  issues_match = re.search(r"ISSUES:\s*([\s\S]+)", raw, re.IGNORECASE)
132
-
133
  result = result_match.group(1).upper() if result_match else "UNKNOWN"
134
  accuracy = int(accuracy_match.group(1)) if accuracy_match else -1
135
  summary = summary_match.group(1).strip() if summary_match else "Could not extract summary."
136
-
137
  if issues_match:
138
  raw_issues = issues_match.group(1).strip()
139
  issues = [
@@ -143,7 +136,7 @@ def parse_output(raw: str) -> dict:
143
  ]
144
  else:
145
  issues = ["Could not extract issues from model response."]
146
-
147
  return {
148
  "result": result,
149
  "accuracy": accuracy,
@@ -151,8 +144,8 @@ def parse_output(raw: str) -> dict:
151
  "issues": issues,
152
  "raw": raw.strip(),
153
  }
154
-
155
-
156
  def format_for_display(parsed: dict) -> tuple[str, str, str]:
157
  """
158
  Converts the parsed dict into three Gradio-friendly strings:
@@ -160,24 +153,24 @@ def format_for_display(parsed: dict) -> tuple[str, str, str]:
160
  - metrics (accuracy + summary)
161
  - issues_text (bullet list)
162
  """
163
- emoji = "βœ…" if parsed["result"] == "PASS" else ("❌" if parsed["result"] == "FAIL" else "⚠️")
164
  verdict = f"{emoji} {parsed['result']}"
165
-
166
  acc_str = f"{parsed['accuracy']}%" if parsed["accuracy"] >= 0 else "N/A"
167
  metrics = f"Accuracy: {acc_str}\n\nSummary: {parsed['summary']}"
168
-
169
  issues_text = "\n".join(f"β€’ {issue}" for issue in parsed["issues"])
170
  return verdict, metrics, issues_text
171
-
172
-
173
  # ---------------------------------------------------------------------------
174
  # MODULE 4 β€” Generation Module (inference call)
175
  # ---------------------------------------------------------------------------
176
  def generate(prompt: str) -> str:
177
- outputs = pipe(prompt, return_full_text=False)
178
  return outputs[0]["generated_text"]
179
-
180
-
181
  # ---------------------------------------------------------------------------
182
  # MODULE 2 β€” Validation & Flow Management Module
183
  # ---------------------------------------------------------------------------
@@ -191,48 +184,45 @@ def validate_and_evaluate(description: str, code: str):
191
  return "", "", "", "⚠️ Please provide a requirements description."
192
  if not code or not code.strip():
193
  return "", "", "", "⚠️ Please provide Python code to evaluate."
194
-
195
  # --- Pre-processing ---
196
  prompt = build_prompt(description, code)
197
-
 
198
  token_count = len(get_tokenizer().encode(prompt))
199
  if token_count > 2048:
200
  return "", "", "", (
201
  f"⚠️ Input too long ({token_count} tokens). "
202
  "Please shorten your description or code and try again."
203
  )
204
-
205
  # --- Generation ---
206
  try:
207
  raw_output = generate(prompt)
208
  except Exception as exc:
209
  return "", "", "", f"❌ Model error: {exc}"
210
-
211
  # --- Output ---
212
  parsed = parse_output(raw_output)
213
  verdict, metrics, issues = format_for_display(parsed)
214
-
215
  return verdict, metrics, issues, "" # empty error = success
216
-
217
-
218
  # ---------------------------------------------------------------------------
219
  # MODULE 1 β€” UI Module (Gradio)
220
  # ---------------------------------------------------------------------------
221
- with gr.Blocks(
222
- title="Python Code Evaluator β€” SE-Group1",
223
- theme=gr.themes.Soft(primary_hue="blue"),
224
- ) as demo:
225
-
226
  gr.Markdown(
227
  """
228
  # 🐍 Python Code Evaluator
229
  **COS60011 β€” SE-Group1** | Powered by Gemma-4 via Hugging Face
230
-
231
  Enter a **requirements description** and your **Python code**.
232
  The system will evaluate whether the code correctly implements the described behaviour.
233
  """
234
  )
235
-
236
  with gr.Row():
237
  with gr.Column(scale=1):
238
  description_input = gr.Textbox(
@@ -247,19 +237,19 @@ with gr.Blocks(
247
  value='def add(a, b):\n return a + b\n',
248
  )
249
  submit_btn = gr.Button("β–Ά Evaluate", variant="primary", size="lg")
250
-
251
  with gr.Column(scale=1):
252
- error_output = gr.Textbox(label="⚠️ Validation Error", visible=True, interactive=False)
253
  verdict_output = gr.Textbox(label="🏁 Verdict", interactive=False, lines=1)
254
  metrics_output = gr.Textbox(label="πŸ“Š Metrics & Summary", interactive=False, lines=4)
255
  issues_output = gr.Textbox(label="πŸ” Issues Found", interactive=False, lines=8)
256
-
257
  submit_btn.click(
258
  fn=validate_and_evaluate,
259
  inputs=[description_input, code_input],
260
  outputs=[verdict_output, metrics_output, issues_output, error_output],
261
  )
262
-
263
  gr.Markdown(
264
  """
265
  ---
@@ -267,6 +257,6 @@ with gr.Blocks(
267
  > Results should be treated as supplementary feedback, not a replacement for unit testing.
268
  """
269
  )
270
-
271
  if __name__ == "__main__":
272
- demo.launch(share=False)
 
1
  """
2
  Python Code Evaluator β€” SE-Group1
3
  COS60011 Technology Design Project
 
4
  Implements the 5-module architecture from the design document:
5
  1. UI Module β€” Gradio web interface
6
  2. Validation & Flow β€” Input validation and routing
 
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
15
  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
 
47
  do_sample=False, # deterministic output
48
  )
49
  return _pipe
50
+
51
+
52
  # ---------------------------------------------------------------------------
53
  # MODULE 3 β€” Pre-processing Module (6-Element Framework)
54
  # ---------------------------------------------------------------------------
 
67
  You are an expert Python code reviewer. Your sole task is to determine whether the
68
  provided Python code correctly implements the behaviour described in the user's
69
  requirements description.
 
70
  ### CONTEXT
71
  Developers sometimes write code that does not fully satisfy the requirements they
72
  were given. You will analyse the semantic relationship between a natural-language
73
  description and a Python code snippet, then produce a structured evaluation report.
 
74
  ### INPUT DATA
75
  **Requirements Description:**
76
  {description.strip()}
 
77
  **Python Code:**
78
  ```python
79
  {code.strip()}
80
  ```
 
81
  ### TASK
82
  1. Read the requirements description carefully.
83
  2. Analyse the Python code line by line.
 
85
  4. Estimate an accuracy percentage (0–100) reflecting how completely the code
86
  matches the description.
87
  5. List any specific requirements that are missing or incorrectly implemented.
 
88
  ### CONSTRAINTS
89
  - Do NOT execute the code.
90
  - Base your evaluation solely on static code analysis and logical reasoning.
91
  - Keep feedback concise, clear, and actionable.
92
  - Your response MUST follow the output format exactly.
 
93
  ### OUTPUT FORMAT
94
  Respond only with the following structure β€” no extra text before or after:
 
95
  RESULT: <PASS or FAIL>
96
  ACCURACY: <integer 0-100>%
97
  SUMMARY: <one sentence overall assessment>
 
103
  <start_of_turn>model
104
  """
105
  return prompt
106
+
107
+
108
  # ---------------------------------------------------------------------------
109
  # MODULE 5 β€” Output Module
110
  # ---------------------------------------------------------------------------
 
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
+
121
  result_match = re.search(r"RESULT:\s*(PASS|FAIL)", raw, re.IGNORECASE)
122
  accuracy_match = re.search(r"ACCURACY:\s*(\d{1,3})%?", raw, re.IGNORECASE)
123
  summary_match = re.search(r"SUMMARY:\s*(.+)", raw, re.IGNORECASE)
124
  issues_match = re.search(r"ISSUES:\s*([\s\S]+)", raw, re.IGNORECASE)
125
+
126
  result = result_match.group(1).upper() if result_match else "UNKNOWN"
127
  accuracy = int(accuracy_match.group(1)) if accuracy_match else -1
128
  summary = summary_match.group(1).strip() if summary_match else "Could not extract summary."
129
+
130
  if issues_match:
131
  raw_issues = issues_match.group(1).strip()
132
  issues = [
 
136
  ]
137
  else:
138
  issues = ["Could not extract issues from model response."]
139
+
140
  return {
141
  "result": result,
142
  "accuracy": accuracy,
 
144
  "issues": issues,
145
  "raw": raw.strip(),
146
  }
147
+
148
+
149
  def format_for_display(parsed: dict) -> tuple[str, str, str]:
150
  """
151
  Converts the parsed dict into three Gradio-friendly strings:
 
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']}"
158
+
159
  acc_str = f"{parsed['accuracy']}%" if parsed["accuracy"] >= 0 else "N/A"
160
  metrics = f"Accuracy: {acc_str}\n\nSummary: {parsed['summary']}"
161
+
162
  issues_text = "\n".join(f"β€’ {issue}" for issue in parsed["issues"])
163
  return verdict, metrics, issues_text
164
+
165
+
166
  # ---------------------------------------------------------------------------
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
+
174
  # ---------------------------------------------------------------------------
175
  # MODULE 2 β€” Validation & Flow Management Module
176
  # ---------------------------------------------------------------------------
 
184
  return "", "", "", "⚠️ Please provide a requirements description."
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 "", "", "", (
195
  f"⚠️ Input too long ({token_count} tokens). "
196
  "Please shorten your description or code and try again."
197
  )
198
+
199
  # --- Generation ---
200
  try:
201
  raw_output = generate(prompt)
202
  except Exception as exc:
203
  return "", "", "", f"❌ Model error: {exc}"
204
+
205
  # --- Output ---
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
  """
224
  )
225
+
226
  with gr.Row():
227
  with gr.Column(scale=1):
228
  description_input = gr.Textbox(
 
237
  value='def add(a, b):\n return a + b\n',
238
  )
239
  submit_btn = gr.Button("β–Ά Evaluate", variant="primary", size="lg")
240
+
241
  with gr.Column(scale=1):
242
+ error_output = gr.Textbox(label="⚠️ Validation Error", visible=True, interactive=False)
243
  verdict_output = gr.Textbox(label="🏁 Verdict", interactive=False, lines=1)
244
  metrics_output = gr.Textbox(label="πŸ“Š Metrics & Summary", interactive=False, lines=4)
245
  issues_output = gr.Textbox(label="πŸ” Issues Found", interactive=False, lines=8)
246
+
247
  submit_btn.click(
248
  fn=validate_and_evaluate,
249
  inputs=[description_input, code_input],
250
  outputs=[verdict_output, metrics_output, issues_output, error_output],
251
  )
252
+
253
  gr.Markdown(
254
  """
255
  ---
 
257
  > Results should be treated as supplementary feedback, not a replacement for unit testing.
258
  """
259
  )
260
+
261
  if __name__ == "__main__":
262
+ demo.launch(share=False, theme=gr.themes.Soft(primary_hue="blue"))