-
Notifications
You must be signed in to change notification settings - Fork 0
/
llmexcel.bas
112 lines (97 loc) · 4.04 KB
/
llmexcel.bas
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
100
101
102
103
104
105
106
107
108
109
110
111
112
'''
' LLM Excel - Talk to LLMs (like ChatGPT) in Excel
' @author root.node@gmail.com
' @license MIT (http://www.opensource.org/licenses/mit-license.php)
'''
Function LLM(prompt As String, Optional ByVal model As String = "gpt-4o-mini", Optional ByVal refresh As Boolean = False, Optional ByVal temperature As Single = 1) As Variant
' Don't re-calculate unless the prompt changes
Application.Volatile False
' Set up request
Dim jsonRequest As String
jsonRequest = "{""response_format"":{""type"":""json_object""},""model"":""" + model + """"
jsonRequest = jsonRequest + ",""messages"":[{""role"":""system"",""content"":""Return only 1 JSON array""},{""role"":""user"",""content"":""" + Replace(prompt, """", """""") + """}]"
If temperature <> 1 Then
jsonRequest = jsonRequest + ",""temperature"":" + ConvertToJson(temperature)
End If
jsonRequest = jsonRequest + "}"
' Get the API Key from OPENAI_API_KEY environment variable
Dim apiKey As String
If Environ("OPENAI_API_KEY") <> "" Then
apiKey = Environ("OPENAI_API_KEY")
Else
LLM = "#ERROR Missing environment variable OPENAI_API_KEY"
Exit Function
End If
' Send the HTTP request
Dim http As Object
Set http = CreateObject("Msxml2.XMLHTTP.6.0")
' Do not set timeouts. XMLHTTP doesn't support it. ServerXMLHTTP doesn't work
' http.setTimeouts 5000, 5000, 5000, 30000
http.Open "POST", "https://api.openai.com/v1/chat/completions", False
http.setRequestHeader "Content-Type", "application/json"
http.setRequestHeader "Authorization", "Bearer " & apiKey
If Not refresh Then
http.setRequestHeader "Cache-Control", "max-age=86400"
End If
http.Send jsonRequest
' Parse the JSON response and return the content
Dim responseJSON As Object
On Error GoTo CannotParseResponseAsJSON
Set responseJSON = JsonConverter.ParseJson(http.responseText)
' If error, show error and exit
If Not IsEmpty(responseJSON("error")) Then
LLM = "#ERROR: " & responseJSON("error")("message")
Exit Function
End If
Dim content As String
On Error GoTo CannotGetContent
content = responseJSON("choices")(1)("message")("content")
Dim answerJSON As Variant
On Error GoTo CannotParseContentAsJSON
Set answerJSON = JsonConverter.ParseJson(content)
Dim answerType As String
answerType = TypeName(answerJSON)
On Error GoTo CannotExtractResult
If answerType = "Dictionary" Or answerType = "Collection" Then
' If answerJSON is an object, get the values
Dim result() As String
Dim i As Integer
Dim item As Variant
ReDim result(answerJSON.Count - 1)
i = 0
For Each item In answerJSON
' ParseJson returns a Dictionary yields an empty key at the end. Handle that
If IsEmpty(item) Then Exit For
' Reconvert to JSON if value is not a string
If answerType = "Dictionary" Then
If TypeName(answerJSON(item)) = "String" Then
result(i) = answerJSON(item)
Else
result(i) = ConvertToJson(answerJSON(item))
End If
Else
If TypeName(item) = "String" Then
result(i) = item
Else
result(i) = ConvertToJson(item)
End If
End If
i = i + 1
Next item
LLM = result
Else
LLM = "#ERROR: Not JSON: " & content
End If
Exit Function
CannotParseResponseAsJSON:
LLM = "#ERROR: Cannot parse response as JSON: " & http.responseText
Exit Function
CannotGetContent:
LLM = "#ERROR: Cannot get choices[0].message.content: " & responseJSON
Exit Function
CannotParseContentAsJSON:
LLM = "#ERROR: Cannot parse content as JSON: " & content
Exit Function
CannotExtractResult:
LLM = "#ERROR: Cannot extract result from: " & content
End Function