j-js commited on
Commit
60b42a6
·
verified ·
1 Parent(s): b7fc6a5

Update conversation_logic.py

Browse files
Files changed (1) hide show
  1. conversation_logic.py +90 -25
conversation_logic.py CHANGED
@@ -2,49 +2,96 @@ from __future__ import annotations
2
 
3
  from typing import Any, Dict, List, Optional
4
 
5
- from context_parser import intent_to_help_mode
6
  from formatting import format_reply
7
  from generator_engine import GeneratorEngine
8
  from models import RetrievedChunk, SolverResult
9
  from quant_solver import is_quant_question, solve_quant
10
  from retrieval_engine import RetrievalEngine
11
- from utils import short_lines
12
 
13
 
14
  def _teaching_lines(chunks: List[RetrievedChunk]) -> List[str]:
15
- lines = []
16
  for chunk in chunks:
17
- text = chunk.text.strip().replace("\n", " ")
18
  if len(text) > 220:
19
  text = text[:217].rstrip() + "…"
20
- lines.append(f"- {chunk.topic}: {text}")
 
21
  return lines
22
 
23
 
24
- def _compose_quant_reply(result: SolverResult, intent: str, reveal_answer: bool, verbosity: float) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  steps = result.steps or []
26
- internal = result.internal_answer or result.answer_value or ""
 
 
 
 
 
27
 
28
  if intent == "hint":
29
- return steps[0] if steps else "Start by translating the wording into an equation."
30
-
31
- if intent == "method":
32
- body = "Use this method:\n" + "\n".join(f"- {s}" for s in steps[:3])
 
 
 
 
 
 
 
33
  if reveal_answer and internal:
34
- body += f"\n\nInternal result: {internal}."
35
  return body
36
 
37
  if intent in {"step_by_step", "full_working"}:
38
- body = "\n".join(f"{i+1}. {s}" for i, s in enumerate(steps[:4])) if steps else "Work through the algebra one step at a time."
 
 
 
 
39
  if reveal_answer and internal:
40
  body += f"\n\nSo the result is {internal}."
41
  return body
42
 
 
 
 
 
 
 
 
 
 
43
  if reveal_answer and internal:
44
  return f"The result is {internal}."
45
 
46
  if steps:
47
  return "\n".join(f"- {s}" for s in steps[:2])
 
48
  return result.reply or "I can help solve this, but I need a little more structure from the question."
49
 
50
 
@@ -67,34 +114,52 @@ class ConversationEngine:
67
  retrieval_context: str = "",
68
  ) -> SolverResult:
69
  user_text = (raw_user_text or "").strip()
70
- question_block = "\n".join([x for x in [question_text.strip(), options_text.strip()] if x]).strip()
71
- solver_input = user_text or question_text or question_block
72
 
73
- if is_quant_question(solver_input) or (question_text and is_quant_question(question_text)):
74
- result = solve_quant(solver_input if is_quant_question(solver_input) else question_text)
 
 
 
 
 
 
 
75
  result.help_mode = help_mode
 
76
  reveal_answer = intent in {"answer", "full_working"} or transparency >= 0.85
77
 
78
- if result.topic:
79
- chunks = self.retriever.search(question_text or user_text, topic=result.topic, intent=intent, k=3)
80
- else:
81
- chunks = self.retriever.search(question_text or user_text, topic="general", intent=intent, k=3)
 
 
82
  result.teaching_chunks = chunks
83
  result.used_retrieval = bool(chunks)
84
 
85
- core = _compose_quant_reply(result, intent, reveal_answer=reveal_answer, verbosity=verbosity)
86
- if chunks and intent in {"hint", "method", "step_by_step", "full_working"}:
 
 
 
 
 
 
87
  core += "\n\nRelevant study notes:\n" + "\n".join(_teaching_lines(chunks))
 
88
  result.reply = format_reply(core, tone, verbosity, transparency, help_mode)
89
  return result
90
 
91
- # Non-quant conversational support
92
  result = SolverResult(domain="general", solved=False, help_mode=help_mode)
 
93
  prompt = (
94
  "You are a helpful study assistant. Reply naturally and briefly. "
95
  "Do not invent facts. If the user is asking for emotional support or general help, be supportive and practical.\n\n"
96
  f"User message: {user_text}"
97
  )
 
98
  generated = self.generator.generate(prompt) if self.generator and self.generator.available() else None
99
  if generated:
100
  result.reply = format_reply(generated, tone, verbosity, transparency, help_mode)
@@ -103,4 +168,4 @@ class ConversationEngine:
103
 
104
  fallback = "I can help with the current question, explain a method, or talk through the next step."
105
  result.reply = format_reply(fallback, tone, verbosity, transparency, help_mode)
106
- return result
 
2
 
3
  from typing import Any, Dict, List, Optional
4
 
 
5
  from formatting import format_reply
6
  from generator_engine import GeneratorEngine
7
  from models import RetrievedChunk, SolverResult
8
  from quant_solver import is_quant_question, solve_quant
9
  from retrieval_engine import RetrievalEngine
 
10
 
11
 
12
  def _teaching_lines(chunks: List[RetrievedChunk]) -> List[str]:
13
+ lines: List[str] = []
14
  for chunk in chunks:
15
+ text = (chunk.text or "").strip().replace("\n", " ")
16
  if len(text) > 220:
17
  text = text[:217].rstrip() + "…"
18
+ topic = chunk.topic or "general"
19
+ lines.append(f"- {topic}: {text}")
20
  return lines
21
 
22
 
