Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,20 +14,20 @@ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
|
| 14 |
model.eval()
|
| 15 |
|
| 16 |
# -------------------------------
|
| 17 |
-
# Scoring function
|
| 18 |
# -------------------------------
|
| 19 |
def score_essay(essay: str):
|
| 20 |
-
|
| 21 |
-
if not essay or not essay.strip():
|
| 22 |
return {
|
| 23 |
"Task Achievement": 0.0,
|
| 24 |
"Coherence & Cohesion": 0.0,
|
| 25 |
"Vocabulary": 0.0,
|
| 26 |
"Grammar": 0.0,
|
| 27 |
"Overall": 0.0,
|
|
|
|
| 28 |
}
|
| 29 |
|
| 30 |
-
# Tokenize input
|
| 31 |
inputs = tokenizer(
|
| 32 |
essay,
|
| 33 |
return_tensors="pt",
|
|
@@ -39,45 +39,79 @@ def score_essay(essay: str):
|
|
| 39 |
with torch.no_grad():
|
| 40 |
outputs = model(**inputs)
|
| 41 |
|
| 42 |
-
# Raw logits from the model
|
| 43 |
preds = outputs.logits.squeeze().cpu().numpy()
|
| 44 |
|
| 45 |
# -------------------------------
|
| 46 |
-
#
|
| 47 |
# -------------------------------
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
rounded = np.round(scores * 2) / 2
|
| 53 |
|
| 54 |
-
|
| 55 |
-
word_count = len(essay.split())
|
| 56 |
-
if word_count < 150:
|
| 57 |
-
rounded -= 1.0
|
| 58 |
-
elif word_count < 250:
|
| 59 |
-
rounded -= 0.5
|
| 60 |
|
| 61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
|
| 63 |
-
labels = [
|
| 64 |
-
"Task Achievement",
|
| 65 |
-
"Coherence & Cohesion",
|
| 66 |
-
"Vocabulary",
|
| 67 |
-
"Grammar",
|
| 68 |
-
"Overall"
|
| 69 |
-
]
|
| 70 |
|
| 71 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
|
| 73 |
# -------------------------------
|
| 74 |
# Gradio UI
|
| 75 |
# -------------------------------
|
| 76 |
with gr.Blocks() as demo:
|
| 77 |
-
gr.Markdown("## 📝 Automated IELTS Writing Scorer")
|
| 78 |
gr.Markdown(
|
| 79 |
"Paste your IELTS Task 2 essay below. "
|
| 80 |
-
"The system
|
| 81 |
)
|
| 82 |
|
| 83 |
essay_input = gr.Textbox(
|
|
@@ -85,10 +119,9 @@ with gr.Blocks() as demo:
|
|
| 85 |
placeholder="Paste your IELTS essay here..."
|
| 86 |
)
|
| 87 |
|
| 88 |
-
score_output = gr.JSON(label="Estimated IELTS Band Scores")
|
| 89 |
|
| 90 |
submit_btn = gr.Button("Score Essay")
|
| 91 |
-
|
| 92 |
submit_btn.click(
|
| 93 |
fn=score_essay,
|
| 94 |
inputs=essay_input,
|
|
@@ -96,7 +129,7 @@ with gr.Blocks() as demo:
|
|
| 96 |
)
|
| 97 |
|
| 98 |
gr.Markdown(
|
| 99 |
-
"⚠️
|
| 100 |
)
|
| 101 |
|
| 102 |
# -------------------------------
|
|
|
|
| 14 |
model.eval()
|
| 15 |
|
| 16 |
# -------------------------------
|
| 17 |
+
# Scoring + Feedback function
|
| 18 |
# -------------------------------
|
| 19 |
def score_essay(essay: str):
|
| 20 |
+
if not essay.strip():
|
|
|
|
| 21 |
return {
|
| 22 |
"Task Achievement": 0.0,
|
| 23 |
"Coherence & Cohesion": 0.0,
|
| 24 |
"Vocabulary": 0.0,
|
| 25 |
"Grammar": 0.0,
|
| 26 |
"Overall": 0.0,
|
| 27 |
+
"Feedback": "Please write an essay to get a score."
|
| 28 |
}
|
| 29 |
|
| 30 |
+
# Tokenize input
|
| 31 |
inputs = tokenizer(
|
| 32 |
essay,
|
| 33 |
return_tensors="pt",
|
|
|
|
| 39 |
with torch.no_grad():
|
| 40 |
outputs = model(**inputs)
|
| 41 |
|
|
|
|
| 42 |
preds = outputs.logits.squeeze().cpu().numpy()
|
| 43 |
|
| 44 |
# -------------------------------
|
| 45 |
+
# Refined piecewise scaling
|
| 46 |
# -------------------------------
|
| 47 |
+
scores = preds.copy()
|
| 48 |
+
for i in range(len(scores)):
|
| 49 |
+
if scores[i] < 4.0: # very weak essays
|
| 50 |
+
scores[i] = scores[i]*1.25 + 0.3
|
| 51 |
+
elif scores[i] < 6.0: # medium essays
|
| 52 |
+
scores[i] = scores[i]*1.1 + 0.2
|
| 53 |
+
elif scores[i] < 8.0: # good essays
|
| 54 |
+
scores[i] = scores[i]*1.05 + 0.1
|
| 55 |
+
else: # very strong essays
|
| 56 |
+
scores[i] = scores[i] # keep unchanged
|
| 57 |
|
| 58 |
+
# -------------------------------
|
| 59 |
+
# Word count bonus
|
| 60 |
+
# -------------------------------
|
| 61 |
+
wc = len(essay.split())
|
| 62 |
+
if wc >= 250:
|
| 63 |
+
scores += 0.3
|
| 64 |
+
elif wc >= 200:
|
| 65 |
+
scores += 0.15
|
| 66 |
+
|
| 67 |
+
# -------------------------------
|
| 68 |
+
# Clamp and round to 0.5
|
| 69 |
+
# -------------------------------
|
| 70 |
+
scores = np.clip(scores, 0, 9)
|
| 71 |
rounded = np.round(scores * 2) / 2
|
| 72 |
|
| 73 |
+
ta, cc, vocab, gram, overall_dummy = rounded # we will compute weighted overall
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
+
# -------------------------------
|
| 76 |
+
# Weighted overall band
|
| 77 |
+
# -------------------------------
|
| 78 |
+
overall = 0.3*ta + 0.25*cc + 0.2*vocab + 0.25*gram
|
| 79 |
+
overall = np.clip(overall, 0, 9)
|
| 80 |
+
overall = np.round(overall * 2) / 2
|
| 81 |
+
rounded[-1] = overall # replace last element
|
| 82 |
|
| 83 |
+
labels = ["Task Achievement", "Coherence & Cohesion", "Vocabulary", "Grammar", "Overall"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
+
# -------------------------------
|
| 86 |
+
# Dynamic mini feedback
|
| 87 |
+
# -------------------------------
|
| 88 |
+
feedback_lines = []
|
| 89 |
+
|
| 90 |
+
if ta < 5:
|
| 91 |
+
feedback_lines.append("Task: Ideas are underdeveloped; give examples and elaboration.")
|
| 92 |
+
if cc < 5:
|
| 93 |
+
feedback_lines.append("Coherence: Improve transitions; use connectors like 'however', 'moreover'.")
|
| 94 |
+
if vocab < 5:
|
| 95 |
+
feedback_lines.append("Vocabulary: Use a wider range of words and avoid repetition.")
|
| 96 |
+
if gram < 5:
|
| 97 |
+
feedback_lines.append("Grammar: Check articles, plurals, tenses, and sentence structures.")
|
| 98 |
+
if overall >= 5:
|
| 99 |
+
feedback_lines.append("Overall: Good attempt! Refine grammar and vocabulary to increase your band.")
|
| 100 |
+
|
| 101 |
+
feedback = "\n".join(feedback_lines[:4]) # max 4 lines
|
| 102 |
+
|
| 103 |
+
result = {label: float(score) for label, score in zip(labels, rounded)}
|
| 104 |
+
result["Feedback"] = feedback
|
| 105 |
+
return result
|
| 106 |
|
| 107 |
# -------------------------------
|
| 108 |
# Gradio UI
|
| 109 |
# -------------------------------
|
| 110 |
with gr.Blocks() as demo:
|
| 111 |
+
gr.Markdown("## 📝 Refined Automated IELTS Writing Scorer")
|
| 112 |
gr.Markdown(
|
| 113 |
"Paste your IELTS Task 2 essay below. "
|
| 114 |
+
"The system estimates band scores with mini feedback."
|
| 115 |
)
|
| 116 |
|
| 117 |
essay_input = gr.Textbox(
|
|
|
|
| 119 |
placeholder="Paste your IELTS essay here..."
|
| 120 |
)
|
| 121 |
|
| 122 |
+
score_output = gr.JSON(label="Estimated IELTS Band Scores + Feedback")
|
| 123 |
|
| 124 |
submit_btn = gr.Button("Score Essay")
|
|
|
|
| 125 |
submit_btn.click(
|
| 126 |
fn=score_essay,
|
| 127 |
inputs=essay_input,
|
|
|
|
| 129 |
)
|
| 130 |
|
| 131 |
gr.Markdown(
|
| 132 |
+
"⚠️ Note: AI-based estimator; not an official IELTS score."
|
| 133 |
)
|
| 134 |
|
| 135 |
# -------------------------------
|