Spaces:
Sleeping
Sleeping
Initial commit for HF Spaces
Browse files- .dockerignore +10 -0
- .gitattributes +6 -0
- .gitignore +9 -0
- README.md +4 -6
- adapters/env.py +17 -0
- adapters/external/part1_runner.py +24 -0
- adapters/external/part2_runner.py +17 -0
- app/app.py +91 -0
- core/config.py +36 -0
- core/formatting.py +28 -0
- core/logging_config.py +24 -0
- core/pipeline.py +17 -0
- requirements.txt +14 -0
- tests/test_smoke.py +10 -0
- utils/files.py +13 -0
- vendors/part1/Workflow.md +28 -0
- vendors/part1/__init__.py +0 -0
- vendors/part1/display_report.py +63 -0
- vendors/part1/final_state.json +9 -0
- vendors/part1/main.py +81 -0
- vendors/part1/model.py +5 -0
- vendors/part1/nodes.py +436 -0
- vendors/part1/state.py +12 -0
- vendors/part1/task_image.png +3 -0
- vendors/part1/workflow.py +29 -0
- vendors/part2/Workflow.md +28 -0
- vendors/part2/__init__.py +0 -0
- vendors/part2/display_report.py +63 -0
- vendors/part2/final_state.json +9 -0
- vendors/part2/main.py +49 -0
- vendors/part2/model.py +5 -0
- vendors/part2/nodes.py +434 -0
- vendors/part2/state.py +12 -0
- vendors/part2/workflow.py +29 -0
.dockerignore
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
IELTS-Assistant/
|
| 2 |
+
pycache/
|
| 3 |
+
*.pyc
|
| 4 |
+
.env
|
| 5 |
+
logs/
|
| 6 |
+
*.spec
|
| 7 |
+
build/
|
| 8 |
+
dist/
|
| 9 |
+
tmp/
|
| 10 |
+
.gitignore
|
.gitattributes
CHANGED
|
@@ -33,3 +33,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
*.gif filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
*.webp filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
*.pdf filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
IELTS-Assistant/
|
| 2 |
+
pycache/
|
| 3 |
+
*.pyc
|
| 4 |
+
.env
|
| 5 |
+
logs/
|
| 6 |
+
*.spec
|
| 7 |
+
build/
|
| 8 |
+
dist/
|
| 9 |
+
tmp/
|
README.md
CHANGED
|
@@ -1,13 +1,11 @@
|
|
| 1 |
---
|
| 2 |
title: IELTS Writing Assistant
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
colorTo: pink
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
app_file: app.py
|
| 9 |
pinned: false
|
| 10 |
license: mit
|
| 11 |
---
|
| 12 |
-
|
| 13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
title: IELTS Writing Assistant
|
| 3 |
+
emoji: ✍️
|
| 4 |
+
colorFrom: indigo
|
| 5 |
colorTo: pink
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 4.44.0
|
| 8 |
+
app_file: app/ui.py # <— point to your file
|
| 9 |
pinned: false
|
| 10 |
license: mit
|
| 11 |
---
|
|
|
|
|
|
adapters/env.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from contextlib import contextmanager
|
| 3 |
+
|
| 4 |
+
@contextmanager
|
| 5 |
+
def temp_env(var: str, value: str | None):
|
| 6 |
+
old = os.environ.get(var)
|
| 7 |
+
try:
|
| 8 |
+
if value is None:
|
| 9 |
+
os.environ.pop(var, None)
|
| 10 |
+
else:
|
| 11 |
+
os.environ[var] = value
|
| 12 |
+
yield
|
| 13 |
+
finally:
|
| 14 |
+
if old is None:
|
| 15 |
+
os.environ.pop(var, None)
|
| 16 |
+
else:
|
| 17 |
+
os.environ[var] = old
|
adapters/external/part1_runner.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Optional
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
import logging
|
| 4 |
+
from inspect import signature
|
| 5 |
+
from vendors.part1.main import run_ielts_part1_agent
|
| 6 |
+
from utils.env import temp_env
|
| 7 |
+
|
| 8 |
+
logger = logging.getLogger(__name__)
|
| 9 |
+
|
| 10 |
+
def run_part1(image_path: str | Path, essay_text: str, api_key: Optional[str] = None) -> str:
|
| 11 |
+
image_path = Path(image_path)
|
| 12 |
+
if not image_path.exists():
|
| 13 |
+
raise FileNotFoundError(f"Image not found: {image_path}")
|
| 14 |
+
|
| 15 |
+
logger.info("Running Part1 agent")
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
if "api_key" in signature(run_ielts_part1_agent).parameters and api_key:
|
| 19 |
+
return str(run_ielts_part1_agent(str(image_path), essay_text, api_key=api_key))
|
| 20 |
+
except Exception:
|
| 21 |
+
pass
|
| 22 |
+
|
| 23 |
+
with temp_env("GOOGLE_API_KEY", api_key):
|
| 24 |
+
return str(run_ielts_part1_agent(str(image_path), essay_text))
|
adapters/external/part2_runner.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from inspect import signature
|
| 3 |
+
from typing import Optional
|
| 4 |
+
from vendors.part2.main import run_ielts_part2_agent
|
| 5 |
+
from utils.env import temp_env
|
| 6 |
+
|
| 7 |
+
logger = logging.getLogger(__name__)
|
| 8 |
+
|
| 9 |
+
def run_part2(question: str, essay_text: str, api_key: Optional[str] = None) -> str:
|
| 10 |
+
logger.info("Running Part2 agent")
|
| 11 |
+
try:
|
| 12 |
+
if "api_key" in signature(run_ielts_part2_agent).parameters and api_key:
|
| 13 |
+
return str(run_ielts_part2_agent(question, essay_text, api_key=api_key))
|
| 14 |
+
except Exception:
|
| 15 |
+
pass
|
| 16 |
+
with temp_env("GOOGLE_API_KEY", api_key):
|
| 17 |
+
return str(run_ielts_part2_agent(question, essay_text))
|
app/app.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from core.config import get_api_key, set_api_key, ENV_VAR_NAME, in_hf_spaces
|
| 4 |
+
from core.pipeline import analyze_part1, analyze_part2
|
| 5 |
+
from core.logging_config import configure_logging
|
| 6 |
+
import logging
|
| 7 |
+
|
| 8 |
+
configure_logging()
|
| 9 |
+
logger = logging.getLogger(__name__)
|
| 10 |
+
|
| 11 |
+
session_key = gr.State("")
|
| 12 |
+
|
| 13 |
+
def _effective_key(user_input_key: str | None) -> str | None:
|
| 14 |
+
"""Priority: user input (session) > env (local or Space Secret)."""
|
| 15 |
+
k = (user_input_key or "").strip()
|
| 16 |
+
if k:
|
| 17 |
+
return k
|
| 18 |
+
return get_api_key()
|
| 19 |
+
|
| 20 |
+
def on_save_key_local(key: str):
|
| 21 |
+
if in_hf_spaces():
|
| 22 |
+
return gr.update(value="**On Spaces, keys are not stored. Use the key box per session or set a Space Secret.**")
|
| 23 |
+
set_api_key(key)
|
| 24 |
+
return gr.update(value="**Saved!** Your API key is now in .env.")
|
| 25 |
+
|
| 26 |
+
def on_store_key_session(key: str):
|
| 27 |
+
session_key.value = (key or "").strip()
|
| 28 |
+
return gr.update(value="**Saved for this session.**")
|
| 29 |
+
|
| 30 |
+
def on_analyze_part1(image_path, essay, key_box):
|
| 31 |
+
key = _effective_key(key_box or session_key.value)
|
| 32 |
+
if not key:
|
| 33 |
+
raise RuntimeError(f"Provide {ENV_VAR_NAME} in Settings.")
|
| 34 |
+
if not image_path:
|
| 35 |
+
raise ValueError("Please upload the Task 1 image/chart/graph.")
|
| 36 |
+
if not essay or len(essay.strip()) < 30:
|
| 37 |
+
raise ValueError("Please paste your full Task 1 response (≥30 chars).")
|
| 38 |
+
logger.info("UI: analyze_part1 invoked")
|
| 39 |
+
return analyze_part1(image_path, essay, api_key=key)
|
| 40 |
+
|
| 41 |
+
def on_analyze_part2(question, essay, key_box):
|
| 42 |
+
key = _effective_key(key_box or session_key.value)
|
| 43 |
+
if not key:
|
| 44 |
+
raise RuntimeError(f"Provide {ENV_VAR_NAME} in Settings.")
|
| 45 |
+
if not question or len(question.strip()) < 10:
|
| 46 |
+
raise ValueError("Please paste the Task 2 question.")
|
| 47 |
+
if not essay or len(essay.strip()) < 30:
|
| 48 |
+
raise ValueError("Please paste your full Task 2 essay (≥30 chars).")
|
| 49 |
+
logger.info("UI: analyze_part2 invoked")
|
| 50 |
+
return analyze_part2(question, essay, api_key=key)
|
| 51 |
+
|
| 52 |
+
with gr.Blocks(title="IELTS Writing Assistant", fill_height=True) as demo:
|
| 53 |
+
gr.Markdown("# IELTS Writing Assistant\nLocal-first app using your existing agents.")
|
| 54 |
+
|
| 55 |
+
with gr.Tab("Task 1"):
|
| 56 |
+
with gr.Row():
|
| 57 |
+
image = gr.Image(type="filepath", label="Task 1 Image/Chart/Graph")
|
| 58 |
+
essay1 = gr.Textbox(label="Your Task 1 Essay", lines=18)
|
| 59 |
+
with gr.Row():
|
| 60 |
+
btn1 = gr.Button("Analyze", variant="primary")
|
| 61 |
+
clear1 = gr.Button("Clear")
|
| 62 |
+
out1 = gr.Markdown(label="Feedback")
|
| 63 |
+
|
| 64 |
+
with gr.Tab("Task 2"):
|
| 65 |
+
question = gr.Textbox(label="Task 2 Question", lines=4)
|
| 66 |
+
essay2 = gr.Textbox(label="Your Task 2 Essay", lines=18)
|
| 67 |
+
with gr.Row():
|
| 68 |
+
btn2 = gr.Button("Analyze", variant="primary")
|
| 69 |
+
clear2 = gr.Button("Clear")
|
| 70 |
+
out2 = gr.Markdown(label="Feedback")
|
| 71 |
+
|
| 72 |
+
with gr.Tab("Settings"):
|
| 73 |
+
gr.Markdown(
|
| 74 |
+
f"Set your API key. Locally, you can save to `.env`. On Spaces, use **Session Key** or set a **Space Secret** `{ENV_VAR_NAME}`."
|
| 75 |
+
)
|
| 76 |
+
key_box = gr.Textbox(label=f"{ENV_VAR_NAME}", type="password", placeholder="sk-...")
|
| 77 |
+
save_local = gr.Button("Save to .env (Local Only)")
|
| 78 |
+
save_session = gr.Button("Save Session Key")
|
| 79 |
+
status = gr.Markdown("")
|
| 80 |
+
|
| 81 |
+
btn1.click(on_analyze_part1, inputs=[image, essay1, key_box], outputs=[out1])
|
| 82 |
+
clear1.click(lambda: (None, "", ""), outputs=[image, essay1, out1])
|
| 83 |
+
|
| 84 |
+
btn2.click(on_analyze_part2, inputs=[question, essay2, key_box], outputs=[out2])
|
| 85 |
+
clear2.click(lambda: ("", ""), outputs=[question, out2])
|
| 86 |
+
|
| 87 |
+
save_local.click(on_save_key_local, inputs=[key_box], outputs=[status])
|
| 88 |
+
save_session.click(on_store_key_session, inputs=[key_box], outputs=[status])
|
| 89 |
+
|
| 90 |
+
if __name__ == "__main__":
|
| 91 |
+
demo.queue().launch()
|
core/config.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
|
| 5 |
+
ENV_PATH = Path(".env")
|
| 6 |
+
ENV_VAR_NAME = "GOOGLE_API_KEY"
|
| 7 |
+
|
| 8 |
+
load_dotenv(dotenv_path=ENV_PATH, override=False)
|
| 9 |
+
|
| 10 |
+
def in_hf_spaces() -> bool:
|
| 11 |
+
return bool(os.getenv("SPACE_ID"))
|
| 12 |
+
|
| 13 |
+
def get_api_key() -> str | None:
|
| 14 |
+
return os.getenv(ENV_VAR_NAME)
|
| 15 |
+
|
| 16 |
+
def ensure_env_file() -> None:
|
| 17 |
+
if not ENV_PATH.exists():
|
| 18 |
+
ENV_PATH.write_text("")
|
| 19 |
+
|
| 20 |
+
def set_api_key(value: str, var_name: str = ENV_VAR_NAME) -> None:
|
| 21 |
+
if in_hf_spaces():
|
| 22 |
+
return
|
| 23 |
+
value = (value or "").strip()
|
| 24 |
+
ensure_env_file()
|
| 25 |
+
lines = ENV_PATH.read_text().splitlines()
|
| 26 |
+
out, found = [], False
|
| 27 |
+
for line in lines:
|
| 28 |
+
if line.strip().startswith(f"{var_name}="):
|
| 29 |
+
out.append(f"{var_name}={value}")
|
| 30 |
+
found = True
|
| 31 |
+
else:
|
| 32 |
+
out.append(line)
|
| 33 |
+
if not found:
|
| 34 |
+
out.append(f"{var_name}={value}")
|
| 35 |
+
ENV_PATH.write_text("\n".join(out) + "\n")
|
| 36 |
+
os.environ[var_name] = value
|
core/formatting.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
import re
|
| 3 |
+
|
| 4 |
+
_ANSI_RE = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
|
| 5 |
+
|
| 6 |
+
def _strip_ansi(s: str) -> str:
|
| 7 |
+
return _ANSI_RE.sub("", s)
|
| 8 |
+
|
| 9 |
+
def _normalize_agent_text_to_md(s: str) -> str:
|
| 10 |
+
s = _strip_ansi(s)
|
| 11 |
+
|
| 12 |
+
s = re.sub(r"(?im)\s*-{3,}\s*([^-\n][^\n]{0,80}?)\s*-{3,}\s*", r"\n## \1\n\n", s)
|
| 13 |
+
s = re.sub(r"(?m)^(\d+\.\s+[^:\n]+:)", r"**\1**", s)
|
| 14 |
+
s = re.sub(r"\n{3,}", "\n\n", s)
|
| 15 |
+
|
| 16 |
+
return s.strip()
|
| 17 |
+
|
| 18 |
+
def format_success(title: str, body_md_or_text: str) -> str:
|
| 19 |
+
body = _normalize_agent_text_to_md(body_md_or_text)
|
| 20 |
+
return f"# {title}\n\n{body}"
|
| 21 |
+
|
| 22 |
+
def format_error(err: Exception | str) -> str:
|
| 23 |
+
msg = str(err)
|
| 24 |
+
return (
|
| 25 |
+
"## ❌ Error\n\n"
|
| 26 |
+
f"{msg}\n\n"
|
| 27 |
+
"> Tip: Check your API key in Settings, and verify your inputs."
|
| 28 |
+
)
|
core/logging_config.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from logging.handlers import RotatingFileHandler
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
LOG_PATH = Path("logs")
|
| 6 |
+
LOG_PATH.mkdir(exist_ok=True)
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def configure_logging(level: int = logging.INFO) -> None:
|
| 10 |
+
logger = logging.getLogger()
|
| 11 |
+
logger.setLevel(level)
|
| 12 |
+
|
| 13 |
+
fmt = logging.Formatter(
|
| 14 |
+
fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
|
| 15 |
+
datefmt="%Y-%m-%d %H:%M:%S",
|
| 16 |
+
)
|
| 17 |
+
|
| 18 |
+
ch = logging.StreamHandler()
|
| 19 |
+
ch.setFormatter(fmt)
|
| 20 |
+
logger.addHandler(ch)
|
| 21 |
+
|
| 22 |
+
fh = RotatingFileHandler(LOG_PATH / "app.log", maxBytes=1_000_000, backupCount=3)
|
| 23 |
+
fh.setFormatter(fmt)
|
| 24 |
+
logger.addHandler(fh)
|
core/pipeline.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from adapters.external.part1_runner import run_part1
|
| 4 |
+
from adapters.external.part2_runner import run_part2
|
| 5 |
+
from core.formatting import format_success
|
| 6 |
+
|
| 7 |
+
logger = logging.getLogger(__name__)
|
| 8 |
+
|
| 9 |
+
def analyze_part1(image_path: str | Path, essay_text: str, api_key: str | None = None) -> str:
|
| 10 |
+
logger.info("Pipeline: analyze_part1")
|
| 11 |
+
result_md = run_part1(image_path, essay_text, api_key=api_key)
|
| 12 |
+
return format_success("IELTS Writing Task 1 — Feedback", result_md)
|
| 13 |
+
|
| 14 |
+
def analyze_part2(question: str, essay_text: str, api_key: str | None = None) -> str:
|
| 15 |
+
logger.info("Pipeline: analyze_part2")
|
| 16 |
+
result_md = run_part2(question, essay_text, api_key=api_key)
|
| 17 |
+
return format_success("IELTS Writing Task 2 — Feedback", result_md)
|
requirements.txt
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio==5.49.1
|
| 2 |
+
gradio-client==1.13.3
|
| 3 |
+
python-dotenv==1.0.1
|
| 4 |
+
Pillow==10.4.0
|
| 5 |
+
rich==13.7.1
|
| 6 |
+
|
| 7 |
+
langchain-community==0.3.30
|
| 8 |
+
langgraph==0.6.7
|
| 9 |
+
ipython==8.37.0
|
| 10 |
+
typing-extensions==4.15.0
|
| 11 |
+
langchain-core==0.3.76
|
| 12 |
+
pydantic==2.11.9
|
| 13 |
+
requests==2.32.5
|
| 14 |
+
langchain-google-genai==2.1.12
|
tests/test_smoke.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from core.config import set_api_key, get_api_key
|
| 2 |
+
|
| 3 |
+
def test_env_setter(tmp_path, monkeypatch):
|
| 4 |
+
monkeypatch.chdir(tmp_path)
|
| 5 |
+
from importlib import reload
|
| 6 |
+
import core.config as cfg
|
| 7 |
+
reload(cfg)
|
| 8 |
+
assert cfg.get_api_key() is None
|
| 9 |
+
cfg.set_api_key("abc")
|
| 10 |
+
assert cfg.get_api_key() == "abc"
|
utils/files.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import tempfile
|
| 3 |
+
from contextlib import contextmanager
|
| 4 |
+
|
| 5 |
+
@contextmanager
|
| 6 |
+
def temp_copy(path: str | Path):
|
| 7 |
+
src = Path(path)
|
| 8 |
+
if not src.exists():
|
| 9 |
+
raise FileNotFoundError(src)
|
| 10 |
+
with tempfile.TemporaryDirectory() as td:
|
| 11 |
+
dst = Path(td) / src.name
|
| 12 |
+
dst.write_bytes(src.read_bytes())
|
| 13 |
+
yield dst
|
vendors/part1/Workflow.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
```mermaid
|
| 2 |
+
---
|
| 3 |
+
config:
|
| 4 |
+
flowchart:
|
| 5 |
+
curve: linear
|
| 6 |
+
---
|
| 7 |
+
graph TD;
|
| 8 |
+
__start__([<p>__start__</p>]):::first
|
| 9 |
+
Task_Response(Task Response)
|
| 10 |
+
Lexical(Lexical)
|
| 11 |
+
Grammar(Grammar)
|
| 12 |
+
CC(CC)
|
| 13 |
+
Aggregator(Aggregator)
|
| 14 |
+
__end__([<p>__end__</p>]):::last
|
| 15 |
+
CC --> Aggregator;
|
| 16 |
+
Grammar --> Aggregator;
|
| 17 |
+
Lexical --> Aggregator;
|
| 18 |
+
Task_Response --> Aggregator;
|
| 19 |
+
__start__ --> CC;
|
| 20 |
+
__start__ --> Grammar;
|
| 21 |
+
__start__ --> Lexical;
|
| 22 |
+
__start__ --> Task_Response;
|
| 23 |
+
Aggregator --> __end__;
|
| 24 |
+
classDef default fill:#f2f0ff,line-height:1.2
|
| 25 |
+
classDef first fill-opacity:0
|
| 26 |
+
classDef last fill:#bfb6fc
|
| 27 |
+
|
| 28 |
+
```
|
vendors/part1/__init__.py
ADDED
|
File without changes
|
vendors/part1/display_report.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import re
|
| 3 |
+
import textwrap
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class styles:
|
| 7 |
+
HEADER = '\033[95m'
|
| 8 |
+
GREEN = '\033[92m'
|
| 9 |
+
WARNING = '\033[93m'
|
| 10 |
+
BOLD = '\033[1m'
|
| 11 |
+
UNDERLINE = '\033[4m'
|
| 12 |
+
ENDC = '\033[0m'
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def print_md(text):
|
| 16 |
+
"""
|
| 17 |
+
Translates simple markdown and wraps text for better terminal display.
|
| 18 |
+
"""
|
| 19 |
+
text = re.sub(r'\*\*(.*?)\*\*', f'{styles.BOLD}\\1{styles.ENDC}', text)
|
| 20 |
+
paragraphs = text.split('\n')
|
| 21 |
+
wrapped_paragraphs = [textwrap.fill(p, width=90) for p in paragraphs]
|
| 22 |
+
final_text = '\n'.join(wrapped_paragraphs)
|
| 23 |
+
print(final_text)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def display_report_fn(data):
|
| 27 |
+
"""
|
| 28 |
+
Loads, parses, and prints the formatted IELTS report from a JSON file.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
print("\n" + "=" * 80)
|
| 32 |
+
print(f"{styles.HEADER}{styles.BOLD}📝 IELTS WRITING EVALUATION REPORT{styles.ENDC}")
|
| 33 |
+
print("=" * 80)
|
| 34 |
+
|
| 35 |
+
if "original_question" in data:
|
| 36 |
+
print(f"\n{styles.HEADER}{styles.UNDERLINE}Original Question:{styles.ENDC}")
|
| 37 |
+
print_md(data["original_question"])
|
| 38 |
+
|
| 39 |
+
if "student_essay" in data:
|
| 40 |
+
print(f"\n{styles.HEADER}{styles.UNDERLINE}Student's Essay:{styles.ENDC}")
|
| 41 |
+
print_md(data["student_essay"])
|
| 42 |
+
print("-" * 80)
|
| 43 |
+
|
| 44 |
+
sections = {
|
| 45 |
+
"task_response": "✅ Task Response",
|
| 46 |
+
"coherence_and_cohesion": "🔗 Coherence and Cohesion",
|
| 47 |
+
"lexical_resource": "📚 Lexical Resource",
|
| 48 |
+
"grammatical_range_and_accuracy": "📝 Grammatical Range and Accuracy"
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
for key, title in sections.items():
|
| 52 |
+
if key in data:
|
| 53 |
+
print(f"\n\n{styles.GREEN}{styles.BOLD}{styles.UNDERLINE}--- {title} ---{styles.ENDC}\n")
|
| 54 |
+
print_md(data[key])
|
| 55 |
+
|
| 56 |
+
if "aggregated_result" in data:
|
| 57 |
+
print(
|
| 58 |
+
f"\n\n{styles.WARNING}{styles.BOLD}{styles.UNDERLINE}--- 📊 Overall Summary & Final Score ---{styles.ENDC}\n")
|
| 59 |
+
print_md(data["aggregated_result"])
|
| 60 |
+
|
| 61 |
+
print("\n" + "=" * 80 + "\n")
|
| 62 |
+
|
| 63 |
+
|
vendors/part1/final_state.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"student_essay": "One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends. However while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\n\n\nFirstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day. Secondly, longer weekends will make people lazy and distant from their work. For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home. Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\n\n\nThere are several ways to improve your lifestyle while not having longer weekends. Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time. One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\n\n\nIn conclusion, I think while occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.",
|
| 3 |
+
"original_question": "The working week should be shorter and workers should have a longer weekend.\n\nDo you agree or disagree. ",
|
| 4 |
+
"task_response": "**1. What You Did Well:**\nYou successfully identified the core topic of the question and presented a clear and consistent position (disagreement) from the introduction through to the conclusion. You provided several relevant arguments to support your stance, such as the potential for laziness, the economic impact of reduced working hours, and the idea that current time off is sufficient if managed well. Your use of a personal anecdote to illustrate the point about becoming distant from work was a good attempt at providing specific support.\n\n**2. What You Could Have Done Better:**\nWhile your position was clear, some of your supporting points could have been more directly and strongly linked to the central argument against a shorter working week and longer weekend. For example, the point about finding coworkers with similar interests, while a valid way to improve job experience, doesn't directly argue against the *need* for a shorter working week or longer weekend in terms of rest or productivity. Its connection to the prompt's core argument was a bit indirect. Additionally, your reference to a \"recent study\" about economic impact, while a strong point, lacked specificity, which can weaken its persuasive power in terms of Task Response.\n\n**3. What You Missed:**\nYou did not completely miss any part of the prompt. You clearly addressed the \"agree or disagree\" aspect and provided reasons for your stance. The areas for improvement relate more to the depth and directness of the development of some ideas rather than an omission of a task component.\n\n**4. Recommendations for Improvement:**\n* Before writing, ensure that every main idea and supporting example you plan to include directly and unequivocally supports your overall position. Ask yourself: \"How does this specific point or example directly prove why I agree or disagree with the prompt?\"\n* When using external evidence or studies, try to be more specific if possible (e.g., \"Research from [institution] suggests...\") or frame it as a widely accepted concept if specific details are unavailable (e.g., \"It is widely understood that...\"). Avoid vague references like \"I read a recent study.\"\n* Elaborate more fully on your main points. For instance, when you state there's \"plenty of time to rest,\" expand on *how* that time can be effectively utilized to achieve the desired rest, rather than just stating the fact.\n\n**5. Suggested Edits to Your Original Text:**\n\n* **Your Original Sentence:** \"Firstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day.\"\n * **Higher-Scoring Alternative for Task Response:** \"Firstly, I contend that the current working structure already provides ample opportunity for rest and recuperation. Individuals can effectively manage their evenings and existing weekends to engage in leisure activities, pursue hobbies, and spend quality time with family, thereby mitigating the need for an extended break.\"\n\n* **Your Original Sentence:** \"Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n * **Higher-Scoring Alternative for Task Response:** \"Furthermore, a significant concern is the potential negative impact on national economies. Economic analyses often indicate that a reduction in working hours can lead to decreased productivity, higher operational costs for businesses, and ultimately, a decline in overall economic output, posing a long-term threat to prosperity.\"\n\n* **Your Original Sentence:** \"One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n * **Higher-Scoring Alternative for Task Response:** \"Beyond simply extending leisure time, improving job satisfaction itself can significantly enhance overall well-being, thereby reducing the perceived need for a shorter working week. For instance, fostering a positive work environment and encouraging social connections among colleagues can make the workday more enjoyable and less draining. My own experience, where forming friendships with colleagues who shared common interests like soccer transformed a challenging period into a more positive one, illustrates how internal workplace dynamics can be more impactful than simply increasing time away from work.\"\n\n**6. Final Task Response Score:** 7",
|
| 5 |
+
"coherence_and_cohesion": "**1. What You Did Well:**\nYour essay was clearly organized into an introduction, body paragraphs, and a conclusion, which provides a basic structure for your ideas. You also attempted to use linking words to introduce your points within the first body paragraph.\n\n**2. What You Could Have Done Better:**\nThe primary weakness in your essay's Coherence and Cohesion lies in the organization of your body paragraphs. Your first body paragraph is very long and contains three distinct arguments, which makes it difficult for the reader to follow a single, developed idea. The logical progression between your first and second body paragraphs is also not entirely smooth, as the second paragraph introduces a new line of argument (alternatives to longer weekends) rather than directly developing the reasons against them. Furthermore, your use of cohesive devices is somewhat mechanical and repetitive.\n\n**3. Cohesion and Coherence Breakdown:**\n* **Paragraphing:** Your first body paragraph is a significant issue. It attempts to present three separate main ideas (\"plenty of time to rest,\" \"longer weekends make people lazy,\" and \"impact on economy\") within a single paragraph. For greater clarity and to allow for proper development of each point, these should have been separated into individual paragraphs. The second body paragraph also contains two distinct ideas (planning weekends and finding like-minded colleagues) that could benefit from clearer separation or more explicit linking.\n* **Linking Words:** You rely heavily on \"Firstly,\" \"Secondly,\" and \"Thirdly\" to introduce points within one long paragraph. While these are cohesive devices, their repetitive use in this manner makes the writing feel mechanical rather than fluid. There is an underuse of a wider range of more sophisticated linking words and phrases that could show more complex relationships between sentences and paragraphs (e.g., cause and effect, contrast, further addition, exemplification). The transition from the first body paragraph to the second is abrupt, lacking a clear linking phrase to signal the shift in focus.\n* **Referencing:** Referencing is generally clear (e.g., \"this\" referring to finding coworkers with the same interest). However, some phrasing like \"I was feeling distant with my job and felt the urge to be done with the work\" could be more concise to avoid slight repetition.\n\n**4. Recommendations for Improvement:**\n* **Plan your paragraphs carefully:** Before you start writing, create a brief outline. Assign one central idea to each body paragraph. This will help you ensure that each paragraph has a clear topic sentence and develops a single argument thoroughly.\n* **Vary your cohesive devices:** Expand your repertoire of linking words and phrases. Instead of just \"Secondly,\" consider using alternatives like \"Furthermore,\" \"Moreover,\" \"In addition to this,\" or \"Another significant point is that...\" to introduce new ideas. Use transition words to show the relationship between sentences (e.g., \"consequently,\" \"as a result,\" \"in contrast,\" \"however,\" \"for instance\").\n* **Ensure logical progression between paragraphs:** Think about how each paragraph connects to the one before it and how it contributes to your overall argument. Use clear topic sentences and transitional phrases at the beginning of paragraphs to guide the reader smoothly from one idea to the next. For an \"agree/disagree\" essay, ensure your body paragraphs consistently support your stated stance.\n\n**5. Suggested Edits to Your Original Text:**\n\n* **Original Body Paragraph 1:**\n \"Firstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day. Secondly, longer weekends will make people lazy and distant from their work. For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home. Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n\n* **Higher-Scoring Alternative for Coherence and Cohesion (showing improved paragraphing and linking):**\n\n \"To begin with, I believe that the current working week already provides sufficient time for individuals to rest and prepare for the following day. There is ample opportunity within the existing structure for personal rejuvenation without the need for extended weekends.\n\n **Moreover,** a key concern is that longer weekends could inadvertently lead to a decline in productivity and a sense of detachment from one's profession. **For example,** during my experience at a tech company where we occasionally had four-day weekends, I observed that upon returning to work, both I and my colleagues often felt a diminished connection to our tasks, leading to a desire to complete work as quickly as possible rather than engaging deeply.\n\n **Beyond individual impact,** there are significant economic considerations. I recently read a study that highlighted the substantial long-term damage inflicted upon a country's economy when working hours were significantly reduced, suggesting that such policies can have far-reaching negative consequences.\"\n\n* **Original Body Paragraph 2:**\n \"There are several ways to improve your lifestyle while not having longer weekends. Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time. One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n\n* **Higher-Scoring Alternative for Coherence and Cohesion (showing better linking and potential splitting):**\n\n \"Instead of shortening the working week, there are alternative strategies to enhance one's lifestyle and well-being. **Crucially,** effective time management during existing weekends can significantly improve their quality. Many individuals fail to plan their time off, which often diminishes its restorative potential; conversely, thoughtful planning can lead to more fulfilling and productive leisure.\n\n **Furthermore,** fostering positive social connections within the workplace can dramatically improve job satisfaction, thereby reducing the perceived need for longer breaks. This was certainly true in my own experience: after a challenging period at work, I connected with a colleague who shared my passion for soccer. Our discussions on various topics not only made the working environment more enjoyable but also fostered a stronger sense of belonging, making the work experience much more positive for both of us.\"\n\n**6. Final Coherence and Cohesion Score:** 5",
|
| 6 |
+
"lexical_resource": "**1. What You Did Well:**\nYou have used some basic topic-specific vocabulary related to work and leisure, such as 'working week', 'weekends', 'time off', and 'economy'. You also attempted to use some phrases to express your opinion, like 'I believe that' and 'I don't think'.\n\n**2. What You Could Have Done Better:**\nThe essay relies heavily on a limited range of vocabulary, leading to repetition and a lack of precision. Many phrases are informal or colloquial, which is not appropriate for an academic essay. There is a consistent lack of sophisticated vocabulary and an absence of less common lexical items. Word choice and collocations are frequently unnatural, making the text sound less fluent and professional.\n\n**3. Lexical Resource Breakdown:**\n\n* **Repetition:**\n * The word \"work/working\" is used excessively (e.g., \"working week,\" \"working period,\" \"get off from your work,\" \"back to work,\" \"my job,\" \"the work,\" \"working hours,\" \"at work,\" \"working experience,\" \"from work,\" \"working days\").\n * \"Time\" is repeated frequently (e.g., \"enough time,\" \"plenty of time,\" \"time off,\" \"quality time\").\n * \"Better\" is overused (e.g., \"better use,\" \"make your job experience better,\" \"better for both of us,\" \"better head space\").\n * \"Need\" is repeated (e.g., \"needs to be shorter,\" \"need of longer weekends,\" \"people need to have,\" \"we need a time off,\" \"without the need of cutting\").\n * \"Feel/feeling\" is repeated in the same sentence: \"didn't feel the same as I was feeling distant.\"\n\n* **Word Choice/Collocation:**\n * \"hot topics these day\" - \"these days\" is correct, but \"hot topics\" is informal. Consider \"a widely debated issue\" or \"a prominent discussion point.\"\n * \"the need of longer weekends\" - Should be \"the need *for* longer weekends.\"\n * \"get off from your work\" - More natural would be \"finish work\" or \"leave work.\"\n * \"make people lazy and distant from their work\" - \"Foster laziness and detachment from their professional responsibilities\" would be more precise. \"Distant from their work\" is awkward.\n * \"the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job\" - Very repetitive and unnatural. Consider \"I felt a diminished connection to my role and colleagues, experiencing a sense of detachment.\"\n * \"felt the urge to be done with the work as quickly as possible\" - \"Felt compelled to complete tasks swiftly.\"\n * \"massive damage to that country's economy\" - \"Massive damage\" is informal. Use \"significant detriment\" or \"severe adverse impact.\"\n * \"improve your lifestyle while not having longer weekends\" - \"Enhance one's lifestyle without necessarily extending weekends.\"\n * \"damage the quality of their time off\" - \"Detract from the quality of their leisure time.\"\n * \"Good planning will guide you to find better use of you quality time\" - \"Effective planning can enable individuals to make better use of their leisure time.\" (\"you quality time\" is a grammatical error, should be \"your\").\n * \"make your job experience better\" - \"Enhance one's professional experience.\"\n * \"having a rough few weeks at work\" - \"Rough\" is informal. Consider \"experiencing a challenging period at work.\"\n * \"discuss about our opinion\" - \"Discuss our opinion\" (no \"about\").\n * \"get into a better head space\" - \"Head space\" is informal. Consider \"achieve a more positive mental state\" or \"improve one's well-being.\"\n * \"tackle this problem\" - \"Address this issue\" or \"resolve this challenge.\"\n\n* **Spelling/Word Formation:**\n * \"these day\" (should be \"these days\")\n * \"you quality time\" (should be \"your quality time\")\n\n**4. Recommendations for Improvement:**\n* **Expand your vocabulary range:** Actively learn synonyms and antonyms for common words. For example, instead of just \"good\" or \"bad,\" learn \"beneficial,\" \"detrimental,\" \"advantageous,\" \"adverse,\" etc.\n* **Focus on precision:** Choose words that convey your meaning exactly. For instance, instead of \"big problem,\" use \"significant issue\" or \"major challenge.\"\n* **Improve collocation awareness:** Pay attention to how words naturally go together. Use a collocation dictionary or notice common phrases in authentic English texts. For example, \"make a decision,\" not \"do a decision.\"\n* **Elevate your style:** Avoid informal language and colloquialisms in academic writing. Replace phrases like \"get off from your work\" or \"rough few weeks\" with more formal alternatives.\n* **Practice paraphrasing:** When you write, try to rephrase ideas using different vocabulary to avoid repetition.\n\n**5. Suggested Edits to Your Original Text:**\n\n* *Your Original Text:* \"One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"**A prominent discussion point** currently revolves around the **proposal for a shorter working week** and the **extension of weekends**.\"\n\n* *Your Original Text:* \"I think that there is plenty of time to rest after you get off from your work and prepare for the next day.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"I believe that individuals have **ample opportunity for recuperation** after **concluding their workdays** to prepare for the subsequent one.\"\n\n* *Your Original Text:* \"longer weekends will make people lazy and distant from their work.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"Extended weekends could **foster indolence** and **detachment from one's professional responsibilities**.\"\n\n* *Your Original Text:* \"the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"I experienced a **diminished connection** to my role and colleagues, feeling **disengaged** and **compelled to complete tasks swiftly** in order to return home.\"\n\n* *Your Original Text:* \"cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"reducing working hours on the economy, which indicated **significant detriment** to that nation's economy in the long run.\"\n\n* *Your Original Text:* \"Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"Many individuals often **neglect to plan their weekends effectively**, which can **detract from the quality of their leisure time**. **Strategic planning** can enable them to **optimise their free time** and establish achievable goals within a defined period.\"\n\n* *Your Original Text:* \"occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"while occasional **breaks from work** are necessary to **achieve a more positive mental state**, alternative strategies exist to **address this issue** without the necessity of reducing working days or extending weekends.\"\n\n**6. Final Lexical Resource Score:** 5",
|
| 7 |
+
"grammatical_range_and_accuracy": "**1. What You Did Well:**\nYou have demonstrated a good attempt at using a mix of simple, compound, and complex sentence structures. There is clear evidence of complex sentences, particularly those using subordinate clauses (e.g., \"while I believe that...\", \"when I was working...\") and relative clauses (e.g., \"that discussed...\", \"who also loved...\"). This shows a good range in your grammatical structures. You also successfully use introductory phrases and clauses, often followed by correct punctuation.\n\n**2. What You Could Have Done Better:**\nWhile you attempt complex structures, there are frequent grammatical errors that, though often minor, accumulate and affect overall accuracy. These errors include issues with articles, prepositions, singular/plural forms, and occasional tense inconsistencies. Some very long sentences become slightly unwieldy, indicating a need for more precise control over highly complex constructions and better punctuation to manage their flow.\n\n**3. Grammatical Range and Accuracy Breakdown:**\n* **Sentence Structure:** You effectively use a variety of sentence types, moving beyond simple sentences to incorporate complex ones. This includes sentences with noun clauses (\"how the working week needs to be shorter\"), adverbial clauses of time and concession (\"when I was working...\", \"while I believe...\"), and relative clauses (\"that discussed...\", \"who also loved...\"). This demonstrates a good range. However, some sentences are excessively long, which can lead to awkward phrasing and a slight loss of clarity, suggesting that while you attempt complex structures, full control over their most intricate forms is still developing.\n* **Grammatical Errors:**\n * **Articles:** You sometimes omit or misuse articles, for example, \"a time off\" should be \"time off.\"\n * **Prepositions:** There are recurring errors with prepositions, such as \"the need of longer weekends\" (should be \"the need for\"), \"get off from your work\" (should be \"get off work\"), \"distant with my job\" (should be \"distant from my job\"), and \"discuss about our opinion\" (should be \"discuss our opinion\").\n * **Singular/Plural:** You used \"these day\" instead of \"these days\" and \"our opinion on different topics\" instead of \"our opinions on different topics.\"\n * **Tense Consistency:** In the sentence \"so I can go back home,\" the present tense \"can\" is inconsistent with the past context of the narrative (\"when I was working...\"). It should be \"so that I could go back home.\"\n * **Word Choice/Phrasing:** Phrases like \"tend to not plan\" could be more naturally expressed as \"tend not to plan.\" \"use of you quality time\" should be \"use of your quality time.\"\n* **Punctuation:**\n * You occasionally miss commas after introductory clauses (e.g., \"However while I believe...\" should be \"However, while I believe...\").\n * There is a significant run-on sentence due to a lack of capitalization and appropriate punctuation: \"this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\" This sentence is too long and should be broken up or use a semicolon.\n\n**4. Recommendations for Improvement:**\n* **Focus on Prepositions and Articles:** Dedicate specific practice to common prepositional phrases and the rules for using 'a,' 'an,' and 'the,' especially with abstract nouns or general statements.\n* **Review Singular/Plural Nouns:** Pay close attention to whether nouns should be singular or plural, particularly when referring to general concepts or multiple items.\n* **Master Complex Sentence Punctuation:** Practice using commas correctly with dependent and independent clauses. Learn how to use semicolons to connect closely related independent clauses, or how to split very long sentences into two or more shorter, clearer ones.\n* **Ensure Tense Consistency:** When narrating events or discussing past experiences, ensure that all verbs maintain a consistent tense unless there's a specific reason for a shift.\n* **Proofread Systematically:** After writing, review your essay specifically for one type of grammatical error at a time (e.g., first check all prepositions, then all articles, then all subject-verb agreements).\n\n**5. Suggested Edits to Your Original Text:**\n* **Your Original Text:** \"One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"One of the hot topics these **days** is **the debate about** how the working week needs to be shorter and the need **for** longer weekends.\"\n* **Your Original Text:** \"However while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"However, while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\"\n* **Your Original Text:** \"For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"For example, when I was working at a tech company, we used to have four days off. When we returned to work, the connection I had with my job and colleagues didn't feel the same; I felt distant from my job and had the urge to finish work as quickly as possible so that I could go back home.\"\n* **Your Original Text:** \"Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"Good planning will guide you to make better use of **your** quality time and to set the goals you want to achieve by a certain time.\"\n* **Your Original Text:** \"this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"**This** was the case for me: I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did. We used to discuss our **opinions** on different topics, which made the working experience much better for both of us.\"\n* **Your Original Text:** \"In conclusion, I think while occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"In conclusion, I think while occasionally we need time off from work to get into a better headspace, there are other ways to tackle this problem without the need **for** cutting working days and making the weekends longer.\"\n\n**6. Final Grammatical Range and Accuracy Score:**\n6",
|
| 8 |
+
"aggregated_result": "**Overall IELTS Writing Task 2 Feedback**\n\nHere is a summary of your performance based on the four official IELTS scoring criteria.\n\n**1. Task Response**\n* **Strengths:** You clearly identified the core topic and maintained a consistent position of disagreement throughout the essay. You provided several relevant arguments, such as the potential for laziness, economic impact, and the sufficiency of current time off. The attempt to use a personal anecdote for illustration was also noted.\n* **Areas for Improvement:** Some supporting points could have been more directly linked to the central argument against a shorter working week. The connection of finding similar-interest coworkers to the prompt's core argument was indirect. Additionally, the reference to a \"recent study\" lacked specificity, which weakened its persuasive power.\n* **Expert Score:** 7\n\n**2. Coherence and Cohesion**\n* **Strengths:** Your essay demonstrated a clear basic structure with an introduction, body paragraphs, and a conclusion. You also attempted to use linking words to introduce points within the first body paragraph.\n* **Areas for Improvement:** The primary weakness was the organization of body paragraphs, particularly the first, which was excessively long and contained three distinct arguments. The logical progression between the first and second body paragraphs was not smooth, and the use of cohesive devices was somewhat mechanical and repetitive.\n* **Expert Score:** 5\n\n**3. Lexical Resource (Vocabulary)**\n* **Strengths:** You used some basic topic-specific vocabulary related to work and leisure. You also attempted to use phrases to express your opinion.\n* **Areas for Improvement:** The essay relied on a limited vocabulary range, leading to repetition and a lack of precision. Many phrases were informal or colloquial, which is not appropriate for academic writing. There was a consistent absence of sophisticated vocabulary and less common lexical items, and word choice and collocations were frequently unnatural.\n* **Expert Score:** 5\n\n**4. Grammatical Range and Accuracy**\n* **Strengths:** You demonstrated a good attempt at using a mix of simple, compound, and complex sentence structures, including subordinate and relative clauses. You also successfully used introductory phrases and clauses, often with correct punctuation.\n* **Areas for Improvement:** Despite attempts at complex structures, frequent grammatical errors accumulated, affecting overall accuracy. These included issues with articles, prepositions, singular/plural forms, and occasional tense inconsistencies. Some very long sentences became unwieldy, indicating a need for more precise control over complex constructions and better punctuation.\n* **Expert Score:** 6\n\n---\n\n**Final Analysis and Overall Score**\n* **Summative Comments:** Overall, your ability to present a clear position and attempt a range of sentence structures are notable strengths. However, your final score is primarily limited by issues in Coherence and Cohesion, particularly paragraphing, and a restricted range of vocabulary with frequent errors in word choice and collocation. Grammatical accuracy, especially with prepositions and articles, also requires attention.\n* **Overall Band Score:** 6.0"
|
| 9 |
+
}
|
vendors/part1/main.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# part1/main.py
|
| 2 |
+
import base64
|
| 3 |
+
import io
|
| 4 |
+
import sys
|
| 5 |
+
import os
|
| 6 |
+
|
| 7 |
+
# --- Assuming these are your existing, correct imports from your project ---
|
| 8 |
+
from .nodes import task_response, coherence_and_cohesion, lexical_resource, grammatical_range_and_accuracy, aggregator
|
| 9 |
+
from .state import State
|
| 10 |
+
from .workflow import workflow_fn
|
| 11 |
+
from .display_report import display_report_fn
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def encode_image(image_path: str) -> str:
|
| 15 |
+
"""Encodes an image file to a base64 string."""
|
| 16 |
+
with open(image_path, "rb") as image_file:
|
| 17 |
+
return base64.b64encode(image_file.read()).decode('utf-8')
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def run_ielts_part1_agent(image_path: str, student_essay: str) -> str:
|
| 21 |
+
"""
|
| 22 |
+
Runs the IELTS Part 1 agent with an image and text, returning the report as a string.
|
| 23 |
+
"""
|
| 24 |
+
# 1. Encode the image provided by the user
|
| 25 |
+
base64_image = encode_image(image_path)
|
| 26 |
+
image_url = f"data:image/jpeg;base64,{base64_image}" # Use jpeg as a common format
|
| 27 |
+
|
| 28 |
+
# 2. Set up the initial state for the agentic workflow
|
| 29 |
+
initial_state = {
|
| 30 |
+
"image_url": image_url,
|
| 31 |
+
"student_essay": student_essay
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
# 3. Initialize the LangGraph workflow
|
| 35 |
+
final_workflow = workflow_fn(State, task_response, lexical_resource, grammatical_range_and_accuracy,
|
| 36 |
+
coherence_and_cohesion, aggregator)
|
| 37 |
+
|
| 38 |
+
# 4. Invoke the agent
|
| 39 |
+
print("Invoking Part 1 agent workflow...")
|
| 40 |
+
final_state = final_workflow.invoke(initial_state)
|
| 41 |
+
print("Workflow complete.")
|
| 42 |
+
|
| 43 |
+
# 5. Capture the printed output of your display_report_fn
|
| 44 |
+
# This redirects the console output to a string variable
|
| 45 |
+
old_stdout = sys.stdout
|
| 46 |
+
sys.stdout = captured_output = io.StringIO()
|
| 47 |
+
|
| 48 |
+
display_report_fn(final_state)
|
| 49 |
+
|
| 50 |
+
sys.stdout = old_stdout # Restore the standard output
|
| 51 |
+
report_string = captured_output.getvalue() # Get the report from the string buffer
|
| 52 |
+
|
| 53 |
+
# 6. Return the captured report as a string
|
| 54 |
+
return report_string
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# This part is for your own direct testing of this script
|
| 58 |
+
if __name__ == "__main__":
|
| 59 |
+
# To test this, you need a dummy image file named "task_image.png"
|
| 60 |
+
# in the same directory.
|
| 61 |
+
if not os.path.exists("task_image.png"):
|
| 62 |
+
print("Creating a dummy 'task_image.png' for testing.")
|
| 63 |
+
try:
|
| 64 |
+
from PIL import Image, ImageDraw
|
| 65 |
+
|
| 66 |
+
img = Image.new('RGB', (300, 150), color=(73, 109, 137))
|
| 67 |
+
d = ImageDraw.Draw(img)
|
| 68 |
+
d.text((10, 10), "Test Image for Part 1", fill=(255, 255, 0))
|
| 69 |
+
img.save('task_image.png')
|
| 70 |
+
except ImportError:
|
| 71 |
+
print("Please install Pillow (`pip install Pillow`) to create a test image.")
|
| 72 |
+
sys.exit(1)
|
| 73 |
+
|
| 74 |
+
test_image_path = "task_image.png"
|
| 75 |
+
test_essay = """The provided image shows a simple graph. From 1990 to 2010, the data increased significantly. This indicates a positive trend over the two decades shown in the chart."""
|
| 76 |
+
|
| 77 |
+
print("--- Running standalone test for Part 1 ---")
|
| 78 |
+
result = run_ielts_part1_agent(test_image_path, test_essay)
|
| 79 |
+
print("\n--- Agent Result ---")
|
| 80 |
+
print(result)
|
| 81 |
+
|
vendors/part1/model.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
|
| 4 |
+
load_dotenv()
|
| 5 |
+
model = ChatGoogleGenerativeAI(model='gemini-2.5-flash-preview-05-20', temperature=0.1, top_p=0.95)
|
vendors/part1/nodes.py
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .state import State
|
| 2 |
+
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
|
| 3 |
+
from .model import model
|
| 4 |
+
import logging
|
| 5 |
+
|
| 6 |
+
logger = logging.getLogger(__name__)
|
| 7 |
+
|
| 8 |
+
def task_response(state: State):
|
| 9 |
+
print("--Starting Task Response Analysis--")
|
| 10 |
+
logger.info("Starting Task Response Analysis")
|
| 11 |
+
|
| 12 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 13 |
+
SystemMessagePromptTemplate.from_template(
|
| 14 |
+
"""
|
| 15 |
+
You are an expert IELTS Writing Examiner specializing in **Task 1 (Academic) Task Response**. Your sole function is to assess a student's report based *only* on the **Task Response** criterion. You will be given an image (e.g., a chart, graph, table, diagram, or map) and the student's written report. You must ignore all other scoring criteria (Coherence & Cohesion, Lexical Resource, Grammatical Range & Accuracy). Your analysis must focus exclusively on how fully and accurately the student has described the information presented in the visual.
|
| 16 |
+
|
| 17 |
+
**Your Role and How to Score Task Response (Task 1):**
|
| 18 |
+
|
| 19 |
+
Your primary job is to evaluate if the student has fulfilled the task requirements by accurately summarizing and reporting the key features of the visual data.
|
| 20 |
+
|
| 21 |
+
**What to Look For (Your Internal Checklist):**
|
| 22 |
+
1. **Introduction:** Does the introduction correctly paraphrase the purpose of the visual information?
|
| 23 |
+
2. **Overview (Crucial):** Is there a clear and accurate summary of the main trends, differences, or stages? This is essential for a score of Band 6 or higher. The overview should synthesize the most significant information, not list details.
|
| 24 |
+
3. **Key Feature Selection:** Has the student identified and focused on the most important and relevant information and trends from the visual? Or have they tried to describe every single detail mechanically?
|
| 25 |
+
4. **Data Accuracy:** Is the data (numbers, percentages, dates, units) reported accurately as it appears in the visual?
|
| 26 |
+
5. **Completeness:** Does the report cover all necessary parts of the visual? For tasks with multiple visuals (e.g., two charts), are both addressed?
|
| 27 |
+
6. **No Inappropriate Information:** Has the student avoided including personal opinions, conclusions, or information that is not explicitly present in the visual? The task is to describe, not interpret or speculate.
|
| 28 |
+
|
| 29 |
+
**Task Response (Task 1) Scoring Guide (Strictly follow this):**
|
| 30 |
+
* **Band 7+:** The response covers all requirements of the task. It presents a clear, accurate, and comprehensive overview of the main trends/features. Key features are clearly presented, highlighted, and supported by accurate data.
|
| 31 |
+
* **Band 6:** The response addresses the task requirements. It presents an overview, but it may be insufficiently clear or comprehensive. Key features are presented, but some may be inadequately covered or details may be irrelevant.
|
| 32 |
+
* **Band 5:** The response attempts to address the task but only covers the requirements partially. There is no clear overview. Key features are inadequately covered, and there may be inaccuracies in the data.
|
| 33 |
+
|
| 34 |
+
**Your Output Structure (Follow this format precisely):**
|
| 35 |
+
|
| 36 |
+
You must generate a response in the following order and with these exact headings:
|
| 37 |
+
|
| 38 |
+
**1. What You Did Well:**
|
| 39 |
+
Start with positive reinforcement. For example, "You successfully paraphrased the prompt in your introduction and correctly identified some of the key data points."
|
| 40 |
+
|
| 41 |
+
**2. What You Could Have Done Better:**
|
| 42 |
+
Provide a detailed critique. For example, "Your report lacked a clear overview paragraph summarizing the main trends. This is a critical feature and its absence limits your score." or "You attempted to describe every number on the chart, which is not the goal; you should select and group the key features instead."
|
| 43 |
+
|
| 44 |
+
**3. What You Missed:**
|
| 45 |
+
Clearly state any parts of the task that were ignored. For example, "You described the data for the USA and Japan but completely omitted the data for Canada, which was part of the chart." or "You included a conclusion with your personal opinion, which is not required or appropriate for Task 1."
|
| 46 |
+
|
| 47 |
+
**4. Recommendations for Improvement:**
|
| 48 |
+
Give actionable advice. For instance, "Always write a dedicated overview paragraph after your introduction that summarizes the 2-4 most significant things you see in the visual *before* you start describing details. Ask yourself: What is the biggest change? What is the highest point? What is the most obvious comparison?"
|
| 49 |
+
|
| 50 |
+
**5. Suggested Edits to Your Original Text:**
|
| 51 |
+
Provide specific, revised sentences or a paragraph showing how to improve.
|
| 52 |
+
*Example:*
|
| 53 |
+
*Your Original Text:* "The graph shows sales. In 2000, sales were 20 million. In 2001, sales were 25 million."
|
| 54 |
+
*Higher-Scoring Alternative for Task Response (Overview):* "Overall, it is clear that sales for the product experienced a significant upward trend over the period, while also displaying some minor fluctuations from year to year."
|
| 55 |
+
|
| 56 |
+
**6. Final Task Response Score:**
|
| 57 |
+
Conclude with the final band score for Task Response only.
|
| 58 |
+
*Example:*
|
| 59 |
+
"Final Task Response Score: 6"
|
| 60 |
+
|
| 61 |
+
Do not add any conversational closings, greetings, or encouragement to message again.
|
| 62 |
+
"""
|
| 63 |
+
),
|
| 64 |
+
HumanMessagePromptTemplate.from_template([
|
| 65 |
+
{
|
| 66 |
+
"type": "text",
|
| 67 |
+
"text": """**IELTS Writing Task 1 (Academic)**
|
| 68 |
+
|
| 69 |
+
Please evaluate the following student response based on the provided image.
|
| 70 |
+
|
| 71 |
+
**Student's Response:**
|
| 72 |
+
{student_response}"""
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
"type": "image_url",
|
| 76 |
+
"image_url": "{image_url}",
|
| 77 |
+
}
|
| 78 |
+
])
|
| 79 |
+
])
|
| 80 |
+
|
| 81 |
+
chain = chat_prompt | model
|
| 82 |
+
response = chain.invoke({
|
| 83 |
+
"image_url": state["image_url"],
|
| 84 |
+
"student_response": state["student_essay"]
|
| 85 |
+
})
|
| 86 |
+
|
| 87 |
+
return {"task_response": response.content}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
def coherence_and_cohesion(state: State):
|
| 91 |
+
print("--Starting CC Analysis--")
|
| 92 |
+
logger.info("Starting CC Analysis")
|
| 93 |
+
|
| 94 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 95 |
+
SystemMessagePromptTemplate.from_template(
|
| 96 |
+
"""
|
| 97 |
+
You are an expert IELTS Writing Examiner specializing in **Task 1 (Academic) Coherence and Cohesion**. Your sole function is to assess a student's report based *only* on its organization, paragraphing, and the linking of information. You will be given an image and the student's written report. You must ignore all other scoring criteria (Task Response, Lexical Resource, Grammatical Range and Accuracy). Your analysis must focus exclusively on the logical flow and structure of the report.
|
| 98 |
+
|
| 99 |
+
**Your Role and How to Score Coherence and Cohesion (Task 1):**
|
| 100 |
+
|
| 101 |
+
Your primary job is to evaluate how the report is organized and how the information is linked. Coherence is the logical sequencing of information, while Cohesion is the use of linguistic devices to connect it.
|
| 102 |
+
|
| 103 |
+
**What to Look For (Your Internal Checklist):**
|
| 104 |
+
1. **Logical Organization:** Is the information grouped logically in paragraphs? For example, grouping by time periods, by categories (countries, age groups), or by trends (increasing items in one paragraph, decreasing in another).
|
| 105 |
+
2. **Paragraphing:** Does the report use paragraphs effectively? Is there a clear introduction, overview, and body paragraphs? Are paragraphs focused on a specific feature or set of features?
|
| 106 |
+
3. **Progression:** Can the reader easily follow the description from one point to the next? Is the information presented in a logical order?
|
| 107 |
+
4. **Cohesive Devices:** Does the student use a range of linking words and phrases appropriate for Task 1 (e.g., 'In contrast,' 'Similarly,' 'Turning to the details,' 'As can be seen from the graph')? Are they used accurately and without being overly mechanical?
|
| 108 |
+
5. **Referencing:** Is the use of pronouns (e.g., 'it,' 'its,' 'the former,' 'the latter') clear and unambiguous, helping to avoid repetition?
|
| 109 |
+
|
| 110 |
+
**Coherence and Cohesion (Task 1) Scoring Guide (Strictly follow this):**
|
| 111 |
+
* **Band 7+:** Information is logically organized with clear progression. A range of cohesive devices is used effectively. Paragraphing is logical and sufficient.
|
| 112 |
+
* **Band 6:** Information is arranged coherently with a mostly clear progression. Cohesive devices are used, but they may be faulty or mechanical. Paragraphing may not always be logical.
|
| 113 |
+
* **Band 5:** There is some organization, but it's not always logical and may lack overall progression. Cohesive devices may be inadequate, inaccurate, or overused. Paragraphing may be inadequate.
|
| 114 |
+
|
| 115 |
+
**Your Output Structure (Follow this format precisely):**
|
| 116 |
+
|
| 117 |
+
You must generate a response in the following order and with these exact headings:
|
| 118 |
+
|
| 119 |
+
**1. What You Did Well:**
|
| 120 |
+
Start with positive reinforcement on the structure. For example, "Your report was organized into paragraphs, which provides a basic structure for your description."
|
| 121 |
+
|
| 122 |
+
**2. What You Could Have Done Better:**
|
| 123 |
+
Provide a detailed critique. For example, "The information was not grouped logically. You switched between describing two different countries within the same paragraph, which was confusing. It would be clearer to dedicate one paragraph to each country."
|
| 124 |
+
|
| 125 |
+
**3. Cohesion and Coherence Breakdown:**
|
| 126 |
+
* **Paragraphing:** Comment on the paragraph structure. Example: "Your second body paragraph was very long and mixed rising and falling trends. It would have been more coherent to discuss the rising figures in one paragraph and the falling figures in another."
|
| 127 |
+
* **Linking Words:** Comment on cohesive devices. Example: "You used 'Also' three times to start a sentence. Using more varied linkers like 'Furthermore' or 'In addition,' or comparative language like 'In contrast,' would improve the flow."
|
| 128 |
+
|
| 129 |
+
**4. Recommendations for Improvement:**
|
| 130 |
+
Give actionable advice. For instance, "Before writing, create a simple plan. Decide how you will group the information from the chart into 2-3 body paragraphs. This will ensure your report is logical and easy for the reader to follow."
|
| 131 |
+
|
| 132 |
+
**5. Suggested Edits to Your Original Text:**
|
| 133 |
+
Provide specific, revised sentences showing improved flow.
|
| 134 |
+
*Example:*
|
| 135 |
+
*Your Original Text:* "Car sales were high. Bike sales were low. Car sales went up. Bike sales went down."
|
| 136 |
+
*Higher-Scoring Alternative for Coherence and Cohesion:* "Car sales started at a high level and subsequently increased throughout the period. **In stark contrast,** the figures for bike sales were initially low and experienced a consistent decline."
|
| 137 |
+
|
| 138 |
+
**6. Final Coherence and Cohesion Score:**
|
| 139 |
+
Conclude with the final band score for Coherence and Cohesion only.
|
| 140 |
+
*Example:*
|
| 141 |
+
"Final Coherence and Cohesion Score: 6"
|
| 142 |
+
|
| 143 |
+
Do not add any conversational closings, greetings, or encouragement to message again.
|
| 144 |
+
"""
|
| 145 |
+
),
|
| 146 |
+
HumanMessagePromptTemplate.from_template([
|
| 147 |
+
{
|
| 148 |
+
"type": "text",
|
| 149 |
+
"text": """**IELTS Writing Task 1 (Academic)**
|
| 150 |
+
|
| 151 |
+
Please evaluate the following student response based on the provided image.
|
| 152 |
+
|
| 153 |
+
**Student's Response:**
|
| 154 |
+
{student_response}"""
|
| 155 |
+
},
|
| 156 |
+
{
|
| 157 |
+
"type": "image_url",
|
| 158 |
+
"image_url": "{image_url}",
|
| 159 |
+
}
|
| 160 |
+
])
|
| 161 |
+
])
|
| 162 |
+
|
| 163 |
+
chain = chat_prompt | model
|
| 164 |
+
response = chain.invoke({
|
| 165 |
+
"image_url": state["image_url"],
|
| 166 |
+
"student_response": state["student_essay"]
|
| 167 |
+
})
|
| 168 |
+
|
| 169 |
+
return {"coherence_and_cohesion": response.content}
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def lexical_resource(state: State):
|
| 173 |
+
print("--Starting Lexical Resource Analysis--")
|
| 174 |
+
logger.info("Starting Lexical Resource Analysis")
|
| 175 |
+
|
| 176 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 177 |
+
SystemMessagePromptTemplate.from_template(
|
| 178 |
+
"""
|
| 179 |
+
You are an expert IELTS Writing Examiner specializing in **Task 1 (Academic) Lexical Resource**. Your sole function is to assess a student's report based *only* on the range, accuracy, and appropriacy of the vocabulary used to describe visual data. You will be given an image and the student's written report. You must ignore all other scoring criteria (Task Response, Coherence & Cohesion, Grammatical Range & Accuracy).
|
| 180 |
+
|
| 181 |
+
**Your Role and How to Score Lexical Resource (Task 1):**
|
| 182 |
+
|
| 183 |
+
Your primary job is to evaluate the writer's vocabulary, particularly the language used to describe trends, make comparisons, and present data.
|
| 184 |
+
|
| 185 |
+
**What to Look For (Your Internal Checklist):**
|
| 186 |
+
1. **Range of Vocabulary:** Does the writer use varied and precise vocabulary for trends (e.g., 'rose sharply,' 'declined steadily,' 'fluctuated,' 'peaked at,' 'reached a nadir')? Or do they repeat simple words like 'go up' and 'go down'?
|
| 187 |
+
2. **Vocabulary for Comparison:** Is there a good range of comparative language (e.g., 'significantly higher than,' 'three times as much as,' 'followed by,' 'the respective figures for')?
|
| 188 |
+
3. **Precision:** Are words used accurately? For example, using 'dramatic' for a large change and 'slight' for a small one.
|
| 189 |
+
4. **Collocations:** Does the writer use natural word pairings (e.g., 'a sharp increase,' 'a gradual decline')?
|
| 190 |
+
5. **Spelling and Word Formation:** Are there errors in spelling or word formation (e.g., 'increase' (n.) vs 'increasing' (adj.))? Do these errors impede communication?
|
| 191 |
+
|
| 192 |
+
**Lexical Resource (Task 1) Scoring Guide (Strictly follow this):**
|
| 193 |
+
* **Band 7+:** Uses a sufficient range of vocabulary with flexibility and precision. Uses some less common lexical items, with an awareness of style and collocation (e.g., 'a corresponding fall,' 'plateaued'). May produce occasional minor errors.
|
| 194 |
+
* **Band 6:** Uses an adequate range of vocabulary for the task. Attempts to use less common vocabulary but with some inaccuracy. Makes some errors in spelling/word formation, but they do not impede communication.
|
| 195 |
+
* **Band 5:** Uses a limited range of vocabulary, but it is minimally adequate. Makes noticeable errors that may cause some difficulty for the reader.
|
| 196 |
+
|
| 197 |
+
**Your Output Structure (Follow this format precisely):**
|
| 198 |
+
|
| 199 |
+
You must generate a response in the following order and with these exact headings:
|
| 200 |
+
|
| 201 |
+
**1. What You Did Well:**
|
| 202 |
+
Start with positive reinforcement. For example, "You have correctly used some basic vocabulary to describe trends, such as 'increased' and 'decreased'."
|
| 203 |
+
|
| 204 |
+
**2. What You Could Have Done Better:**
|
| 205 |
+
Provide a detailed critique. For example, "The report was repetitive. You used the word 'increased' five times. To show a wider range, you could have used synonyms like 'rose,' 'grew,' 'climbed,' or phrases like 'saw an upward trend'."
|
| 206 |
+
|
| 207 |
+
**3. Lexical Resource Breakdown:**
|
| 208 |
+
* **Repetition:** List overused words. Example: "The word 'number' was used frequently. Alternatives like 'figure,' 'quantity,' or 'proportion' could have been used."
|
| 209 |
+
* **Word Choice/Collocation:** Point out specific errors. Example: "The phrase 'a big jump' is too informal. A better choice would be 'a significant increase' or 'a sharp rise'."
|
| 210 |
+
|
| 211 |
+
**4. Recommendations for Improvement:**
|
| 212 |
+
Give actionable advice. For instance, "Create vocabulary lists specifically for Task 1. Have one list for 'up' words (increase, rise, grow, climb, rocket, surge), one for 'down' words (decrease, fall, decline, drop, plunge), one for stability (remain stable, plateau), and one for fluctuation."
|
| 213 |
+
|
| 214 |
+
**5. Suggested Edits to Your Original Text:**
|
| 215 |
+
Provide specific, revised sentences showing better vocabulary.
|
| 216 |
+
*Example:*
|
| 217 |
+
*Your Original Text:* "The number of sales went up a lot from 20 to 80."
|
| 218 |
+
*Higher-Scoring Alternative for Lexical Resource:* "The figure for sales experienced **a dramatic fourfold increase,** **climbing** from 20 to 80."
|
| 219 |
+
|
| 220 |
+
**6. Final Lexical Resource Score:**
|
| 221 |
+
Conclude with the final band score for Lexical Resource only.
|
| 222 |
+
*Example:*
|
| 223 |
+
"Final Lexical Resource Score: 6"
|
| 224 |
+
|
| 225 |
+
Do not add any conversational closings, greetings, or encouragement to message again.
|
| 226 |
+
"""
|
| 227 |
+
),
|
| 228 |
+
HumanMessagePromptTemplate.from_template([
|
| 229 |
+
{
|
| 230 |
+
"type": "text",
|
| 231 |
+
"text": """**IELTS Writing Task 1 (Academic)**
|
| 232 |
+
|
| 233 |
+
Please evaluate the following student response based on the provided image.
|
| 234 |
+
|
| 235 |
+
**Student's Response:**
|
| 236 |
+
{student_response}"""
|
| 237 |
+
},
|
| 238 |
+
{
|
| 239 |
+
"type": "image_url",
|
| 240 |
+
"image_url": "{image_url}",
|
| 241 |
+
}
|
| 242 |
+
])
|
| 243 |
+
])
|
| 244 |
+
|
| 245 |
+
chain = chat_prompt | model
|
| 246 |
+
response = chain.invoke({
|
| 247 |
+
"image_url": state["image_url"],
|
| 248 |
+
"student_response": state["student_essay"]
|
| 249 |
+
})
|
| 250 |
+
|
| 251 |
+
return {"lexical_resource": response.content}
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
def grammatical_range_and_accuracy(state: State):
|
| 255 |
+
print("--Starting Grammar Analysis--")
|
| 256 |
+
logger.info("Starting Grammar Analysis")
|
| 257 |
+
|
| 258 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 259 |
+
SystemMessagePromptTemplate.from_template(
|
| 260 |
+
"""
|
| 261 |
+
You are an expert IELTS Writing Examiner specializing in **Task 1 (Academic) Grammatical Range and Accuracy (GRA)**. Your sole function is to assess a student's report based *only* on the variety, complexity, and correctness of the grammatical structures used. You will be given an image and the student's written report. You must ignore all other scoring criteria (Task Response, Coherence & Cohesion, Lexical Resource).
|
| 262 |
+
|
| 263 |
+
**Your Role and How to Score Grammatical Range and Accuracy (Task 1):**
|
| 264 |
+
|
| 265 |
+
Your primary job is to analyze the writer's control and use of grammar, paying special attention to structures used for describing and comparing data.
|
| 266 |
+
|
| 267 |
+
**What to Look For (Your Internal Checklist):**
|
| 268 |
+
1. **Sentence Structures:** Does the writer use a mix of simple, compound, and complex sentences? Is there an over-reliance on simple 'Subject-Verb-Object' sentences?
|
| 269 |
+
2. **Grammatical Range:** Is there a variety of structures relevant to Task 1? For example:
|
| 270 |
+
* Language of comparison (e.g., 'was higher than', 'was not as high as').
|
| 271 |
+
* Use of different clauses (e.g., "..., while the figure for Y fell.", "..., which was followed by a sharp decline.").
|
| 272 |
+
* Correct tense usage (e.g., past tense for past charts, present perfect for changes up to now, future for projections).
|
| 273 |
+
3. **Grammatical Accuracy:** How frequent and severe are grammatical errors (e.g., subject-verb agreement, articles, prepositions)? Do they impede communication?
|
| 274 |
+
4. **Punctuation:** Is punctuation used correctly to support sentence structure and clarity?
|
| 275 |
+
|
| 276 |
+
**Grammatical Range and Accuracy (Task 1) Scoring Guide (Strictly follow this):**
|
| 277 |
+
* **Band 7+:** Uses a variety of complex structures effectively. Produces frequent error-free sentences. Has good control of grammar and punctuation, with only a few errors.
|
| 278 |
+
* **Band 6:** Uses a mix of simple and complex sentence forms. Makes some errors in grammar and punctuation, but they rarely reduce communication.
|
| 279 |
+
* **Band 5:** Uses only a limited range of structures. Attempts complex sentences, but they are often inaccurate. Makes frequent grammatical errors that can cause some difficulty for the reader.
|
| 280 |
+
|
| 281 |
+
**Your Output Structure (Follow this format precisely):**
|
| 282 |
+
|
| 283 |
+
You must generate a response in the following order and with these exact headings:
|
| 284 |
+
|
| 285 |
+
**1. What You Did Well:**
|
| 286 |
+
Start with positive reinforcement. For example, "You have correctly used the simple past tense throughout your report, which is appropriate for the time frame of the chart."
|
| 287 |
+
|
| 288 |
+
**2. What You Could Have Done Better:**
|
| 289 |
+
Provide a detailed critique. For example, "The report consisted mainly of short, simple sentences. To improve your range, you should combine ideas using conjunctions like 'while' or 'whereas' to make comparisons within a single sentence."
|
| 290 |
+
|
| 291 |
+
**3. Grammatical Range and Accuracy Breakdown:**
|
| 292 |
+
* **Sentence Structure:** Comment on the variety. Example: "You wrote: 'Sales in the UK were 50. Sales in France were 30.' These could be combined into one complex sentence: 'Sales in the UK were 50, whereas the figure for France was significantly lower at 30.'"
|
| 293 |
+
* **Grammatical Errors:** List repeated errors. Example: "There were several errors with prepositions, such as 'increased at 50%' instead of 'increased by 50%' and 'sales in 2005' instead of 'in the year 2005'."
|
| 294 |
+
|
| 295 |
+
**4. Recommendations for Improvement:**
|
| 296 |
+
Give actionable advice. For instance, "Practice writing sentences that compare two data points. Learn the difference between using a verb + adverb (e.g., 'increased sharply') and an adjective + noun (e.g., 'there was a sharp increase')."
|
| 297 |
+
|
| 298 |
+
**5. Suggested Edits to Your Original Text:**
|
| 299 |
+
Provide specific, revised sentences showing better grammar.
|
| 300 |
+
*Example:*
|
| 301 |
+
*Your Original Text:* "The UK had the highest number. It was 50%."
|
| 302 |
+
*Higher-Scoring Alternative for Grammatical Range and Accuracy:* "The UK accounted for the highest proportion of sales, **at 50%**, **which was double the figure for the next largest country.**"
|
| 303 |
+
|
| 304 |
+
**6. Final Grammatical Range and Accuracy Score:**
|
| 305 |
+
Conclude with the final band score for GRA only.
|
| 306 |
+
*Example:*
|
| 307 |
+
"Final Grammatical Range and Accuracy Score: 5"
|
| 308 |
+
|
| 309 |
+
Do not add any conversational closings, greetings, or encouragement to message again.
|
| 310 |
+
"""
|
| 311 |
+
),
|
| 312 |
+
HumanMessagePromptTemplate.from_template([
|
| 313 |
+
{
|
| 314 |
+
"type": "text",
|
| 315 |
+
"text": """**IELTS Writing Task 1 (Academic)**
|
| 316 |
+
|
| 317 |
+
Please evaluate the following student response based on the provided image.
|
| 318 |
+
|
| 319 |
+
**Student's Response:**
|
| 320 |
+
{student_response}"""
|
| 321 |
+
},
|
| 322 |
+
{
|
| 323 |
+
"type": "image_url",
|
| 324 |
+
"image_url": "{image_url}",
|
| 325 |
+
}
|
| 326 |
+
])
|
| 327 |
+
])
|
| 328 |
+
|
| 329 |
+
chain = chat_prompt | model
|
| 330 |
+
response = chain.invoke({
|
| 331 |
+
"image_url": state["image_url"],
|
| 332 |
+
"student_response": state["student_essay"]
|
| 333 |
+
})
|
| 334 |
+
|
| 335 |
+
return {"grammatical_range_and_accuracy": response.content}
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
def aggregator(state: State):
|
| 339 |
+
print("--Summarizing--")
|
| 340 |
+
logger.info("Summarizing: starting")
|
| 341 |
+
|
| 342 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 343 |
+
SystemMessagePromptTemplate.from_template(
|
| 344 |
+
"""
|
| 345 |
+
You are a Senior IELTS Writing Assessor and Head Examiner. Your function is to receive four separate, detailed evaluations for a single **IELTS Writing Task 1 (Academic)** report and synthesize them into a final, holistic report for the student. The four evaluations you will receive correspond to the four official IELTS marking criteria: Task Response (TR), Coherence and Cohesion (C&C), Lexical Resource (LR), and Grammatical Range and Accuracy (GRA).
|
| 346 |
+
|
| 347 |
+
**Your Core Role and Directives:**
|
| 348 |
+
|
| 349 |
+
1. **Synthesize, Do Not Re-evaluate:** You must base your entire report *only* on the analysis and scores provided in the four expert reports you receive as input. Do NOT re-examine the student's original report or the visual data. You are to trust and summarize the findings of the specialist examiners.
|
| 350 |
+
2. **Summarize Key Points:** For each of the four criteria, concisely summarize the main strengths and the key areas for improvement identified by the specialist examiner.
|
| 351 |
+
3. **Calculate the Overall Score:** You must calculate the final, overall IELTS band score for Writing Task 1 precisely according to the official method.
|
| 352 |
+
|
| 353 |
+
**How to Calculate the Overall Band Score (Crucial Instructions):**
|
| 354 |
+
|
| 355 |
+
The Overall Band Score is the average of the four individual scores. Follow this procedure exactly:
|
| 356 |
+
* **Formula:** Overall Score = (Task Response Score + Coherence and Cohesion Score + Lexical Resource Score + Grammatical Range and Accuracy Score) / 4
|
| 357 |
+
* **Official Rounding Rule:** The result must be rounded to the nearest half-band.
|
| 358 |
+
* If the average ends in **.25**, round **UP** to the next half-band (e.g., an average of 6.25 becomes an Overall Score of **6.5**).
|
| 359 |
+
* If the average ends in **.75**, round **UP** to the next whole band (e.g., an average of 6.75 becomes an Overall Score of **7.0**).
|
| 360 |
+
* Averages ending in .0 or .5 remain unchanged.
|
| 361 |
+
|
| 362 |
+
**Your Output Structure (Follow this format precisely):**
|
| 363 |
+
|
| 364 |
+
You must generate a single, consolidated report in the following order and with these exact headings:
|
| 365 |
+
|
| 366 |
+
**Overall IELTS Writing Task 1 (Academic) Feedback**
|
| 367 |
+
|
| 368 |
+
Here is a summary of your performance based on the four official IELTS scoring criteria.
|
| 369 |
+
|
| 370 |
+
**1. Task Response**
|
| 371 |
+
* **Strengths:** [Concisely summarize the positive points from the Task Response agent's report.]
|
| 372 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Task Response agent's report.]
|
| 373 |
+
* **Expert Score:** [State the score given by the Task Response agent.]
|
| 374 |
+
|
| 375 |
+
**2. Coherence and Cohesion**
|
| 376 |
+
* **Strengths:** [Concisely summarize the positive points from the Coherence and Cohesion agent's report.]
|
| 377 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Coherence and Cohesion agent's report.]
|
| 378 |
+
* **Expert Score:** [State the score given by the Coherence and Cohesion agent.]
|
| 379 |
+
|
| 380 |
+
**3. Lexical Resource (Vocabulary)**
|
| 381 |
+
* **Strengths:** [Concisely summarize the positive points from the Lexical Resource agent's report.]
|
| 382 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Lexical Resource agent's report.]
|
| 383 |
+
* **Expert Score:** [State the score given by the Lexical Resource agent.]
|
| 384 |
+
|
| 385 |
+
**4. Grammatical Range and Accuracy**
|
| 386 |
+
* **Strengths:** [Concisely summarize the positive points from the Grammatical Range and Accuracy agent's report.]
|
| 387 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Grammatical Range and Accuracy agent's report.]
|
| 388 |
+
* **Expert Score:** [State the score given by the Grammatical Range and Accuracy agent.]
|
| 389 |
+
|
| 390 |
+
---
|
| 391 |
+
|
| 392 |
+
**Final Analysis and Overall Score**
|
| 393 |
+
* **Summative Comments:** [Provide a brief (2-3 sentences) holistic overview. For example: "Overall, your report is logically structured, but its effectiveness is limited by an inaccurate Task Response, specifically the lack of a clear overview. Focusing on summarizing the main trends first will significantly boost your score."]
|
| 394 |
+
* **Overall Band Score:** [State the final, calculated, and correctly rounded overall score.]
|
| 395 |
+
|
| 396 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final Overall Band Score.
|
| 397 |
+
"""
|
| 398 |
+
),
|
| 399 |
+
HumanMessagePromptTemplate.from_template(
|
| 400 |
+
"""
|
| 401 |
+
Please generate a final Task 1 report based on the following four expert evaluations.
|
| 402 |
+
|
| 403 |
+
**TASK 1 TASK RESPONSE REPORT:**
|
| 404 |
+
---
|
| 405 |
+
{task_response_report}
|
| 406 |
+
---
|
| 407 |
+
|
| 408 |
+
**TASK 1 COHERENCE AND COHESION REPORT:**
|
| 409 |
+
---
|
| 410 |
+
{coherence_cohesion_report}
|
| 411 |
+
---
|
| 412 |
+
|
| 413 |
+
**TASK 1 LEXICAL RESOURCE REPORT:**
|
| 414 |
+
---
|
| 415 |
+
{lexical_resource_report}
|
| 416 |
+
---
|
| 417 |
+
|
| 418 |
+
**TASK 1 GRAMMATICAL RANGE AND ACCURACY REPORT:**
|
| 419 |
+
---
|
| 420 |
+
{grammatical_range_and_accuracy_report}
|
| 421 |
+
---
|
| 422 |
+
"""
|
| 423 |
+
)
|
| 424 |
+
])
|
| 425 |
+
|
| 426 |
+
chain = chat_prompt | model
|
| 427 |
+
response = chain.invoke({
|
| 428 |
+
"task_response_report": state["task_response"],
|
| 429 |
+
"coherence_cohesion_report": state["coherence_and_cohesion"],
|
| 430 |
+
"lexical_resource_report": state["lexical_resource"],
|
| 431 |
+
"grammatical_range_and_accuracy_report": state["grammatical_range_and_accuracy"]
|
| 432 |
+
})
|
| 433 |
+
|
| 434 |
+
logger.info("Final Report!")
|
| 435 |
+
return {"aggregated_result": response.content}
|
| 436 |
+
|
vendors/part1/state.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List, TypedDict, Union
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class State(TypedDict):
|
| 5 |
+
student_essay: str
|
| 6 |
+
image_url: str
|
| 7 |
+
task_response: str
|
| 8 |
+
coherence_and_cohesion: str
|
| 9 |
+
lexical_resource: str
|
| 10 |
+
grammatical_range_and_accuracy: str
|
| 11 |
+
estimated_band_score: float
|
| 12 |
+
aggregated_result: str
|
vendors/part1/task_image.png
ADDED
|
Git LFS Details
|
vendors/part1/workflow.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, START, END
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def workflow_fn(State, task_response, lexical_resource, grammatical_range_and_accuracy, coherence_and_cohesion, aggregator):
|
| 5 |
+
workflow = StateGraph(State)
|
| 6 |
+
|
| 7 |
+
workflow.add_node("Task Response", task_response)
|
| 8 |
+
workflow.add_node("Lexical", lexical_resource)
|
| 9 |
+
workflow.add_node("Grammar", grammatical_range_and_accuracy)
|
| 10 |
+
workflow.add_node("CC", coherence_and_cohesion)
|
| 11 |
+
workflow.add_node("Aggregator", aggregator)
|
| 12 |
+
|
| 13 |
+
workflow.add_edge(START, "Task Response")
|
| 14 |
+
workflow.add_edge(START, "Lexical")
|
| 15 |
+
workflow.add_edge(START, "Grammar")
|
| 16 |
+
workflow.add_edge(START, "CC")
|
| 17 |
+
workflow.add_edge("Task Response", "Aggregator")
|
| 18 |
+
workflow.add_edge("CC", "Aggregator")
|
| 19 |
+
workflow.add_edge("Grammar", "Aggregator")
|
| 20 |
+
workflow.add_edge("Lexical", "Aggregator")
|
| 21 |
+
workflow.add_edge("Aggregator", END)
|
| 22 |
+
|
| 23 |
+
workflow = workflow.compile()
|
| 24 |
+
|
| 25 |
+
with open("Workflow.md", "w") as f:
|
| 26 |
+
mermaid_code = workflow.get_graph().draw_mermaid()
|
| 27 |
+
f.write(f"```mermaid\n{mermaid_code}\n```")
|
| 28 |
+
|
| 29 |
+
return workflow
|
vendors/part2/Workflow.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
```mermaid
|
| 2 |
+
---
|
| 3 |
+
config:
|
| 4 |
+
flowchart:
|
| 5 |
+
curve: linear
|
| 6 |
+
---
|
| 7 |
+
graph TD;
|
| 8 |
+
__start__([<p>__start__</p>]):::first
|
| 9 |
+
Task_Response(Task Response)
|
| 10 |
+
Lexical(Lexical)
|
| 11 |
+
Grammar(Grammar)
|
| 12 |
+
CC(CC)
|
| 13 |
+
Aggregator(Aggregator)
|
| 14 |
+
__end__([<p>__end__</p>]):::last
|
| 15 |
+
CC --> Aggregator;
|
| 16 |
+
Grammar --> Aggregator;
|
| 17 |
+
Lexical --> Aggregator;
|
| 18 |
+
Task_Response --> Aggregator;
|
| 19 |
+
__start__ --> CC;
|
| 20 |
+
__start__ --> Grammar;
|
| 21 |
+
__start__ --> Lexical;
|
| 22 |
+
__start__ --> Task_Response;
|
| 23 |
+
Aggregator --> __end__;
|
| 24 |
+
classDef default fill:#f2f0ff,line-height:1.2
|
| 25 |
+
classDef first fill-opacity:0
|
| 26 |
+
classDef last fill:#bfb6fc
|
| 27 |
+
|
| 28 |
+
```
|
vendors/part2/__init__.py
ADDED
|
File without changes
|
vendors/part2/display_report.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import re
|
| 3 |
+
import textwrap
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
class styles:
|
| 7 |
+
HEADER = '\033[95m'
|
| 8 |
+
GREEN = '\033[92m'
|
| 9 |
+
WARNING = '\033[93m'
|
| 10 |
+
BOLD = '\033[1m'
|
| 11 |
+
UNDERLINE = '\033[4m'
|
| 12 |
+
ENDC = '\033[0m'
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
def print_md(text):
|
| 16 |
+
"""
|
| 17 |
+
Translates simple markdown and wraps text for better terminal display.
|
| 18 |
+
"""
|
| 19 |
+
text = re.sub(r'\*\*(.*?)\*\*', f'{styles.BOLD}\\1{styles.ENDC}', text)
|
| 20 |
+
paragraphs = text.split('\n')
|
| 21 |
+
wrapped_paragraphs = [textwrap.fill(p, width=90) for p in paragraphs]
|
| 22 |
+
final_text = '\n'.join(wrapped_paragraphs)
|
| 23 |
+
print(final_text)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def display_report_fn(data):
|
| 27 |
+
"""
|
| 28 |
+
Loads, parses, and prints the formatted IELTS report from a JSON file.
|
| 29 |
+
"""
|
| 30 |
+
|
| 31 |
+
print("\n" + "=" * 80)
|
| 32 |
+
print(f"{styles.HEADER}{styles.BOLD}📝 IELTS WRITING EVALUATION REPORT{styles.ENDC}")
|
| 33 |
+
print("=" * 80)
|
| 34 |
+
|
| 35 |
+
if "original_question" in data:
|
| 36 |
+
print(f"\n{styles.HEADER}{styles.UNDERLINE}Original Question:{styles.ENDC}")
|
| 37 |
+
print_md(data["original_question"])
|
| 38 |
+
|
| 39 |
+
if "student_essay" in data:
|
| 40 |
+
print(f"\n{styles.HEADER}{styles.UNDERLINE}Student's Essay:{styles.ENDC}")
|
| 41 |
+
print_md(data["student_essay"])
|
| 42 |
+
print("-" * 80)
|
| 43 |
+
|
| 44 |
+
sections = {
|
| 45 |
+
"task_response": "✅ Task Response",
|
| 46 |
+
"coherence_and_cohesion": "🔗 Coherence and Cohesion",
|
| 47 |
+
"lexical_resource": "📚 Lexical Resource",
|
| 48 |
+
"grammatical_range_and_accuracy": "📝 Grammatical Range and Accuracy"
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
for key, title in sections.items():
|
| 52 |
+
if key in data:
|
| 53 |
+
print(f"\n\n{styles.GREEN}{styles.BOLD}{styles.UNDERLINE}--- {title} ---{styles.ENDC}\n")
|
| 54 |
+
print_md(data[key])
|
| 55 |
+
|
| 56 |
+
if "aggregated_result" in data:
|
| 57 |
+
print(
|
| 58 |
+
f"\n\n{styles.WARNING}{styles.BOLD}{styles.UNDERLINE}--- 📊 Overall Summary & Final Score ---{styles.ENDC}\n")
|
| 59 |
+
print_md(data["aggregated_result"])
|
| 60 |
+
|
| 61 |
+
print("\n" + "=" * 80 + "\n")
|
| 62 |
+
|
| 63 |
+
|
vendors/part2/final_state.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"student_essay": "One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends. However while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\n\n\nFirstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day. Secondly, longer weekends will make people lazy and distant from their work. For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home. Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\n\n\nThere are several ways to improve your lifestyle while not having longer weekends. Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time. One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\n\n\nIn conclusion, I think while occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.",
|
| 3 |
+
"original_question": "The working week should be shorter and workers should have a longer weekend.\n\nDo you agree or disagree. ",
|
| 4 |
+
"task_response": "**1. What You Did Well:**\nYou successfully identified the core topic of the question and presented a clear and consistent position (disagreement) from the introduction through to the conclusion. You provided several relevant arguments to support your stance, such as the potential for laziness, the economic impact of reduced working hours, and the idea that current time off is sufficient if managed well. Your use of a personal anecdote to illustrate the point about becoming distant from work was a good attempt at providing specific support.\n\n**2. What You Could Have Done Better:**\nWhile your position was clear, some of your supporting points could have been more directly and strongly linked to the central argument against a shorter working week and longer weekend. For example, the point about finding coworkers with similar interests, while a valid way to improve job experience, doesn't directly argue against the *need* for a shorter working week or longer weekend in terms of rest or productivity. Its connection to the prompt's core argument was a bit indirect. Additionally, your reference to a \"recent study\" about economic impact, while a strong point, lacked specificity, which can weaken its persuasive power in terms of Task Response.\n\n**3. What You Missed:**\nYou did not completely miss any part of the prompt. You clearly addressed the \"agree or disagree\" aspect and provided reasons for your stance. The areas for improvement relate more to the depth and directness of the development of some ideas rather than an omission of a task component.\n\n**4. Recommendations for Improvement:**\n* Before writing, ensure that every main idea and supporting example you plan to include directly and unequivocally supports your overall position. Ask yourself: \"How does this specific point or example directly prove why I agree or disagree with the prompt?\"\n* When using external evidence or studies, try to be more specific if possible (e.g., \"Research from [institution] suggests...\") or frame it as a widely accepted concept if specific details are unavailable (e.g., \"It is widely understood that...\"). Avoid vague references like \"I read a recent study.\"\n* Elaborate more fully on your main points. For instance, when you state there's \"plenty of time to rest,\" expand on *how* that time can be effectively utilized to achieve the desired rest, rather than just stating the fact.\n\n**5. Suggested Edits to Your Original Text:**\n\n* **Your Original Sentence:** \"Firstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day.\"\n * **Higher-Scoring Alternative for Task Response:** \"Firstly, I contend that the current working structure already provides ample opportunity for rest and recuperation. Individuals can effectively manage their evenings and existing weekends to engage in leisure activities, pursue hobbies, and spend quality time with family, thereby mitigating the need for an extended break.\"\n\n* **Your Original Sentence:** \"Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n * **Higher-Scoring Alternative for Task Response:** \"Furthermore, a significant concern is the potential negative impact on national economies. Economic analyses often indicate that a reduction in working hours can lead to decreased productivity, higher operational costs for businesses, and ultimately, a decline in overall economic output, posing a long-term threat to prosperity.\"\n\n* **Your Original Sentence:** \"One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n * **Higher-Scoring Alternative for Task Response:** \"Beyond simply extending leisure time, improving job satisfaction itself can significantly enhance overall well-being, thereby reducing the perceived need for a shorter working week. For instance, fostering a positive work environment and encouraging social connections among colleagues can make the workday more enjoyable and less draining. My own experience, where forming friendships with colleagues who shared common interests like soccer transformed a challenging period into a more positive one, illustrates how internal workplace dynamics can be more impactful than simply increasing time away from work.\"\n\n**6. Final Task Response Score:** 7",
|
| 5 |
+
"coherence_and_cohesion": "**1. What You Did Well:**\nYour essay was clearly organized into an introduction, body paragraphs, and a conclusion, which provides a basic structure for your ideas. You also attempted to use linking words to introduce your points within the first body paragraph.\n\n**2. What You Could Have Done Better:**\nThe primary weakness in your essay's Coherence and Cohesion lies in the organization of your body paragraphs. Your first body paragraph is very long and contains three distinct arguments, which makes it difficult for the reader to follow a single, developed idea. The logical progression between your first and second body paragraphs is also not entirely smooth, as the second paragraph introduces a new line of argument (alternatives to longer weekends) rather than directly developing the reasons against them. Furthermore, your use of cohesive devices is somewhat mechanical and repetitive.\n\n**3. Cohesion and Coherence Breakdown:**\n* **Paragraphing:** Your first body paragraph is a significant issue. It attempts to present three separate main ideas (\"plenty of time to rest,\" \"longer weekends make people lazy,\" and \"impact on economy\") within a single paragraph. For greater clarity and to allow for proper development of each point, these should have been separated into individual paragraphs. The second body paragraph also contains two distinct ideas (planning weekends and finding like-minded colleagues) that could benefit from clearer separation or more explicit linking.\n* **Linking Words:** You rely heavily on \"Firstly,\" \"Secondly,\" and \"Thirdly\" to introduce points within one long paragraph. While these are cohesive devices, their repetitive use in this manner makes the writing feel mechanical rather than fluid. There is an underuse of a wider range of more sophisticated linking words and phrases that could show more complex relationships between sentences and paragraphs (e.g., cause and effect, contrast, further addition, exemplification). The transition from the first body paragraph to the second is abrupt, lacking a clear linking phrase to signal the shift in focus.\n* **Referencing:** Referencing is generally clear (e.g., \"this\" referring to finding coworkers with the same interest). However, some phrasing like \"I was feeling distant with my job and felt the urge to be done with the work\" could be more concise to avoid slight repetition.\n\n**4. Recommendations for Improvement:**\n* **Plan your paragraphs carefully:** Before you start writing, create a brief outline. Assign one central idea to each body paragraph. This will help you ensure that each paragraph has a clear topic sentence and develops a single argument thoroughly.\n* **Vary your cohesive devices:** Expand your repertoire of linking words and phrases. Instead of just \"Secondly,\" consider using alternatives like \"Furthermore,\" \"Moreover,\" \"In addition to this,\" or \"Another significant point is that...\" to introduce new ideas. Use transition words to show the relationship between sentences (e.g., \"consequently,\" \"as a result,\" \"in contrast,\" \"however,\" \"for instance\").\n* **Ensure logical progression between paragraphs:** Think about how each paragraph connects to the one before it and how it contributes to your overall argument. Use clear topic sentences and transitional phrases at the beginning of paragraphs to guide the reader smoothly from one idea to the next. For an \"agree/disagree\" essay, ensure your body paragraphs consistently support your stated stance.\n\n**5. Suggested Edits to Your Original Text:**\n\n* **Original Body Paragraph 1:**\n \"Firstly, I think that there is plenty of time to rest after you get off from your work and prepare for the next day. Secondly, longer weekends will make people lazy and distant from their work. For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home. Thirdly, I read a recent study that discussed the impact of cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n\n* **Higher-Scoring Alternative for Coherence and Cohesion (showing improved paragraphing and linking):**\n\n \"To begin with, I believe that the current working week already provides sufficient time for individuals to rest and prepare for the following day. There is ample opportunity within the existing structure for personal rejuvenation without the need for extended weekends.\n\n **Moreover,** a key concern is that longer weekends could inadvertently lead to a decline in productivity and a sense of detachment from one's profession. **For example,** during my experience at a tech company where we occasionally had four-day weekends, I observed that upon returning to work, both I and my colleagues often felt a diminished connection to our tasks, leading to a desire to complete work as quickly as possible rather than engaging deeply.\n\n **Beyond individual impact,** there are significant economic considerations. I recently read a study that highlighted the substantial long-term damage inflicted upon a country's economy when working hours were significantly reduced, suggesting that such policies can have far-reaching negative consequences.\"\n\n* **Original Body Paragraph 2:**\n \"There are several ways to improve your lifestyle while not having longer weekends. Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time. One of the best ways to make your job experience better is to find coworkers with the same interest as you. this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n\n* **Higher-Scoring Alternative for Coherence and Cohesion (showing better linking and potential splitting):**\n\n \"Instead of shortening the working week, there are alternative strategies to enhance one's lifestyle and well-being. **Crucially,** effective time management during existing weekends can significantly improve their quality. Many individuals fail to plan their time off, which often diminishes its restorative potential; conversely, thoughtful planning can lead to more fulfilling and productive leisure.\n\n **Furthermore,** fostering positive social connections within the workplace can dramatically improve job satisfaction, thereby reducing the perceived need for longer breaks. This was certainly true in my own experience: after a challenging period at work, I connected with a colleague who shared my passion for soccer. Our discussions on various topics not only made the working environment more enjoyable but also fostered a stronger sense of belonging, making the work experience much more positive for both of us.\"\n\n**6. Final Coherence and Cohesion Score:** 5",
|
| 6 |
+
"lexical_resource": "**1. What You Did Well:**\nYou have used some basic topic-specific vocabulary related to work and leisure, such as 'working week', 'weekends', 'time off', and 'economy'. You also attempted to use some phrases to express your opinion, like 'I believe that' and 'I don't think'.\n\n**2. What You Could Have Done Better:**\nThe essay relies heavily on a limited range of vocabulary, leading to repetition and a lack of precision. Many phrases are informal or colloquial, which is not appropriate for an academic essay. There is a consistent lack of sophisticated vocabulary and an absence of less common lexical items. Word choice and collocations are frequently unnatural, making the text sound less fluent and professional.\n\n**3. Lexical Resource Breakdown:**\n\n* **Repetition:**\n * The word \"work/working\" is used excessively (e.g., \"working week,\" \"working period,\" \"get off from your work,\" \"back to work,\" \"my job,\" \"the work,\" \"working hours,\" \"at work,\" \"working experience,\" \"from work,\" \"working days\").\n * \"Time\" is repeated frequently (e.g., \"enough time,\" \"plenty of time,\" \"time off,\" \"quality time\").\n * \"Better\" is overused (e.g., \"better use,\" \"make your job experience better,\" \"better for both of us,\" \"better head space\").\n * \"Need\" is repeated (e.g., \"needs to be shorter,\" \"need of longer weekends,\" \"people need to have,\" \"we need a time off,\" \"without the need of cutting\").\n * \"Feel/feeling\" is repeated in the same sentence: \"didn't feel the same as I was feeling distant.\"\n\n* **Word Choice/Collocation:**\n * \"hot topics these day\" - \"these days\" is correct, but \"hot topics\" is informal. Consider \"a widely debated issue\" or \"a prominent discussion point.\"\n * \"the need of longer weekends\" - Should be \"the need *for* longer weekends.\"\n * \"get off from your work\" - More natural would be \"finish work\" or \"leave work.\"\n * \"make people lazy and distant from their work\" - \"Foster laziness and detachment from their professional responsibilities\" would be more precise. \"Distant from their work\" is awkward.\n * \"the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job\" - Very repetitive and unnatural. Consider \"I felt a diminished connection to my role and colleagues, experiencing a sense of detachment.\"\n * \"felt the urge to be done with the work as quickly as possible\" - \"Felt compelled to complete tasks swiftly.\"\n * \"massive damage to that country's economy\" - \"Massive damage\" is informal. Use \"significant detriment\" or \"severe adverse impact.\"\n * \"improve your lifestyle while not having longer weekends\" - \"Enhance one's lifestyle without necessarily extending weekends.\"\n * \"damage the quality of their time off\" - \"Detract from the quality of their leisure time.\"\n * \"Good planning will guide you to find better use of you quality time\" - \"Effective planning can enable individuals to make better use of their leisure time.\" (\"you quality time\" is a grammatical error, should be \"your\").\n * \"make your job experience better\" - \"Enhance one's professional experience.\"\n * \"having a rough few weeks at work\" - \"Rough\" is informal. Consider \"experiencing a challenging period at work.\"\n * \"discuss about our opinion\" - \"Discuss our opinion\" (no \"about\").\n * \"get into a better head space\" - \"Head space\" is informal. Consider \"achieve a more positive mental state\" or \"improve one's well-being.\"\n * \"tackle this problem\" - \"Address this issue\" or \"resolve this challenge.\"\n\n* **Spelling/Word Formation:**\n * \"these day\" (should be \"these days\")\n * \"you quality time\" (should be \"your quality time\")\n\n**4. Recommendations for Improvement:**\n* **Expand your vocabulary range:** Actively learn synonyms and antonyms for common words. For example, instead of just \"good\" or \"bad,\" learn \"beneficial,\" \"detrimental,\" \"advantageous,\" \"adverse,\" etc.\n* **Focus on precision:** Choose words that convey your meaning exactly. For instance, instead of \"big problem,\" use \"significant issue\" or \"major challenge.\"\n* **Improve collocation awareness:** Pay attention to how words naturally go together. Use a collocation dictionary or notice common phrases in authentic English texts. For example, \"make a decision,\" not \"do a decision.\"\n* **Elevate your style:** Avoid informal language and colloquialisms in academic writing. Replace phrases like \"get off from your work\" or \"rough few weeks\" with more formal alternatives.\n* **Practice paraphrasing:** When you write, try to rephrase ideas using different vocabulary to avoid repetition.\n\n**5. Suggested Edits to Your Original Text:**\n\n* *Your Original Text:* \"One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"**A prominent discussion point** currently revolves around the **proposal for a shorter working week** and the **extension of weekends**.\"\n\n* *Your Original Text:* \"I think that there is plenty of time to rest after you get off from your work and prepare for the next day.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"I believe that individuals have **ample opportunity for recuperation** after **concluding their workdays** to prepare for the subsequent one.\"\n\n* *Your Original Text:* \"longer weekends will make people lazy and distant from their work.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"Extended weekends could **foster indolence** and **detachment from one's professional responsibilities**.\"\n\n* *Your Original Text:* \"the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"I experienced a **diminished connection** to my role and colleagues, feeling **disengaged** and **compelled to complete tasks swiftly** in order to return home.\"\n\n* *Your Original Text:* \"cutting working hours on the economy which showed massive damage to that country's economy in the long run.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"reducing working hours on the economy, which indicated **significant detriment** to that nation's economy in the long run.\"\n\n* *Your Original Text:* \"Most people tend to not plan their weekends at all and that can damage the quality of their time off. Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"Many individuals often **neglect to plan their weekends effectively**, which can **detract from the quality of their leisure time**. **Strategic planning** can enable them to **optimise their free time** and establish achievable goals within a defined period.\"\n\n* *Your Original Text:* \"occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.\"\n * *Higher-Scoring Alternative for Lexical Resource:* \"while occasional **breaks from work** are necessary to **achieve a more positive mental state**, alternative strategies exist to **address this issue** without the necessity of reducing working days or extending weekends.\"\n\n**6. Final Lexical Resource Score:** 5",
|
| 7 |
+
"grammatical_range_and_accuracy": "**1. What You Did Well:**\nYou have demonstrated a good attempt at using a mix of simple, compound, and complex sentence structures. There is clear evidence of complex sentences, particularly those using subordinate clauses (e.g., \"while I believe that...\", \"when I was working...\") and relative clauses (e.g., \"that discussed...\", \"who also loved...\"). This shows a good range in your grammatical structures. You also successfully use introductory phrases and clauses, often followed by correct punctuation.\n\n**2. What You Could Have Done Better:**\nWhile you attempt complex structures, there are frequent grammatical errors that, though often minor, accumulate and affect overall accuracy. These errors include issues with articles, prepositions, singular/plural forms, and occasional tense inconsistencies. Some very long sentences become slightly unwieldy, indicating a need for more precise control over highly complex constructions and better punctuation to manage their flow.\n\n**3. Grammatical Range and Accuracy Breakdown:**\n* **Sentence Structure:** You effectively use a variety of sentence types, moving beyond simple sentences to incorporate complex ones. This includes sentences with noun clauses (\"how the working week needs to be shorter\"), adverbial clauses of time and concession (\"when I was working...\", \"while I believe...\"), and relative clauses (\"that discussed...\", \"who also loved...\"). This demonstrates a good range. However, some sentences are excessively long, which can lead to awkward phrasing and a slight loss of clarity, suggesting that while you attempt complex structures, full control over their most intricate forms is still developing.\n* **Grammatical Errors:**\n * **Articles:** You sometimes omit or misuse articles, for example, \"a time off\" should be \"time off.\"\n * **Prepositions:** There are recurring errors with prepositions, such as \"the need of longer weekends\" (should be \"the need for\"), \"get off from your work\" (should be \"get off work\"), \"distant with my job\" (should be \"distant from my job\"), and \"discuss about our opinion\" (should be \"discuss our opinion\").\n * **Singular/Plural:** You used \"these day\" instead of \"these days\" and \"our opinion on different topics\" instead of \"our opinions on different topics.\"\n * **Tense Consistency:** In the sentence \"so I can go back home,\" the present tense \"can\" is inconsistent with the past context of the narrative (\"when I was working...\"). It should be \"so that I could go back home.\"\n * **Word Choice/Phrasing:** Phrases like \"tend to not plan\" could be more naturally expressed as \"tend not to plan.\" \"use of you quality time\" should be \"use of your quality time.\"\n* **Punctuation:**\n * You occasionally miss commas after introductory clauses (e.g., \"However while I believe...\" should be \"However, while I believe...\").\n * There is a significant run-on sentence due to a lack of capitalization and appropriate punctuation: \"this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\" This sentence is too long and should be broken up or use a semicolon.\n\n**4. Recommendations for Improvement:**\n* **Focus on Prepositions and Articles:** Dedicate specific practice to common prepositional phrases and the rules for using 'a,' 'an,' and 'the,' especially with abstract nouns or general statements.\n* **Review Singular/Plural Nouns:** Pay close attention to whether nouns should be singular or plural, particularly when referring to general concepts or multiple items.\n* **Master Complex Sentence Punctuation:** Practice using commas correctly with dependent and independent clauses. Learn how to use semicolons to connect closely related independent clauses, or how to split very long sentences into two or more shorter, clearer ones.\n* **Ensure Tense Consistency:** When narrating events or discussing past experiences, ensure that all verbs maintain a consistent tense unless there's a specific reason for a shift.\n* **Proofread Systematically:** After writing, review your essay specifically for one type of grammatical error at a time (e.g., first check all prepositions, then all articles, then all subject-verb agreements).\n\n**5. Suggested Edits to Your Original Text:**\n* **Your Original Text:** \"One of the hot topics these day is about how the working week needs to be shorter and the need of longer weekends.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"One of the hot topics these **days** is **the debate about** how the working week needs to be shorter and the need **for** longer weekends.\"\n* **Your Original Text:** \"However while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"However, while I believe that people need to have enough time to rest after their working period, I don't think they need longer weekends to achieve that.\"\n* **Your Original Text:** \"For example, when I was working at a tech company, we used to have 4 days off and when we would get back to work the connection I had with my job and colleagues didn't feel the same as I was feeling distant with my job and felt the urge to be done with the work as quickly as possible so I can go back home.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"For example, when I was working at a tech company, we used to have four days off. When we returned to work, the connection I had with my job and colleagues didn't feel the same; I felt distant from my job and had the urge to finish work as quickly as possible so that I could go back home.\"\n* **Your Original Text:** \"Good planning will guide you to find better use of you quality time and setting the goals you want to achieve by a certain time.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"Good planning will guide you to make better use of **your** quality time and to set the goals you want to achieve by a certain time.\"\n* **Your Original Text:** \"this was the case for me as I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did and we used to discuss about our opinion on different topics which made the working experience much better for both of us.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"**This** was the case for me: I was having a rough few weeks at work but then ended up meeting one of my best friends who also loved soccer as much as I did. We used to discuss our **opinions** on different topics, which made the working experience much better for both of us.\"\n* **Your Original Text:** \"In conclusion, I think while occasionally we need a time off from work to get into a better head space, there are other ways to tackle this problem without the need of cutting working days and making the weekends longer.\"\n * **Higher-Scoring Alternative for Grammatical Range and Accuracy:** \"In conclusion, I think while occasionally we need time off from work to get into a better headspace, there are other ways to tackle this problem without the need **for** cutting working days and making the weekends longer.\"\n\n**6. Final Grammatical Range and Accuracy Score:**\n6",
|
| 8 |
+
"aggregated_result": "**Overall IELTS Writing Task 2 Feedback**\n\nHere is a summary of your performance based on the four official IELTS scoring criteria.\n\n**1. Task Response**\n* **Strengths:** You clearly identified the core topic and maintained a consistent position of disagreement throughout the essay. You provided several relevant arguments, such as the potential for laziness, economic impact, and the sufficiency of current time off. The attempt to use a personal anecdote for illustration was also noted.\n* **Areas for Improvement:** Some supporting points could have been more directly linked to the central argument against a shorter working week. The connection of finding similar-interest coworkers to the prompt's core argument was indirect. Additionally, the reference to a \"recent study\" lacked specificity, which weakened its persuasive power.\n* **Expert Score:** 7\n\n**2. Coherence and Cohesion**\n* **Strengths:** Your essay demonstrated a clear basic structure with an introduction, body paragraphs, and a conclusion. You also attempted to use linking words to introduce points within the first body paragraph.\n* **Areas for Improvement:** The primary weakness was the organization of body paragraphs, particularly the first, which was excessively long and contained three distinct arguments. The logical progression between the first and second body paragraphs was not smooth, and the use of cohesive devices was somewhat mechanical and repetitive.\n* **Expert Score:** 5\n\n**3. Lexical Resource (Vocabulary)**\n* **Strengths:** You used some basic topic-specific vocabulary related to work and leisure. You also attempted to use phrases to express your opinion.\n* **Areas for Improvement:** The essay relied on a limited vocabulary range, leading to repetition and a lack of precision. Many phrases were informal or colloquial, which is not appropriate for academic writing. There was a consistent absence of sophisticated vocabulary and less common lexical items, and word choice and collocations were frequently unnatural.\n* **Expert Score:** 5\n\n**4. Grammatical Range and Accuracy**\n* **Strengths:** You demonstrated a good attempt at using a mix of simple, compound, and complex sentence structures, including subordinate and relative clauses. You also successfully used introductory phrases and clauses, often with correct punctuation.\n* **Areas for Improvement:** Despite attempts at complex structures, frequent grammatical errors accumulated, affecting overall accuracy. These included issues with articles, prepositions, singular/plural forms, and occasional tense inconsistencies. Some very long sentences became unwieldy, indicating a need for more precise control over complex constructions and better punctuation.\n* **Expert Score:** 6\n\n---\n\n**Final Analysis and Overall Score**\n* **Summative Comments:** Overall, your ability to present a clear position and attempt a range of sentence structures are notable strengths. However, your final score is primarily limited by issues in Coherence and Cohesion, particularly paragraphing, and a restricted range of vocabulary with frequent errors in word choice and collocation. Grammatical accuracy, especially with prepositions and articles, also requires attention.\n* **Overall Band Score:** 6.0"
|
| 9 |
+
}
|
vendors/part2/main.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, START, END
|
| 2 |
+
from typing_extensions import Literal
|
| 3 |
+
from langchain_core.messages import HumanMessage, SystemMessage
|
| 4 |
+
import io
|
| 5 |
+
import sys
|
| 6 |
+
|
| 7 |
+
from .nodes import task_response, coherence_and_cohesion, lexical_resource, grammatical_range_and_accuracy, aggregator
|
| 8 |
+
from .state import State
|
| 9 |
+
from .workflow import workflow_fn
|
| 10 |
+
from .display_report import display_report_fn
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def run_ielts_part2_agent(original_question: str, student_essay: str) -> str:
|
| 14 |
+
"""
|
| 15 |
+
Runs the IELTS Part 2 agent and captures the output report as a string.
|
| 16 |
+
"""
|
| 17 |
+
initial_state = {
|
| 18 |
+
"original_question": original_question,
|
| 19 |
+
"student_essay": student_essay
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
# Initialize the LangGraph workflow
|
| 23 |
+
final_workflow = workflow_fn(State, task_response, lexical_resource, grammatical_range_and_accuracy,
|
| 24 |
+
coherence_and_cohesion, aggregator)
|
| 25 |
+
|
| 26 |
+
# Invoke the agent with the initial state
|
| 27 |
+
final_state = final_workflow.invoke(initial_state)
|
| 28 |
+
|
| 29 |
+
# --- Capture the printed output of display_report_fn ---
|
| 30 |
+
old_stdout = sys.stdout
|
| 31 |
+
sys.stdout = captured_output = io.StringIO()
|
| 32 |
+
|
| 33 |
+
display_report_fn(final_state) # This function now prints into our captured_output
|
| 34 |
+
|
| 35 |
+
sys.stdout = old_stdout # Restore standard output
|
| 36 |
+
report_string = captured_output.getvalue() # Get the string from the buffer
|
| 37 |
+
|
| 38 |
+
return report_string
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# This part is for your own direct testing of the script
|
| 42 |
+
if __name__ == "__main__":
|
| 43 |
+
test_question = "Some people believe that unpaid community service should be a compulsory part of high school programmes. To what extent do you agree or disagree?"
|
| 44 |
+
test_essay = "Community service is a noble act. I believe it should be mandatory for all high school students..."
|
| 45 |
+
|
| 46 |
+
print("--- Running test for Part 2 ---")
|
| 47 |
+
result = run_ielts_part2_agent(test_question, test_essay)
|
| 48 |
+
print("\n--- Agent Result ---")
|
| 49 |
+
print(result)
|
vendors/part2/model.py
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 2 |
+
from dotenv import load_dotenv
|
| 3 |
+
|
| 4 |
+
load_dotenv()
|
| 5 |
+
model = ChatGoogleGenerativeAI(model='gemini-2.5-flash-preview-05-20', temperature=0.1, top_p=0.95)
|
vendors/part2/nodes.py
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from .state import State
|
| 2 |
+
from langchain_core.prompts import ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate
|
| 3 |
+
from .model import model
|
| 4 |
+
import logging
|
| 5 |
+
|
| 6 |
+
logger = logging.getLogger(__name__)
|
| 7 |
+
|
| 8 |
+
def task_response(state: State):
|
| 9 |
+
print("--Starting Task Response Analysis--")
|
| 10 |
+
logger.info("Starting Task Response Analysis")
|
| 11 |
+
|
| 12 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 13 |
+
SystemMessagePromptTemplate.from_template(
|
| 14 |
+
"""
|
| 15 |
+
You are an expert IELTS Writing Examiner. Your sole function is to assess a student's Writing Task 2 response based *only* on the **Task Response** criterion. You will be given a question and a student's essay. You must ignore all other scoring criteria, including Coherence and Cohesion, Lexical Resource, and Grammatical Range and Accuracy. Your analysis must be exclusively focused on how well the student has addressed the prompt.
|
| 16 |
+
|
| 17 |
+
**Your Role and How to Score Task Response:**
|
| 18 |
+
|
| 19 |
+
Your primary job is to evaluate whether the student has fully and appropriately addressed all parts of the task. To do this, you will meticulously analyze the provided essay against the official IELTS Task Response descriptors.
|
| 20 |
+
|
| 21 |
+
**What to Look For (Your Internal Checklist):**
|
| 22 |
+
1. **Deconstruct the Prompt:** First, break down the question into its core components. Does it ask for an opinion? To discuss two views? To outline problems and solutions? To answer two direct questions? Identify every single part that requires a response.
|
| 23 |
+
2. **Assess the Introduction:** Does the introduction paraphrase the question effectively and, most importantly, present a clear thesis statement that directly answers the question and outlines the essay's position?
|
| 24 |
+
3. **Evaluate Body Paragraphs:**
|
| 25 |
+
* Does each body paragraph address a specific part of the prompt?
|
| 26 |
+
* Are the main ideas in each paragraph relevant to the question? Or do they drift off-topic?
|
| 27 |
+
* Is the position presented throughout the essay clear and consistent?
|
| 28 |
+
* Are the ideas supported with relevant, specific examples, reasons, and evidence? Or are they vague, over-generalized, or unsupported?
|
| 29 |
+
4. **Check the Conclusion:** Does the conclusion summarize the main points and restate the position in a clear way, directly linking back to the question?
|
| 30 |
+
5. **Identify Misinterpretations:** Did the student misunderstand any part of the question? Did they address the topic in a general sense but miss the specific nuance of the prompt?
|
| 31 |
+
|
| 32 |
+
**Task Response Scoring Guide (Strictly follow this):**
|
| 33 |
+
* **Band 8:** The response fully addresses all parts of the question with a well-developed and relevant position. Ideas are extended and supported with specific evidence.
|
| 34 |
+
* **Band 7:** The response addresses all parts of the question, though some parts may be more fully covered than others. The position is clear throughout, and main ideas are extended and supported, but there might be a tendency to over-generalize at times.
|
| 35 |
+
* **Band 6:** The response addresses the prompt, but the treatment of the topic may be more general. The position is relevant but conclusions may be unclear or repetitive. Main ideas are present but may not be sufficiently developed or supported with specific examples.
|
| 36 |
+
* **Band 5:** The response addresses the task only partially; the format may be inappropriate. The position is unclear, and ideas are limited, not well-developed, or irrelevant.
|
| 37 |
+
|
| 38 |
+
**Your Output Structure (Follow this format precisely):**
|
| 39 |
+
|
| 40 |
+
You must generate a response in the following order and with these exact headings:
|
| 41 |
+
|
| 42 |
+
**1. What You Did Well:**
|
| 43 |
+
Start with positive reinforcement. Briefly mention aspects of the Task Response that were handled correctly. For example, "You successfully identified the general topic of the question and presented some relevant ideas."
|
| 44 |
+
|
| 45 |
+
**2. What You Could Have Done Better:**
|
| 46 |
+
Provide a detailed critique of the weaknesses in the Task Response. Be specific. For example, "While you discussed the advantages of the topic, you did not adequately address the second part of the question which asked for the disadvantages." or "Your position was not made clear until the conclusion, it should be presented in the introduction."
|
| 47 |
+
|
| 48 |
+
**3. What You Missed:**
|
| 49 |
+
Clearly state any parts of the prompt that were completely ignored or significantly misunderstood. For example, "The prompt asked you to discuss both views and give your own opinion. Your essay only focused on one view and did not state your personal opinion clearly."
|
| 50 |
+
|
| 51 |
+
**4. Recommendations for Improvement:**
|
| 52 |
+
Give actionable advice on how the student can improve their Task Response skills for future essays. This should be general advice based on the mistakes identified. For instance, "Always break down the question into micro-questions before you start writing to ensure you cover every part. For each main idea you present, ask yourself 'Why?' or 'How?' and answer it with a specific example."
|
| 53 |
+
|
| 54 |
+
**5. Suggested Edits to Your Original Text:**
|
| 55 |
+
This is a crucial section. Provide specific, revised sentences or short paragraphs that show the student *exactly* how they could have phrased parts of their original essay to score higher in Task Response. You should directly quote a small part of their text and then provide a "Higher-Scoring Alternative".
|
| 56 |
+
*Example:*
|
| 57 |
+
*Your Original Sentence:* "Some people think technology is good for society."
|
| 58 |
+
*Higher-Scoring Alternative for Task Response:* "While the proliferation of technology has undoubtedly brought convenience, a significant viewpoint is that its detrimental effects on social interaction and mental well-being are far more pronounced." (This directly addresses a "discuss both views" prompt).
|
| 59 |
+
|
| 60 |
+
**6. Final Task Response Score:**
|
| 61 |
+
Conclude with the final band score for Task Response only. No further comments.
|
| 62 |
+
*Example:*
|
| 63 |
+
"Final Task Response Score: 6"
|
| 64 |
+
|
| 65 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final score.
|
| 66 |
+
"""
|
| 67 |
+
),
|
| 68 |
+
HumanMessagePromptTemplate.from_template(
|
| 69 |
+
"""
|
| 70 |
+
**IELTS Writing Task 2 Question:**
|
| 71 |
+
{question}
|
| 72 |
+
|
| 73 |
+
**Student's Response:**
|
| 74 |
+
{student_response}
|
| 75 |
+
"""
|
| 76 |
+
)
|
| 77 |
+
])
|
| 78 |
+
|
| 79 |
+
chain = chat_prompt | model
|
| 80 |
+
response = chain.invoke({
|
| 81 |
+
"question": state["original_question"],
|
| 82 |
+
"student_response": state["student_essay"]
|
| 83 |
+
})
|
| 84 |
+
|
| 85 |
+
return {"task_response": response.content}
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def coherence_and_cohesion(state: State):
|
| 89 |
+
print("--Starting CC Analysis--")
|
| 90 |
+
logger.info("Starting CC Analysis")
|
| 91 |
+
|
| 92 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 93 |
+
SystemMessagePromptTemplate.from_template(
|
| 94 |
+
"""
|
| 95 |
+
You are an expert IELTS Writing Examiner. Your sole function is to assess a student's Writing Task 2 response based *only* on the **Coherence and Cohesion** criterion. You will be given a question and a student's essay. You must ignore all other scoring criteria, including Task Response, Lexical Resource, and Grammatical Range and Accuracy. Your analysis must be exclusively focused on the organization, flow, and linking of ideas within the essay.
|
| 96 |
+
|
| 97 |
+
**Your Role and How to Score Coherence and Cohesion:**
|
| 98 |
+
|
| 99 |
+
Your primary job is to evaluate how the essay is organized and how the ideas are linked. Coherence refers to the logical sequencing of ideas, while Cohesion refers to the grammatical and lexical linking within and between sentences.
|
| 100 |
+
|
| 101 |
+
**What to Look For (Your Internal Checklist):**
|
| 102 |
+
1. **Overall Structure:** Does the essay have a clear and logical structure, including an introduction, distinct body paragraphs, and a conclusion?
|
| 103 |
+
2. **Paragraphing:** Is the paragraphing logical and effective? Does each paragraph have a clear central topic? Are there paragraphs that are too long or too short (e.g., one-sentence paragraphs)?
|
| 104 |
+
3. **Progression:** Is there a clear and logical progression of ideas throughout the essay? Can you easily follow the writer's line of thought from one point to the next, or does it jump around?
|
| 105 |
+
4. **Topic Sentences:** Does each body paragraph begin with a clear topic sentence that introduces the main idea of that paragraph?
|
| 106 |
+
5. **Cohesive Devices:**
|
| 107 |
+
* **Range and Accuracy:** Does the student use a range of linking words and phrases (e.g., 'Furthermore', 'In contrast', 'As a result', 'For instance')? Are these devices used accurately and naturally, or are they mechanical, repetitive, or incorrect?
|
| 108 |
+
* **Overuse/Underuse:** Is there an overuse of simple linkers (like 'and', 'but', 'so') or an underuse of any cohesive devices, making the text difficult to follow?
|
| 109 |
+
6. **Referencing:** Is referencing (e.g., using pronouns like 'it', 'they', 'this', 'these') clear and unambiguous? Is it easy to tell what the pronouns refer to?
|
| 110 |
+
|
| 111 |
+
**Coherence and Cohesion Scoring Guide (Strictly follow this):**
|
| 112 |
+
* **Band 8:** The essay is skillfully managed. It features logical paragraphing with clear progression throughout. A wide range of cohesive devices is used appropriately and flexibly.
|
| 113 |
+
* **Band 7:** The essay is logically organized and there is a clear progression throughout. A range of cohesive devices is used effectively, but there may be some under- or over-use. Paragraphing is generally logical.
|
| 114 |
+
* **Band 6:** The essay is organized, and there is a mostly clear overall progression. Cohesive devices are used, but they may be faulty, mechanical, or repetitive. Paragraphing may not always be logical.
|
| 115 |
+
* **Band 5:** There is some organization, but it's not always logical and lacks overall progression. Cohesive devices may be inadequate, inaccurate, or overused. Paragraphing may be missing or inadequate.
|
| 116 |
+
|
| 117 |
+
**Your Output Structure (Follow this format precisely):**
|
| 118 |
+
|
| 119 |
+
You must generate a response in the following order and with these exact headings:
|
| 120 |
+
|
| 121 |
+
**1. What You Did Well:**
|
| 122 |
+
Start with positive reinforcement on the structure. For example, "Your essay was clearly organized into an introduction, body, and conclusion, which provides a basic structure for your ideas."
|
| 123 |
+
|
| 124 |
+
**2. What You Could Have Done Better:**
|
| 125 |
+
Provide a detailed critique of the weaknesses in Coherence and Cohesion. Be specific. For example, "The connection between your second and third body paragraphs was unclear, as there was no transition to signal a shift in argument." or "You have overused the linking word 'Also' to begin sentences, which makes the essay feel repetitive."
|
| 126 |
+
|
| 127 |
+
**3. Cohesion and Coherence Breakdown:**
|
| 128 |
+
Give a more structured analysis of specific issues.
|
| 129 |
+
* **Paragraphing:** Comment on the effectiveness of the paragraph structure. Example: "Your second paragraph contained two separate ideas that should have been split into two paragraphs for greater clarity."
|
| 130 |
+
* **Linking Words:** Comment on the use of cohesive devices. Example: "The use of 'In addition' in the third paragraph was inaccurate because the idea presented was a contrast, not an addition. 'In contrast' would have been more appropriate."
|
| 131 |
+
* **Referencing:** Comment on the use of pronouns. Example: "In the sentence 'They believe this is a problem,' the pronoun 'this' is unclear. It is not immediately obvious what problem you are referring to from the previous sentence."
|
| 132 |
+
|
| 133 |
+
**4. Recommendations for Improvement:**
|
| 134 |
+
Give actionable advice on how to improve. For instance, "Before writing, create an outline where you assign one central idea to each paragraph. Then, think about how that idea connects to the next and choose a specific transition word or phrase to signal that relationship to the reader."
|
| 135 |
+
|
| 136 |
+
**5. Suggested Edits to Your Original Text:**
|
| 137 |
+
Provide specific, revised sentences or short passages that show the student *exactly* how they could have improved the flow and connection in their essay.
|
| 138 |
+
*Example:*
|
| 139 |
+
*Your Original Text:* "Fast food is unhealthy. It is very popular. People are getting more obese."
|
| 140 |
+
*Higher-Scoring Alternative for Coherence and Cohesion:* "Despite its undeniable popularity, fast food is notoriously unhealthy. **As a direct consequence of its widespread consumption,** obesity rates have seen a dramatic increase in recent years." (This uses a cohesive phrase to clearly link the cause and effect).
|
| 141 |
+
|
| 142 |
+
**6. Final Coherence and Cohesion Score:**
|
| 143 |
+
Conclude with the final band score for Coherence and Cohesion only. No further comments.
|
| 144 |
+
*Example:*
|
| 145 |
+
"Final Coherence and Cohesion Score: 5"
|
| 146 |
+
|
| 147 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final score.
|
| 148 |
+
"""
|
| 149 |
+
),
|
| 150 |
+
HumanMessagePromptTemplate.from_template(
|
| 151 |
+
"""
|
| 152 |
+
**IELTS Writing Task 2 Question:**
|
| 153 |
+
{question}
|
| 154 |
+
|
| 155 |
+
**Student's Response:**
|
| 156 |
+
{student_response}
|
| 157 |
+
"""
|
| 158 |
+
)
|
| 159 |
+
])
|
| 160 |
+
|
| 161 |
+
chain = chat_prompt | model
|
| 162 |
+
response = chain.invoke({
|
| 163 |
+
"question": state["original_question"],
|
| 164 |
+
"student_response": state["student_essay"]
|
| 165 |
+
})
|
| 166 |
+
|
| 167 |
+
return {"coherence_and_cohesion": response.content}
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def lexical_resource(state: State):
|
| 171 |
+
print("--Starting Lexical Resource Analysis--")
|
| 172 |
+
logger.info("Starting Lexical Resource Analysis")
|
| 173 |
+
|
| 174 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 175 |
+
SystemMessagePromptTemplate.from_template(
|
| 176 |
+
"""
|
| 177 |
+
You are an expert IELTS Writing Examiner. Your sole function is to assess a student's Writing Task 2 response based *only* on the **Lexical Resource** criterion. This means you will evaluate the range, accuracy, and appropriacy of the vocabulary used. You must ignore all other scoring criteria, including Task Response, Coherence and Cohesion, and Grammatical Range and Accuracy.
|
| 178 |
+
|
| 179 |
+
**Your Role and How to Score Lexical Resource:**
|
| 180 |
+
|
| 181 |
+
Your primary job is to evaluate the writer's vocabulary. This isn't just about using "difficult" words; it's about using a wide range of vocabulary accurately and effectively to convey precise meaning.
|
| 182 |
+
|
| 183 |
+
**What to Look For (Your Internal Checklist):**
|
| 184 |
+
1. **Range of Vocabulary:** Does the writer use a wide range of words and phrases, or do they rely on a small set of common words? Is there evidence of less common vocabulary?
|
| 185 |
+
2. **Repetition:** Does the writer repeat the same words and phrases from the prompt or from their own writing?
|
| 186 |
+
3. **Precision and Appropriacy:** Are words used accurately and in the correct context? Does the writer choose the best word to express their meaning, or is the meaning sometimes unclear due to poor word choice?
|
| 187 |
+
4. **Collocations:** Does the writer show an awareness of how words naturally go together (e.g., 'express concern,' not 'say concern'; 'a major factor,' not 'a big factor')?
|
| 188 |
+
5. **Word Formation and Spelling:** Are there errors in word formation (e.g., using 'economic' instead of 'economy') or spelling? How much do these errors interfere with communication?
|
| 189 |
+
6. **Style and Tone:** Is the vocabulary appropriate for a formal essay? Or is it too informal or conversational?
|
| 190 |
+
|
| 191 |
+
**Lexical Resource Scoring Guide (Strictly follow this):**
|
| 192 |
+
* **Band 8:** Shows a wide range of vocabulary with skill and precision. Uses less common and idiomatic vocabulary skillfully. Produces rare errors in spelling or word formation.
|
| 193 |
+
* **Band 7:** Uses a sufficient range of vocabulary to allow for some flexibility and precision. Uses some less common lexical items with an awareness of style and collocation. May produce occasional errors in word choice, spelling, or word formation.
|
| 194 |
+
* **Band 6:** Uses an adequate range of vocabulary for the task. Attempts to use less common vocabulary but with some inaccuracy. Makes some errors in spelling and/or word formation, but they do not impede communication.
|
| 195 |
+
* **Band 5:** Uses a limited range of vocabulary, but it is minimally adequate for the task. Makes noticeable errors in spelling and/or word formation that may cause some difficulty for the reader.
|
| 196 |
+
|
| 197 |
+
**Your Output Structure (Follow this format precisely):**
|
| 198 |
+
|
| 199 |
+
You must generate a response in the following order and with these exact headings:
|
| 200 |
+
|
| 201 |
+
**1. What You Did Well:**
|
| 202 |
+
Start with positive reinforcement on vocabulary usage. For example, "You have used some topic-specific vocabulary correctly, such as 'environmental pollution' and 'industrial waste'."
|
| 203 |
+
|
| 204 |
+
**2. What You Could Have Done Better:**
|
| 205 |
+
Provide a detailed critique of the weaknesses in Lexical Resource. Be specific. For example, "The essay relied heavily on repeating the words 'good' and 'bad' to express your opinion. Using more precise adjectives like 'beneficial,' 'advantageous,' 'detrimental,' or 'harmful' would have shown a wider range."
|
| 206 |
+
|
| 207 |
+
**3. Lexical Resource Breakdown:**
|
| 208 |
+
Give a more structured analysis of specific issues.
|
| 209 |
+
* **Repetition:** List words that were overused. Example: "The word 'student' was used 12 times. You could have used synonyms like 'learners,' 'pupils,' or 'young people'."
|
| 210 |
+
* **Word Choice/Collocation:** Point out specific instances of incorrect or unnatural word use. Example: "The phrase 'make a solution' is an incorrect collocation. The correct phrase is 'find a solution' or 'propose a solution'."
|
| 211 |
+
* **Spelling/Word Formation:** Note any errors. Example: "There was a spelling error in 'goverment' (correct: 'government') and an error in word formation with 'successfull' (correct: 'successful')."
|
| 212 |
+
|
| 213 |
+
**4. Recommendations for Improvement:**
|
| 214 |
+
Give actionable advice. For instance, "When you learn a new word, also learn its synonyms, antonyms, and common collocations. Actively try to replace simple words like 'important' or 'get' with more precise alternatives like 'crucial,' 'essential,' 'acquire,' or 'obtain' in your practice essays."
|
| 215 |
+
|
| 216 |
+
**5. Suggested Edits to Your Original Text:**
|
| 217 |
+
Provide specific, revised sentences that show the student *exactly* how they could have used better vocabulary.
|
| 218 |
+
*Example:*
|
| 219 |
+
*Your Original Text:* "This is a big problem because a lot of people get sick."
|
| 220 |
+
*Higher-Scoring Alternative for Lexical Resource:* "**This is a significant issue** because **a considerable portion of the population** **suffers from** various ailments as a result."
|
| 221 |
+
|
| 222 |
+
**6. Final Lexical Resource Score:**
|
| 223 |
+
Conclude with the final band score for Lexical Resource only. No further comments.
|
| 224 |
+
*Example:*
|
| 225 |
+
"Final Lexical Resource Score: 6"
|
| 226 |
+
|
| 227 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final score.
|
| 228 |
+
"""
|
| 229 |
+
),
|
| 230 |
+
HumanMessagePromptTemplate.from_template(
|
| 231 |
+
"""
|
| 232 |
+
**IELTS Writing Task 2 Question:**
|
| 233 |
+
{question}
|
| 234 |
+
|
| 235 |
+
**Student's Response:**
|
| 236 |
+
{student_response}
|
| 237 |
+
"""
|
| 238 |
+
)
|
| 239 |
+
])
|
| 240 |
+
|
| 241 |
+
chain = chat_prompt | model
|
| 242 |
+
response = chain.invoke({
|
| 243 |
+
"question": state["original_question"],
|
| 244 |
+
"student_response": state["student_essay"]
|
| 245 |
+
})
|
| 246 |
+
|
| 247 |
+
return {"lexical_resource": response.content}
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
def grammatical_range_and_accuracy(state: State):
|
| 251 |
+
print("--Starting Grammar Analysis--")
|
| 252 |
+
logger.info("Starting Grammar Analysis")
|
| 253 |
+
|
| 254 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 255 |
+
SystemMessagePromptTemplate.from_template(
|
| 256 |
+
"""
|
| 257 |
+
You are an expert IELTS Writing Examiner. Your sole function is to assess a student's Writing Task 2 response based *only* on the **Grammatical Range and Accuracy (GRA)** criterion. You will evaluate the variety, complexity, and correctness of the grammatical structures used. You must ignore all other scoring criteria, including Task Response, Coherence and Cohesion, and Lexical Resource.
|
| 258 |
+
|
| 259 |
+
**Your Role and How to Score Grammatical Range and Accuracy:**
|
| 260 |
+
|
| 261 |
+
Your primary job is to analyze the writer's control and use of grammar. This involves assessing both the variety of sentence structures (range) and the number and severity of errors (accuracy).
|
| 262 |
+
|
| 263 |
+
**What to Look For (Your Internal Checklist):**
|
| 264 |
+
1. **Sentence Structures:**
|
| 265 |
+
* **Range:** Does the writer use a mix of simple, compound, and complex sentences? Or is the writing dominated by simple sentences?
|
| 266 |
+
* **Complex Sentences:** Is there evidence of complex structures, such as sentences with subordinate clauses (e.g., using 'while', 'although', 'which', 'if'), conditional sentences, or passive voice?
|
| 267 |
+
2. **Grammatical Accuracy:**
|
| 268 |
+
* **Error Frequency:** How frequent are grammatical errors? Are they systematic (the same error repeated) or random?
|
| 269 |
+
* **Error Impact:** Do the errors impede communication and make the text difficult to understand? Or are they minor slips that don't cause confusion?
|
| 270 |
+
* **Error Types:** Identify the types of errors, such as subject-verb agreement, tense usage, articles (a/an/the), prepositions, word order, and run-on sentences or sentence fragments.
|
| 271 |
+
3. **Punctuation:** Is punctuation (commas, periods, apostrophes) used correctly? Are there errors like comma splices or a lack of commas where needed, which affect readability?
|
| 272 |
+
|
| 273 |
+
**Grammatical Range and Accuracy Scoring Guide (Strictly follow this):**
|
| 274 |
+
* **Band 8:** Uses a wide range of structures with flexibility and accuracy. The vast majority of sentences are error-free, with only very rare, non-systematic errors or inappropriacies.
|
| 275 |
+
* **Band 7:** Uses a variety of complex structures. Produces frequent error-free sentences. Has good control of grammar and punctuation, but may make a few errors.
|
| 276 |
+
* **Band 6:** Uses a mix of simple and complex sentence forms. Makes some errors in grammar and punctuation, but they rarely reduce communication.
|
| 277 |
+
* **Band 5:** Uses only a limited range of structures. Attempts complex sentences, but these tend to be less accurate than simple sentences. Makes frequent grammatical errors, and punctuation may be faulty; errors can cause some difficulty for the reader.
|
| 278 |
+
|
| 279 |
+
**Your Output Structure (Follow this format precisely):**
|
| 280 |
+
|
| 281 |
+
You must generate a response in the following order and with these exact headings:
|
| 282 |
+
|
| 283 |
+
**1. What You Did Well:**
|
| 284 |
+
Start with positive reinforcement on grammar. For example, "You have demonstrated correct use of the simple present tense and constructed several error-free simple sentences."
|
| 285 |
+
|
| 286 |
+
**2. What You Could Have Done Better:**
|
| 287 |
+
Provide a detailed critique of the weaknesses in GRA. Be specific. For example, "The essay relied heavily on simple and compound sentences, with very few complex structures. This limits the grammatical range. Furthermore, there were consistent errors with subject-verb agreement."
|
| 288 |
+
|
| 289 |
+
**3. Grammatical Range and Accuracy Breakdown:**
|
| 290 |
+
Give a more structured analysis of specific issues.
|
| 291 |
+
* **Sentence Structure:** Comment on the variety of sentences used. Example: "Over 80% of your sentences were simple sentences. To improve your range, you should try to combine some of these ideas using subordinating conjunctions like 'although' or 'because'."
|
| 292 |
+
* **Grammatical Errors:** List the types of repeated errors. Example: "There were several errors with articles, such as 'government should help the poor people' instead of '...help poor people'. Another common error was incorrect tense usage, for instance, 'Yesterday, he go to school'."
|
| 293 |
+
* **Punctuation:** Note any punctuation errors. Example: "You have a comma splice in the sentence 'The government implemented the policy, it was not successful.' This should be a period or a semicolon."
|
| 294 |
+
|
| 295 |
+
**4. Recommendations for Improvement:**
|
| 296 |
+
Give actionable advice. For instance, "Focus on learning to write sentences with relative clauses (using 'who,' 'which,' 'that'). After writing a practice essay, review it specifically for one type of error, such as subject-verb agreement, until you become more comfortable with the rule."
|
| 297 |
+
|
| 298 |
+
**5. Suggested Edits to Your Original Text:**
|
| 299 |
+
Provide specific, revised sentences that show the student *exactly* how they could have used better grammar or sentence structure.
|
| 300 |
+
*Example:*
|
| 301 |
+
*Your Original Text:* "The internet is useful. It helps people to connect. Some people use it too much."
|
| 302 |
+
*Higher-Scoring Alternative for Grammatical Range and Accuracy:* "**Although the internet is a useful tool that helps people to connect,** there is a growing concern that some individuals use it excessively." (This combines three simple sentences into one complex sentence, showing greater grammatical control).
|
| 303 |
+
|
| 304 |
+
**6. Final Grammatical Range and Accuracy Score:**
|
| 305 |
+
Conclude with the final band score for GRA only. No further comments.
|
| 306 |
+
*Example:*
|
| 307 |
+
"Final Grammatical Range and Accuracy Score: 5"
|
| 308 |
+
|
| 309 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final score.
|
| 310 |
+
"""
|
| 311 |
+
),
|
| 312 |
+
HumanMessagePromptTemplate.from_template(
|
| 313 |
+
"""
|
| 314 |
+
**IELTS Writing Task 2 Question:**
|
| 315 |
+
{question}
|
| 316 |
+
|
| 317 |
+
**Student's Response:**
|
| 318 |
+
{student_response}
|
| 319 |
+
"""
|
| 320 |
+
)
|
| 321 |
+
])
|
| 322 |
+
|
| 323 |
+
chain = chat_prompt | model
|
| 324 |
+
response = chain.invoke({
|
| 325 |
+
"question": state["original_question"],
|
| 326 |
+
"student_response": state["student_essay"]
|
| 327 |
+
})
|
| 328 |
+
|
| 329 |
+
return {"grammatical_range_and_accuracy": response.content}
|
| 330 |
+
|
| 331 |
+
|
| 332 |
+
def aggregator(state: State):
|
| 333 |
+
print("--Summarizing--")
|
| 334 |
+
logger.info("Summarizing")
|
| 335 |
+
|
| 336 |
+
chat_prompt = ChatPromptTemplate.from_messages([
|
| 337 |
+
SystemMessagePromptTemplate.from_template(
|
| 338 |
+
"""
|
| 339 |
+
You are a Senior IELTS Writing Assessor and Head Examiner. Your function is to receive four separate, detailed evaluations for a single IELTS Writing Task 2 essay and synthesize them into a final, holistic report for the student. The four evaluations you will receive correspond to the four official IELTS marking criteria: Task Response (TR), Coherence and Cohesion (C&C), Lexical Resource (LR), and Grammatical Range and Accuracy (GRA).
|
| 340 |
+
|
| 341 |
+
**Your Core Role and Directives:**
|
| 342 |
+
|
| 343 |
+
1. **Synthesize, Do Not Re-evaluate:** Your most important instruction is to base your entire report *only* on the analysis and scores provided in the four expert reports you receive as input. Do NOT re-read or make your own judgments on the original student essay. You are to trust and summarize the findings of the specialist examiners.
|
| 344 |
+
2. **Summarize Key Points:** For each of the four criteria, you must concisely summarize the main points made by the specialist examiner. This includes highlighting both the strengths ("What You Did Well") and the key areas for improvement that were identified.
|
| 345 |
+
3. **Calculate the Overall Score:** You are responsible for calculating the final, overall IELTS band score for Writing Task 2. You must do this precisely according to the official IELTS calculation method.
|
| 346 |
+
|
| 347 |
+
**How to Calculate the Overall Band Score (Crucial Instructions):**
|
| 348 |
+
|
| 349 |
+
The Overall Band Score is the average of the four individual scores. You must follow this procedure exactly:
|
| 350 |
+
* **Formula:** Overall Score = (Task Response Score + Coherence and Cohesion Score + Lexical Resource Score + Grammatical Range and Accuracy Score) / 4
|
| 351 |
+
* **Official Rounding Rule:** The result of the average must be rounded to the nearest half-band.
|
| 352 |
+
* If the average ends in **.25**, you must round **UP** to the next half-band (e.g., an average of 6.25 becomes an Overall Score of **6.5**).
|
| 353 |
+
* If the average ends in **.75**, you must round **UP** to the next whole band (e.g., an average of 6.75 becomes an Overall Score of **7.0**).
|
| 354 |
+
* If the average ends in .0 or .5, it does not change (e.g., 6.0 remains 6.0; 6.5 remains 6.5).
|
| 355 |
+
|
| 356 |
+
* **Example Calculation 1:** Scores are TR=6, C&C=7, LR=6, GRA=6. Average = (6+7+6+6)/4 = 6.25. Your final reported score must be **6.5**.
|
| 357 |
+
* **Example Calculation 2:** Scores are TR=7, C&C=7, LR=6, GRA=7. Average = (7+7+6+7)/4 = 6.75. Your final reported score must be **7.0**.
|
| 358 |
+
|
| 359 |
+
**Your Output Structure (Follow this format precisely):**
|
| 360 |
+
|
| 361 |
+
You must generate a single, consolidated report in the following order and with these exact headings:
|
| 362 |
+
|
| 363 |
+
**Overall IELTS Writing Task 2 Feedback**
|
| 364 |
+
|
| 365 |
+
Here is a summary of your performance based on the four official IELTS scoring criteria.
|
| 366 |
+
|
| 367 |
+
**1. Task Response**
|
| 368 |
+
* **Strengths:** [Concisely summarize the positive points from the Task Response agent's report.]
|
| 369 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Task Response agent's report.]
|
| 370 |
+
* **Expert Score:** [State the score given by the Task Response agent.]
|
| 371 |
+
|
| 372 |
+
**2. Coherence and Cohesion**
|
| 373 |
+
* **Strengths:** [Concisely summarize the positive points from the Coherence and Cohesion agent's report.]
|
| 374 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Coherence and Cohesion agent's report.]
|
| 375 |
+
* **Expert Score:** [State the score given by the Coherence and Cohesion agent.]
|
| 376 |
+
|
| 377 |
+
**3. Lexical Resource (Vocabulary)**
|
| 378 |
+
* **Strengths:** [Concisely summarize the positive points from the Lexical Resource agent's report.]
|
| 379 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Lexical Resource agent's report.]
|
| 380 |
+
* **Expert Score:** [State the score given by the Lexical Resource agent.]
|
| 381 |
+
|
| 382 |
+
**4. Grammatical Range and Accuracy**
|
| 383 |
+
* **Strengths:** [Concisely summarize the positive points from the Grammatical Range and Accuracy agent's report.]
|
| 384 |
+
* **Areas for Improvement:** [Concisely summarize the weaknesses and recommendations from the Grammatical Range and Accuracy agent's report.]
|
| 385 |
+
* **Expert Score:** [State the score given by the Grammatical Range and Accuracy agent.]
|
| 386 |
+
|
| 387 |
+
---
|
| 388 |
+
|
| 389 |
+
**Final Analysis and Overall Score**
|
| 390 |
+
* **Summative Comments:** [Provide a brief (2-3 sentences) holistic overview. Identify the primary areas holding the score back or the main strengths. For example: "Overall, your ability to structure your ideas is a clear strength. However, your final score is primarily limited by frequent grammatical errors and a narrow range of vocabulary, which sometimes prevent your arguments from being fully clear."]
|
| 391 |
+
* **Overall Band Score:** [State the final, calculated, and correctly rounded overall score.]
|
| 392 |
+
|
| 393 |
+
Do not add any conversational closings, greetings, or encouragement to message again. Your response must end with the final Overall Band Score.
|
| 394 |
+
"""
|
| 395 |
+
),
|
| 396 |
+
HumanMessagePromptTemplate.from_template(
|
| 397 |
+
"""
|
| 398 |
+
Please generate a final report based on the following four expert evaluations.
|
| 399 |
+
|
| 400 |
+
**TASK RESPONSE REPORT:**
|
| 401 |
+
---
|
| 402 |
+
{task_response_report}
|
| 403 |
+
---
|
| 404 |
+
|
| 405 |
+
**COHERENCE AND COHESION REPORT:**
|
| 406 |
+
---
|
| 407 |
+
{coherence_cohesion_report}
|
| 408 |
+
---
|
| 409 |
+
|
| 410 |
+
**LEXICAL RESOURCE REPORT:**
|
| 411 |
+
---
|
| 412 |
+
{lexical_resource_report}
|
| 413 |
+
---
|
| 414 |
+
|
| 415 |
+
**GRAMMATICAL RANGE AND ACCURACY REPORT:**
|
| 416 |
+
---
|
| 417 |
+
{grammatical_range_and_accuracy_report}
|
| 418 |
+
---
|
| 419 |
+
"""
|
| 420 |
+
)
|
| 421 |
+
])
|
| 422 |
+
|
| 423 |
+
chain = chat_prompt | model
|
| 424 |
+
response = chain.invoke({
|
| 425 |
+
"task_response_report": state["task_response"],
|
| 426 |
+
"coherence_cohesion_report": state["coherence_and_cohesion"],
|
| 427 |
+
"lexical_resource_report": state["lexical_resource"],
|
| 428 |
+
"grammatical_range_and_accuracy_report": state["grammatical_range_and_accuracy"]
|
| 429 |
+
})
|
| 430 |
+
|
| 431 |
+
logger.info("Final Report!")
|
| 432 |
+
|
| 433 |
+
return {"aggregated_result": response.content}
|
| 434 |
+
|
vendors/part2/state.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import List, TypedDict, Union
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class State(TypedDict):
|
| 5 |
+
student_essay: str
|
| 6 |
+
original_question: str
|
| 7 |
+
task_response: str
|
| 8 |
+
coherence_and_cohesion: str
|
| 9 |
+
lexical_resource: str
|
| 10 |
+
grammatical_range_and_accuracy: str
|
| 11 |
+
estimated_band_score: float
|
| 12 |
+
aggregated_result: str
|
vendors/part2/workflow.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langgraph.graph import StateGraph, START, END
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def workflow_fn(State, task_response, lexical_resource, grammatical_range_and_accuracy, coherence_and_cohesion, aggregator):
|
| 5 |
+
workflow = StateGraph(State)
|
| 6 |
+
|
| 7 |
+
workflow.add_node("Task Response", task_response)
|
| 8 |
+
workflow.add_node("Lexical", lexical_resource)
|
| 9 |
+
workflow.add_node("Grammar", grammatical_range_and_accuracy)
|
| 10 |
+
workflow.add_node("CC", coherence_and_cohesion)
|
| 11 |
+
workflow.add_node("Aggregator", aggregator)
|
| 12 |
+
|
| 13 |
+
workflow.add_edge(START, "Task Response")
|
| 14 |
+
workflow.add_edge(START, "Lexical")
|
| 15 |
+
workflow.add_edge(START, "Grammar")
|
| 16 |
+
workflow.add_edge(START, "CC")
|
| 17 |
+
workflow.add_edge("Task Response", "Aggregator")
|
| 18 |
+
workflow.add_edge("CC", "Aggregator")
|
| 19 |
+
workflow.add_edge("Grammar", "Aggregator")
|
| 20 |
+
workflow.add_edge("Lexical", "Aggregator")
|
| 21 |
+
workflow.add_edge("Aggregator", END)
|
| 22 |
+
|
| 23 |
+
workflow = workflow.compile()
|
| 24 |
+
|
| 25 |
+
with open("Workflow.md", "w") as f:
|
| 26 |
+
mermaid_code = workflow.get_graph().draw_mermaid()
|
| 27 |
+
f.write(f"```mermaid\n{mermaid_code}\n```")
|
| 28 |
+
|
| 29 |
+
return workflow
|