23
+ def _should_retrieve(intent: str, result: SolverResult) -> bool:
24
+ if not result.solved:
25
+ return True
26
+ return intent in {"hint", "method", "step_by_step", "full_working", "walkthrough", "explain"}
27
+
28
+
29
+ def _retrieval_query(user_text: str, question_text: str, options_text: str) -> str:
30
+ parts = []
31
+ if question_text.strip():
32
+ parts.append(question_text.strip())
33
+ if options_text.strip():
34
+ parts.append(options_text.strip())
35
+ if user_text.strip():
36
+ parts.append(user_text.strip())
37
+ return "\n".join(parts).strip()
38
+
39
+
40
+ def _compose_quant_reply(
41
+ result: SolverResult,
42
+ intent: str,
43
+ reveal_answer: bool,
44
+ verbosity: float,
45
+ ) -> str:
46
  steps = result.steps or []
47
+ internal = (
48
+ getattr(result, "internal_answer", None)
49
+ or getattr(result, "internal_answer_value", None)
50
+ or getattr(result, "answer_value", None)
51
+ or ""
52
+ )
53
 
54
  if intent == "hint":
55
+ if steps:
56
+ return f"Hint:\n- {steps[0]}"
57
+ return "Hint:\n- Start by translating the wording into an equation."
58
+
59
+ if intent in {"method", "walkthrough"}:
60
+ body = "Use this method:"
61
+ if steps:
62
+ limit = 3 if verbosity < 0.75 else 4
63
+ body += "\n" + "\n".join(f"- {s}" for s in steps[:limit])
64
+ else:
65
+ body += "\n- Treat the statement as an equation.\n- Isolate the unknown step by step."
66
  if reveal_answer and internal:
67
+ body += f"\n\nThat gives {internal}."
68
  return body
69
 
70
  if intent in {"step_by_step", "full_working"}:
71
+ if steps:
72
+ limit = 4 if verbosity < 0.75 else min(6, len(steps))
73
+ body = "\n".join(f"{i+1}. {s}" for i, s in enumerate(steps[:limit]))
74
+ else:
75
+ body = "1. Translate the wording into an equation.\n2. Isolate the variable carefully.\n3. Check the result."
76
  if reveal_answer and internal:
77
  body += f"\n\nSo the result is {internal}."
78
  return body
79
 
80
+ if intent == "explain":
81
+ if steps:
82
+ body = "Here is the idea:\n" + "\n".join(f"- {s}" for s in steps[:3])
83
+ else:
84
+ body = "Here is the idea:\n- Turn the wording into a clear mathematical relationship.\n- Solve it step by step."
85
+ if reveal_answer and internal:
86
+ body += f"\n\nThat leads to {internal}."
87
+ return body
88
+
89
  if reveal_answer and internal:
90
  return f"The result is {internal}."
91
 
92
  if steps:
93
  return "\n".join(f"- {s}" for s in steps[:2])
94
+
95
  return result.reply or "I can help solve this, but I need a little more structure from the question."
96
 
97
 
 
114
  retrieval_context: str = "",
115
  ) -> SolverResult:
116
  user_text = (raw_user_text or "").strip()
117
+ question_text = (question_text or "").strip()
118
+ options_text = (options_text or "").strip()
119
 
120
+ question_block = "\n".join([x for x in [question_text, options_text] if x]).strip()
121
+ solver_input = user_text or question_block or question_text
122
+
123
+ quant_from_user = bool(user_text and is_quant_question(user_text))
124
+ quant_from_question = bool(question_text and is_quant_question(question_block or question_text))
125
+
126
+ if quant_from_user or quant_from_question:
127
+ solve_text = user_text if quant_from_user else (question_block or question_text)
128
+ result = solve_quant(solve_text)
129
  result.help_mode = help_mode
130
+
131
  reveal_answer = intent in {"answer", "full_working"} or transparency >= 0.85
132
 
133
+ chunks: List[RetrievedChunk] = []
134
+ if _should_retrieve(intent, result):
135
+ topic = result.topic or getattr(result, "detected_topic", None) or "general"
136
+ query = _retrieval_query(user_text, question_text, options_text)
137
+ chunks = self.retriever.search(query, topic=topic, intent=intent, k=3)
138
+
139
  result.teaching_chunks = chunks
140
  result.used_retrieval = bool(chunks)
141
 
142
+ core = _compose_quant_reply(
143
+ result,
144
+ intent=intent,
145
+ reveal_answer=reveal_answer,
146
+ verbosity=verbosity,
147
+ )
148
+
149
+ if chunks and intent in {"hint", "method", "step_by_step", "full_working", "walkthrough", "explain"}:
150
  core += "\n\nRelevant study notes:\n" + "\n".join(_teaching_lines(chunks))
151
+
152
  result.reply = format_reply(core, tone, verbosity, transparency, help_mode)
153
  return result
154
 
 
155
  result = SolverResult(domain="general", solved=False, help_mode=help_mode)
156
+
157
  prompt = (
158
  "You are a helpful study assistant. Reply naturally and briefly. "
159
  "Do not invent facts. If the user is asking for emotional support or general help, be supportive and practical.\n\n"
160
  f"User message: {user_text}"
161
  )
162
+
163
  generated = self.generator.generate(prompt) if self.generator and self.generator.available() else None
164
  if generated:
165
  result.reply = format_reply(generated, tone, verbosity, transparency, help_mode)
 
168
 
169
  fallback = "I can help with the current question, explain a method, or talk through the next step."
170
  result.reply = format_reply(fallback, tone, verbosity, transparency, help_mode)
171
+ return result