fast-deepseek 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/fast_deepseek/client.rb +9 -46
- data/lib/fast_deepseek/request.rb +107 -0
- data/lib/fast_deepseek/version.rb +1 -1
- data/lib/fast_deepseek.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2712981183f90a1d6a5de3571eb4fcc66ae0a29f31c91816a566598b6c7e7d6a
|
|
4
|
+
data.tar.gz: bccffaf9ae7a7c2047f95f5f36bdf9a9e82d28b0c45e558a627d55a7937317cb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 355f7001010c8bf9f38316f399a5ebd6ba4dc4e74f8982b20dde51a5c1fefa1459bb8ac7c2f109864f179072e35197c78bc884351d2936dcbdd1b1285848171a
|
|
7
|
+
data.tar.gz: 2e7b1b48184e7f41caec3d2313d91658edda09dcf0be618309671b6baa3bc5db5c10b8a66edfc6bc858b104aa36e42c0ffbe8506198d0eafdefeb44325d3641c
|
data/lib/fast_deepseek/client.rb
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "faraday"
|
|
4
|
-
require "json"
|
|
5
|
-
require "logger"
|
|
6
3
|
require "dotenv/load"
|
|
4
|
+
require_relative "request"
|
|
7
5
|
|
|
8
6
|
module FastDeepseek
|
|
9
7
|
# Client for interacting with the DeepSeek API.
|
|
@@ -14,56 +12,21 @@ module FastDeepseek
|
|
|
14
12
|
@api_key = api_key || ENV.fetch("DEEPSEEK_API_KEY", nil)
|
|
15
13
|
raise Error, "DEEPSEEK_API_KEY is missing! Set it in the .env file or pass it explicitly." unless @api_key
|
|
16
14
|
|
|
17
|
-
@
|
|
18
|
-
@conn = Faraday.new(url: base_url) do |faraday|
|
|
19
|
-
faraday.adapter Faraday.default_adapter
|
|
20
|
-
faraday.headers["Content-Type"] = "application/json"
|
|
21
|
-
end
|
|
15
|
+
@request = Request.new(api_key: @api_key, base_url: base_url)
|
|
22
16
|
end
|
|
23
17
|
|
|
24
18
|
def chat(prompt, model:, options: {})
|
|
25
|
-
|
|
19
|
+
payload = { model: model, messages: [{ role: "user", content: prompt }], stream: false }.merge(options)
|
|
20
|
+
@request.call("chat", payload)
|
|
26
21
|
end
|
|
27
22
|
|
|
28
|
-
def
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
def request(endpoint, payload = nil, method: :post)
|
|
35
|
-
response = send_request(endpoint, payload, method)
|
|
36
|
-
handle_response(response)
|
|
37
|
-
rescue Faraday::Error => e
|
|
38
|
-
@logger.error("API request failed: #{e.message}")
|
|
39
|
-
raise Error, "API request failed: #{e.message}"
|
|
40
|
-
rescue JSON::ParserError => e
|
|
41
|
-
@logger.error("Invalid API response: #{e.message}")
|
|
42
|
-
raise Error, "Invalid API response: #{e.message}"
|
|
23
|
+
def chat_stream(prompt, model:, options: {}, &)
|
|
24
|
+
payload = { model: model, messages: [{ role: "user", content: prompt }], stream: true }.merge(options)
|
|
25
|
+
@request.stream("chat", payload, &)
|
|
43
26
|
end
|
|
44
27
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
@conn.public_send(method, path) do |req|
|
|
48
|
-
req.headers["Authorization"] = format("Bearer %s", @api_key)
|
|
49
|
-
req.body = payload.to_json if payload
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def handle_response(response)
|
|
54
|
-
case response.status
|
|
55
|
-
when 429
|
|
56
|
-
@logger.error("API rate limit exceeded. Please try again later.")
|
|
57
|
-
raise RateLimitError, "API rate limit exceeded. Please try again later."
|
|
58
|
-
when 500..599
|
|
59
|
-
@logger.error("Server error occurred. Please try again later.")
|
|
60
|
-
raise ServerError, "Server error occurred. Please try again later."
|
|
61
|
-
when 200..299
|
|
62
|
-
JSON.parse(response.body)
|
|
63
|
-
else
|
|
64
|
-
@logger.error("API request failed: #{response.status} - #{response.body}")
|
|
65
|
-
raise Error, "API request failed: #{response.status} - #{response.body}"
|
|
66
|
-
end
|
|
28
|
+
def models
|
|
29
|
+
@request.call("models", method: :get)
|
|
67
30
|
end
|
|
68
31
|
end
|
|
69
32
|
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "faraday"
|
|
4
|
+
require "json"
|
|
5
|
+
require "logger"
|
|
6
|
+
require_relative "errors"
|
|
7
|
+
|
|
8
|
+
module FastDeepseek
|
|
9
|
+
# Handles HTTP requests and API response parsing.
|
|
10
|
+
class Request
|
|
11
|
+
def initialize(api_key:, base_url:, logger: nil)
|
|
12
|
+
@api_key = api_key
|
|
13
|
+
@logger = logger || Logger.new($stdout)
|
|
14
|
+
@conn = Faraday.new(url: base_url) do |faraday|
|
|
15
|
+
faraday.adapter Faraday.default_adapter
|
|
16
|
+
faraday.headers["Content-Type"] = "application/json"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def call(endpoint, payload = nil, method: :post)
|
|
21
|
+
response = send_request(endpoint, payload, method)
|
|
22
|
+
handle_response(response)
|
|
23
|
+
rescue Faraday::Error => e
|
|
24
|
+
@logger.error("API request failed: #{e.message}")
|
|
25
|
+
raise Error, "API request failed: #{e.message}"
|
|
26
|
+
rescue JSON::ParserError => e
|
|
27
|
+
@logger.error("Invalid API response: #{e.message}")
|
|
28
|
+
raise Error, "Invalid API response: #{e.message}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def stream(endpoint, payload, &block)
|
|
32
|
+
raise ArgumentError, "a block is required for streaming" unless block
|
|
33
|
+
|
|
34
|
+
buffer = +""
|
|
35
|
+
response = send_stream_request(endpoint, payload) do |chunk|
|
|
36
|
+
process_stream_chunk(buffer, chunk, &block)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
handle_status(response)
|
|
40
|
+
rescue Faraday::Error => e
|
|
41
|
+
@logger.error("API request failed: #{e.message}")
|
|
42
|
+
raise Error, "API request failed: #{e.message}"
|
|
43
|
+
rescue JSON::ParserError => e
|
|
44
|
+
@logger.error("Invalid streaming response: #{e.message}")
|
|
45
|
+
raise Error, "Invalid streaming response: #{e.message}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def send_request(endpoint, payload, method)
|
|
51
|
+
path = method == :post ? "#{endpoint}/completions" : endpoint
|
|
52
|
+
@conn.public_send(method, path) do |req|
|
|
53
|
+
req.headers["Authorization"] = format("Bearer %s", @api_key)
|
|
54
|
+
req.body = payload.to_json if payload
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def send_stream_request(endpoint, payload, &)
|
|
59
|
+
@conn.post("#{endpoint}/completions") do |req|
|
|
60
|
+
req.headers["Authorization"] = format("Bearer %s", @api_key)
|
|
61
|
+
req.headers["Accept"] = "text/event-stream"
|
|
62
|
+
req.body = payload.to_json
|
|
63
|
+
req.options.on_data = proc do |chunk, _bytes_received, _env|
|
|
64
|
+
yield chunk
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def process_stream_chunk(buffer, chunk, &)
|
|
70
|
+
buffer << chunk
|
|
71
|
+
process_stream_buffer(buffer, &)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def handle_response(response)
|
|
75
|
+
handle_status(response)
|
|
76
|
+
JSON.parse(response.body)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def handle_status(response)
|
|
80
|
+
case response.status
|
|
81
|
+
when 429
|
|
82
|
+
@logger.error("API rate limit exceeded. Please try again later.")
|
|
83
|
+
raise RateLimitError, "API rate limit exceeded. Please try again later."
|
|
84
|
+
when 500..599
|
|
85
|
+
@logger.error("Server error occurred. Please try again later.")
|
|
86
|
+
raise ServerError, "Server error occurred. Please try again later."
|
|
87
|
+
when 200..299
|
|
88
|
+
true
|
|
89
|
+
else
|
|
90
|
+
@logger.error("API request failed: #{response.status} - #{response.body}")
|
|
91
|
+
raise Error, "API request failed: #{response.status} - #{response.body}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def process_stream_buffer(buffer)
|
|
96
|
+
while (line = buffer.slice!(/.*\n/))
|
|
97
|
+
next unless line.start_with?("data: ")
|
|
98
|
+
|
|
99
|
+
data = line.delete_prefix("data: ").strip
|
|
100
|
+
next if data.empty? || data == "[DONE]"
|
|
101
|
+
|
|
102
|
+
content = JSON.parse(data).dig("choices", 0, "delta", "content")
|
|
103
|
+
yield content if content
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
data/lib/fast_deepseek.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fast-deepseek
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Uday Kadaboina
|
|
@@ -49,6 +49,7 @@ files:
|
|
|
49
49
|
- lib/fast_deepseek.rb
|
|
50
50
|
- lib/fast_deepseek/client.rb
|
|
51
51
|
- lib/fast_deepseek/errors.rb
|
|
52
|
+
- lib/fast_deepseek/request.rb
|
|
52
53
|
- lib/fast_deepseek/version.rb
|
|
53
54
|
homepage: https://github.com/udaykadaboina/fast-deepseek
|
|
54
55
|
licenses:
|
|
@@ -56,7 +57,7 @@ licenses:
|
|
|
56
57
|
metadata:
|
|
57
58
|
homepage_uri: https://github.com/udaykadaboina/fast-deepseek
|
|
58
59
|
source_code_uri: https://github.com/udaykadaboina/fast-deepseek
|
|
59
|
-
changelog_uri: https://github.com/udaykadaboina/fast-deepseek/releases/tag/v0.
|
|
60
|
+
changelog_uri: https://github.com/udaykadaboina/fast-deepseek/releases/tag/v0.3.0
|
|
60
61
|
rubygems_mfa_required: 'true'
|
|
61
62
|
rdoc_options: []
|
|
62
63
|
require_paths:
|