Module: SmartPrompt::HTTPClient
- Included in:
- SenseNovaAdapter, SiliconFlowAdapter, ZhipuAIAdapter
- Defined in:
- lib/smart_prompt/concerns/http_client.rb
Overview
Shared Net::HTTP plumbing for Net::HTTP-style adapters (ZhipuAI, SenseNova, SiliconFlow). Each previously carried its own copy of post/get/binary/multipart + SSE stream helpers, differing only in the provider label sprinkled through log/exception messages — which the ‘provider_label` hook now supplies.
http_post_multipart takes the general 5-arg shape (file_field + mime); Zhipu’s ASR call site uses a 3-arg shim defined on the adapter itself.
Instance Method Summary collapse
- #http_get_json(url) ⇒ Object
-
#http_post_binary(url, body) ⇒ Object
Returns the raw response body bytes (for binary payloads like TTS audio).
- #http_post_json(url, body) ⇒ Object
-
#http_post_multipart(url, form, file_field, file_path, mime) ⇒ Object
multipart/form-data POST with a file upload (ASR, voice upload).
-
#stream_chat(url, body) ⇒ Object
POST with stream:true and yield each parsed SSE ‘data:` payload to the block.
Instance Method Details
#http_get_json(url) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/smart_prompt/concerns/http_client.rb', line 34 def http_get_json(url) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.open_timeout = 30 http.read_timeout = 60 req = Net::HTTP::Get.new(uri.request_uri) req["Authorization"] = "Bearer #{@api_key}" SmartPrompt.logger.debug "#{provider_label} GET #{uri}" resp = http.request(req) if resp.is_a?(Net::HTTPSuccess) resp.body.to_s.empty? ? {} : JSON.parse(resp.body) else raise LLMAPIError, "#{provider_label} API error: #{resp.code} - #{resp.body}" end end |
#http_post_binary(url, body) ⇒ Object
Returns the raw response body bytes (for binary payloads like TTS audio).
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/smart_prompt/concerns/http_client.rb', line 52 def http_post_binary(url, body) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.open_timeout = 30 http.read_timeout = 120 req = Net::HTTP::Post.new(uri.request_uri) req["Content-Type"] = "application/json" req["Authorization"] = "Bearer #{@api_key}" req.body = body.to_json resp = http.request(req) if resp.is_a?(Net::HTTPSuccess) resp.body else raise LLMAPIError, "#{provider_label} TTS API error: #{resp.code} - #{resp.body}" end end |
#http_post_json(url, body) ⇒ Object
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/smart_prompt/concerns/http_client.rb', line 14 def http_post_json(url, body) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.open_timeout = 30 http.read_timeout = 240 req = Net::HTTP::Post.new(uri.request_uri) req["Content-Type"] = "application/json" req["Authorization"] = "Bearer #{@api_key}" req.body = body.to_json SmartPrompt.logger.debug "#{provider_label} POST #{uri} body=#{body.to_json}" resp = http.request(req) if resp.is_a?(Net::HTTPSuccess) resp.body.to_s.empty? ? {} : JSON.parse(resp.body) else SmartPrompt.logger.error "#{provider_label} API error: #{resp.code} - #{resp.body}" raise LLMAPIError, "#{provider_label} API error: #{resp.code} - #{resp.body}" end end |
#http_post_multipart(url, form, file_field, file_path, mime) ⇒ Object
multipart/form-data POST with a file upload (ASR, voice upload). Returns parsed JSON.
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 |
# File 'lib/smart_prompt/concerns/http_client.rb', line 71 def http_post_multipart(url, form, file_field, file_path, mime) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.open_timeout = 30 http.read_timeout = 180 boundary = "----SmartPrompt#{object_id}" body = +"" form.each do |k, v| body << "--#{boundary}\r\n" body << "Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n" body << "#{v}\r\n" end File.open(file_path, "rb") do |f| body << "--#{boundary}\r\n" body << "Content-Disposition: form-data; name=\"#{file_field}\"; filename=\"#{File.basename(file_path)}\"\r\n" body << "Content-Type: #{mime}\r\n\r\n" body << f.read body << "\r\n" end body << "--#{boundary}--\r\n" req = Net::HTTP::Post.new(uri.request_uri) req["Content-Type"] = "multipart/form-data; boundary=#{boundary}" req["Authorization"] = "Bearer #{@api_key}" req.body = body resp = http.request(req) if resp.is_a?(Net::HTTPSuccess) resp.body.to_s.empty? ? {} : JSON.parse(resp.body) else raise LLMAPIError, "#{provider_label} multipart API error: #{resp.code} - #{resp.body}" end end |
#stream_chat(url, body) ⇒ Object
POST with stream:true and yield each parsed SSE ‘data:` payload to the block.
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 145 |
# File 'lib/smart_prompt/concerns/http_client.rb', line 107 def stream_chat(url, body) uri = URI.parse(url) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.open_timeout = 30 http.read_timeout = 300 req = Net::HTTP::Post.new(uri.request_uri) req["Content-Type"] = "application/json" req["Authorization"] = "Bearer #{@api_key}" req["Accept"] = "text/event-stream" req.body = body.to_json buffer = +"" done = false http.request(req) do |response| unless response.is_a?(Net::HTTPSuccess) raise LLMAPIError, "#{provider_label} stream error: #{response.code} - #{response.body}" end response.read_body do |segment| break if done buffer << segment while (idx = buffer.index("\n")) line = buffer.slice!(0, idx + 1).strip next if line.empty? || !line.start_with?("data:") payload = line.sub(/\Adata:\s*/, "") if payload == "[DONE]" done = true break end begin yield JSON.parse(payload) rescue JSON::ParserError next end end end end end |