j-js commited on
Commit
6204838
·
verified ·
1 Parent(s): 14a41e4

Update models.py

Browse files
Files changed (1) hide show
  1. models.py +183 -69
models.py CHANGED
@@ -1,71 +1,185 @@
1
  from __future__ import annotations
2
 
3
- from dataclasses import dataclass, field
4
- from typing import Any, Dict, List, Optional
5
-
6
- from pydantic import BaseModel
7
-
8
-
9
- class ChatRequest(BaseModel):
10
- message: Optional[str] = None
11
- prompt: Optional[str] = None
12
- query: Optional[str] = None
13
- text: Optional[str] = None
14
- user_message: Optional[str] = None
15
-
16
- tone: Optional[float] = 0.5
17
- verbosity: Optional[float] = 0.5
18
- transparency: Optional[float] = 0.5
19
-
20
- help_mode: Optional[str] = None
21
- chat_history: Optional[List[Dict[str, Any]]] = None
22
- history: Optional[List[Dict[str, Any]]] = None
23
-
24
- question_text: Optional[str] = None
25
- question_id: Optional[str] = None
26
- session_id: Optional[str] = None
27
- user_id: Optional[str] = None
28
-
29
-
30
- class SessionStartRequest(BaseModel):
31
- session_id: str
32
- user_id: Optional[str] = None
33
- condition: Optional[str] = None
34
- metadata: Optional[Dict[str, Any]] = None
35
-
36
-
37
- class EventLogRequest(BaseModel):
38
- session_id: str
39
- event_type: str
40
- timestamp: Optional[str] = None
41
- payload: Optional[Dict[str, Any]] = None
42
-
43
-
44
- class SessionFinalizeRequest(BaseModel):
45
- session_id: str
46
- summary: Optional[Dict[str, Any]] = None
47
-
48
-
49
- @dataclass
50
- class RetrievedChunk:
51
- text: str
52
- topic: str = "general"
53
- source: str = "local"
54
- score: float = 0.0
55
-
56
-
57
- @dataclass
58
- class SolverResult:
59
- reply: str = ""
60
- domain: str = "fallback"
61
- solved: bool = False
62
- help_mode: str = "answer"
63
- answer_letter: Optional[str] = None
64
- answer_value: Optional[str] = None
65
- topic: Optional[str] = None
66
- used_retrieval: bool = False
67
- used_generator: bool = False
68
- internal_answer: Optional[str] = None
69
- steps: List[str] = field(default_factory=list)
70
- teaching_chunks: List[RetrievedChunk] = field(default_factory=list)
71
- meta: Dict[str, Any] = field(default_factory=dict)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  from __future__ import annotations
2
 
