File size: 3,089 Bytes
9cbdd68 47868ec c0ffcf0 5b2eeff a132742 9cbdd68 b60cd75 47868ec b60cd75 47868ec a132742 47868ec 4cbd4c5 47868ec b60cd75 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 73b8ea4 c0ffcf0 73b8ea4 c0ffcf0 73b8ea4 c0ffcf0 5b2eeff c0ffcf0 5b2eeff c0ffcf0 5b2eeff |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# app/helpers/exercise_standardizer.py
from langchain_core.prompts import ChatPromptTemplate
from typing import Any, Literal, List, Union
from pydantic import BaseModel
from config.format_mappings import FORMAT_MAPPINGS_EXERCISES
async def standardize_exercise(user_query: str, exercise_format: str, template: ChatPromptTemplate, llm: Any) -> str:
"""
Standardizes an exercise's format using the specified template and LLM, and updates the UI via standardized_format_state.
"""
if exercise_format == "Raw (original)":
return user_query # No transformation needed
formatting_instructions = FORMAT_MAPPINGS_EXERCISES.get(
exercise_format,
"Please reformat the given exercise to ease further processing."
)
prompt_std = await template.aformat_prompt(
user_input=user_query,
formatting_instructions=formatting_instructions
)
std_messages = prompt_std.to_messages()
response = await llm.ainvoke(std_messages)
standardized_exercise = getattr(response, "content", response)
return standardized_exercise
class Exercise(BaseModel):
id: int
prompt: str
choice_id_1: str
choice_id_2: str
choice_id_3: Union[str, None]
choice_id_4: Union[str, None]
correct_answer_id: Literal[1, 2, 3, 4]
explanation: Union[str, None]
class ExerciseSet(BaseModel):
id: int
exercises: List[Exercise]
async def structurize_exercise(
fluster_text: str,
template: ChatPromptTemplate,
llm: Any # e.g. ChatOpenAI
) -> ExerciseSet:
"""
Distills individual exercises and their components from the fluster text
using a structured-output call that returns a Fluster pydantic object.
"""
# 1) Format the prompt
prompt_str = await template.aformat_prompt(fluster=fluster_text)
messages = prompt_str.to_messages()
# 2) Call the LLM with the schema
response = await llm.with_structured_output(ExerciseSet).ainvoke(messages)
exercise_set = response.choices[0].message.parsed
# If the model refused or the schema was violated, you might get None or an error
if exercise_set is None:
raise ValueError(f"LLM refusal or invalid structured data.\nLLM response: {response}")
return exercise_set
# unpacking a structurized exercise for display
def exercise_to_string(ex):
choices = [ex.choice_id_1, ex.choice_id_2, ex.choice_id_3, ex.choice_id_4]
choice_texts = [f" {idx + 1}) {choice}" for idx, choice in enumerate(choices) if choice and choice != 'None']
correct_choice_text = next(
(f" Correct answer: {idx + 1}. {choice}"
for idx, choice in enumerate(choices) if choice == ex.correct_answer_id),
" Correct answer: Unknown"
)
explanation_text = f" Explanation: {ex.explanation}" if ex.explanation else ""
plaintext_exercise = (
f"Exercise {ex.id}:\n"
f" {ex.prompt}\n"
+ "\n".join(choice_texts) + "\n"
+ correct_choice_text + "\n"
+ explanation_text + "\n\n"
)
return plaintext_exercise
|