-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathHTTPSSEClient_modified.gd
144 lines (119 loc) · 4.03 KB
/
HTTPSSEClient_modified.gd
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class_name HTTPSSEClient
extends Node
signal new_sse_event
signal connected
signal connection_error(error)
var httpclient = HTTPClient.new()
var is_connected = false
var domain
var url_after_domain
var headers : PackedStringArray
var body: String
var port
var told_to_connect = false
var connection_in_progress = false
var request_in_progress = false
var is_requested = false
var response_body = PackedByteArray()
var ai_status_message
func connect_to_host(domain : String, url_after_domain : String, headers: PackedStringArray, body: String, ai_message: ChatMessageAI, port : int = -1):
self.domain = domain
self.url_after_domain = url_after_domain
self.port = port
self.headers = headers
self.body = body
told_to_connect = true
ai_status_message = ai_message
func close_connection():
httpclient.close()
is_connected = false
told_to_connect = false
connection_in_progress = false
request_in_progress = false
is_requested = false
func attempt_to_connect():
var err = httpclient.connect_to_host(domain, port)
if err == OK:
emit_signal("connected")
is_connected = true
else:
emit_signal("connection_error", str(err))
func attempt_to_request(httpclient_status):
if httpclient_status == HTTPClient.STATUS_CONNECTING or httpclient_status == HTTPClient.STATUS_RESOLVING:
return
if httpclient_status == HTTPClient.STATUS_CONNECTED:
var err = httpclient.request(HTTPClient.METHOD_POST, url_after_domain, headers, body)
if err == OK:
is_requested = true
func _process(delta):
if !told_to_connect:
return
if !is_connected:
if !connection_in_progress:
attempt_to_connect()
connection_in_progress = true
return
httpclient.poll()
var httpclient_status = httpclient.get_status()
if !is_requested:
if !request_in_progress:
attempt_to_request(httpclient_status)
return
var httpclient_has_response = httpclient.has_response()
if httpclient_has_response or httpclient_status == HTTPClient.STATUS_BODY:
var response_headers = httpclient.get_response_headers_as_dictionary()
httpclient.poll()
var chunk = httpclient.read_response_body_chunk()
if(chunk.size() == 0):
return
else:
# each chunk sometimes can contain more than one delta of data.
response_body = chunk
var string_body = response_body.get_string_from_utf8()
if string_body:
var partial_reply = get_open_ai_events_data(string_body)
emit_signal("new_sse_event", partial_reply, ai_status_message)
# Since each chunk sometimes can contain more than one delta of data this
# function will iterate through each "data" block found and extract its
# content concatenating it in an array.
func get_open_ai_events_data(string_body: String) -> Array:
var results = []
string_body = string_body.strip_edges() # Remove leading and trailing whitespaces, including new lines
var data_entries = string_body.split("\n\n") # Split the body into individual data entries
for entry in data_entries:
if entry == "data: [DONE]":
results.append("[DONE]")
continue
entry = entry.replace("data: ", "")
print("Processing entry: ", entry) # Debugging line
var parsed_data = JSON.parse_string(entry)
if parsed_data == null:
printerr("Error: Received data is not a valid JSON object")
results.append("[ERROR]")
else:
if "choices" in parsed_data and parsed_data["choices"].size() > 0:
var choices = parsed_data["choices"][0]
if "delta" in choices:
var delta = choices["delta"]
if "content" in delta:
results.append(delta["content"])
elif delta.is_empty():
results.append("[EMPTY DELTA]")
else:
printerr("Error: 'content' field not found in the 'delta'")
results.append("[ERROR]")
else:
printerr("Error: 'delta' field not found in the first choice")
results.append("[ERROR]")
else:
printerr("Error: 'choices' field not found in the received data")
results.append("[ERROR]")
return results
func _exit_tree():
if httpclient:
httpclient.close()
func _notification(what):
if what == NOTIFICATION_WM_CLOSE_REQUEST:
if httpclient:
httpclient.close()
get_tree().quit()