Spaces:
Running
Running
import json | |
import hashlib | |
import re | |
from typing import Dict, Any, List | |
class ScenarioNode: | |
def __init__(self, question: str, options: Dict[str, Any], correct_answer: str = None, feedback: str = None): | |
self.question = question | |
self.options = options | |
self.correct_answer = correct_answer | |
self.feedback = feedback | |
def to_dict(self): | |
return { | |
"question": self.question, | |
"options": self.options, | |
"correct_answer": self.correct_answer, | |
"feedback": self.feedback | |
} | |
class ScenarioBuilder: | |
def __init__(self, ai_engine): | |
self.ai_engine = ai_engine | |
self.scenarios = {} | |
async def create_scenario_from_query(self, query: str, num_questions: int = 5) -> Dict[str, Any]: | |
prompt = f""" | |
You are a medical training assistant. | |
Based on the topic: "{query}", generate a {num_questions}-question interactive medical scenario. Each question must have: | |
- a `question` (string) | |
- an `options` object with keys "A"–"D" | |
- a `correct_answer` ("A", "B", "C", or "D") | |
- a `feedback` string | |
Respond ONLY with this exact JSON format: | |
[ | |
{{ | |
"question": "...", | |
"options": {{ | |
"A": "...", | |
"B": "...", | |
"C": "...", | |
"D": "..." | |
}}, | |
"correct_answer": "A|B|C|D", | |
"feedback": "..." | |
}}, | |
... | |
] | |
⚠️ No markdown. No prose. No headings. Just valid JSON array. Your job is to act like a JSON API. | |
""" | |
try: | |
# Use Groq for accurate structure | |
raw_response = self.ai_engine._generate_with_groq( | |
query=query, | |
refined_prompt=prompt | |
) | |
# Clean any wrapping or garbage | |
start = raw_response.find("[") | |
end = raw_response.rfind("]") + 1 | |
json_block = raw_response[start:end].strip() | |
print("🧪 Raw Groq output preview:", json_block[:200]) | |
scenario_data = json.loads(json_block) | |
# Turn into ScenarioNode objects | |
nodes = [] | |
for q in scenario_data: | |
node = ScenarioNode( | |
question=q["question"], | |
options=q["options"], | |
correct_answer=q["correct_answer"], | |
feedback=q["feedback"] | |
) | |
nodes.append(node) | |
scenario_id = hashlib.md5(query.encode()).hexdigest() | |
self.scenarios[scenario_id] = nodes | |
return { | |
"scenario_id": scenario_id, | |
"questions": [n.to_dict() for n in nodes] | |
} | |
except json.JSONDecodeError as e: | |
print("❌ JSON parse error:", e) | |
print("⚠️ Raw Groq output:", raw_response[:500]) | |
return { | |
"error": "Failed to parse AI-generated scenario. Invalid JSON format.", | |
"details": str(e) | |
} | |
except Exception as e: | |
print("❌ Scenario generation error:", e) | |
return { | |
"error": "Failed to generate scenario.", | |
"details": str(e) | |
} | |
def get_scenario(self, scenario_id: str) -> List[ScenarioNode]: | |
return self.scenarios.get(scenario_id) | |