mh-engine / app /engine.py
Godswill-IoT's picture
Upload 12 files
72d8571 verified
Raw
History Blame Contribute Delete
5.21 kB
import json
from app.contracts import EngineRequest, EngineResponse, EngineError
from app.hf_client import HFClient
class MicroHintsEngine:
def __init__(self):
self.client = HFClient()
async def process(self, request: EngineRequest) -> EngineResponse:
try:
action = request.action.lower()
if action == "detect_struggle":
return await self._detect_struggle(request)
elif action == "generate_hint_package":
# This acts as the composite action "process_trigger" -> full package
return await self._generate_hint_package(request)
elif action == "score_checks":
return await self._score_checks(request)
else:
raise ValueError(f"Unknown action: {action}")
except Exception as e:
return EngineResponse(
request_id=request.request_id,
ok=False,
status="error",
engine="micro-hints-engine",
action=request.action,
error=EngineError(code="ENGINE_EXECUTION_ERROR", detail=str(e))
)
async def _detect_struggle(self, request: EngineRequest) -> EngineResponse:
# In a real system, this would analyze telemetry.
# Here we mock intelligence to decide if a trigger is needed based on input signals.
signals = request.input.refs.get("signals", {})
prompt = (
f"Signals: {json.dumps(signals)}\n"
"Analyze if this learner is struggling. "
"Output JSON: 'is_struggling' (bool), 'trigger_confidence' (0.0-1.0), 'error_pattern' (string)."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
analysis = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
analysis = {"is_struggling": False, "raw_output": response_text}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="micro-hints-engine",
action="detect_struggle",
result=analysis
)
async def _generate_hint_package(self, request: EngineRequest) -> EngineResponse:
trigger_data = request.input.refs.get("trigger", {})
concept_id = trigger_data.get("concept_id", "unknown_concept")
error_pattern = trigger_data.get("error_pattern", "general_confusion")
# 1. Generate Hint + Analogy + Checks in one go (or sequential calls)
prompt = (
f"Concept: {concept_id}\nError Pattern: {error_pattern}\n"
"Task: Generate a 'MicroHintPackage' to unblock the learner.\n"
"Requirements:\n"
"1. Hint: A 30-second directional hint (not the answer).\n"
"2. Analogy: A 30-second personalized analogy.\n"
"3. Checks: 1-2 comprehension questions (short/numeric).\n"
"Output JSON with keys: 'hint', 'analogy', 'checks' (list of {q, type})."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
package_content = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
package_content = {"hint": "Review the concept.", "analogy": "None", "checks": []}
# Add micro-demo stub
package_content["micro_demo"] = {
"type": "interactive_example",
"ref": f"asset://demo/{concept_id.lower().replace(' ', '_')}_01"
}
package_content["concept_id"] = concept_id
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="micro-hints-engine",
action="generate_hint_package",
result=package_content
)
async def _score_checks(self, request: EngineRequest) -> EngineResponse:
responses = request.input.refs.get("responses", [])
prompt = (
f"Learner Responses: {json.dumps(responses)}\n"
"Evaluate comprehension. Did they pass the check? "
"Output JSON: 'checks_passed' (bool), 'hint_effectiveness' (high/medium/low)."
)
messages = [{"role": "system", "content": prompt}]
response_text = await self.client.generate(messages)
try:
score_data = json.loads(response_text.replace("```json", "").replace("```", "").strip())
except:
score_data = {"checks_passed": False, "note": "Failed to parse score."}
return EngineResponse(
request_id=request.request_id,
ok=True,
status="success",
engine="micro-hints-engine",
action="score_checks",
result=score_data
)
engine = MicroHintsEngine()