-
Notifications
You must be signed in to change notification settings - Fork 1
/
server.rb
113 lines (85 loc) · 2.64 KB
/
server.rb
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
# frozen_string_literal: true
require "bundler/setup"
require "json"
require "rack"
require "open3"
require "logger"
require_relative "config/app"
require_relative "lib/errors"
require_relative "lib/llm"
class Server
CONTENT = "application/json"
PLAIN = "text/plain"
def initialize
App.instance.config(__dir__)
LLM.instance
end
def call(env)
request = Rack::Request.new(env)
if request.post? && request.path == "/completion"
response_data = completion_action(request)
return response_data if !response_data.is_a?(Hash)
success_response(JSON.generate(response_data), CONTENT)
elsif request.get? && request.path == "/heartbeat"
App.logger.info("#{request.request_method} #{request.ip} #{request.path}")
success_response(Time.now.to_i.to_s, PLAIN)
else
error_response(404, "Not Found")
end
rescue Errno::EPIPE
error_response(503, "Service Unavailable")
end
private
def completion_action(request)
result = negotiate_content!(request)
return result if !result.nil?
result = extract_content_type!(request)
return result if !result.nil?
App.logger.info("#{request.request_method} #{request.ip} #{request.path}")
# Parse body
data = parse_body(request.body.read)
return error_response(400, "Bad request") if data.nil?
prompt = data.dig("prompt")
prompt&.strip!
result = if prompt.nil? || prompt == ""
""
elsif App.instance.interactive?
LLM.instance.send_prompt(prompt)
LLM.instance.read_result
else
LLM.instance.send_prompt(prompt)
end
{response: result, model: App.instance.current_model["model"]}
end
def success_response(data, content_type)
status = 200
App.logger.info(status)
response = Rack::Response.new(data, status)
response["Content-Type"] = content_type
response.finish
end
def parse_body(content)
JSON.parse(content)
rescue
nil
end
def negotiate_content!(request)
# Extract Accept header
accept_header = request.get_header("HTTP_ACCEPT") || CONTENT
valid_header = accept_header.include?("*/*") || accept_header.include?(CONTENT)
return error_response(406, "Not Acceptable") if !valid_header
nil
end
def extract_content_type!(request)
# Extract Content Type
content_type_header = request.get_header("CONTENT_TYPE") || CONTENT
return error_response(415, "Unsupported Media Type") if content_type_header != CONTENT
nil
end
def error_response(status, message)
App.logger.error("#{status}: #{message}")
response = Rack::Response.new(message, status)
response["Content-Type"] = PLAIN
response.finish
end
end