ruby-openai 5.0.0 → 5.2.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/.devcontainer/Dockerfile +16 -0
- data/.devcontainer/devcontainer.json +36 -0
- data/.devcontainer/docker-compose.yml +19 -0
- data/.github/FUNDING.yml +13 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +3 -1
- data/README.md +21 -6
- data/lib/openai/http.rb +17 -5
- data/lib/openai/version.rb +1 -1
- data/lib/openai.rb +12 -0
- data/ruby-openai.gemspec +1 -0
- metadata +31 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 996d39cd32c3c05c73efea0177c12d0751b5dda208b2855aaac440af7b2702d8
|
|
4
|
+
data.tar.gz: 65471a670e34f537fe4878322c87978f1c2beaf93336a7f2104baaa86b018c60
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: deab41c7c7f4ee21b4ed1a17f289b147b2e4960b33fd12ce863d5bdb8c835a955215d01438890c1ab8d9a1c7026faba0e5b8359c1fe3d9139082f8de58dce616
|
|
7
|
+
data.tar.gz: 3309d1c3a68736816c4f3bd1d465021ee3f162b5f5c3dbb7915ed5ce6f3a8d7014f9f1c4b07cf630f3f90201bdbe0ec308f1dc00fb6b075f45546fe519afb553
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
FROM ruby:3.2.2-slim-bullseye
|
|
2
|
+
|
|
3
|
+
ENV TZ="Europe/London"
|
|
4
|
+
|
|
5
|
+
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
|
|
6
|
+
&& apt-get -y install --no-install-recommends \
|
|
7
|
+
apt-utils \
|
|
8
|
+
build-essential \
|
|
9
|
+
curl \
|
|
10
|
+
git \
|
|
11
|
+
vim \
|
|
12
|
+
zsh
|
|
13
|
+
|
|
14
|
+
RUN gem install bundler
|
|
15
|
+
|
|
16
|
+
WORKDIR /workspace
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
|
|
2
|
+
// https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/ruby-rails-postgres
|
|
3
|
+
// Update the VARIANT arg in docker-compose.yml to pick a Ruby version
|
|
4
|
+
{
|
|
5
|
+
"name": "ruby-openai",
|
|
6
|
+
"dockerComposeFile": "docker-compose.yml",
|
|
7
|
+
"service": "app",
|
|
8
|
+
"workspaceFolder": "/workspace",
|
|
9
|
+
"containerEnv": {
|
|
10
|
+
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
|
|
11
|
+
"GITHUB_USER": "${localEnv:GITHUB_USER}"
|
|
12
|
+
},
|
|
13
|
+
// Configure tool-specific properties.
|
|
14
|
+
"customizations": {
|
|
15
|
+
// Configure properties specific to VS Code.
|
|
16
|
+
"vscode": {
|
|
17
|
+
// Add the IDs of extensions you want installed when the container is created.
|
|
18
|
+
"extensions": [
|
|
19
|
+
"rebornix.Ruby",
|
|
20
|
+
"sleistner.vscode-fileutils",
|
|
21
|
+
"ms-azuretools.vscode-docker",
|
|
22
|
+
"samverschueren.final-newline",
|
|
23
|
+
"GitHub.copilot",
|
|
24
|
+
"usernamehw.remove-empty-lines",
|
|
25
|
+
"wingrunr21.vscode-ruby",
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
// Use 'postCreateCommand' to run commands after the container is created.
|
|
30
|
+
"postCreateCommand": "bundle install",
|
|
31
|
+
// Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
|
|
32
|
+
"features": {
|
|
33
|
+
"git": "os-provided",
|
|
34
|
+
"github-cli": "latest"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
|
|
3
|
+
services:
|
|
4
|
+
app:
|
|
5
|
+
build:
|
|
6
|
+
context: ..
|
|
7
|
+
dockerfile: .devcontainer/Dockerfile
|
|
8
|
+
|
|
9
|
+
volumes:
|
|
10
|
+
- ..:/workspace:cached
|
|
11
|
+
- bundle_cache:/bundle
|
|
12
|
+
|
|
13
|
+
command: sleep infinity
|
|
14
|
+
|
|
15
|
+
environment:
|
|
16
|
+
TZ: Europe/London
|
|
17
|
+
|
|
18
|
+
volumes:
|
|
19
|
+
bundle_cache:
|
data/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# These are supported funding model platforms
|
|
2
|
+
|
|
3
|
+
github: alexrudall
|
|
4
|
+
patreon: # Replace with a single Patreon username
|
|
5
|
+
open_collective: # Replace with a single Open Collective username
|
|
6
|
+
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
8
|
+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
+
liberapay: # Replace with a single Liberapay username
|
|
10
|
+
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
+
otechie: # Replace with a single Otechie username
|
|
12
|
+
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
|
13
|
+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [5.2.0] - 2023-10-30
|
|
9
|
+
|
|
10
|
+
### Fix
|
|
11
|
+
|
|
12
|
+
- Added more spec-compliant SSE parsing: see here https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
|
|
13
|
+
- Fixes issue where OpenAI or an intermediary returns only partial JSON per chunk of streamed data
|
|
14
|
+
- Huge thanks to [@atesgoral](https://github.com/atesgoral) for this important fix!
|
|
15
|
+
|
|
16
|
+
## [5.1.0] - 2023-08-20
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Added rough_token_count to estimate tokens in a string according to OpenAI's "rules of thumb". Thank you to [@jamiemccarthy](https://github.com/jamiemccarthy) for the idea and implementation!
|
|
21
|
+
|
|
8
22
|
## [5.0.0] - 2023-08-14
|
|
9
23
|
|
|
10
24
|
### Added
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ruby-openai (5.
|
|
4
|
+
ruby-openai (5.2.0)
|
|
5
|
+
event_stream_parser (>= 0.3.0, < 1.0.0)
|
|
5
6
|
faraday (>= 1)
|
|
6
7
|
faraday-multipart (>= 1)
|
|
7
8
|
|
|
@@ -16,6 +17,7 @@ GEM
|
|
|
16
17
|
rexml
|
|
17
18
|
diff-lcs (1.5.0)
|
|
18
19
|
dotenv (2.8.1)
|
|
20
|
+
event_stream_parser (0.3.0)
|
|
19
21
|
faraday (2.7.10)
|
|
20
22
|
faraday-net_http (>= 2.0, < 3.1)
|
|
21
23
|
ruby2_keywords (>= 0.0.4)
|
data/README.md
CHANGED
|
@@ -8,11 +8,9 @@ Use the [OpenAI API](https://openai.com/blog/openai-api/) with Ruby! 🤖❤️
|
|
|
8
8
|
|
|
9
9
|
Stream text with GPT-4, transcribe and translate audio with Whisper, or create images with DALL·E...
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
🚢 Based in the UK and want to hire me? Now you can! [railsai.com](https://railsai.com?utm_source=ruby-openai&utm_medium=readme&utm_id=26072023)
|
|
12
12
|
|
|
13
|
-
[
|
|
14
|
-
|
|
15
|
-
Follow me on [Twitter](https://twitter.com/alexrudall) for more Ruby / AI content
|
|
13
|
+
[🎮 Ruby AI Builders Discord](https://discord.gg/k4Uc224xVD) | [🐦 Twitter](https://twitter.com/alexrudall) | [🧠 Anthropic Gem](https://github.com/alexrudall/anthropic) | [🚂 Midjourney Gem](https://github.com/alexrudall/midjourney)
|
|
16
14
|
|
|
17
15
|
### Bundler
|
|
18
16
|
|
|
@@ -24,13 +22,17 @@ gem "ruby-openai"
|
|
|
24
22
|
|
|
25
23
|
And then execute:
|
|
26
24
|
|
|
25
|
+
```bash
|
|
27
26
|
$ bundle install
|
|
27
|
+
```
|
|
28
28
|
|
|
29
29
|
### Gem install
|
|
30
30
|
|
|
31
31
|
Or install with:
|
|
32
32
|
|
|
33
|
+
```bash
|
|
33
34
|
$ gem install ruby-openai
|
|
35
|
+
```
|
|
34
36
|
|
|
35
37
|
and require with:
|
|
36
38
|
|
|
@@ -86,7 +88,8 @@ client = OpenAI::Client.new(
|
|
|
86
88
|
extra_headers: {
|
|
87
89
|
"X-Proxy-TTL" => "43200", # For https://github.com/6/openai-caching-proxy-worker#specifying-a-cache-ttl
|
|
88
90
|
"X-Proxy-Refresh": "true", # For https://github.com/6/openai-caching-proxy-worker#refreshing-the-cache
|
|
89
|
-
"Helicone-Auth": "Bearer HELICONE_API_KEY" # For https://docs.helicone.ai/getting-started/integration-method/openai-proxy
|
|
91
|
+
"Helicone-Auth": "Bearer HELICONE_API_KEY", # For https://docs.helicone.ai/getting-started/integration-method/openai-proxy
|
|
92
|
+
"helicone-stream-force-format" => "true", # Use this with Helicone otherwise streaming drops chunks # https://github.com/alexrudall/ruby-openai/issues/251
|
|
90
93
|
}
|
|
91
94
|
)
|
|
92
95
|
```
|
|
@@ -122,6 +125,18 @@ To use the [Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/cognit
|
|
|
122
125
|
|
|
123
126
|
where `AZURE_OPENAI_URI` is e.g. `https://custom-domain.openai.azure.com/openai/deployments/gpt-35-turbo`
|
|
124
127
|
|
|
128
|
+
### Counting Tokens
|
|
129
|
+
|
|
130
|
+
OpenAI parses prompt text into [tokens](https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them), which are words or portions of words. (These tokens are unrelated to your API access_token.) Counting tokens can help you estimate your [costs](https://openai.com/pricing). It can also help you ensure your prompt text size is within the max-token limits of your model's context window, and choose an appropriate [`max_tokens`](https://platform.openai.com/docs/api-reference/chat/create#chat/create-max_tokens) completion parameter so your response will fit as well.
|
|
131
|
+
|
|
132
|
+
To estimate the token-count of your text:
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
OpenAI.rough_token_count("Your text")
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If you need a more accurate count, try [tiktoken_ruby](https://github.com/IAPark/tiktoken_ruby).
|
|
139
|
+
|
|
125
140
|
### Models
|
|
126
141
|
|
|
127
142
|
There are different models that can be used to generate text. For a full list and to retrieve information about a single model:
|
|
@@ -180,7 +195,7 @@ client.chat(
|
|
|
180
195
|
# => "Anna is a young woman in her mid-twenties, with wavy chestnut hair that falls to her shoulders..."
|
|
181
196
|
```
|
|
182
197
|
|
|
183
|
-
Note: the API docs state that token usage is included in the streamed chat chunk objects, but this doesn't currently appear to be the case.
|
|
198
|
+
Note: the API docs state that token usage is included in the streamed chat chunk objects, but this doesn't currently appear to be the case. To count tokens while streaming, try `OpenAI.rough_token_count` or [tiktoken_ruby](https://github.com/IAPark/tiktoken_ruby).
|
|
184
199
|
|
|
185
200
|
### Functions
|
|
186
201
|
|
data/lib/openai/http.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "event_stream_parser"
|
|
2
|
+
|
|
1
3
|
module OpenAI
|
|
2
4
|
module HTTP
|
|
3
5
|
def get(path:)
|
|
@@ -53,15 +55,25 @@ module OpenAI
|
|
|
53
55
|
# @param user_proc [Proc] The inner proc to call for each JSON object in the chunk.
|
|
54
56
|
# @return [Proc] An outer proc that iterates over a raw stream, converting it to JSON.
|
|
55
57
|
def to_json_stream(user_proc:)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
parser = EventStreamParser::Parser.new
|
|
59
|
+
|
|
60
|
+
proc do |chunk, _bytes, env|
|
|
61
|
+
if env && env.status != 200
|
|
62
|
+
emit_json(json: chunk, user_proc: user_proc)
|
|
63
|
+
else
|
|
64
|
+
parser.feed(chunk) do |_type, data|
|
|
65
|
+
emit_json(json: data, user_proc: user_proc) unless data == "[DONE]"
|
|
66
|
+
end
|
|
61
67
|
end
|
|
62
68
|
end
|
|
63
69
|
end
|
|
64
70
|
|
|
71
|
+
def emit_json(json:, user_proc:)
|
|
72
|
+
user_proc.call(JSON.parse(json))
|
|
73
|
+
rescue JSON::ParserError
|
|
74
|
+
# Ignore invalid JSON.
|
|
75
|
+
end
|
|
76
|
+
|
|
65
77
|
def conn(multipart: false)
|
|
66
78
|
Faraday.new do |f|
|
|
67
79
|
f.options[:timeout] = @request_timeout
|
data/lib/openai/version.rb
CHANGED
data/lib/openai.rb
CHANGED
|
@@ -52,4 +52,16 @@ module OpenAI
|
|
|
52
52
|
def self.configure
|
|
53
53
|
yield(configuration)
|
|
54
54
|
end
|
|
55
|
+
|
|
56
|
+
# Estimate the number of tokens in a string, using the rules of thumb from OpenAI:
|
|
57
|
+
# https://help.openai.com/en/articles/4936856-what-are-tokens-and-how-to-count-them
|
|
58
|
+
def self.rough_token_count(content = "")
|
|
59
|
+
raise ArgumentError, "rough_token_count requires a string" unless content.is_a? String
|
|
60
|
+
return 0 if content.empty?
|
|
61
|
+
|
|
62
|
+
count_by_chars = content.size / 4.0
|
|
63
|
+
count_by_words = content.split.size * 4.0 / 3
|
|
64
|
+
estimate = ((count_by_chars + count_by_words) / 2.0).round
|
|
65
|
+
[1, estimate].max
|
|
66
|
+
end
|
|
55
67
|
end
|
data/ruby-openai.gemspec
CHANGED
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
|
25
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
26
26
|
spec.require_paths = ["lib"]
|
|
27
27
|
|
|
28
|
+
spec.add_dependency "event_stream_parser", ">= 0.3.0", "< 1.0.0"
|
|
28
29
|
spec.add_dependency "faraday", ">= 1"
|
|
29
30
|
spec.add_dependency "faraday-multipart", ">= 1"
|
|
30
31
|
end
|
metadata
CHANGED
|
@@ -1,15 +1,35 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-openai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2023-
|
|
11
|
+
date: 2023-10-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: event_stream_parser
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 0.3.0
|
|
20
|
+
- - "<"
|
|
21
|
+
- !ruby/object:Gem::Version
|
|
22
|
+
version: 1.0.0
|
|
23
|
+
type: :runtime
|
|
24
|
+
prerelease: false
|
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
+
requirements:
|
|
27
|
+
- - ">="
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: 0.3.0
|
|
30
|
+
- - "<"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.0.0
|
|
13
33
|
- !ruby/object:Gem::Dependency
|
|
14
34
|
name: faraday
|
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,7 +58,7 @@ dependencies:
|
|
|
38
58
|
- - ">="
|
|
39
59
|
- !ruby/object:Gem::Version
|
|
40
60
|
version: '1'
|
|
41
|
-
description:
|
|
61
|
+
description:
|
|
42
62
|
email:
|
|
43
63
|
- alexrudall@users.noreply.github.com
|
|
44
64
|
executables: []
|
|
@@ -46,6 +66,10 @@ extensions: []
|
|
|
46
66
|
extra_rdoc_files: []
|
|
47
67
|
files:
|
|
48
68
|
- ".circleci/config.yml"
|
|
69
|
+
- ".devcontainer/Dockerfile"
|
|
70
|
+
- ".devcontainer/devcontainer.json"
|
|
71
|
+
- ".devcontainer/docker-compose.yml"
|
|
72
|
+
- ".github/FUNDING.yml"
|
|
49
73
|
- ".github/ISSUE_TEMPLATE/bug_report.md"
|
|
50
74
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
|
51
75
|
- ".github/dependabot.yml"
|
|
@@ -83,7 +107,7 @@ metadata:
|
|
|
83
107
|
source_code_uri: https://github.com/alexrudall/ruby-openai
|
|
84
108
|
changelog_uri: https://github.com/alexrudall/ruby-openai/blob/main/CHANGELOG.md
|
|
85
109
|
rubygems_mfa_required: 'true'
|
|
86
|
-
post_install_message:
|
|
110
|
+
post_install_message:
|
|
87
111
|
rdoc_options: []
|
|
88
112
|
require_paths:
|
|
89
113
|
- lib
|
|
@@ -98,8 +122,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
98
122
|
- !ruby/object:Gem::Version
|
|
99
123
|
version: '0'
|
|
100
124
|
requirements: []
|
|
101
|
-
rubygems_version: 3.4.
|
|
102
|
-
signing_key:
|
|
125
|
+
rubygems_version: 3.4.10
|
|
126
|
+
signing_key:
|
|
103
127
|
specification_version: 4
|
|
104
128
|
summary: "OpenAI API + Ruby! \U0001F916❤️"
|
|
105
129
|
test_files: []
|