v0 fluster chain
Browse files- app/helpers/exercise_standardizer.py +37 -0
- app/ui/write_fluster_tab.py +53 -0
- chains/exercises/fluster_writing_chain.py +25 -0
- chains/exercises/runner.py +93 -0
- config/chain_configs.py +19 -3
- config/system_prompt_texts.py +394 -8
- config/templates.py +47 -93
- main.py +32 -13
app/helpers/exercise_standardizer.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
| 1 |
# app/helpers/exercise_standardizer.py
|
| 2 |
from langchain_core.prompts import ChatPromptTemplate
|
| 3 |
from typing import Any
|
|
|
|
|
|
|
|
|
|
| 4 |
from config.format_mappings import FORMAT_MAPPINGS_EXERCISES
|
| 5 |
|
| 6 |
|
|
@@ -28,3 +31,37 @@ async def standardize_exercise(user_query: str, exercise_format: str, template:
|
|
| 28 |
|
| 29 |
return standardized_exercise
|
| 30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# app/helpers/exercise_standardizer.py
|
| 2 |
from langchain_core.prompts import ChatPromptTemplate
|
| 3 |
from typing import Any
|
| 4 |
+
|
| 5 |
+
from pydantic import BaseModel
|
| 6 |
+
|
| 7 |
from config.format_mappings import FORMAT_MAPPINGS_EXERCISES
|
| 8 |
|
| 9 |
|
|
|
|
| 31 |
|
| 32 |
return standardized_exercise
|
| 33 |
|
| 34 |
+
class ExerciseComplete(BaseModel):
|
| 35 |
+
id: int
|
| 36 |
+
content: str
|
| 37 |
+
choice_id_1: str
|
| 38 |
+
choice_id_2: str
|
| 39 |
+
choice_id_3: str
|
| 40 |
+
choice_id_4: str
|
| 41 |
+
correct_answer_id: Literal[1, 2, 3, 4]
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
async def structurize_exercise(user_query: str, exercise_format: str, template: ChatPromptTemplate, llm: Any):
|
| 46 |
+
"""
|
| 47 |
+
Standardizes an exercise's format using the specified template and LLM
|
| 48 |
+
"""
|
| 49 |
+
if exercise_format == "Raw (original)":
|
| 50 |
+
return user_query # No transformation needed
|
| 51 |
+
|
| 52 |
+
formatting_instructions = FORMAT_MAPPINGS_EXERCISES.get(
|
| 53 |
+
exercise_format,
|
| 54 |
+
"Please reformat the given exercise to ease further processing."
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
prompt_std = await template.aformat_prompt(
|
| 58 |
+
user_input=user_query,
|
| 59 |
+
formatting_instructions=formatting_instructions
|
| 60 |
+
)
|
| 61 |
+
|
| 62 |
+
std_messages = prompt_std.to_messages()
|
| 63 |
+
response = await llm.ainvoke(std_messages)
|
| 64 |
+
standardized_exercise = getattr(response, "content", response)
|
| 65 |
+
|
| 66 |
+
return standardized_exercise
|
| 67 |
+
|
app/ui/write_fluster_tab.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from chains.learning_objectives_generator.runner import run_learning_objectives_generator
|
| 3 |
+
from config.llm_config import llms
|
| 4 |
+
|
| 5 |
+
def build_write_fluster_tab():
|
| 6 |
+
with gr.TabItem("✍️ Write Fluster"):
|
| 7 |
+
gr.HTML(
|
| 8 |
+
"""
|
| 9 |
+
<div style="margin-bottom: 10px;">
|
| 10 |
+
<span style="font-size: 1.5em; cursor: help;" title="Generates one exercise set (one fluster) of 3 exercises for the given learning objective">
|
| 11 |
+
ℹ️
|
| 12 |
+
</span>
|
| 13 |
+
</div>
|
| 14 |
+
"""
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
with gr.Row():
|
| 18 |
+
# 2 dropdowns for the user-chosen LLMs:
|
| 19 |
+
model_choice_1 = gr.Dropdown(
|
| 20 |
+
choices=list(llms.keys()),
|
| 21 |
+
value="o1 (high reasoning_effort)",
|
| 22 |
+
label="LLM 1"
|
| 23 |
+
)
|
| 24 |
+
model_choice_2 = gr.Dropdown(
|
| 25 |
+
choices=list(llms.keys()),
|
| 26 |
+
value="GPT-4o-mini (low temp)",
|
| 27 |
+
label="LLM 2"
|
| 28 |
+
)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
exercises_input = gr.Textbox(label="Enter a learning objective", placeholder="De student weet dat ...")
|
| 32 |
+
write_fluster_button = gr.Button("Generate Fluster")
|
| 33 |
+
|
| 34 |
+
# 2×2 textboxes => 4 total
|
| 35 |
+
# For clarity:
|
| 36 |
+
# row 1 => (box_0, box_1)
|
| 37 |
+
# row 2 => (box_2, box_3)
|
| 38 |
+
with gr.Row():
|
| 39 |
+
box_0 = gr.Textbox(label="Prompt A + LLM 1", interactive=False)
|
| 40 |
+
box_1 = gr.Textbox(label="Prompt B + LLM 1", interactive=False)
|
| 41 |
+
with gr.Row():
|
| 42 |
+
box_2 = gr.Textbox(label="Prompt A + LLM 2", interactive=False)
|
| 43 |
+
box_3 = gr.Textbox(label="Prompt B + LLM 2", interactive=False)
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
# Return references if needed
|
| 48 |
+
return (model_choice_1,
|
| 49 |
+
model_choice_2,
|
| 50 |
+
exercises_input,
|
| 51 |
+
write_fluster_button,
|
| 52 |
+
[box_0, box_1, box_2, box_3],
|
| 53 |
+
)
|
chains/exercises/fluster_writing_chain.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# chains/exercise_writing/fluster_writing_chain.py
|
| 2 |
+
from pydantic import BaseModel
|
| 3 |
+
from typing import Any
|
| 4 |
+
from langchain_core.prompts.chat import ChatPromptTemplate
|
| 5 |
+
|
| 6 |
+
class FlusterWritingChain(BaseModel):
|
| 7 |
+
"""
|
| 8 |
+
A chain that:
|
| 9 |
+
- Generates exercises from two prompts (A/B)
|
| 10 |
+
- Refines distractors
|
| 11 |
+
- Sanitizes final text
|
| 12 |
+
"""
|
| 13 |
+
template_write_a: ChatPromptTemplate
|
| 14 |
+
template_write_b: ChatPromptTemplate
|
| 15 |
+
default_llm_a: Any
|
| 16 |
+
default_llm_b: Any
|
| 17 |
+
|
| 18 |
+
template_refine_distractors: ChatPromptTemplate
|
| 19 |
+
llm_refine: Any
|
| 20 |
+
|
| 21 |
+
template_sanitize_fluster: ChatPromptTemplate
|
| 22 |
+
llm_sanitize: Any
|
| 23 |
+
|
| 24 |
+
class Config:
|
| 25 |
+
arbitrary_types_allowed = True
|
chains/exercises/runner.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# chains/exercises/runner.py
|
| 2 |
+
import asyncio
|
| 3 |
+
from typing import AsyncGenerator
|
| 4 |
+
from config.llm_config import llms
|
| 5 |
+
from config.chain_configs import chain_configs
|
| 6 |
+
|
| 7 |
+
async def run_fluster(
|
| 8 |
+
user_input_text: str,
|
| 9 |
+
model_choice_1: str, # for "LLM A"
|
| 10 |
+
model_choice_2: str # for "LLM B"
|
| 11 |
+
) -> AsyncGenerator[tuple, None]:
|
| 12 |
+
"""
|
| 13 |
+
Generates exercises in 4 parallel tracks:
|
| 14 |
+
- (Prompt A, LLM A), (Prompt B, LLM A), (Prompt A, LLM B), (Prompt B, LLM B)
|
| 15 |
+
Then refines distractors, then sanitizes.
|
| 16 |
+
Yields partial updates (4 textboxes) as each track completes.
|
| 17 |
+
"""
|
| 18 |
+
|
| 19 |
+
# Get the chain config
|
| 20 |
+
config = chain_configs["exercises"]
|
| 21 |
+
|
| 22 |
+
# Extract the chain object fields
|
| 23 |
+
template_write_a = config["template_write_a"]
|
| 24 |
+
template_write_b = config["template_write_b"]
|
| 25 |
+
|
| 26 |
+
# pick the LLMs based on user input or the default from config
|
| 27 |
+
llm_a = llms.get(model_choice_1, config["default_llm_a"])
|
| 28 |
+
llm_b = llms.get(model_choice_2, config["default_llm_b"])
|
| 29 |
+
|
| 30 |
+
template_refine = config["template_refine_distractors"]
|
| 31 |
+
llm_refine = config["llm_refine"]
|
| 32 |
+
|
| 33 |
+
template_sanitize = config["template_sanitize"]
|
| 34 |
+
llm_sanitize = config["llm_sanitize"]
|
| 35 |
+
|
| 36 |
+
# We'll hold the final results for each of the 4 tracks in a list
|
| 37 |
+
partial_results = ["", "", "", ""]
|
| 38 |
+
|
| 39 |
+
# Helper function: runs the pipeline for a single track
|
| 40 |
+
async def run_track(track_index: int):
|
| 41 |
+
"""
|
| 42 |
+
Steps for each track:
|
| 43 |
+
1) pick prompt A or B
|
| 44 |
+
2) pick LLM A or B
|
| 45 |
+
3) generate
|
| 46 |
+
4) refine
|
| 47 |
+
5) sanitize
|
| 48 |
+
6) return final text
|
| 49 |
+
"""
|
| 50 |
+
# Decide which prompt to use
|
| 51 |
+
if track_index in (0, 2):
|
| 52 |
+
gen_template = template_write_a
|
| 53 |
+
else:
|
| 54 |
+
gen_template = template_write_b
|
| 55 |
+
|
| 56 |
+
# Decide which LLM to use
|
| 57 |
+
if track_index in (0, 1):
|
| 58 |
+
gen_llm = llm_a
|
| 59 |
+
else:
|
| 60 |
+
gen_llm = llm_b
|
| 61 |
+
|
| 62 |
+
# 1) Generate
|
| 63 |
+
gen_msg = await gen_template.aformat_prompt(user_input=user_input_text)
|
| 64 |
+
gen_resp = await gen_llm.ainvoke(gen_msg.to_messages())
|
| 65 |
+
write_fluster_result = getattr(gen_resp, "content", gen_resp)
|
| 66 |
+
|
| 67 |
+
# 2) Refine distractors
|
| 68 |
+
refine_msg = await template_refine.aformat_prompt(raw_exercise=write_fluster_result)
|
| 69 |
+
refine_resp = await llm_refine.ainvoke(refine_msg.to_messages())
|
| 70 |
+
refined_output = getattr(refine_resp, "content", refine_resp)
|
| 71 |
+
|
| 72 |
+
# 3) Sanitize
|
| 73 |
+
sanitize_msg = await template_sanitize.aformat_prompt(raw_output=refined_output)
|
| 74 |
+
sanitize_resp = await llm_sanitize.ainvoke(sanitize_msg.to_messages())
|
| 75 |
+
sanitized_output = getattr(sanitize_resp, "content", sanitize_resp)
|
| 76 |
+
|
| 77 |
+
return track_index, sanitized_output
|
| 78 |
+
|
| 79 |
+
# Prepare the 4 tasks
|
| 80 |
+
tasks = [
|
| 81 |
+
run_track(0),
|
| 82 |
+
run_track(1),
|
| 83 |
+
run_track(2),
|
| 84 |
+
run_track(3),
|
| 85 |
+
]
|
| 86 |
+
|
| 87 |
+
# Run them in parallel
|
| 88 |
+
for coro in asyncio.as_completed(tasks):
|
| 89 |
+
track_idx, final_text = await coro
|
| 90 |
+
partial_results[track_idx] = final_text
|
| 91 |
+
|
| 92 |
+
# Yield partial update (4-tuple). The UI will map each item to a separate textbox.
|
| 93 |
+
yield tuple(partial_results)
|
config/chain_configs.py
CHANGED
|
@@ -12,11 +12,16 @@ from config.templates import (
|
|
| 12 |
template_consolidate_distractors,
|
| 13 |
template_gen_prompt_a,
|
| 14 |
template_gen_prompt_b,
|
| 15 |
-
template_sanitize_learning_objectives
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
)
|
| 17 |
from chains.diagnoser.diagnoser_chain import DiagnoserChain
|
| 18 |
from chains.distractors.distractors_chain import DistractorsChain
|
| 19 |
from chains.learning_objectives_generator.learning_objectives_chain import LearningObjectivesChain
|
|
|
|
| 20 |
from config.llm_config import llms
|
| 21 |
|
| 22 |
# Note: The default LLM here is GPT-4o (low temp); the UI can override this choice.
|
|
@@ -47,7 +52,7 @@ chain_configs = {
|
|
| 47 |
"llm_brainstorm_1": llms["GPT-4o (low temp)"],
|
| 48 |
"llm_brainstorm_2": llms["GPT-4o (mid temp)"],
|
| 49 |
"template_consolidate": template_consolidate_distractors,
|
| 50 |
-
"llm_consolidate": llms["GPT-4o (low temp)"],
|
| 51 |
},
|
| 52 |
"learning_objectives": {
|
| 53 |
"class": LearningObjectivesChain,
|
|
@@ -60,5 +65,16 @@ chain_configs = {
|
|
| 60 |
"template_sanitize": template_sanitize_learning_objectives,
|
| 61 |
"llm_sanitize": "GPT-4o-mini (zero temp)",
|
| 62 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
}
|
| 64 |
-
|
|
|
|
| 12 |
template_consolidate_distractors,
|
| 13 |
template_gen_prompt_a,
|
| 14 |
template_gen_prompt_b,
|
| 15 |
+
template_sanitize_learning_objectives,
|
| 16 |
+
template_write_fluster_a,
|
| 17 |
+
template_write_fluster_b,
|
| 18 |
+
template_refine_distractors,
|
| 19 |
+
template_sanitize_fluster,
|
| 20 |
)
|
| 21 |
from chains.diagnoser.diagnoser_chain import DiagnoserChain
|
| 22 |
from chains.distractors.distractors_chain import DistractorsChain
|
| 23 |
from chains.learning_objectives_generator.learning_objectives_chain import LearningObjectivesChain
|
| 24 |
+
from chains.exercises.fluster_writing_chain import FlusterWritingChain
|
| 25 |
from config.llm_config import llms
|
| 26 |
|
| 27 |
# Note: The default LLM here is GPT-4o (low temp); the UI can override this choice.
|
|
|
|
| 52 |
"llm_brainstorm_1": llms["GPT-4o (low temp)"],
|
| 53 |
"llm_brainstorm_2": llms["GPT-4o (mid temp)"],
|
| 54 |
"template_consolidate": template_consolidate_distractors,
|
| 55 |
+
"llm_consolidate": llms["GPT-4o (low temp)"],
|
| 56 |
},
|
| 57 |
"learning_objectives": {
|
| 58 |
"class": LearningObjectivesChain,
|
|
|
|
| 65 |
"template_sanitize": template_sanitize_learning_objectives,
|
| 66 |
"llm_sanitize": "GPT-4o-mini (zero temp)",
|
| 67 |
},
|
| 68 |
+
"exercises": {
|
| 69 |
+
"class": FlusterWritingChain,
|
| 70 |
+
"template_write_fluster_a": template_write_fluster_a,
|
| 71 |
+
"template_write_fluster_b": template_write_fluster_b,
|
| 72 |
+
"default_llm_a": llms["o1 (high reasoning_effort)"],
|
| 73 |
+
"default_llm_b": llms["o3-mini (high reasoning_effort)"],
|
| 74 |
+
# Prompt & LLM for the refine-distractors step
|
| 75 |
+
"template_refine_distractors": template_refine_distractors,
|
| 76 |
+
"llm_refine": llms["o1 (high reasoning_effort)"],
|
| 77 |
+
"template_sanitize": template_sanitize_fluster,
|
| 78 |
+
"llm_sanitize": "GPT-4o-mini (zero temp)",
|
| 79 |
+
},
|
| 80 |
}
|
|
|
config/system_prompt_texts.py
CHANGED
|
@@ -230,13 +230,24 @@ template_distractors_brainstorm_2_text = """
|
|
| 230 |
template_consolidate_distractors_text = """
|
| 231 |
"""
|
| 232 |
|
|
|
|
| 233 |
template_gen_prompt_a_text = """
|
| 234 |
# Learning Objective Extraction Task
|
| 235 |
|
| 236 |
-
Your task is to analyze a study text and extract high-quality learning objectives that will later serve as the basis for multiple-choice questions. Each learning objective must perfectly adhere to all specified requirements.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
|
| 238 |
## Analysis Approach
|
| 239 |
-
Before extracting learning objectives:
|
| 240 |
* Carefully analyze the text's language level and target audience
|
| 241 |
* Note the terminology, voice (active/passive), and perspective (2nd/3rd person)
|
| 242 |
* Pay attention to the complexity of vocabulary and sentence structures used
|
|
@@ -273,7 +284,7 @@ Before extracting learning objectives:
|
|
| 273 |
</examples>
|
| 274 |
|
| 275 |
### Content Quality
|
| 276 |
-
* **Self-contained**: Must be understandable without relying on any outside context, like 'previous' learning objectives (they will in fact be presented to the student non-chronologically, so cannot build on each other)
|
| 277 |
* **Falsifiable**: Must be unambiguously, demonstrably true or false
|
| 278 |
* **Factually Equivalent**: Must represent exactly the knowledge as written
|
| 279 |
* **Specific**: Must express the smallest testable knowledge unit, instead of combining several at once. For knowledge that consists of parts, just focus on each part one by one (one learning objective focused on each), including callbacks to the whole.
|
|
@@ -281,7 +292,7 @@ Before extracting learning objectives:
|
|
| 281 |
<examples>
|
| 282 |
<self-contained_example>
|
| 283 |
<too_context_dependent>- De student weet dat als je dit gevoel krijgt, je hierop moet letten en moet onderzoeken waar het vandaan komt.</too_context_dependent>
|
| 284 |
-
<explanation>From just reading the learning objective, it is not clear what
|
| 285 |
<better>- De student weet dat als je een onderbuikgevoel krijgt, je hierop moet letten en moet onderzoeken waar het vandaan komt.</better>
|
| 286 |
<explanation>Now it includes the relevant part of the text such that the objective becomes self-contained, not referencing any info outside of it</explanation>
|
| 287 |
</self-contained_example>
|
|
@@ -296,14 +307,14 @@ Before extracting learning objectives:
|
|
| 296 |
</better>
|
| 297 |
<explanation>Focuses on each smallest specific knowledge element individually, while maintaining coherence via the callback to the whole between brackets</explanation>
|
| 298 |
<too_broad>- De student weet dat de Wvggz vier hoofddoelstellingen heeft: (1) het beperken of voorkomen van dwang, (2) het versterken van de rechtspositie van zorgvragers met een psychische aandoening, (3) het verbeteren van de kwaliteit van de zorg en (4) het leveren van (dwang)zorg op maat.</too_broad>
|
| 299 |
-
<explanation>'Knowing Wggz's key objectives' can be seen as one coherent learning objective, but it consists of clearly discrete parts that each can (and therefore should) be tested separately.</explanation>
|
| 300 |
<better>
|
| 301 |
- De student weet dat "dwang beperken" een van de vier hoofddoelen is van de Wvggz (naast het versterken van de rechtspositie van zorgvragers met een psychische aandoening, verbeteren van de kwaliteit van de zorg en (dwang)zorg op maat leveren.
|
| 302 |
- De student weet dat "het versterken van de rechtspositie van zorgvragers met een psychische aandoening" een van de vier hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het verbeteren van de kwaliteit van de zorg en het leveren van (dwang)zorg op maat).
|
| 303 |
- De student weet dat "het verbeteren van de kwaliteit van de zorg" een van de hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het versterken van de rechtspositie van zorgvragers met een psychische aandoening en het leveren van (dwang)zorg op maat).
|
| 304 |
- De student weet dat "het leveren van (dwang)zorg op maat" een van de hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het versterken van de rechtspositie van zorgvragers met een psychische aandoening en het verbeteren van de kwaliteit van de zorg).
|
| 305 |
</better>
|
| 306 |
-
<explanation>This may seem tedious, but it
|
| 307 |
</specificity_examples>
|
| 308 |
</examples>
|
| 309 |
|
|
@@ -394,13 +405,388 @@ Before extracting learning objectives:
|
|
| 394 |
</examples_of_>
|
| 395 |
"""
|
| 396 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 397 |
|
| 398 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
"""
|
| 400 |
|
| 401 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 402 |
"""
|
| 403 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 404 |
XML_templates= [
|
| 405 |
"""
|
| 406 |
<example>
|
|
|
|
| 230 |
template_consolidate_distractors_text = """
|
| 231 |
"""
|
| 232 |
|
| 233 |
+
# new prompt 1
|
| 234 |
template_gen_prompt_a_text = """
|
| 235 |
# Learning Objective Extraction Task
|
| 236 |
|
| 237 |
+
Your task is to analyze a study text and extract high-quality learning objectives that will later serve as the basis for multiple-choice questions. Each learning objective must perfectly adhere to all specified requirements. Here are some examples of various good learning objectives (without the texts they're based on) to familiarize you with the concept:
|
| 238 |
+
<examples>
|
| 239 |
+
<various_good_learning_objectives>
|
| 240 |
+
- De student weet dat eenzaamheid subjectief is.
|
| 241 |
+
- De student weet dat erfelijkheid een van de hoofddingen is die je persoonlijkheid vormen (naast opvoeding, sociale omgeving en zelfbepaling).
|
| 242 |
+
- De student weet dat sociale omgeving een van de hoofddingen is die je persoonlijkheid vormen (naast erfelijkheid, opvoeding en zelfbepaling).
|
| 243 |
+
- De student weet dat de secondary survey plaatsvindt wanneer de primary survey inclusief resuscitatie is afgerond.
|
| 244 |
+
- De student weet dat de S in SBAR staat voor Situation ('situatie').
|
| 245 |
+
- De student weet dat de B in SBAR staat voor Background ('achtergrond').
|
| 246 |
+
</various_good_learning_objectives>
|
| 247 |
+
<examples>
|
| 248 |
|
| 249 |
## Analysis Approach
|
| 250 |
+
Before extracting learning objectives from the text:
|
| 251 |
* Carefully analyze the text's language level and target audience
|
| 252 |
* Note the terminology, voice (active/passive), and perspective (2nd/3rd person)
|
| 253 |
* Pay attention to the complexity of vocabulary and sentence structures used
|
|
|
|
| 284 |
</examples>
|
| 285 |
|
| 286 |
### Content Quality
|
| 287 |
+
* **Self-contained**: Must be understandable without relying on any outside context, like 'previous' learning objectives (they will in fact be presented to the student non-chronologically, so they cannot build on each other)
|
| 288 |
* **Falsifiable**: Must be unambiguously, demonstrably true or false
|
| 289 |
* **Factually Equivalent**: Must represent exactly the knowledge as written
|
| 290 |
* **Specific**: Must express the smallest testable knowledge unit, instead of combining several at once. For knowledge that consists of parts, just focus on each part one by one (one learning objective focused on each), including callbacks to the whole.
|
|
|
|
| 292 |
<examples>
|
| 293 |
<self-contained_example>
|
| 294 |
<too_context_dependent>- De student weet dat als je dit gevoel krijgt, je hierop moet letten en moet onderzoeken waar het vandaan komt.</too_context_dependent>
|
| 295 |
+
<explanation>From just reading the learning objective, it is not clear what "dit" refers to</explanation>
|
| 296 |
<better>- De student weet dat als je een onderbuikgevoel krijgt, je hierop moet letten en moet onderzoeken waar het vandaan komt.</better>
|
| 297 |
<explanation>Now it includes the relevant part of the text such that the objective becomes self-contained, not referencing any info outside of it</explanation>
|
| 298 |
</self-contained_example>
|
|
|
|
| 307 |
</better>
|
| 308 |
<explanation>Focuses on each smallest specific knowledge element individually, while maintaining coherence via the callback to the whole between brackets</explanation>
|
| 309 |
<too_broad>- De student weet dat de Wvggz vier hoofddoelstellingen heeft: (1) het beperken of voorkomen van dwang, (2) het versterken van de rechtspositie van zorgvragers met een psychische aandoening, (3) het verbeteren van de kwaliteit van de zorg en (4) het leveren van (dwang)zorg op maat.</too_broad>
|
| 310 |
+
<explanation>'Knowing Wggz's key objectives' can be seen as one coherent learning objective, but it consists of too many clearly discrete parts that each can (and therefore should) be tested separately.</explanation>
|
| 311 |
<better>
|
| 312 |
- De student weet dat "dwang beperken" een van de vier hoofddoelen is van de Wvggz (naast het versterken van de rechtspositie van zorgvragers met een psychische aandoening, verbeteren van de kwaliteit van de zorg en (dwang)zorg op maat leveren.
|
| 313 |
- De student weet dat "het versterken van de rechtspositie van zorgvragers met een psychische aandoening" een van de vier hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het verbeteren van de kwaliteit van de zorg en het leveren van (dwang)zorg op maat).
|
| 314 |
- De student weet dat "het verbeteren van de kwaliteit van de zorg" een van de hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het versterken van de rechtspositie van zorgvragers met een psychische aandoening en het leveren van (dwang)zorg op maat).
|
| 315 |
- De student weet dat "het leveren van (dwang)zorg op maat" een van de hoofddoelen is van de Wvggz (naast het beperken of voorkomen van dwang, het versterken van de rechtspositie van zorgvragers met een psychische aandoening en het verbeteren van de kwaliteit van de zorg).
|
| 316 |
</better>
|
| 317 |
+
<explanation>This repetition may seem tedious, but it is crucial for composite knowledge like this. It allows us to later craft effective, self-contained multiple choice questions based on each knowledge part independently, while retaining the connection to the whole. This way, we can do targeted, piecemeal testing of the student's knowledge without sacrificing coherence.</explanation>
|
| 318 |
</specificity_examples>
|
| 319 |
</examples>
|
| 320 |
|
|
|
|
| 405 |
</examples_of_>
|
| 406 |
"""
|
| 407 |
|
| 408 |
+
# existing old (current) prompt stripped refocused for LOs only
|
| 409 |
+
template_gen_prompt_b_text = """
|
| 410 |
+
You are given a study text. Based on this, you will identify learning objectives. Follow the following protocol meticulously:
|
| 411 |
+
|
| 412 |
+
# Protocol for Creating Exercises for eLearning Modules
|
| 413 |
+
## General Working Method
|
| 414 |
+
|
| 415 |
+
### Text Orientation
|
| 416 |
+
Assigned a study text, your initial task is to read it to understand the topic for creating exercises.
|
| 417 |
+
|
| 418 |
+
### Learning objectives
|
| 419 |
+
Based on the text, define clear, concise learning objectives. Make sure you have enough learning objectives so that all information is covered, but not too many so that learning objectives won't overlap. It's really important that every learning objective only states 1 single fact and doesn't combine multiple facts. Choose objectives based on text analysis and audience level. Objectives always start with 'The student knows that', or whichever semantic equivalent matching the language of the study text (eg. for Dutch texts, use 'De student weet dat').
|
| 420 |
+
|
| 421 |
+
Observe the following rules meticulously when writing learning objectives:
|
| 422 |
+
|
| 423 |
+
#### Avoid 'always' and 'never'
|
| 424 |
+
Don't use words like 'always' or 'never' in learning objectives, it is likely an exception exists. Instead use constructions like 'X *fits with* Y', 'X *suggests* Y', 'X *is more common than* Y'
|
| 425 |
+
|
| 426 |
+
So not:
|
| 427 |
+
> BAD: The students knows that fever *never* occurs with a viral infection.
|
| 428 |
+
> BAD: The students knows that fever *always* occurs with a viral infection.
|
| 429 |
+
|
| 430 |
+
But:
|
| 431 |
+
> GOOD: The students knows that fever is a symptom *that fits with* a viral infection.
|
| 432 |
+
|
| 433 |
+
#### Avoid 'can', 'could', 'may' or 'might'
|
| 434 |
+
Don't use words like *'can'*, *'could'*, *'may'* or *'might'* in learning objectives, because almost everything can, could or might be something, so too suggestive. Instead use constructions like 'X *fits with* Y', 'X *suggests* Y', 'X *is more common than* Y'
|
| 435 |
+
|
| 436 |
+
So not:
|
| 437 |
+
> BAD: The students knows that pain *might* occur with rheumatoid arthritis.
|
| 438 |
+
> BAD: The students knows that pain *can* occur with rheumatoid arthritis.
|
| 439 |
+
> BAD: The students knows that pain *could* occur with rheumatoid arthritis.
|
| 440 |
+
> BAD: The students knows that pain *may* occur with rheumatoid arthritis.
|
| 441 |
+
|
| 442 |
+
But:
|
| 443 |
+
> GOOD: The students knows that pain *is a symptom of* rheumatoid arthritis.
|
| 444 |
+
|
| 445 |
+
#### Avoid subjective terminology like many, few and common
|
| 446 |
+
Don't use words like *'many'*, *'few'*, *'common'*, *'rare'* et cetera as these are subjective. Instead be specific. Instead use terminology like *'in most cases'* or compare: *'symptom A is more common than symptom B'*.
|
| 447 |
+
|
| 448 |
+
Example of a bad learning objective, leading to suggestive or subjective answers:
|
| 449 |
+
> BAD: The student knows that fever commonly occurs with a viral infection.
|
| 450 |
+
|
| 451 |
+
#### Avoid important, essential significant
|
| 452 |
+
Don't use words like *'important'*, *'essential'*, *'significant'* et cetera in learning objectives, as these are prone to subjectivity.
|
| 453 |
+
|
| 454 |
+
Examples of a bad learning objective, leading to suggestive or subjective answers:
|
| 455 |
+
> BAD: The students knows that it's *important* to rest when having a viral infection.
|
| 456 |
+
|
| 457 |
+
The objective uses the word *'important'* which is subjective.
|
| 458 |
+
|
| 459 |
+
> BAD: The students knows that it's *essential* to rest when having a viral infection.
|
| 460 |
+
|
| 461 |
+
The objective uses the word *'essential'* which is subjective.
|
| 462 |
+
|
| 463 |
+
> BAD: The students knows that fever has a *significant* effect on how people feel when they are sick.
|
| 464 |
+
|
| 465 |
+
The objective uses the word *'significant'* which is subjective.
|
| 466 |
+
|
| 467 |
+
> BAD: The student knows that drinking *enough* water is *important* to stay hydrated.
|
| 468 |
+
|
| 469 |
+
The objective uses the word *'important'* which is subjective. Also the word *'enough'* is subjective.
|
| 470 |
+
|
| 471 |
+
|
| 472 |
+
A good example is:
|
| 473 |
+
|
| 474 |
+
> GOOD: The student knows that proteinuria is a symptom of nephrotic syndrome.
|
| 475 |
+
|
| 476 |
+
An example of a bad learning objective:
|
| 477 |
+
|
| 478 |
+
> BAD: The student knows the symptoms of nephrotic syndrome.
|
| 479 |
+
|
| 480 |
+
The bad objective does not specify a single fact as symptoms are not specified.
|
| 481 |
+
|
| 482 |
+
A good example is:
|
| 483 |
+
|
| 484 |
+
> GOOD: The student knows that besides pain, rheumatoid arthritis also causes loss of mobility.
|
| 485 |
+
|
| 486 |
+
An example of a bad learning objective:
|
| 487 |
+
|
| 488 |
+
> BAD: The student knows that problems with movement due to joint problems, such as rheumatism, can be painful or completely limit movement
|
| 489 |
+
|
| 490 |
+
The latter objective does not specify a single fact but combines two (can be painful or completely limit movement). The first objective focuses on the 'loss of mobility' element, while the 'pain- element' is already considered known. The exercises generated by this learning objective will test the 'loss of mobility' element (so not the 'pain-element'
|
| 491 |
+
"""
|
| 492 |
+
|
| 493 |
+
template_sanitize_learning_objectives_text = """
|
| 494 |
+
"""
|
| 495 |
+
|
| 496 |
+
template_write_fluster_a_text= """
|
| 497 |
+
# Task outline
|
| 498 |
+
Given a learning objective, your goal is to write an exercise set of 3 high-quality multiple choice exercises that all test the exact same knowledge that's stated in the learning objective.
|
| 499 |
|
| 500 |
+
# Concepts
|
| 501 |
+
## Learning objective
|
| 502 |
+
Tests a specific fact. For example: "De student weet dat de Wet Bopz sinds 1994 in gebruik was (toen hij werd opgevolgd door de Wvggz)."
|
| 503 |
+
|
| 504 |
+
## Exercise set
|
| 505 |
+
Comprises 3 exercises that all test the same single learning objective: one bigger multiple choice exercise and two smaller correct/incorrect statements.
|
| 506 |
+
<exercise_set>
|
| 507 |
+
<multiple_choice_exercise>
|
| 508 |
+
Stelling:
|
| 509 |
+
De wet Bopz was sinds ..... in gebruik.
|
| 510 |
+
|
| 511 |
+
1. 1984
|
| 512 |
+
2. 1999
|
| 513 |
+
3. 2004
|
| 514 |
+
4. 2009
|
| 515 |
+
|
| 516 |
+
Juiste antwoord: 2
|
| 517 |
+
|
| 518 |
+
Extra info:
|
| 519 |
+
In 1993 werd de wet Bopz opgevolgd door de Wvggz.
|
| 520 |
+
</multiple_choice_exercise>
|
| 521 |
+
<correct_statement>
|
| 522 |
+
Stelling:
|
| 523 |
+
De wet Bopz was sinds 1994 in gebruik.
|
| 524 |
+
|
| 525 |
+
1. Deze stelling is correct
|
| 526 |
+
2. Deze stelling is niet correct
|
| 527 |
+
|
| 528 |
+
Juiste antwoord: 1
|
| 529 |
+
|
| 530 |
+
Extra info:
|
| 531 |
+
In 1993 werd de wet Bopz opgevolgd door de Wvggz.
|
| 532 |
+
</correct_statement>
|
| 533 |
+
<incorrect_statement>
|
| 534 |
+
Stelling:
|
| 535 |
+
De wet Bopz was sinds 1984 in gebruik.
|
| 536 |
+
|
| 537 |
+
1. Deze stelling is correct
|
| 538 |
+
2. Deze stelling is niet correct
|
| 539 |
+
|
| 540 |
+
Juiste antwoord: 2
|
| 541 |
+
|
| 542 |
+
Extra info:
|
| 543 |
+
De wet Bopz was sinds 1994 in gebruik. Toen werd hij opgevolgd door de Wvggz.
|
| 544 |
+
</incorrect_statement>
|
| 545 |
+
</exercise_set>
|
| 546 |
+
|
| 547 |
+
Here's another example of an exercise set, this time for the learning objective: "De student weet dat je dagelijks oefent om zo objectief (zonder je eigen mening) mogelijk te observeren."
|
| 548 |
+
"<exercise_set>
|
| 549 |
+
<multiple_choice_exercise>
|
| 550 |
+
Theorie:
|
| 551 |
+
Objectief betekent "zonder je eigen mening".
|
| 552 |
+
|
| 553 |
+
Vraag:
|
| 554 |
+
Wat moet je doen om zo objectief mogelijk te observeren?
|
| 555 |
+
|
| 556 |
+
1. Je intuïtie volgen
|
| 557 |
+
2. Veel theorie leren
|
| 558 |
+
3. Iemand anders erbij roepen
|
| 559 |
+
4. Dagelijks oefenen
|
| 560 |
+
|
| 561 |
+
Juiste antwoord: 4
|
| 562 |
+
</multiple_choice_exercise>
|
| 563 |
+
<correct_statement>
|
| 564 |
+
Theorie:
|
| 565 |
+
Objectief betekent "zonder je eigen mening".
|
| 566 |
+
|
| 567 |
+
Stelling:
|
| 568 |
+
Om zo objectief mogelijk te observeren moet je dagelijks oefenen.
|
| 569 |
+
|
| 570 |
+
1. Deze stelling is correct
|
| 571 |
+
2. Deze stelling is niet correct
|
| 572 |
+
|
| 573 |
+
Juiste antwoord: 1
|
| 574 |
+
</correct_statement>
|
| 575 |
+
<incorrect_statement>
|
| 576 |
+
Theorie:
|
| 577 |
+
Objectief betekent "zonder je eigen mening".
|
| 578 |
+
|
| 579 |
+
Stelling:
|
| 580 |
+
Om zo objectief mogelijk te observeren moet je een keer per jaar oefenen.
|
| 581 |
+
|
| 582 |
+
1. Deze stelling is correct
|
| 583 |
+
2. Deze stelling is niet correct
|
| 584 |
+
|
| 585 |
+
Juiste antwoord: 2
|
| 586 |
+
|
| 587 |
+
Extra info:
|
| 588 |
+
Je moet <b>dagelijks<b> oefenen om zo objectief mogelijk te observeren.
|
| 589 |
+
</incorrect_statement>
|
| 590 |
+
</exercise_set>
|
| 591 |
+
|
| 592 |
+
|
| 593 |
+
## Distractors
|
| 594 |
+
The alternative answer options of the multiple choice exercise that are not the correct answer are called distractors. These are the most important part of the exercise. Effective distractors strike the perfect balance between "very plausible to someone who doesn't know the answer to the question" and "clearly wrong to someone who does know the answer to the question".
|
| 595 |
+
|
| 596 |
+
## Theory
|
| 597 |
+
Optional. Sometimes there's additional knowledge present in the learning objective (often between parentheses) that is not the direct focus to test, but useful to know for the student beforehand to better understand the question. This is then added as Theory. The student gets to see this as part of the exercise prompt.
|
| 598 |
+
|
| 599 |
+
# Extra info
|
| 600 |
+
Optional. Sometimes there's additional knowledge present in the learning objective (often between parentheses, or as a subclause) that is not the direct focus to know, but useful related, additional info. The student gets to see this after they pick their answer. Incorrect statements always need extra info, to tell the student why the statement is incorrect (explaining what the correct statement would have been).
|
| 601 |
+
|
| 602 |
+
# Approach
|
| 603 |
+
Think long and hard about the ideal three exercises to test the given learning objective. Especially spend a lot of time picking good distractors for the first multiple choice exercise.
|
| 604 |
+
Imagine the typical slightly more stupid target student among the target audience for this learning objective. Would they sometimes find each distractor sound appealing if they hadn't studied for the test? We want to avoid the possibility that they can too easily dismiss and eliminate a distractor as clearly not a serious option, just on the basis of it looking weird to them. Imagine whether very stupid students with limited general knowledge, and no knowledge of the topic of the exercise, might find the distractor plausible. That's the goal.
|
| 605 |
+
At the same time, a distractor must not be too close to the truth either. That would be misleading. Imagine asking 10 domain experts to judge this. All of them should agree that the correct answer is the clearly best answer in this exercise. If there's any doubt, rephrase the distractor to be a bit less true, and imagine again.
|
| 606 |
+
After lots of iterative prep and reasoning, considering a wide range of options, weighing what would be the best, finally return a complete exercise set of 1 multiple choice exercise and 2 statements.
|
| 607 |
+
|
| 608 |
+
## Pointers
|
| 609 |
+
- Try to exactly match the content and language level in the learning objective. If it's stated in simple words, use equally simple words in the exercises as well.
|
| 610 |
+
- Output format doesn't matter. It can all be haphazard and jumbled, just prioritize sound reasoning at all costs. We will reformat later in a separate step.
|
| 611 |
"""
|
| 612 |
|
| 613 |
+
# The existing prompt in Course Generator webapp
|
| 614 |
+
template_write_fluster_b_text= """
|
| 615 |
+
You are given a learning objective. Based on this, you will create an exercise set of 3 exercises.
|
| 616 |
+
Follow the following protocol meticulously:
|
| 617 |
+
|
| 618 |
+
# Protocol for Creating Exercises for eLearning Modules
|
| 619 |
+
## Definitions:
|
| 620 |
+
### Exercise
|
| 621 |
+
An exercise assesses knowledge related to a specific learning objective.
|
| 622 |
+
|
| 623 |
+
### Exercise set
|
| 624 |
+
An exercise set, comprising three exercises, tests the same learning objective and combines various exercise types targeting that objective.
|
| 625 |
+
|
| 626 |
+
## General Working Method
|
| 627 |
+
|
| 628 |
+
### Exercise Structure
|
| 629 |
+
Below is the recommended exercise structure. Headings in brackets are optional.
|
| 630 |
+
|
| 631 |
+
#### Exercise sets
|
| 632 |
+
Create an exercise set for each objective. Make sure all exercises in the set test the given learning objective only and do not (partially) test anything else. Consequently, all exercises in the set test the same learning objective.
|
| 633 |
+
Also make sure that the exercise types vary.
|
| 634 |
+
|
| 635 |
+
#### (Theory:/Case:)
|
| 636 |
+
An exercise might begin with 'theory' for context or a 'case', a practical scenario, followed by a related exercise.
|
| 637 |
+
|
| 638 |
+
Example:
|
| 639 |
+
> Case: A 23 year old woman presents at the ED due to exacerbation of
|
| 640 |
+
> bronchial asthma. She was cyanotic and can only speak in short
|
| 641 |
+
> sentences. ABG measurement showed the following values:
|
| 642 |
+
> **pH:** 7.40
|
| 643 |
+
> **PaCO2:** 40 mmHg/5.3 kPa
|
| 644 |
+
> **HCO3:** 24 mmol/L
|
| 645 |
+
> Question: What is the patient's acid-base abnormality?
|
| 646 |
+
|
| 647 |
+
#### Question/Statement:
|
| 648 |
+
Ensure questions or statements are concise. End questions with a question mark and statements with a period. Write the question or statement in a JSON property called *'question'*
|
| 649 |
+
|
| 650 |
+
#### Multiple-Choice Answers
|
| 651 |
+
Formulate answer choices briefly. Start with a capital letter. List answers without labels like A) B) C) or 1. 2. 3. List the correct answer choice in the JSON property *'answer'* and the remaining answer choices in a JSON array of strings called *'distractors'*
|
| 652 |
+
|
| 653 |
+
#### (Extra Info:)
|
| 654 |
+
Provide additional information after each exercise for clarification, especially when the correct answer isn't obvious from the question. If it is just a repeat of the question and/or answer without adding anything for clarity, leave the extra info out. Write the extra info in the optional JSON property *'explanation'*.
|
| 655 |
+
|
| 656 |
+
### Exercise set
|
| 657 |
+
#### Variants in a exercise set
|
| 658 |
+
Create for every learning objective a exercise set consisting of three variants:
|
| 659 |
+
- Question or fill in the blank with 3 or 4 answers choices
|
| 660 |
+
- Correct/incorrect statement, answer is correct
|
| 661 |
+
- Correct/incorrect statement, answer is incorrect
|
| 662 |
+
|
| 663 |
+
Creating variants prevents students from just recognizing the exercise and answer, and encourages thinking about the correct answer.
|
| 664 |
+
|
| 665 |
+
#### Multiple choice question (mcq)
|
| 666 |
+
Label a mcq with 'question' and end with a question mark. Example:
|
| 667 |
+
|
| 668 |
+
[
|
| 669 |
+
{
|
| 670 |
+
'question': 'Question: Which layer of the digestive tract has the myenteric neural plexus?',
|
| 671 |
+
'answer': 'Muscular layer'
|
| 672 |
+
'distractors': [
|
| 673 |
+
'Mucosa',
|
| 674 |
+
'Submucosa',
|
| 675 |
+
'Serosa'
|
| 676 |
+
]
|
| 677 |
+
}
|
| 678 |
+
]
|
| 679 |
+
|
| 680 |
+
#### Multiple choice statement (mcs)
|
| 681 |
+
Create a statement with a fill in the blank. Use 'statement' instead of 'question' and end with a full stop. Use exactly 5 dots for the gap. Never have more than 1 gap. Example:
|
| 682 |
+
```json
|
| 683 |
+
[
|
| 684 |
+
{
|
| 685 |
+
'question': 'Statement: The ..... is the inner lining of the digestive tract. ',
|
| 686 |
+
'answer': 'Mucosa',
|
| 687 |
+
'distractors': [
|
| 688 |
+
'Muscular layer',
|
| 689 |
+
'Submucosa',
|
| 690 |
+
'Serosa'
|
| 691 |
+
]
|
| 692 |
+
}
|
| 693 |
+
]
|
| 694 |
+
```
|
| 695 |
+
##### Correct/incorrect exercise set variants
|
| 696 |
+
Two variants in the exercise set, can be derived from the mcq or mcs. One has the correct mcq/mcs answer (answer “This statement is correct”), the other has an incorrect mcq/mcs answer (answer “This statement is incorrect”). Balance the correct and incorrect exercises in each exercise set. Start with a mcq or mcs followed by the 2 correct/incorrect variants.
|
| 697 |
+
|
| 698 |
+
|
| 699 |
+
#### Avoid double negatives
|
| 700 |
+
Don't use negations like 'no' or 'not' or 'never' or words with a comparable meaning in the statement / question in order to avoid double negations with the 'incorrect' answer option.
|
| 701 |
+
|
| 702 |
+
#### Avoid 'always' and 'never'
|
| 703 |
+
Don't use words like 'always' or 'never' in exercise statements or questions, it is likely an exception exists rendering the statement or question inherently incorrect.
|
| 704 |
+
|
| 705 |
+
So not:
|
| 706 |
+
> Statement: Fever can occur with a viral infection.
|
| 707 |
+
> Question: What can occur with a viral infection.
|
| 708 |
+
|
| 709 |
+
But:
|
| 710 |
+
> Statement: fever is a classic symptom of a viral infection.
|
| 711 |
+
> Question: What is a classic symptom of a viral infection.
|
| 712 |
+
|
| 713 |
+
#### Avoid 'can', 'could' or 'might'
|
| 714 |
+
Don't use words like 'can', 'could' or 'might' in exercise statements or questions, because almost everything can, could or might be something, rendering the statement or question inherently correct.
|
| 715 |
+
|
| 716 |
+
So not:
|
| 717 |
+
> Statement: pain might occur with rheumatoid arthritis.
|
| 718 |
+
> Question: what symptoms can occur with rheumatoid arthritis?
|
| 719 |
+
|
| 720 |
+
But:
|
| 721 |
+
> Statement: pain is a symptom that fits rheumatoid arthritis.
|
| 722 |
+
> Question: Which symptom best describes rheumatoid arthritis?
|
| 723 |
+
|
| 724 |
+
#### Using theory
|
| 725 |
+
Starting an exercise with Theory isn't mandatory. Add it for context or to shorten the question/statement.
|
| 726 |
+
|
| 727 |
+
#### Providing context
|
| 728 |
+
Each exercise should be clear on its own, also without the context of the study text it is about. Consider adding theory for clarity if needed.
|
| 729 |
+
|
| 730 |
+
#### Shortening the statement/question
|
| 731 |
+
Keep statements/questions short and concise. Put extra context in the theory section.
|
| 732 |
+
|
| 733 |
+
Example: instead of
|
| 734 |
+
```json
|
| 735 |
+
{
|
| 736 |
+
'question': 'Statement: Between the liver and the anterior abdominal wall and diaphragm is the ..... ',
|
| 737 |
+
'answer': 'Falciform ligament ',
|
| 738 |
+
'distractors': {'Greater omentum', 'Lesser omentum', 'Mesentery proper'}
|
| 739 |
+
}
|
| 740 |
+
```
|
| 741 |
+
move some info to the theory for clarity:
|
| 742 |
+
```json
|
| 743 |
+
{
|
| 744 |
+
'question': 'Theory: A visceral mesentery connects the liver to the anterior abdominal wall and diaphragm.\nQuestion: Which mesentery is this? ',
|
| 745 |
+
'answer': 'Falciform ligament ',
|
| 746 |
+
'distractors': {'Greater omentum', 'Lesser omentum', 'Mesentery proper'}
|
| 747 |
+
}
|
| 748 |
+
```
|
| 749 |
+
### Answer options
|
| 750 |
+
#### Format and length
|
| 751 |
+
Maintain similar format and length for all options in an exercise.
|
| 752 |
+
|
| 753 |
+
#### Choosing plausible incorrect options
|
| 754 |
+
Select incorrect options that might seem true to someone who doesn't know the answer.
|
| 755 |
+
|
| 756 |
+
#### Numbers
|
| 757 |
+
Use numbers only if relevant. For cut-off points, ensure incorrect answers are truly incorrect. Use terms like 'cut-off point' or 'lower/upper limit' for clarity.
|
| 758 |
+
For example:
|
| 759 |
+
```json
|
| 760 |
+
{
|
| 761 |
+
"question": "Statement: A systolic blood pressure less than 70 mmHg is considered hypotension.",
|
| 762 |
+
"answer": "This statement is incorrect",
|
| 763 |
+
"distractors": [
|
| 764 |
+
"This statement is correct"
|
| 765 |
+
],
|
| 766 |
+
"explanation": "It is considered hypotension from 90 mmHg."
|
| 767 |
+
}
|
| 768 |
+
```
|
| 769 |
+
The statement above is actually correct because less than 70 is also less than 90! What the writer intended to test was the cut-off point. You can solve this problem by explicitly using the terms 'cut-off point' or 'lower/upper limit' in the question
|
| 770 |
+
|
| 771 |
+
|
| 772 |
+
#### Accuracy
|
| 773 |
+
Always aim to avoid debates over exercise accuracy. Correct answers must be wholly true, and incorrect ones entirely false, eliminating any argument possibility.
|
| 774 |
+
Be precise. Shun absolute terms like 'never' or 'always', as they imply complete rightness or wrongness, which is rarely the case due to real-world exceptions. Choose words like 'typically', 'most characteristic of', or 'in most cases' and use relative terms such as “Is best described by ….”. When stating 'more/less than', clarify what it's in comparison to. Eschew 'can'. Including 'can' in questions or statements likely makes your wrong options not fully incorrect, as theoretically, much can occur.
|
| 775 |
"""
|
| 776 |
|
| 777 |
+
|
| 778 |
+
template_refine_distractors_text = """
|
| 779 |
+
Given some source data containing exercises, critically analyze this with the goal of refining and improving the exercises.
|
| 780 |
+
Play devil's advocate here: in what ways is this version of the exercises not perfect? Do some reasoning about this, and then give the improved exercises. If you didn't find anything to improve, just return the exercises as they are.
|
| 781 |
+
"""
|
| 782 |
+
|
| 783 |
+
|
| 784 |
+
template_sanitize_fluster_text = """
|
| 785 |
+
Your task is to process the source data, and extract only the exercises from it. This should be your only output: a neat plaintext representation of all final exercises.
|
| 786 |
+
"""
|
| 787 |
+
|
| 788 |
+
|
| 789 |
+
|
| 790 |
XML_templates= [
|
| 791 |
"""
|
| 792 |
<example>
|
config/templates.py
CHANGED
|
@@ -15,6 +15,10 @@ from config.system_prompt_texts import (
|
|
| 15 |
template_gen_prompt_a_text,
|
| 16 |
template_gen_prompt_b_text,
|
| 17 |
template_sanitize_learning_objectives_text,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
)
|
| 19 |
|
| 20 |
|
|
@@ -181,102 +185,10 @@ template_gen_prompt_a = ChatPromptTemplate(
|
|
| 181 |
input_variables=["standardized_text"]
|
| 182 |
)
|
| 183 |
|
| 184 |
-
"""
|
| 185 |
-
<illustration of 'specific'>
|
| 186 |
-
<bad example: not specific enough>
|
| 187 |
-
|
| 188 |
-
</bad example: not specific enough>
|
| 189 |
-
<good example: states isolated fact>
|
| 190 |
-
|
| 191 |
-
</good example: states isolated fact>
|
| 192 |
-
</illustration of 'specific'>
|
| 193 |
-
"""
|
| 194 |
|
| 195 |
template_gen_prompt_b = ChatPromptTemplate(
|
| 196 |
messages=[
|
| 197 |
-
("system",
|
| 198 |
-
You are given a study text. Based on this, you will identify learning objectives. Follow the following protocol meticulously:
|
| 199 |
-
|
| 200 |
-
# Protocol for Creating Exercises for eLearning Modules
|
| 201 |
-
## General Working Method
|
| 202 |
-
|
| 203 |
-
### Text Orientation
|
| 204 |
-
Assigned a study text, your initial task is to read it to understand the topic for creating exercises.
|
| 205 |
-
|
| 206 |
-
### Learning objectives
|
| 207 |
-
Based on the text, define clear, concise learning objectives. Make sure you have enough learning objectives so that all information is covered, but not too many so that learning objectives won't overlap. It's really important that every learning objective only states 1 single fact and doesn't combine multiple facts. Choose objectives based on text analysis and audience level. Objectives always start with 'The student knows that', or whichever semantic equivalent matching the language of the study text (eg. for Dutch texts, use 'De student weet dat').
|
| 208 |
-
|
| 209 |
-
Observe the following rules meticulously when writing learning objectives:
|
| 210 |
-
|
| 211 |
-
#### Avoid 'always' and 'never'
|
| 212 |
-
Don't use words like 'always' or 'never' in learning objectives, it is likely an exception exists. Instead use constructions like 'X *fits with* Y', 'X *suggests* Y', 'X *is more common than* Y'
|
| 213 |
-
|
| 214 |
-
So not:
|
| 215 |
-
> BAD: The students knows that fever *never* occurs with a viral infection.
|
| 216 |
-
> BAD: The students knows that fever *always* occurs with a viral infection.
|
| 217 |
-
|
| 218 |
-
But:
|
| 219 |
-
> GOOD: The students knows that fever is a symptom *that fits with* a viral infection.
|
| 220 |
-
|
| 221 |
-
#### Avoid 'can', 'could', 'may' or 'might'
|
| 222 |
-
Don't use words like *'can'*, *'could'*, *'may'* or *'might'* in learning objectives, because almost everything can, could or might be something, so too suggestive. Instead use constructions like 'X *fits with* Y', 'X *suggests* Y', 'X *is more common than* Y'
|
| 223 |
-
|
| 224 |
-
So not:
|
| 225 |
-
> BAD: The students knows that pain *might* occur with rheumatoid arthritis.
|
| 226 |
-
> BAD: The students knows that pain *can* occur with rheumatoid arthritis.
|
| 227 |
-
> BAD: The students knows that pain *could* occur with rheumatoid arthritis.
|
| 228 |
-
> BAD: The students knows that pain *may* occur with rheumatoid arthritis.
|
| 229 |
-
|
| 230 |
-
But:
|
| 231 |
-
> GOOD: The students knows that pain *is a symptom of* rheumatoid arthritis.
|
| 232 |
-
|
| 233 |
-
#### Avoid subjective terminology like many, few and common
|
| 234 |
-
Don't use words like *'many'*, *'few'*, *'common'*, *'rare'* et cetera as these are subjective. Instead be specific. Instead use terminology like *'in most cases'* or compare: *'symptom A is more common than symptom B'*.
|
| 235 |
-
|
| 236 |
-
Example of a bad learning objective, leading to suggestive or subjective answers:
|
| 237 |
-
> BAD: The student knows that fever commonly occurs with a viral infection.
|
| 238 |
-
|
| 239 |
-
#### Avoid important, essential significant
|
| 240 |
-
Don't use words like *'important'*, *'essential'*, *'significant'* et cetera in learning objectives, as these are prone to subjectivity.
|
| 241 |
-
|
| 242 |
-
Examples of a bad learning objective, leading to suggestive or subjective answers:
|
| 243 |
-
> BAD: The students knows that it's *important* to rest when having a viral infection.
|
| 244 |
-
|
| 245 |
-
The objective uses the word *'important'* which is subjective.
|
| 246 |
-
|
| 247 |
-
> BAD: The students knows that it's *essential* to rest when having a viral infection.
|
| 248 |
-
|
| 249 |
-
The objective uses the word *'essential'* which is subjective.
|
| 250 |
-
|
| 251 |
-
> BAD: The students knows that fever has a *significant* effect on how people feel when they are sick.
|
| 252 |
-
|
| 253 |
-
The objective uses the word *'significant'* which is subjective.
|
| 254 |
-
|
| 255 |
-
> BAD: The student knows that drinking *enough* water is *important* to stay hydrated.
|
| 256 |
-
|
| 257 |
-
The objective uses the word *'important'* which is subjective. Also the word *'enough'* is subjective.
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
A good example is:
|
| 261 |
-
|
| 262 |
-
> GOOD: The student knows that proteinuria is a symptom of nephrotic syndrome.
|
| 263 |
-
|
| 264 |
-
An example of a bad learning objective:
|
| 265 |
-
|
| 266 |
-
> BAD: The student knows the symptoms of nephrotic syndrome.
|
| 267 |
-
|
| 268 |
-
The bad objective does not specify a single fact as symptoms are not specified.
|
| 269 |
-
|
| 270 |
-
A good example is:
|
| 271 |
-
|
| 272 |
-
> GOOD: The student knows that besides pain, rheumatoid arthritis also causes loss of mobility.
|
| 273 |
-
|
| 274 |
-
An example of a bad learning objective:
|
| 275 |
-
|
| 276 |
-
> BAD: The student knows that problems with movement due to joint problems, such as rheumatism, can be painful or completely limit movement
|
| 277 |
-
|
| 278 |
-
The latter objective does not specify a single fact but combines two (can be painful or completely limit movement). The first objective focuses on the 'loss of mobility' element, while the 'pain- element' is already considered known. The exercises generated by this learning objective will test the 'loss of mobility' element (so not the 'pain-element')
|
| 279 |
-
"""),
|
| 280 |
("human", "{standardized_text}")
|
| 281 |
],
|
| 282 |
input_variables=["standardized_text"]
|
|
@@ -297,3 +209,45 @@ template_sanitize_learning_objectives = ChatPromptTemplate(
|
|
| 297 |
],
|
| 298 |
input_variables=["raw_output"]
|
| 299 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
template_gen_prompt_a_text,
|
| 16 |
template_gen_prompt_b_text,
|
| 17 |
template_sanitize_learning_objectives_text,
|
| 18 |
+
template_write_fluster_a_text,
|
| 19 |
+
template_write_fluster_b_text,
|
| 20 |
+
template_refine_distractors_text,
|
| 21 |
+
template_sanitize_fluster_text,
|
| 22 |
)
|
| 23 |
|
| 24 |
|
|
|
|
| 185 |
input_variables=["standardized_text"]
|
| 186 |
)
|
| 187 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
|
| 189 |
template_gen_prompt_b = ChatPromptTemplate(
|
| 190 |
messages=[
|
| 191 |
+
("system", template_gen_prompt_b_text),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
("human", "{standardized_text}")
|
| 193 |
],
|
| 194 |
input_variables=["standardized_text"]
|
|
|
|
| 209 |
],
|
| 210 |
input_variables=["raw_output"]
|
| 211 |
)
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
template_write_fluster_a = ChatPromptTemplate(
|
| 215 |
+
messages=[
|
| 216 |
+
("system", template_write_fluster_a_text),
|
| 217 |
+
("human", "Here's the learning objective:\n"
|
| 218 |
+
"{learning_objective}")
|
| 219 |
+
],
|
| 220 |
+
input_variables=["learning_objective"]
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
template_write_fluster_b = ChatPromptTemplate(
|
| 224 |
+
messages=[
|
| 225 |
+
("system", template_write_fluster_b_text),
|
| 226 |
+
("human", "Here's the learning objective:\n"
|
| 227 |
+
"{learning_objective}")
|
| 228 |
+
],
|
| 229 |
+
input_variables=["learning_objective"]
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
|
| 233 |
+
template_refine_distractors = ChatPromptTemplate(
|
| 234 |
+
messages=[
|
| 235 |
+
("system", template_refine_distractors_text),
|
| 236 |
+
("human", "Here's the source data:\n"
|
| 237 |
+
"{write_fluster_result}")
|
| 238 |
+
],
|
| 239 |
+
input_variables=["write_fluster_result"]
|
| 240 |
+
)
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
template_sanitize_fluster = ChatPromptTemplate(
|
| 245 |
+
messages=[
|
| 246 |
+
("system", template_sanitize_fluster_text),
|
| 247 |
+
("human", "Here's the source data:\n"
|
| 248 |
+
"{refine_distractors_result}")
|
| 249 |
+
],
|
| 250 |
+
input_variables=["refine_distractors_result"]
|
| 251 |
+
)
|
| 252 |
+
|
| 253 |
+
|
main.py
CHANGED
|
@@ -8,8 +8,10 @@ from app.ui.distractors_tab import build_distractors_tab
|
|
| 8 |
from app.ui.learning_objectives_tab import build_learning_objectives_tab
|
| 9 |
from app.ui.prompts_tab import build_prompts_tab
|
| 10 |
from app.ui.test_set_tab import build_test_set_tab
|
|
|
|
| 11 |
from chains.diagnoser.runner import run_diagnoser
|
| 12 |
from chains.distractors.runner import run_distractors
|
|
|
|
| 13 |
from chains.learning_objectives_generator.runner import run_learning_objectives_generator
|
| 14 |
from utils.auth import login as auth_login
|
| 15 |
|
|
@@ -80,20 +82,31 @@ with gr.Blocks() as interface:
|
|
| 80 |
) = build_distractors_tab()
|
| 81 |
|
| 82 |
# Build Learning Objectives Generator tab
|
| 83 |
-
(
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
) = build_learning_objectives_tab()
|
| 90 |
|
| 91 |
-
# Build
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
(pipeline_choice,
|
| 93 |
search_field_prompts,
|
| 94 |
) = build_prompts_tab()
|
| 95 |
|
| 96 |
-
# Build
|
| 97 |
(subset_choice,
|
| 98 |
search_field_test_set,
|
| 99 |
) = build_test_set_tab()
|
|
@@ -131,16 +144,22 @@ with gr.Blocks() as interface:
|
|
| 131 |
|
| 132 |
learning_objectives_button.click(
|
| 133 |
fn=run_learning_objectives_generator, # Our async generator
|
| 134 |
-
inputs=[studytext_input,
|
| 135 |
-
outputs=[
|
| 136 |
-
# 'stream=True' is needed to allow partial updates
|
| 137 |
-
# in a generator function.
|
| 138 |
-
# In recent Gradio versions, we just do `every=1` or `queue=True`
|
| 139 |
queue=True,
|
| 140 |
api_name=None,
|
| 141 |
# or "stream=True" depending on your version of Gradio
|
| 142 |
)
|
| 143 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
pipeline_choice.change(fn=log_dropdown_choice, inputs=pipeline_choice, outputs=[])
|
| 145 |
subset_choice.change(fn=log_dropdown_choice, inputs=subset_choice, outputs=[])
|
| 146 |
|
|
|
|
| 8 |
from app.ui.learning_objectives_tab import build_learning_objectives_tab
|
| 9 |
from app.ui.prompts_tab import build_prompts_tab
|
| 10 |
from app.ui.test_set_tab import build_test_set_tab
|
| 11 |
+
from app.ui.write_fluster_tab import build_write_fluster_tab
|
| 12 |
from chains.diagnoser.runner import run_diagnoser
|
| 13 |
from chains.distractors.runner import run_distractors
|
| 14 |
+
from chains.exercises.runner import run_fluster
|
| 15 |
from chains.learning_objectives_generator.runner import run_learning_objectives_generator
|
| 16 |
from utils.auth import login as auth_login
|
| 17 |
|
|
|
|
| 82 |
) = build_distractors_tab()
|
| 83 |
|
| 84 |
# Build Learning Objectives Generator tab
|
| 85 |
+
(model_choice_LO_1,
|
| 86 |
+
model_choice_LO_2,
|
| 87 |
+
text_format,
|
| 88 |
+
studytext_input,
|
| 89 |
+
learning_objectives_button,
|
| 90 |
+
[LO_box_0, LO_box_1, LO_box_2, LO_box_3]
|
| 91 |
) = build_learning_objectives_tab()
|
| 92 |
|
| 93 |
+
# Build write_fluster tab
|
| 94 |
+
(model_choice_fluster_1,
|
| 95 |
+
model_choice_fluster_2,
|
| 96 |
+
exercises_input,
|
| 97 |
+
write_fluster_button,
|
| 98 |
+
[fluster_box_0, fluster_box_1, fluster_box_2, fluster_box_3],
|
| 99 |
+
) = build_write_fluster_tab()
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
# Build Prompts tab
|
| 105 |
(pipeline_choice,
|
| 106 |
search_field_prompts,
|
| 107 |
) = build_prompts_tab()
|
| 108 |
|
| 109 |
+
# Build Test Set tab
|
| 110 |
(subset_choice,
|
| 111 |
search_field_test_set,
|
| 112 |
) = build_test_set_tab()
|
|
|
|
| 144 |
|
| 145 |
learning_objectives_button.click(
|
| 146 |
fn=run_learning_objectives_generator, # Our async generator
|
| 147 |
+
inputs=[studytext_input, model_choice_LO_1, model_choice_LO_2, text_format],
|
| 148 |
+
outputs=[LO_box_0, LO_box_1, LO_box_2, LO_box_3, standardized_format_display],
|
|
|
|
|
|
|
|
|
|
| 149 |
queue=True,
|
| 150 |
api_name=None,
|
| 151 |
# or "stream=True" depending on your version of Gradio
|
| 152 |
)
|
| 153 |
|
| 154 |
+
write_fluster_button.click(
|
| 155 |
+
fn=run_fluster, # async generator
|
| 156 |
+
inputs=[exercises_input, model_choice_fluster_1, model_choice_fluster_2],
|
| 157 |
+
outputs=[fluster_box_0, fluster_box_1, fluster_box_2, fluster_box_3], # fill the 4 textboxes
|
| 158 |
+
api_name=None,
|
| 159 |
+
queue=True,
|
| 160 |
+
stream=True,
|
| 161 |
+
)
|
| 162 |
+
|
| 163 |
pipeline_choice.change(fn=log_dropdown_choice, inputs=pipeline_choice, outputs=[])
|
| 164 |
subset_choice.change(fn=log_dropdown_choice, inputs=subset_choice, outputs=[])
|
| 165 |
|