BtB-ExpC commited on
Commit
5b2eeff
·
1 Parent(s): 7c7fc61

v0 fluster chain

Browse files
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)"], # or something else
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 'dit' refers to</explanation>
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 crucially allows us to later craft effective, self-contained multiple choice questions based on each of these elaborate learning objectives independently. This way, we can do targeted, piecemeal testing of the student's knowledge, while maintaining overview and coherence.</explanation>
307
  </specificity_examples>
308
  </examples>
309
 
@@ -394,13 +405,388 @@ Before extracting learning objectives:
394
  </examples_of_>
395
  """
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
 
398
- template_gen_prompt_b_text = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  """
400
 
401
- template_sanitize_learning_objectives_text = """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- (model_choice_1,
84
- model_choice_2,
85
- text_format,
86
- studytext_input,
87
- learning_objectives_button,
88
- [box_0, box_1, box_2, box_3]
89
  ) = build_learning_objectives_tab()
90
 
91
- # Build unfinished tab
 
 
 
 
 
 
 
 
 
 
 
92
  (pipeline_choice,
93
  search_field_prompts,
94
  ) = build_prompts_tab()
95
 
96
- # Build unfinished tab
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, model_choice_1, model_choice_2, text_format],
135
- outputs=[box_0, box_1, box_2, box_3, standardized_format_display],
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