MasteredUltraInstinct commited on
Commit
afecde2
ยท
verified ยท
1 Parent(s): 6578264

Create llm_utils.py

Browse files
Files changed (1) hide show
  1. llm_utils.py +90 -0
llm_utils.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import yaml
3
+
4
+ # === Load theorems.yaml and render it into clean context text for LLM ===
5
+ def load_theorem_context(yaml_path="theorems.yaml"):
6
+ with open(yaml_path, 'r') as f:
7
+ data = yaml.safe_load(f)
8
+
9
+ if not isinstance(data, dict):
10
+ return "โš ๏ธ Invalid theorems format in YAML."
11
+
12
+ context_lines = []
13
+ for idx, th in enumerate(data.get('theorems', []), 1):
14
+ context_lines.append(
15
+ f"**Theorem {idx}: {th.get('name', 'Unnamed')}**\n"
16
+ f"- **Statement**: {th.get('statement', 'N/A')}\n"
17
+ f"- **Tags**: {', '.join(th.get('tags', []))}\n"
18
+ f"- **When to Use**: {th.get('when_to_use', 'N/A')}\n"
19
+ f"- **Short Explanation**: {th.get('short_explanation', 'N/A')}\n"
20
+ )
21
+ context_lines.append('---')
22
+
23
+ return "\n".join(context_lines)
24
+
25
+ # === Build prompt using user steps and theorem context ===
26
+ def build_prompt(equation_type, solution_text, theorem_context):
27
+ return (
28
+ f"You are a helpful math tutor. Below is a theorem reference database.\n\n"
29
+ f"Each theorem includes:\n"
30
+ f"- Name\n- Statement\n- Tags\n- When to use\n- Short Explanation\n\n"
31
+ f"---\n\n"
32
+ f"### ๐Ÿ“˜ Theorem Database:\n\n"
33
+ f"{theorem_context}\n\n"
34
+ f"---\n\n"
35
+ f"### ๐Ÿงฎ User Steps for solving a {equation_type} equation:\n\n"
36
+ f"{solution_text}\n\n"
37
+ f"---\n\n"
38
+ f"### ๐ŸŽฏ Task:\n"
39
+ f"Explain each solution step clearly.\n"
40
+ f"Use relevant theorems by number or name.\n"
41
+ f"Make it understandable to a smart high school student.\n"
42
+ f"Focus on reasoning, not just restating the steps or theorems."
43
+ )
44
+
45
+ # === Request LLM explanation ===
46
+ def explain_with_llm(solution_text, equation_type, llm_url, yaml_path="theorems.yaml"):
47
+ try:
48
+ if not llm_url or not llm_url.strip().startswith("http"):
49
+ return "โŒ Invalid or missing LLM URL."
50
+
51
+ theorem_context = load_theorem_context(yaml_path)
52
+ prompt = build_prompt(equation_type, solution_text, theorem_context)
53
+
54
+ response = requests.post(
55
+ f"{llm_url.strip()}/explain",
56
+ json={"prompt": prompt},
57
+ timeout=90
58
+ )
59
+
60
+ if response.status_code == 200:
61
+ result = response.json()
62
+
63
+ if isinstance(result, dict):
64
+ return result.get("explanation", "โŒ No explanation returned.")
65
+ elif isinstance(result, list):
66
+ return result[0] if result else "โŒ Empty response list."
67
+ else:
68
+ return f"โŒ Unexpected LLM response format: {type(result)}"
69
+
70
+ return f"โŒ LLM request failed: {response.status_code}"
71
+
72
+ except Exception as e:
73
+ return f"โŒ LLM Error: {e}"
74
+
75
+ # === Request fallback if parsing failed ===
76
+ def request_llm_fallback(bad_input, llm_url):
77
+ try:
78
+ response = requests.post(
79
+ f"{llm_url.strip()}/clean",
80
+ json={"prompt": bad_input},
81
+ timeout=20
82
+ )
83
+ result = response.json()
84
+ if isinstance(result, dict):
85
+ return result.get("cleaned_latex", bad_input)
86
+ return bad_input
87
+ except:
88
+ return bad_input
89
+
90
+