STEM-Question-Generator / all_tools.py
bhardwaj08sarthak's picture
Update all_tools.py
4dd6ca5 verified
raw
history blame
4.91 kB
from __future__ import annotations
from typing import Dict, List, Tuple
from smolagents import tool
# Import only the classifier API; DO NOT construct models here.
from level_classifier_tool_2 import classify_levels_phrases
from phrases import BLOOMS_PHRASES, DOK_PHRASES
# ------------------------ Injected state (set from app.py) ------------------------
_INDEX = None
_BACKEND = None
_BLOOM_INDEX = None
_DOK_INDEX = None
def set_retrieval_index(index) -> None:
"""Call this from app.py after loading your LlamaIndex index."""
global _INDEX
_INDEX = index
def set_classifier_state(backend, bloom_index, dok_index) -> None:
"""Call this from app.py after building the backend and prebuilt indices."""
global _BACKEND, _BLOOM_INDEX, _DOK_INDEX
_BACKEND = backend
_BLOOM_INDEX = bloom_index
_DOK_INDEX = dok_index
# ----------------------------- Tools -------------------------------------
@tool
def QuestionRetrieverTool(subject: str, topic: str, grade: str) -> dict:
"""
Retrieve up to 5 closely-related example Q&A pairs from the source datasets.
Args:
subject: The subject area (e.g., "Math", "Science").
topic: The specific topic within the subject (e.g., "Algebra", "Biology").
grade: The grade level (e.g., "Grade 5", "Grade 8").
Returns:
{
"closest questions found for": {"subject": ..., "topic": ..., "grade": ...},
"questions": [{"text": "..."} * up to 5]
}
"""
if _INDEX is None:
return {"error": "Retriever not initialized. Call set_retrieval_index(index) before using this tool."}
query = f"{topic} question for {grade} of the {subject}"
try:
results = _INDEX.as_retriever(similarity_top_k=5).retrieve(query)
question_texts = [r.node.text for r in results]
except Exception as e:
return {"error": f"Retriever error: {e}"}
return {
"closest questions found for": {"subject": subject, "topic": topic, "grade": grade},
"questions": [{"text": q} for q in question_texts]
}
@tool
def classify_and_score(
question: str,
target_bloom: str,
target_dok: str,
agg: str = "max"
) -> dict:
"""
Classify a question against Bloom’s and DOK targets and return guidance.
Args:
question: Question text to evaluate.
target_bloom: Target Bloom’s level (e.g., "Analyze" or "Apply+").
target_dok: Target DOK level (e.g., "DOK3" or "DOK2-DOK3").
agg: Aggregation over phrase sims ("mean", "max", "topk_mean").
Returns:
{
"ok": bool,
"measured": {"bloom_best": str, "bloom_scores": dict, "dok_best": str, "dok_scores": dict},
"feedback": str
}
"""
if _BACKEND is None or _BLOOM_INDEX is None or _DOK_INDEX is None:
return {"error": "Classifier not initialized. Call set_classifier_state(backend, bloom_index, dok_index) first."}
try:
res = classify_levels_phrases(
question,
BLOOMS_PHRASES,
DOK_PHRASES,
backend=_BACKEND,
prebuilt_bloom_index=_BLOOM_INDEX,
prebuilt_dok_index=_DOK_INDEX,
agg=agg,
return_phrase_matches=True
)
except Exception as e:
return {"error": f"classify_levels_phrases failed: {e}"}
def _parse_target_bloom(t: str):
order = ["Remember","Understand","Apply","Analyze","Evaluate","Create"]
if t.endswith("+"):
base = t[:-1]
return set(order[order.index(base):])
return {t}
def _parse_target_dok(t: str):
order = ["DOK1","DOK2","DOK3","DOK4"]
if "-" in t:
lo, hi = t.split("-")
return set(order[order.index(lo):order.index(hi)+1])
return {t}
bloom_target_set = _parse_target_bloom(target_bloom)
dok_target_set = _parse_target_dok(target_dok)
bloom_best = res["blooms"]["best_level"]
dok_best = res["dok"]["best_level"]
bloom_ok = bloom_best in bloom_target_set
dok_ok = dok_best in dok_target_set
feedback_parts = []
if not bloom_ok:
feedback_parts.append(
f"Shift Bloom’s from {bloom_best} toward {sorted(bloom_target_set)}. "
f"Top cues: {res['blooms']['top_phrases'].get(bloom_best, [])[:3]}"
)
if not dok_ok:
feedback_parts.append(
f"Shift DOK from {dok_best} toward {sorted(dok_target_set)}. "
f"Top cues: {res['dok']['top_phrases'].get(dok_best, [])[:3]}"
)
return {
"ok": bool(bloom_ok and dok_ok),
"measured": {
"bloom_best": bloom_best,
"bloom_scores": res["blooms"]["scores"],
"dok_best": dok_best,
"dok_scores": res["dok"]["scores"],
},
"feedback": " ".join(feedback_parts) if feedback_parts else "On target.",
}