cloudflare-ai
cloudflare-ai copied to clipboard
A ruby client for the Cloudflare Workers AI REST API
Cloudflare Workers AI API client for ruby
Cloudflare is testing its Workers AI API. Hopefully this project makes it easier for ruby-first developers to consume Cloudflare's latest and greatest.
I'm really interested in applying retrieval-augmented generation to make legal services more accessible. Email me.
If you're looking for legal help, it's best to book a slot via https://www.krishnan.ca.
Supported features
- [x] Text Generation
- [x] Text Embeddings
- [x] Text Classification
- [x] Translation
- [x] Image Classification
- [x] Text-to-Image
- [x] Automatic Speech Recognition
Table of Contents
- Installation
- Usage
- Logging
- Development
Installation
Install the gem and add to the application's Gemfile by executing:
bundle add cloudflare-ai
If bundler is not being used to manage dependencies, install the gem by executing:
gem install cloudflare-ai
Usage
require "cloudflare/ai"
Cloudflare Workers AI
Please visit the Cloudflare Workers AI website for more details. Thiis gem provides a client that wraps around Cloudflare's REST API.
Client
client = Cloudflare::AI::Client.new(account_id: ENV["CLOUDFLARE_ACCOUNT_ID"], api_token: ENV["CLOUDFLARE_API_TOKEN"])
Model selection
The model name is an optional parameter to every one of the client methods described below. For example, if an example is documented as
result = client.complete(prompt: "Hello my name is")
this is implicitly the same as
result = client.complete(prompt: "Hello my name is", model: "@cf/meta/llama-2-7b-chat-fp16")
The full list of supported models is available here: models.rb. More information is available in the cloudflare documentation. The default model used is the first enumerated model in the applicable set in models.rb.
Text generation
(chat / scoped prompt)
messages = [
Cloudflare::AI::Message.new(role: "system", content: "You are a big fan of Cloudflare and Ruby."),
Cloudflare::AI::Message.new(role: "user", content: "What is your favourite tech stack?"),
Cloudflare::AI::Message.new(role: "assistant", content: "I love building with Ruby on Rails and Cloudflare!"),
Cloudflare::AI::Message.new(role: "user", content: "Really? You like Cloudflare even though there isn't great support for Ruby?"),
]
result = client.chat(messages: messages)
puts result.response # => "Yes, I love Cloudflare!"
(string prompt)
result = client.complete(prompt: "What is your name?", max_tokens: 512)
puts result.response # => "My name is Jonas."
Streaming responses
Responses will be streamed back to the client using Server Side Events (SSE) if a block is passed to the chat or complete method.
result = client.complete(prompt: "Hi!") { |data| puts data}
# {"response":" "}
# {"response":" Hello"}
# {"response":" there"}
# {"response":"!"}
# {"response":""}
# [DONE]
Token limits
Invocations of the prompt and chat can take an optional max_tokens argument that defaults to 256.
Result object
All invocations of the prompt and chat methods return a Cloudflare::AI::Results::TextGeneration object. This object's serializable JSON output is
based on the raw response from the Cloudflare API.
result = client.complete(prompt: "What is your name?")
# Successful
puts result.response # => "My name is John."
puts result.success? # => true
puts result.failure? # => false
puts result.to_json # => {"result":{"response":"My name is John"},"success":true,"errors":[],"messages":[]}
# Unsuccessful
puts result.response # => nil
puts result.success? # => false
puts result.failure? # => true
puts result.to_json # => {"result":null,"success":false,"errors":[{"code":7009,"message":"Upstream service unavailable"}],"messages":[]}
Text embedding
result = client.embed(text: "Hello")
p result.shape # => [1, 768] # (1 embedding, 768 dimensions per embedding)
p result.embedding # => [[-0.008496830239892006, 0.001376907923258841, -0.0323275662958622, ...]]
The input can be either a string (as above) or an array of strings:
result = client.embed(text: ["Hello", "World"])
Result object
All invocations of the embed methods return a Cloudflare::AI::Results::TextEmbedding.
Text classification
result = client.classify(text: "You meanie!")
p result.result # => [{"label"=>"NEGATIVE", "score"=>0.6647962927818298}, {"label"=>"POSITIVE", "score"=>0.3352036774158478}]
Result object
All invocations of the classify methods return a Cloudflare::AI::Results::TextClassification.
Image classification
The image classification endpoint accepts either a path to a file or a file stream.
result = client.classify(image: "/path/to/cat.jpg")
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":[]}
result = client.classify(image: File.open("/path/to/cat.jpg"))
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":[]}
Result object
All invocations of the classify method returns a Cloudflare::AI::Results::TextClassification.
Text to Image
result = client.draw(prompt: "robot with blue eyes")
p result.result # => File:0x0000000110deed68 (png tempfile)
Result object
All invocations of the draw method returns a Cloudflare::AI::Results::TextToImage.
Translation
result = client.translate(text: "Hello Jello", source_lang: "en", target_lang: "fr")
p result.translated_text # => Hola Jello
Result object
All invocations of the translate method returns a Cloudflare::AI::Results::Translate.
Automatic speech recognition
You can pass either a URL (source_url:) or a file (audio:) to the transcribe method.
result = client.transcribe(source_url: "http://example.org/path/to/audio.wav")
p result.text # => "Hello Jello."
p result.word_count # => 2
p result.to_json # => {"result":{"text":"Hello Jello.","word_count":2,"words":[{"word":"Hello","start":0,"end":1.340000033378601},{"word":"Jello.","start":1.340000033378601,"end":1.340000033378601}},"success":true,"errors":[],"messages":[]}
result = client.transcribe(audio: File.open("/path/to/audio.wav"))
# ...
Result object
All invocations of the transcribe method returns a Cloudflare::AI::Results::Transcribe.
Summarization
result = client.summarize(text: "This text should be a lot longer.")
p result.summary # => {"result":{"summary":"Short text"},"success":true,"errors":[],"messages":[]}
Result object
All invocations of the summarize method returns a Cloudflare::AI::Results::Summarization object.
Object detection
The object detection endpoint accepts either a path to a file or a file stream.
result = client.detect_objects(image: "/path/to/cat.jpg")
result = client.classify(image: File.open("/path/to/cat.jpg"))
Result object
All invocations of the detect_objects method returns a Cloudflare::AI::Results::ObjectDetection object.
Image-to-text
The captioning endpoint accepts either a path to a file or a file stream.
client.caption(image: "/path/to/cat.jpg").description # => "a cat sitting on a couch"
client.caption(image: File.open("/path/to/cat.jpg")).description # => "a cat sitting on a couch"
Result object
All invocations of the caption method returns a Cloudflare::AI::Results::ImageToText object.
Logging
This gem uses standard logging mechanisms and defaults to :warn level. Most messages are at info level, but we will add debug or warn statements as needed.
To show all log messages:
Cloudflare::AI.logger.level = :debug
You can use this logger as you would the default ruby logger. For example:
Cloudflare::AI.logger = Logger.new($stdout)
Development
git clone https://github.com/ajaynomics/cloudflare-ai.gitbundle exec raketo ensure that the tests pass and to run standardrb
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/ajaynomics/cloudflare-ai.
License
The gem is available as open source under the terms of the MIT License. A special thanks to the team at langchainrb – I learnt a lot reading your codebase as I muddled my way through the initial effort.