3
+ import math
4
+ import re
5
+ from statistics import mean, median
6
+ from typing import Dict, Optional
7
+
8
+ try:
9
+ import sympy as sp
10
+ except Exception:
11
+ sp = None
12
+
13
+ from models import SolverResult
14
+ from utils import clean_math_text, normalize_spaces
15
+
16
+
17
+ def extract_choices(text: str) -> Dict[str, str]:
18
+ text = text or ""
19
+ matches = list(
20
+ re.finditer(
21
+ r"(?i)\b([A-E])[\)\.:]\s*(.*?)(?=\s+\b[A-E][\)\.:]\s*|$)",
22
+ text,
23
+ )
24
+ )
25
+ return {m.group(1).upper(): normalize_spaces(m.group(2)) for m in matches}
26
+
27
+
28
+ def _solve_successive_percent(text: str) -> Optional[SolverResult]:
29
+
30
+ t = clean_math_text(text).lower()
31
+
32
+ percents = re.findall(r"(\d+(?:\.\d+)?)\s*%", t)
33
+ if len(percents) < 2:
34
+ return None
35
+
36
+ values = [float(p) for p in percents]
37
+
38
+ mult = 1
39
+ for p in values:
40
+ if "decrease" in t or "discount" in t:
41
+ mult *= 1 - p / 100
42
+ else:
43
+ mult *= 1 + p / 100
44
+
45
+ net = (mult - 1) * 100
46
+
47
+ return SolverResult(
48
+ domain="quant",
49
+ solved=True,
50
+ topic="percent",
51
+ answer_value=f"{net:.2f}%",
52
+ internal_answer=f"{net:.2f}%",
53
+ steps=[
54
+ "Convert each percent change to a multiplier.",
55
+ "Multiply the successive multipliers.",
56
+ "Convert the final multiplier back to a percent change.",
57
+ ],
58
+ )
59
+
60
+
61
+ def _solve_ratio_total(text: str) -> Optional[SolverResult]:
62
+
63
+ t = clean_math_text(text)
64
+
65
+ ratio = re.search(r"(\d+)\s*:\s*(\d+)", t)
66
+ total = re.search(r"total\s*(?:is|=)?\s*(\d+)", t.lower())
67
+
68
+ if not ratio or not total:
69
+ return None
70
+
71
+ a = int(ratio.group(1))
72
+ b = int(ratio.group(2))
73
+ total_val = int(total.group(1))
74
+
75
+ part_sum = a + b
76
+ unit = total_val / part_sum
77
+
78
+ return SolverResult(
79
+ domain="quant",
80
+ solved=True,
81
+ topic="ratio",
82
+ answer_value=f"{a * unit:g}",
83
+ internal_answer=f"{a * unit:g}",
84
+ steps=[
85
+ "Add the ratio parts.",
86
+ "Divide the total by the sum of the ratio.",
87
+ "Multiply by the requested ratio component.",
88
+ ],
89
+ )
90
+
91
+
92
+ def _solve_remainder(text: str) -> Optional[SolverResult]:
93
+
94
+ t = clean_math_text(text).lower()
95
+
96
+ m = re.search(r"remainder.*?(\d+).*?divided by (\d+)", t)
97
+
98
+ if not m:
99
+ return None
100
+
101
+ a = int(m.group(1))
102
+ b = int(m.group(2))
103
+
104
+ r = a % b
105
+
106
+ return SolverResult(
107
+ domain="quant",
108
+ solved=True,
109
+ topic="number_theory",
110
+ answer_value=str(r),
111
+ internal_answer=str(r),
112
+ steps=[
113
+ "Divide the number by the divisor.",
114
+ "The remainder is the leftover after division.",
115
+ ],
116
+ )
117
+
118
+
119
+ def _solve_percent(text: str) -> Optional[SolverResult]:
120
+
121
+ lower = clean_math_text(text).lower()
122
+
123
+ m = re.search(r"(\d+)% of a number is (\d+)", lower)
124
+
125
+ if m:
126
+ p = float(m.group(1))
127
+ val = float(m.group(2))
128
+
129
+ ans = val / (p / 100)
130
+
131
+ return SolverResult(
132
+ domain="quant",
133
+ solved=True,
134
+ topic="percent",
135
+ answer_value=f"{ans:g}",
136
+ internal_answer=f"{ans:g}",
137
+ )
138
+
139
+ return None
140
+
141
+
142
+ def _solve_linear_equation(text: str) -> Optional[SolverResult]:
143
+
144
+ if sp is None:
145
+ return None
146
+
147
+ m = re.search(r"([a-z])\s*/\s*(\d+)\s*=\s*(\d+)", text)
148
+
149
+ if not m:
150
+ return None
151
+
152
+ var = m.group(1)
153
+ a = float(m.group(2))
154
+ b = float(m.group(3))
155
+
156
+ ans = a * b
157
+
158
+ return SolverResult(
159
+ domain="quant",
160
+ solved=True,
161
+ topic="algebra",
162
+ answer_value=str(ans),
163
+ internal_answer=str(ans),
164
+ )
165
+
166
+
167
+ def solve_quant(text: str) -> SolverResult:
168
+
169
+ for fn in (
170
+ _solve_successive_percent,
171
+ _solve_ratio_total,
172
+ _solve_remainder,
173
+ _solve_percent,
174
+ _solve_linear_equation,
175
+ ):
176
+ result = fn(text)
177
+ if result:
178
+ return result
179
+
180
+ return SolverResult(
181
+ domain="quant",
182
+ solved=False,
183
+ topic="general_quant",
184
+ reply="This looks quantitative but does not match a strong rule-based solver yet.",
185
+ )