next-metro / app.py
bgaultier's picture
Update app.py
e9f7776 verified
import gradio as gr
import ast
def grade(student_code):
feedback = []
grade = 10
try:
tree = ast.parse(student_code)
# Initial flags
wifi_connected = False
http_request_used = False
json_parsed = False
time_sliced = False
led_setup = False
led_logic = False
for node in ast.walk(tree):
# WiFi connection using station mode
if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute):
if node.func.attr == "connect":
wifi_connected = True
# Use of urequests or requests.get
if isinstance(node, ast.Import) or isinstance(node, ast.ImportFrom):
for alias in node.names:
if alias.name == "urequests" or alias.name == "requests":
http_request_used = True
if isinstance(node, ast.Call):
if hasattr(node.func, 'attr') and node.func.attr == "get":
http_request_used = True
# Use of json() method
if hasattr(node.func, 'attr') and node.func.attr == "json":
json_parsed = True
# Check for slicing used to remove date from string
if isinstance(node, ast.Subscript) and isinstance(node.slice, ast.Slice):
time_sliced = True
# Check red LED setup on pin 21
if isinstance(node, ast.Assign):
if isinstance(node.value, ast.Call) and hasattr(node.value.func, 'attr'):
if node.value.func.attr == "Pin":
args = node.value.args
if len(args) >= 2 and isinstance(args[0], ast.Constant):
if args[0].value == 21:
led_setup = True
# Check comparison for metro < 2 min
if isinstance(node, ast.Compare):
for comparator in node.comparators:
if isinstance(comparator, ast.Constant) and comparator.value == 2:
led_logic = True
if not wifi_connected:
feedback.append("⛔️ WiFi connection not detected (-2 pts).")
grade -= 2
else:
feedback.append("✅ WiFi connection established (+2 pts).")
if not http_request_used:
feedback.append("⛔️ HTTP GET request not detected (-2 pts).")
grade -= 2
else:
feedback.append("✅ HTTP GET request used (+2 pts).")
if not json_parsed:
feedback.append("⛔️ JSON response not parsed (-1 pt).")
grade -= 1
else:
feedback.append("✅ JSON response parsed (+1 pt).")
if not time_sliced:
feedback.append("⛔️ Time string not sliced to remove date (-1 pt).")
grade -= 1
else:
feedback.append("✅ Time string slicing detected (+1 pt).")
if not led_setup:
feedback.append("⛔️ Red LED not configured on pin 21 (-2 pts).")
grade -= 2
else:
feedback.append("✅ Red LED setup detected on pin 21 (+2 pts).")
if not led_logic:
feedback.append("⛔️ No condition found to check if metro is arriving in < 2 minutes (-2 pts).")
grade -= 2
else:
feedback.append("✅ Metro arrival condition (< 2 min) found (+2 pts).")
except Exception as e:
feedback = [f"⛔️ Error parsing code: {e}"]
grade = 0
grade = max(0, grade)
grade_str = f"{grade}/10"
feedback_str = "\n".join(feedback)
return grade_str, feedback_str
# Interface Gradio seulement si le script est exécuté directement
if __name__ == "__main__":
with gr.Blocks(gr.themes.Default(primary_hue="cyan")) as demo:
with gr.Row():
instructions = gr.Markdown("""
## Instructions
1. Based on the examples you've seen so far, write a MicroPython code that follows the instructions above.
2. You can use the [Vittascience simulator](https://fr.vittascience.com/esp32/?mode=code&console=bottom&toolbox=scratch&simu=1&board=basic-esp32) to test your code.
2. Click the "Grade" button to get a grade and feedback.
3. Make sure your code is well-structured and efficient.
4. When you're happy with your code, please upload your solution below to get graded.
6. Good luck!
""", container=False)
code = gr.Code(label="MicroPython code", language="python", value='import time\nimport network\nimport requests\n# Your code here', lines=24)
with gr.Row():
feedback_output = gr.Textbox(label="Feedback", value="Click on the 'Grade' button to get feedback", interactive=False, scale=4)
grade_output = gr.Textbox(label="Grade", interactive=False, value="0/10", scale=1)
grade_btn = gr.Button("Grade", variant="primary")
grade_btn.click(fn=grade, inputs=code, outputs=[grade_output, feedback_output], api_name="grade")
demo.launch(show_error=False, allowed_paths=["/assets", "assets"], show_api=False)