redc007 commited on
Commit
9c4c110
·
verified ·
1 Parent(s): 1b9608f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +166 -0
app.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from transformers import AutoTokenizer, AutoModelForCausalLM
3
+ import torch
4
+ import json
5
+ import os
6
+ from typing import Dict, Union
7
+
8
+ # --- Model and Instruction Configuration ---
9
+ MODEL_ID = "meta-llama/Llama-3.2-1B-Instruct"
10
+
11
+ SYSTEM_INSTRUCTION = """
12
+ You are a strict grading assistant.
13
+ Return ONLY a JSON object with:
14
+ - accuracy (float 0-10)
15
+ - grade (string A-D)
16
+ - feedback (string)
17
+ """
18
+ # ------------------------------------------
19
+
20
+ # Load Model and Tokenizer once for the entire application
21
+ try:
22
+ print(f"Loading model {MODEL_ID} for Gradio app...")
23
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
24
+ model = AutoModelForCausalLM.from_pretrained(
25
+ MODEL_ID,
26
+ torch_dtype=torch.bfloat16,
27
+ device_map="auto",
28
+ )
29
+ TERMINATORS = [
30
+ tokenizer.eos_token_id,
31
+ tokenizer.convert_tokens_to_ids("<|eot_id|>")
32
+ ]
33
+ MODEL_LOADED = True
34
+ except Exception as e:
35
+ print(f"Error loading model or tokenizer: {e}")
36
+ print("Gradio will run, but the grading function will return an error.")
37
+ MODEL_LOADED = False
38
+ tokenizer, model, TERMINATORS = None, None, None
39
+
40
+
41
+ def grade_response(student_response: str) -> Union[Dict, str]:
42
+ """
43
+ Core grading function (same as before)
44
+ """
45
+ if not MODEL_LOADED:
46
+ return {"accuracy": 0.0, "grade": "Error", "feedback": "Model failed to load. Check console for details."}
47
+
48
+ # 1. Construct the Message List
49
+ messages = [
50
+ {"role": "system", "content": SYSTEM_INSTRUCTION},
51
+ {"role": "user", "content": f"Student response to grade: '{student_response}'"},
52
+ ]
53
+
54
+ # 2. Apply Chat Template and Tokenize
55
+ input_ids = tokenizer.apply_chat_template(
56
+ messages,
57
+ add_generation_prompt=True,
58
+ return_tensors="pt"
59
+ ).to(model.device)
60
+
61
+ # 3. Generate the Output
62
+ try:
63
+ output_ids = model.generate(
64
+ input_ids,
65
+ max_new_tokens=200,
66
+ eos_token_id=TERMINATORS,
67
+ do_sample=True,
68
+ temperature=0.5,
69
+ top_p=0.9,
70
+ )
71
+ except Exception as e:
72
+ return {"accuracy": 0.0, "grade": "Error", "feedback": f"Generation error: {e}"}
73
+
74
+ # 4. Decode the Raw Response
75
+ raw_response = tokenizer.decode(
76
+ output_ids[0][input_ids.shape[-1]:],
77
+ skip_special_tokens=True
78
+ ).strip()
79
+
80
+ # 5. Parse the JSON Output
81
+ try:
82
+ start_index = raw_response.find('{')
83
+ end_index = raw_response.rfind('}') + 1
84
+ json_string = raw_response[start_index:end_index]
85
+ return json.loads(json_string)
86
+
87
+ except json.JSONDecodeError:
88
+ # If parsing fails, return a structured error response
89
+ return {"accuracy": 0.0, "grade": "Error", "feedback": f"JSON Decode Error. Raw: {raw_response[:200]}..."}
90
+
91
+ # --- Gradio Wrapper Function ---
92
+
93
+ def gradio_grade_wrapper(student_response: str) -> tuple[float, str, str]:
94
+ """
95
+ Wraps the core grading function to match the required Gradio outputs.
96
+ """
97
+ result = grade_response(student_response)
98
+
99
+ # Check if the result is a dictionary (the expected structured output)
100
+ if isinstance(result, dict):
101
+ # Gradio outputs: (accuracy, grade, feedback)
102
+ return (
103
+ result.get("accuracy", 0.0),
104
+ result.get("grade", "N/A"),
105
+ result.get("feedback", "No feedback generated.")
106
+ )
107
+ else:
108
+ # Should not happen if error handling in grade_response is correct,
109
+ # but here for extreme robustness.
110
+ return (0.0, "ERROR", str(result))
111
+
112
+
113
+ # --- Gradio Interface Definition ---
114
+
115
+ with gr.Blocks(theme=gr.themes.Soft(), title="LLM Essay Grader") as demo:
116
+ gr.Markdown("# 📝 LLM Essay Grading Assistant (Llama-3.2-1B-Instruct)")
117
+ gr.Markdown(
118
+ "Enter a student's response below to receive an automated grade, accuracy score, and feedback "
119
+ "from the Llama-3.2-1B-Instruct model."
120
+ )
121
+
122
+ # Input Component
123
+ with gr.Row():
124
+ student_input = gr.Textbox(
125
+ label="Student Response to Grade",
126
+ placeholder="E.g., 'The main causes of the World War 2 were economic depression and poor leadership.'",
127
+ lines=5,
128
+ scale=3
129
+ )
130
+ grade_button = gr.Button("Submit for Grading", scale=1, variant="primary")
131
+
132
+ gr.Markdown("---")
133
+ gr.Markdown("## Grading Results")
134
+
135
+ # Output Components arranged in a Row for visual clarity
136
+ with gr.Row():
137
+ accuracy_output = gr.Number(label="Accuracy (0-10)", interactive=False, precision=1)
138
+ grade_output = gr.Textbox(label="Grade (A-D)", interactive=False)
139
+
140
+ feedback_output = gr.Textbox(
141
+ label="Detailed Feedback",
142
+ interactive=False,
143
+ lines=4,
144
+ max_lines=10
145
+ )
146
+
147
+ # Event Listener: Connect the button click to the wrapper function
148
+ grade_button.click(
149
+ fn=gradio_grade_wrapper,
150
+ inputs=[student_input],
151
+ outputs=[accuracy_output, grade_output, feedback_output]
152
+ )
153
+
154
+ # Add Examples
155
+ gr.Examples(
156
+ examples=[
157
+ ["The Earth is a cube and its main moon is Mars, which proves that gravity is fake."],
158
+ ["A proper noun is a name used to designate a single, specific person, place, or thing, and is always capitalized."],
159
+ ["The two main drivers of climate change are the burning of fossil fuels (releasing greenhouse gases) and deforestation."],
160
+ ],
161
+ inputs=student_input,
162
+ )
163
+
164
+ # Launch the Gradio App
165
+ if __name__ == "__main__":
166
+ demo.launch()