forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSolveMathProblem.swift
More file actions
100 lines (89 loc) · 2.69 KB
/
SolveMathProblem.swift
File metadata and controls
100 lines (89 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import ChatPlugin
import Foundation
import LangChain
import Logger
import OpenAIService
let systemPrompt = """
Translate a math problem into a expression that can be executed using Python's numexpr library.
Use the output of running this code to answer the question.
Question: ${{Question with math problem.}}
```text
${{single line mathematical expression that solves the problem}}
```
...numexpr.evaluate(text)...
```output
${{Output of running the code}}
```
Answer: ${{Answer}}
Begin.
Question: What is 37593 * 67?
```text
37593 * 67
```
...numexpr.evaluate("37593 * 67")...
```output
2518731
```
Answer: 2518731
Question: 37593^(1/5)
```text
37593**(1/5)
```
...numexpr.evaluate("37593**(1/5)")...
```output
8.222831614237718
```
Answer: 8.222831614237718
"""
/// Extract the math problem with ChatGPT, and pass it to python to get the result.
///
/// [llm_math in
/// LangChain](https://github.com/hwchase17/langchain/blob/master/langchain/chains/llm_math/base.py)
///
/// The logic is basically the same as the LLMMathChain provided in LangChain.
func solveMathProblem(_ question: String) async throws -> String {
guard let reply = try await askChatGPT(
systemPrompt: systemPrompt,
question: "Question: \(question)",
temperature: 0
) else { return "No answer." }
// parse inside text code block
let codeBlockRegex = try NSRegularExpression(pattern: "```text\n(.*?)\n```", options: [])
let codeBlockMatches = codeBlockRegex.matches(
in: reply,
options: [],
range: NSRange(reply.startIndex..<reply.endIndex, in: reply)
)
if let firstMatch = codeBlockMatches.first, let textRange = Range(
firstMatch.range(at: 1),
in: reply
) {
let text = reply[textRange]
let expression = String(text)
let task = Task { try evaluateWithPython(expression) }
if let answer = try await task.value {
return answer
}
}
// parse after Answer:
let answerRegex = try NSRegularExpression(pattern: "Answer: (.*)", options: [])
let answerMatches = answerRegex.matches(
in: reply,
options: [],
range: NSRange(reply.startIndex..<reply.endIndex, in: reply)
)
if let firstMatch = answerMatches.first, let answerRange = Range(
firstMatch.range(at: 1),
in: reply
) {
let answer = reply[answerRange]
return String(answer)
}
return reply
}
func evaluateWithPython(_ expression: String) throws -> String? {
let mathExpression = NSExpression(format: expression)
let value = mathExpression.expressionValue(with: nil, context: nil)
Logger.service.debug(String(describing: value))
return (value as? Int).flatMap(String.init)
}