Update conversation_logic.py
Browse files- conversation_logic.py +146 -1
conversation_logic.py
CHANGED
|
@@ -172,6 +172,80 @@ def _looks_like_question_text(text: str) -> bool:
|
|
| 172 |
)
|
| 173 |
|
| 174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
def _classify_input_type(raw_user_text: str) -> str:
|
| 176 |
text = _clean_text(raw_user_text).lower()
|
| 177 |
if not text:
|
|
@@ -704,6 +778,76 @@ class ConversationEngine:
|
|
| 704 |
result.meta["explainer_understood"] = explainer_understood
|
| 705 |
result.meta["explainer_scaffold"] = explainer_scaffold
|
| 706 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 707 |
# Source selection priority:
|
| 708 |
# 1) question-specific fallback for help modes
|
| 709 |
# 2) explainer for explain when specific support is unavailable
|
|
@@ -755,6 +899,7 @@ class ConversationEngine:
|
|
| 755 |
resolved_help_mode == "answer"
|
| 756 |
and solver_has_steps
|
| 757 |
and result.meta.get("solver_topic_rejected") is None
|
|
|
|
| 758 |
):
|
| 759 |
reply_core = _answer_path_from_steps(solver_steps, verbosity=verbosity)
|
| 760 |
result.meta["response_source"] = "solver_steps"
|
|
@@ -859,4 +1004,4 @@ class ConversationEngine:
|
|
| 859 |
result.meta["session_state"] = state
|
| 860 |
result.meta["used_retrieval"] = False
|
| 861 |
result.meta["used_generator"] = False
|
| 862 |
-
return result
|
|
|
|
| 172 |
)
|
| 173 |
|
| 174 |
|
| 175 |
+
def _is_topic_query(text: str) -> bool:
|
| 176 |
+
low = _clean_text(text).lower()
|
| 177 |
+
if not low:
|
| 178 |
+
return False
|
| 179 |
+
return any(
|
| 180 |
+
phrase in low
|
| 181 |
+
for phrase in [
|
| 182 |
+
"what topic is this question",
|
| 183 |
+
"what topic is this",
|
| 184 |
+
"what is the topic of this question",
|
| 185 |
+
"what type of question is this",
|
| 186 |
+
"what kind of question is this",
|
| 187 |
+
"what area is this",
|
| 188 |
+
"what concept is this",
|
| 189 |
+
"what concept is this testing",
|
| 190 |
+
"what skill is this testing",
|
| 191 |
+
"identify the topic",
|
| 192 |
+
"identify the concept",
|
| 193 |
+
]
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
|
| 197 |
+
def _specific_topic_from_question(question_text: str, fallback_topic: str, classified_topic: str) -> str:
|
| 198 |
+
q = _clean_text(question_text).lower()
|
| 199 |
+
topic = (fallback_topic or classified_topic or "general").lower()
|
| 200 |
+
|
| 201 |
+
if any(k in q for k in ["variability", "spread", "standard deviation"]):
|
| 202 |
+
return "variability"
|
| 203 |
+
if any(k in q for k in ["mean", "average"]):
|
| 204 |
+
return "mean"
|
| 205 |
+
if "median" in q:
|
| 206 |
+
return "median"
|
| 207 |
+
if "range" in q:
|
| 208 |
+
return "range"
|
| 209 |
+
if topic == "data" and any(k in q for k in ["dataset", "table", "chart", "graph"]):
|
| 210 |
+
return "statistics"
|
| 211 |
+
return topic
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def _build_topic_query_reply(question_text: str, fallback_topic: str, classified_topic: str, category: str) -> str:
|
| 215 |
+
specific = _specific_topic_from_question(question_text, fallback_topic, classified_topic)
|
| 216 |
+
cat = (category or "").strip()
|
| 217 |
+
|
| 218 |
+
if specific == "variability":
|
| 219 |
+
return (
|
| 220 |
+
"- This is a statistics / data insight question about variability (spread).\n"
|
| 221 |
+
"- The key idea is to compare how spread out each dataset is, not which one has the biggest average.\n"
|
| 222 |
+
"- A good first move is to compare how far the outer values sit from the middle value in each set."
|
| 223 |
+
)
|
| 224 |
+
if specific == "statistics":
|
| 225 |
+
return (
|
| 226 |
+
"- This is a statistics / data insight question.\n"
|
| 227 |
+
"- The key skill is spotting which statistical idea matters most, then comparing the answer choices using that idea."
|
| 228 |
+
)
|
| 229 |
+
if specific == "algebra":
|
| 230 |
+
return (
|
| 231 |
+
"- This is an algebra question.\n"
|
| 232 |
+
"- The key skill is rewriting the relationship cleanly, then simplifying the expression the question actually asks for."
|
| 233 |
+
)
|
| 234 |
+
if specific == "ratio":
|
| 235 |
+
return (
|
| 236 |
+
"- This is a ratio question.\n"
|
| 237 |
+
"- The key skill is turning the ratio into consistent parts and then building the requested expression from those parts."
|
| 238 |
+
)
|
| 239 |
+
if specific == "percent":
|
| 240 |
+
return (
|
| 241 |
+
"- This is a percent question.\n"
|
| 242 |
+
"- The key skill is identifying the correct base quantity before applying the percent relationship."
|
| 243 |
+
)
|
| 244 |
+
|
| 245 |
+
label = specific if specific != "general" else (cat.lower() if cat else "quantitative reasoning")
|
| 246 |
+
return f"- This looks like a {label} question."
|
| 247 |
+
|
| 248 |
+
|
| 249 |
def _classify_input_type(raw_user_text: str) -> str:
|
| 250 |
text = _clean_text(raw_user_text).lower()
|
| 251 |
if not text:
|
|
|
|
| 778 |
result.meta["explainer_understood"] = explainer_understood
|
| 779 |
result.meta["explainer_scaffold"] = explainer_scaffold
|
| 780 |
|
| 781 |
+
if input_type == "topic_query":
|
| 782 |
+
support_topic = fallback_pack.get("topic") if fallback_pack else ""
|
| 783 |
+
topic_reply_core = _build_topic_query_reply(
|
| 784 |
+
question_text=solver_input,
|
| 785 |
+
fallback_topic=support_topic,
|
| 786 |
+
classified_topic=question_topic if question_topic else "general",
|
| 787 |
+
category=inferred_category if inferred_category else "General",
|
| 788 |
+
)
|
| 789 |
+
reply = format_reply(
|
| 790 |
+
topic_reply_core,
|
| 791 |
+
tone=tone,
|
| 792 |
+
verbosity=verbosity,
|
| 793 |
+
transparency=transparency,
|
| 794 |
+
help_mode="answer",
|
| 795 |
+
hint_stage=hint_stage,
|
| 796 |
+
topic=support_topic or question_topic or result.topic,
|
| 797 |
+
)
|
| 798 |
+
result.topic = support_topic or question_topic or result.topic
|
| 799 |
+
result.reply = reply
|
| 800 |
+
result.help_mode = "answer"
|
| 801 |
+
result.meta["response_source"] = "topic_classifier"
|
| 802 |
+
result.meta["question_support_used"] = bool(fallback_pack)
|
| 803 |
+
result.meta["question_support_source"] = fallback_pack.get("support_source") if fallback_pack else None
|
| 804 |
+
result.meta["question_support_topic"] = support_topic or None
|
| 805 |
+
result.meta["help_mode"] = "answer"
|
| 806 |
+
result.meta["intent"] = "topic_query"
|
| 807 |
+
result.meta["question_text"] = solver_input or ""
|
| 808 |
+
result.meta["options_count"] = len(options_text or [])
|
| 809 |
+
result.meta["category"] = inferred_category if inferred_category else "General"
|
| 810 |
+
result.meta["user_last_input_type"] = input_type
|
| 811 |
+
result.meta["built_on_previous_turn"] = built_on_previous_turn
|
| 812 |
+
state = _update_session_state(
|
| 813 |
+
state,
|
| 814 |
+
question_text=solver_input,
|
| 815 |
+
question_id=question_id,
|
| 816 |
+
hint_stage=hint_stage,
|
| 817 |
+
user_last_input_type=input_type,
|
| 818 |
+
built_on_previous_turn=built_on_previous_turn,
|
| 819 |
+
help_mode="answer",
|
| 820 |
+
intent="topic_query",
|
| 821 |
+
topic=result.topic,
|
| 822 |
+
category=inferred_category,
|
| 823 |
+
)
|
| 824 |
+
result.meta["session_state"] = state
|
| 825 |
+
result.meta["used_retrieval"] = False
|
| 826 |
+
result.meta["used_generator"] = False
|
| 827 |
+
result.meta["can_reveal_answer"] = False
|
| 828 |
+
result.answer_letter = None
|
| 829 |
+
result.answer_value = None
|
| 830 |
+
result.internal_answer = None
|
| 831 |
+
result.meta["internal_answer"] = None
|
| 832 |
+
return result
|
| 833 |
+
|
| 834 |
+
if fallback_pack and fallback_pack.get("topic") == "statistics":
|
| 835 |
+
qlow = (solver_input or "").lower()
|
| 836 |
+
wants_topic = input_type == "topic_query"
|
| 837 |
+
if any(k in qlow for k in ["variability", "spread", "standard deviation"]):
|
| 838 |
+
if wants_topic:
|
| 839 |
+
fallback_reply_core = (
|
| 840 |
+
"- This is a statistics / data insight question about variability (spread).\n"
|
| 841 |
+
"- Focus on how spread out each dataset is rather than the average.\n"
|
| 842 |
+
"- Compare how far the outer values sit from the middle value in each set."
|
| 843 |
+
)
|
| 844 |
+
elif resolved_help_mode == "answer":
|
| 845 |
+
fallback_reply_core = (
|
| 846 |
+
"- Notice this is asking about variability, which means spread, not the mean.\n"
|
| 847 |
+
"- Compare how far the smallest and largest values sit from the middle value in each dataset.\n"
|
| 848 |
+
"- The set with the widest spread has the greatest variability."
|
| 849 |
+
)
|
| 850 |
+
|
| 851 |
# Source selection priority:
|
| 852 |
# 1) question-specific fallback for help modes
|
| 853 |
# 2) explainer for explain when specific support is unavailable
|
|
|
|
| 899 |
resolved_help_mode == "answer"
|
| 900 |
and solver_has_steps
|
| 901 |
and result.meta.get("solver_topic_rejected") is None
|
| 902 |
+
and direct_solve_request
|
| 903 |
):
|
| 904 |
reply_core = _answer_path_from_steps(solver_steps, verbosity=verbosity)
|
| 905 |
result.meta["response_source"] = "solver_steps"
|
|
|
|
| 1004 |
result.meta["session_state"] = state
|
| 1005 |
result.meta["used_retrieval"] = False
|
| 1006 |
result.meta["used_generator"] = False
|
| 1007 |
+
return result
|