cloudflare-ai 0.5.1 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9085ff95f730366db7b3261cc94935f782d719b8129dd1341796ee6d66fd373c
4
- data.tar.gz: 60b29886c88200aebdd1c46e743a28dd597540144494e8288098e05c6ddb8e04
3
+ metadata.gz: 2f16a1fd5c112fb69440d4d89b1f27d167e854c537ca952b91e1f3f673c0efb5
4
+ data.tar.gz: 59f999e994f5bd21071ee2f125b5e138ba353feb857912b1df472f35acc05006
5
5
  SHA512:
6
- metadata.gz: 3b95c01b2cab4dec4c0bdd476d99f5ab65183215a64e6c6711a50caed5874a51ff34b78b530b1877b13a1be8851fc527202a1b250f94d57a554ff46b25716136
7
- data.tar.gz: 86721eb5cf51bfd886a6f9e1a4be71c4b33492cd90e2a2adedbe2f6474c7e601b4e2f1bc52bfd315039a3b24ea202fd627dc032a2dda63e8ad6f04b0e01da08a
6
+ metadata.gz: 1d258b49887ca664f616aad4dbc74afc4bb8d49d0452933c2ee907306af56cf81da0bf084c260ddbe4db9d96f522812cc5abfb771c3d94757f12342334b16fd6
7
+ data.tar.gz: 133fcfd21cedbdb324604ec0e9bd4aacb0750b9f486df7bc217998e4dd117f4e6d482572ba1feee8b629e3362857cb8b8f28d2f1e3c6f1d89acddd18b73752e9
data/README.md CHANGED
@@ -23,8 +23,8 @@ It's still early days, and here are my immediate priorities:
23
23
  * [x] [Text Embeddings](https://developers.cloudflare.com/workers-ai/models/text-embeddings/)
24
24
  * [x] [Text Classification](https://developers.cloudflare.com/workers-ai/models/text-classification/)
25
25
  * [x] [Translation](https://developers.cloudflare.com/workers-ai/models/translation/)
26
- * [ ] [Image Classification](https://developers.cloudflare.com/workers-ai/models/image-classification/)
27
- * [ ] [Text-to-Image](https://developers.cloudflare.com/workers-ai/models/text-to-image/)
26
+ * [x] [Image Classification](https://developers.cloudflare.com/workers-ai/models/image-classification/)
27
+ * [x] [Text-to-Image](https://developers.cloudflare.com/workers-ai/models/text-to-image/)
28
28
  * [ ] [Automatic Speech Recognition](https://developers.cloudflare.com/workers-ai/models/speech-recognition/)
29
29
 
30
30
  # Table of Contents
@@ -75,7 +75,8 @@ The full list of supported models is available here: [models.rb](lib/cloudflare/
75
75
  More information is available [in the cloudflare documentation](https://developers.cloudflare.com/workers-ai/models/).
76
76
  The default model used is the first enumerated model in the applicable set in [models.rb](lib/cloudflare/ai/models.rb).
77
77
 
78
- ### Text generation (chat / scoped prompt)
78
+ ### Text generation
79
+ #### (chat / scoped prompt)
79
80
  ```ruby
80
81
  messages = [
81
82
  Cloudflare::AI::Message.new(role: "system", content: "You are a big fan of Cloudflare and Ruby."),
@@ -86,6 +87,11 @@ messages = [
86
87
  result = client.chat(messages: messages)
87
88
  puts result.response # => "Yes, I love Cloudflare!"
88
89
  ```
90
+ #### (string prompt)
91
+ ```ruby
92
+ result = client.complete(prompt: "What is your name?", max_tokens: 512)
93
+ puts result.response # => "My name is Jonas."
94
+ ```
89
95
 
90
96
  #### Streaming responses
91
97
  Responses will be streamed back to the client using Server Side Events (SSE) if a block is passed to the `chat` or `complete` method.
@@ -101,9 +107,6 @@ result = client.complete(prompt: "Hi!") { |data| puts data}
101
107
  ```
102
108
  #### Token limits
103
109
  Invocations of the `prompt` and `chat` can take an optional `max_tokens` argument that defaults to 256.
104
- ```ruby
105
- result = client.complete(prompt: "What is your name?", max_tokens: 512)
106
- ```
107
110
 
108
111
  #### Result object
109
112
  All invocations of the `prompt` and `chat` methods return a `Cloudflare::AI::Results::TextGeneration` object. This object's serializable JSON output is
@@ -149,6 +152,29 @@ p result.result # => [{"label"=>"NEGATIVE", "score"=>0.6647962927818298}, {"labe
149
152
  #### Result object
150
153
  All invocations of the `classify` methods return a `Cloudflare::AI::Results::TextClassification`.
151
154
 
155
+ ### Image classification
156
+ The image classification endpoint accepts either a path to a file or a file stream.
157
+
158
+ ```ruby
159
+ result = client.classify(image: "/path/to/cat.jpg")
160
+ p result.result # => {"result":[{"label":"TABBY","score":0.6159140467643738},{"label":"TIGER CAT","score":0.12016300112009048},{"label":"EGYPTIAN CAT","score":0.07523812353610992},{"label":"DOORMAT","score":0.018854796886444092},{"label":"ASHCAN","score":0.01314085815101862}],"success":true,"errors":[],"messages":[]}
161
+
162
+ result = client.classify(image: File.open("/path/to/cat.jpg"))
163
+ p result.result # => {"result":[{"label":"TABBY","score":0.6159140467643738},{"label":"TIGER CAT","score":0.12016300112009048},{"label":"EGYPTIAN CAT","score":0.07523812353610992},{"label":"DOORMAT","score":0.018854796886444092},{"label":"ASHCAN","score":0.01314085815101862}],"success":true,"errors":[],"messages":[]}
164
+ ```
165
+
166
+ #### Result object
167
+ All invocations of the `classify` method returns a `Cloudflare::AI::Results::TextClassification`.
168
+
169
+ ### Text to Image
170
+ ```ruby
171
+ result = client.draw(prompt: "robot with blue eyes")
172
+ p result.result # => File:0x0000000110deed68 (png tempfile)
173
+ ```
174
+
175
+ #### Result object
176
+ All invocations of the `draw` method returns a `Cloudflare::AI::Results::TextToImage`.
177
+
152
178
  ### Translation
153
179
  ```ruby
154
180
  result = client.translate(text: "Hello Jello", source_lang: "en", target_lang: "fr")
@@ -2,6 +2,7 @@ require "event_stream_parser"
2
2
  require "faraday"
3
3
 
4
4
  class Cloudflare::AI::Client
5
+ include Cloudflare::AI::Clients::ImageHelpers
5
6
  include Cloudflare::AI::Clients::TextGenerationHelpers
6
7
 
7
8
  attr_reader :url, :account_id, :api_token
@@ -18,11 +19,19 @@ class Cloudflare::AI::Client
18
19
  post_streamable_request(url, payload, &block)
19
20
  end
20
21
 
21
- def classify(text:, model_name: Cloudflare::AI::Models.text_classification.first)
22
+ def classify(text: nil, image: nil, model_name: nil)
23
+ raise ArgumentError, "Must provide either text or image (and not both)" if [text, image].compact.size != 1
24
+
25
+ model_name ||= text ? Cloudflare::AI::Models.text_classification.first : Cloudflare::AI::Models.image_classification.first
22
26
  url = service_url_for(account_id: account_id, model_name: model_name)
23
- payload = {text: text}.to_json
24
27
 
25
- Cloudflare::AI::Results::TextClassification.new(connection.post(url, payload).body)
28
+ if text
29
+ payload = {text: text}.to_json
30
+ Cloudflare::AI::Results::TextClassification.new(connection.post(url, payload).body)
31
+ else
32
+ image = File.open(image) if image.is_a?(String)
33
+ Cloudflare::AI::Results::ImageClassification.new(post_request_with_binary_file(url, image).body)
34
+ end
26
35
  end
27
36
 
28
37
  def complete(prompt:, model_name: default_text_generation_model_name, max_tokens: default_max_tokens, &block)
@@ -32,6 +41,17 @@ class Cloudflare::AI::Client
32
41
  post_streamable_request(url, payload, &block)
33
42
  end
34
43
 
44
+ def draw(prompt:, num_steps: 20, model_name: Cloudflare::AI::Models.text_to_image.first)
45
+ url = service_url_for(account_id: account_id, model_name: model_name)
46
+ payload = {prompt: prompt, num_steps: num_steps}.to_json
47
+
48
+ result = connection.post(url, payload).body
49
+ binary_data = result.split(",").map(&:to_i).pack("C*")
50
+ Cloudflare::AI::Results::TextToImage.new(
51
+ Tempfile.new(["cloudflare-ai", ".png"], binmode: true).tap { |result| result.write(binary_data) }
52
+ )
53
+ end
54
+
35
55
  def embed(text:, model_name: Cloudflare::AI::Models.text_embedding.first)
36
56
  url = service_url_for(account_id: account_id, model_name: model_name)
37
57
  payload = {text: text}.to_json
@@ -0,0 +1,20 @@
1
+ require "faraday/multipart"
2
+
3
+ module Cloudflare
4
+ module AI
5
+ module Clients
6
+ module ImageHelpers
7
+ private
8
+
9
+ def post_request_with_binary_file(url, file)
10
+ connection.post do |req|
11
+ req.url url
12
+ req.headers["Transfer-Encoding"] = "chunked"
13
+ req.headers["Content-Type"] = "multipart/form-data"
14
+ req.body = ::Faraday::UploadIO.new(file, "octet/stream")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -17,7 +17,7 @@ class Cloudflare::AI::Models
17
17
  end
18
18
 
19
19
  def image_classification
20
- %w[@cf/huggingface/distilbert-sst-2-int8]
20
+ %w[@cf/microsoft/resnet-50]
21
21
  end
22
22
 
23
23
  def text_to_image
@@ -30,7 +30,7 @@ class Cloudflare::AI::Result
30
30
  result_data.to_json
31
31
  end
32
32
 
33
- private
33
+ protected
34
34
 
35
35
  attr_reader :result_data
36
36
 
@@ -0,0 +1,3 @@
1
+ class Cloudflare::AI::Results::ImageClassification < Cloudflare::AI::Result
2
+ # Empty seam kept for consistency with other result objects that have more complexity.
3
+ end
@@ -0,0 +1,5 @@
1
+ class Cloudflare::AI::Results::TextToImage < Cloudflare::AI::Result
2
+ def initialize(file)
3
+ @result_data = {result: file, success: true, errors: [], messages: []}
4
+ end
5
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cloudflare
4
4
  module AI
5
- VERSION = "0.5.1"
5
+ VERSION = "0.7.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudflare-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ajay Krishnan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-23 00:00:00.000000000 Z
11
+ date: 2024-01-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday-multipart
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: zeitwerk
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -93,14 +107,17 @@ files:
93
107
  - README.md
94
108
  - lib/cloudflare/ai.rb
95
109
  - lib/cloudflare/ai/client.rb
110
+ - lib/cloudflare/ai/clients/image_helpers.rb
96
111
  - lib/cloudflare/ai/clients/text_generation_helpers.rb
97
112
  - lib/cloudflare/ai/contextual_logger.rb
98
113
  - lib/cloudflare/ai/message.rb
99
114
  - lib/cloudflare/ai/models.rb
100
115
  - lib/cloudflare/ai/result.rb
116
+ - lib/cloudflare/ai/results/image_classification.rb
101
117
  - lib/cloudflare/ai/results/text_classification.rb
102
118
  - lib/cloudflare/ai/results/text_embedding.rb
103
119
  - lib/cloudflare/ai/results/text_generation.rb
120
+ - lib/cloudflare/ai/results/text_to_image.rb
104
121
  - lib/cloudflare/ai/results/translation.rb
105
122
  - lib/cloudflare/ai/version.rb
106
123
  homepage: https://rubygems.org/gems/cloudflare-ai