alphaprep's picture
Update app.py
0c9965a verified
import gradio as gr
from transformers import AutoModelForSequenceClassification, AutoTokenizer
import torch
import numpy as np
# -------------------------------
# Load model and tokenizer
# -------------------------------
MODEL_NAME = "JacobLinCool/IELTS_essay_scoring_safetensors"
model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model.eval()
# -------------------------------
# Scoring + Feedback function
# -------------------------------
def score_essay(essay: str):
if not essay.strip():
return {
"Task Achievement": 0.0,
"Coherence & Cohesion": 0.0,
"Vocabulary": 0.0,
"Grammar": 0.0,
"Overall": 0.0,
"Feedback": "Please write an essay to get a score."
}
# Tokenize input
inputs = tokenizer(
essay,
return_tensors="pt",
truncation=True,
max_length=512
)
# Model inference
with torch.no_grad():
outputs = model(**inputs)
preds = outputs.logits.squeeze().cpu().numpy()
# -------------------------------
# Refined piecewise scaling
# -------------------------------
scores = preds.copy()
for i in range(len(scores)):
if scores[i] < 4.0: # very weak essays
scores[i] = scores[i]*1.25 + 0.3
elif scores[i] < 6.0: # medium essays
scores[i] = scores[i]*1.1 + 0.2
elif scores[i] < 8.0: # good essays
scores[i] = scores[i]*1.05 + 0.1
else: # very strong essays
scores[i] = scores[i] # keep unchanged
# -------------------------------
# Word count bonus
# -------------------------------
wc = len(essay.split())
if wc >= 250:
scores += 0.3
elif wc >= 200:
scores += 0.15
# -------------------------------
# Clamp and round to 0.5
# -------------------------------
scores = np.clip(scores, 0, 9)
rounded = np.round(scores * 2) / 2
ta, cc, vocab, gram, overall_dummy = rounded # we will compute weighted overall
# -------------------------------
# Weighted overall band
# -------------------------------
overall = 0.3*ta + 0.25*cc + 0.2*vocab + 0.25*gram
overall = np.clip(overall, 0, 9)
overall = np.round(overall * 2) / 2
rounded[-1] = overall # replace last element
labels = ["Task Achievement", "Coherence & Cohesion", "Vocabulary", "Grammar", "Overall"]
# -------------------------------
# Dynamic mini feedback
# -------------------------------
feedback_lines = []
if ta < 5:
feedback_lines.append("Task: Ideas are underdeveloped; give examples and elaboration.")
if cc < 5:
feedback_lines.append("Coherence: Improve transitions; use connectors like 'however', 'moreover'.")
if vocab < 5:
feedback_lines.append("Vocabulary: Use a wider range of words and avoid repetition.")
if gram < 5:
feedback_lines.append("Grammar: Check articles, plurals, tenses, and sentence structures.")
if overall >= 5:
feedback_lines.append("Overall: Good attempt! Refine grammar and vocabulary to increase your band.")
feedback = "\n".join(feedback_lines[:4]) # max 4 lines
result = {label: float(score) for label, score in zip(labels, rounded)}
result["Feedback"] = feedback
return result
# -------------------------------
# Gradio UI
# -------------------------------
with gr.Blocks() as demo:
gr.Markdown("## 📝 Refined Automated IELTS Writing Scorer")
gr.Markdown(
"Paste your IELTS Task 2 essay below. "
"The system estimates band scores with mini feedback."
)
essay_input = gr.Textbox(
lines=12,
placeholder="Paste your IELTS essay here..."
)
score_output = gr.JSON(label="Estimated IELTS Band Scores + Feedback")
submit_btn = gr.Button("Score Essay")
submit_btn.click(
fn=score_essay,
inputs=essay_input,
outputs=score_output
)
gr.Markdown(
"⚠️ Note: AI-based estimator; not an official IELTS score."
)
# -------------------------------
# Launch app
# -------------------------------
demo.launch()