ruby-openai 6.4.0 → 7.0.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/.circleci/config.yml +2 -1
- data/CHANGELOG.md +38 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +15 -15
- data/README.md +222 -54
- data/lib/openai/assistants.rb +1 -1
- data/lib/openai/batches.rb +23 -0
- data/lib/openai/client.rb +13 -5
- data/lib/openai/files.rb +36 -4
- data/lib/openai/http.rb +10 -4
- data/lib/openai/messages.rb +2 -2
- data/lib/openai/run_steps.rb +2 -2
- data/lib/openai/runs.rb +6 -2
- data/lib/openai/version.rb +1 -1
- data/lib/openai.rb +10 -9
- data/ruby-openai.gemspec +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8334c2f0658ff33f39e96e8316b5c7122ca8810f5bfaca945c8d5f1add38b85a
|
|
4
|
+
data.tar.gz: b761ed842f7c27ba7f3e6e3137f6d60f2d51cb1a32f585989fd2b1992d256b46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c53448def0a2a9849744a09c10f91fb4c16eb23fbf0d52be748574a9a96b05cb5641821c7728b9d95764cf50399f23c48bfdf3444d86ab80e65602e2264f6ba
|
|
7
|
+
data.tar.gz: 8806bbe03d2cde1b1fdfb691bcc2c4d803837faed6f001027135bdf9ed54a4bdf4eb01128c36d9d84b35622876ec087c494980e67b01a72a8ecb01040180cc72
|
data/.circleci/config.yml
CHANGED
|
@@ -8,7 +8,7 @@ jobs:
|
|
|
8
8
|
rubocop:
|
|
9
9
|
parallelism: 1
|
|
10
10
|
docker:
|
|
11
|
-
- image: cimg/ruby:3.
|
|
11
|
+
- image: cimg/ruby:3.2-node
|
|
12
12
|
steps:
|
|
13
13
|
- checkout
|
|
14
14
|
- ruby/install-deps
|
|
@@ -43,3 +43,4 @@ workflows:
|
|
|
43
43
|
- cimg/ruby:3.0-node
|
|
44
44
|
- cimg/ruby:3.1-node
|
|
45
45
|
- cimg/ruby:3.2-node
|
|
46
|
+
- cimg/ruby:3.3-node
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ 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
|
+
## [7.0.0] - 2024-04-27
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Add support for Batches, thanks to [@simonx1](https://github.com/simonx1) for the PR!
|
|
13
|
+
- Allow use of local LLMs like Ollama! Thanks to [@ThomasSevestre](https://github.com/ThomasSevestre)
|
|
14
|
+
- Update to v2 of the Assistants beta & add documentation on streaming from an Assistant.
|
|
15
|
+
- Add Assistants endpoint to create and run a thread in one go, thank you [@quocphien90](https://github.com/
|
|
16
|
+
quocphien90)
|
|
17
|
+
- Add missing parameters (order, limit, etc) to Runs, RunSteps and Messages - thanks to [@shalecraig](https://github.com/shalecraig) and [@coezbek](https://github.com/coezbek)
|
|
18
|
+
- Add missing Messages#list spec - thanks [@adammeghji](https://github.com/adammeghji)
|
|
19
|
+
- Add Messages#modify to README - thanks to [@nas887](https://github.com/nas887)
|
|
20
|
+
- Don't add the api_version (`/v1/`) to base_uris that already include it - thanks to [@kaiwren](https://github.com/kaiwren) for raising this issue
|
|
21
|
+
- Allow passing a `StringIO` to Files#upload - thanks again to [@simonx1](https://github.com/simonx1)
|
|
22
|
+
- Add Ruby 3.3 to CI
|
|
23
|
+
|
|
24
|
+
### Security
|
|
25
|
+
|
|
26
|
+
- [BREAKING] ruby-openai will no longer log out API errors by default - you can reenable by passing `log_errors: true` to your client. This will help to prevent leaking secrets to logs. Thanks to [@lalunamel](https://github.com/lalunamel) for this PR.
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
|
|
30
|
+
- [BREAKING] Remove deprecated edits endpoint.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Fix README DALL·E 3 error - thanks to [@clayton](https://github.com/clayton)
|
|
35
|
+
- Fix README tool_calls error and add missing tool_choice info - thanks to [@Jbrito6492](https://github.com/Jbrito6492)
|
|
36
|
+
|
|
37
|
+
## [6.5.0] - 2024-03-31
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- Add back the deprecated Completions endpoint that I removed a bit prematurely. Thanks, [@mishranant](https://github.com/
|
|
42
|
+
mishranant) and everyone who requested this.
|
|
43
|
+
|
|
8
44
|
## [6.4.0] - 2024-03-27
|
|
9
45
|
|
|
10
46
|
### Added
|
|
@@ -60,13 +96,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
60
96
|
- [BREAKING] Switch from legacy Finetunes to the new Fine-tune-jobs endpoints. Implemented by [@lancecarlson](https://github.com/lancecarlson)
|
|
61
97
|
- [BREAKING] Remove deprecated Completions endpoints - use Chat instead.
|
|
62
98
|
|
|
63
|
-
###
|
|
99
|
+
### Fixed
|
|
64
100
|
|
|
65
101
|
- [BREAKING] Fix issue where :stream parameters were replaced by a boolean in the client application. Thanks to [@martinjaimem](https://github.com/martinjaimem), [@vickymadrid03](https://github.com/vickymadrid03) and [@nicastelo](https://github.com/nicastelo) for spotting and fixing this issue.
|
|
66
102
|
|
|
67
103
|
## [5.2.0] - 2023-10-30
|
|
68
104
|
|
|
69
|
-
###
|
|
105
|
+
### Fixed
|
|
70
106
|
|
|
71
107
|
- Added more spec-compliant SSE parsing: see here https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
|
|
72
108
|
- Fixes issue where OpenAI or an intermediary returns only partial JSON per chunk of streamed data
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ruby-openai (
|
|
4
|
+
ruby-openai (7.0.0)
|
|
5
5
|
event_stream_parser (>= 0.3.0, < 2.0.0)
|
|
6
6
|
faraday (>= 1)
|
|
7
7
|
faraday-multipart (>= 1)
|
|
@@ -16,10 +16,10 @@ GEM
|
|
|
16
16
|
byebug (11.1.3)
|
|
17
17
|
crack (0.4.5)
|
|
18
18
|
rexml
|
|
19
|
-
diff-lcs (1.5.
|
|
19
|
+
diff-lcs (1.5.1)
|
|
20
20
|
dotenv (2.8.1)
|
|
21
21
|
event_stream_parser (1.0.0)
|
|
22
|
-
faraday (2.
|
|
22
|
+
faraday (2.8.1)
|
|
23
23
|
base64
|
|
24
24
|
faraday-net_http (>= 2.0, < 3.1)
|
|
25
25
|
ruby2_keywords (>= 0.0.4)
|
|
@@ -37,19 +37,19 @@ GEM
|
|
|
37
37
|
rake (13.1.0)
|
|
38
38
|
regexp_parser (2.8.0)
|
|
39
39
|
rexml (3.2.6)
|
|
40
|
-
rspec (3.
|
|
41
|
-
rspec-core (~> 3.
|
|
42
|
-
rspec-expectations (~> 3.
|
|
43
|
-
rspec-mocks (~> 3.
|
|
44
|
-
rspec-core (3.
|
|
45
|
-
rspec-support (~> 3.
|
|
46
|
-
rspec-expectations (3.
|
|
40
|
+
rspec (3.13.0)
|
|
41
|
+
rspec-core (~> 3.13.0)
|
|
42
|
+
rspec-expectations (~> 3.13.0)
|
|
43
|
+
rspec-mocks (~> 3.13.0)
|
|
44
|
+
rspec-core (3.13.0)
|
|
45
|
+
rspec-support (~> 3.13.0)
|
|
46
|
+
rspec-expectations (3.13.0)
|
|
47
47
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
48
|
-
rspec-support (~> 3.
|
|
49
|
-
rspec-mocks (3.
|
|
48
|
+
rspec-support (~> 3.13.0)
|
|
49
|
+
rspec-mocks (3.13.0)
|
|
50
50
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
51
|
-
rspec-support (~> 3.
|
|
52
|
-
rspec-support (3.
|
|
51
|
+
rspec-support (~> 3.13.0)
|
|
52
|
+
rspec-support (3.13.1)
|
|
53
53
|
rubocop (1.50.2)
|
|
54
54
|
json (~> 2.3)
|
|
55
55
|
parallel (~> 1.10)
|
|
@@ -78,7 +78,7 @@ DEPENDENCIES
|
|
|
78
78
|
byebug (~> 11.1.3)
|
|
79
79
|
dotenv (~> 2.8.1)
|
|
80
80
|
rake (~> 13.1)
|
|
81
|
-
rspec (~> 3.
|
|
81
|
+
rspec (~> 3.13)
|
|
82
82
|
rubocop (~> 1.50.2)
|
|
83
83
|
ruby-openai!
|
|
84
84
|
vcr (~> 6.1.0)
|
data/README.md
CHANGED
|
@@ -22,11 +22,13 @@ Stream text with GPT-4, transcribe and translate audio with Whisper, or create i
|
|
|
22
22
|
- [With Config](#with-config)
|
|
23
23
|
- [Custom timeout or base URI](#custom-timeout-or-base-uri)
|
|
24
24
|
- [Extra Headers per Client](#extra-headers-per-client)
|
|
25
|
-
- [
|
|
25
|
+
- [Logging](#logging)
|
|
26
|
+
- [Errors](#errors)
|
|
27
|
+
- [Faraday middleware](#faraday-middleware)
|
|
26
28
|
- [Azure](#azure)
|
|
29
|
+
- [Ollama](#ollama)
|
|
27
30
|
- [Counting Tokens](#counting-tokens)
|
|
28
31
|
- [Models](#models)
|
|
29
|
-
- [Examples](#examples)
|
|
30
32
|
- [Chat](#chat)
|
|
31
33
|
- [Streaming Chat](#streaming-chat)
|
|
32
34
|
- [Vision](#vision)
|
|
@@ -34,6 +36,7 @@ Stream text with GPT-4, transcribe and translate audio with Whisper, or create i
|
|
|
34
36
|
- [Functions](#functions)
|
|
35
37
|
- [Edits](#edits)
|
|
36
38
|
- [Embeddings](#embeddings)
|
|
39
|
+
- [Batches](#batches)
|
|
37
40
|
- [Files](#files)
|
|
38
41
|
- [Finetunes](#finetunes)
|
|
39
42
|
- [Assistants](#assistants)
|
|
@@ -146,6 +149,7 @@ or when configuring the gem:
|
|
|
146
149
|
```ruby
|
|
147
150
|
OpenAI.configure do |config|
|
|
148
151
|
config.access_token = ENV.fetch("OPENAI_ACCESS_TOKEN")
|
|
152
|
+
config.log_errors = true # Optional
|
|
149
153
|
config.organization_id = ENV.fetch("OPENAI_ORGANIZATION_ID") # Optional
|
|
150
154
|
config.uri_base = "https://oai.hconeai.com/" # Optional
|
|
151
155
|
config.request_timeout = 240 # Optional
|
|
@@ -166,7 +170,19 @@ client = OpenAI::Client.new(access_token: "access_token_goes_here")
|
|
|
166
170
|
client.add_headers("X-Proxy-TTL" => "43200")
|
|
167
171
|
```
|
|
168
172
|
|
|
169
|
-
####
|
|
173
|
+
#### Logging
|
|
174
|
+
|
|
175
|
+
##### Errors
|
|
176
|
+
|
|
177
|
+
By default, `ruby-openai` does not log any `Faraday::Error`s encountered while executing a network request to avoid leaking data (e.g. 400s, 500s, SSL errors and more - see [here](https://www.rubydoc.info/github/lostisland/faraday/Faraday/Error) for a complete list of subclasses of `Faraday::Error` and what can cause them).
|
|
178
|
+
|
|
179
|
+
If you would like to enable this functionality, you can set `log_errors` to `true` when configuring the client:
|
|
180
|
+
|
|
181
|
+
```ruby
|
|
182
|
+
client = OpenAI::Client.new(log_errors: true)
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
##### Faraday middleware
|
|
170
186
|
|
|
171
187
|
You can pass [Faraday middleware](https://lostisland.github.io/faraday/#/middleware/index) to the client in a block, eg. to enable verbose logging with Ruby's [Logger](https://ruby-doc.org/3.2.2/stdlibs/logger/Logger.html):
|
|
172
188
|
|
|
@@ -191,6 +207,38 @@ To use the [Azure OpenAI Service](https://learn.microsoft.com/en-us/azure/cognit
|
|
|
191
207
|
|
|
192
208
|
where `AZURE_OPENAI_URI` is e.g. `https://custom-domain.openai.azure.com/openai/deployments/gpt-35-turbo`
|
|
193
209
|
|
|
210
|
+
#### Ollama
|
|
211
|
+
|
|
212
|
+
Ollama allows you to run open-source LLMs, such as Llama 3, locally. It [offers chat compatibility](https://github.com/ollama/ollama/blob/main/docs/openai.md) with the OpenAI API.
|
|
213
|
+
|
|
214
|
+
You can download Ollama [here](https://ollama.com/). On macOS you can install and run Ollama like this:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
brew install ollama
|
|
218
|
+
ollama serve
|
|
219
|
+
ollama pull llama3:latest # In new terminal tab.
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Create a client using your Ollama server and the pulled model, and stream a conversation for free:
|
|
223
|
+
|
|
224
|
+
```ruby
|
|
225
|
+
client = OpenAI::Client.new(
|
|
226
|
+
uri_base: "http://localhost:11434"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
client.chat(
|
|
230
|
+
parameters: {
|
|
231
|
+
model: "llama3", # Required.
|
|
232
|
+
messages: [{ role: "user", content: "Hello!"}], # Required.
|
|
233
|
+
temperature: 0.7,
|
|
234
|
+
stream: proc do |chunk, _bytesize|
|
|
235
|
+
print chunk.dig("choices", 0, "delta", "content")
|
|
236
|
+
end
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
# => Hi! It's nice to meet you. Is there something I can help you with, or would you like to chat?
|
|
240
|
+
```
|
|
241
|
+
|
|
194
242
|
### Counting Tokens
|
|
195
243
|
|
|
196
244
|
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.
|
|
@@ -209,24 +257,9 @@ There are different models that can be used to generate text. For a full list an
|
|
|
209
257
|
|
|
210
258
|
```ruby
|
|
211
259
|
client.models.list
|
|
212
|
-
client.models.retrieve(id: "
|
|
260
|
+
client.models.retrieve(id: "gpt-3.5-turbo")
|
|
213
261
|
```
|
|
214
262
|
|
|
215
|
-
#### Examples
|
|
216
|
-
|
|
217
|
-
- [GPT-4 (limited beta)](https://platform.openai.com/docs/models/gpt-4)
|
|
218
|
-
- gpt-4 (uses current version)
|
|
219
|
-
- gpt-4-0314
|
|
220
|
-
- gpt-4-32k
|
|
221
|
-
- [GPT-3.5](https://platform.openai.com/docs/models/gpt-3-5)
|
|
222
|
-
- gpt-3.5-turbo
|
|
223
|
-
- gpt-3.5-turbo-0301
|
|
224
|
-
- text-davinci-003
|
|
225
|
-
- [GPT-3](https://platform.openai.com/docs/models/gpt-3)
|
|
226
|
-
- text-ada-001
|
|
227
|
-
- text-babbage-001
|
|
228
|
-
- text-curie-001
|
|
229
|
-
|
|
230
263
|
### Chat
|
|
231
264
|
|
|
232
265
|
GPT is a model that can be used to generate text in a conversational style. You can use it to [generate a response](https://platform.openai.com/docs/api-reference/chat/create) to a sequence of [messages](https://platform.openai.com/docs/guides/chat/introduction):
|
|
@@ -338,9 +371,10 @@ You can stream it as well!
|
|
|
338
371
|
|
|
339
372
|
### Functions
|
|
340
373
|
|
|
341
|
-
You can describe and pass in functions and the model will intelligently choose to output a JSON object containing arguments to call
|
|
374
|
+
You can describe and pass in functions and the model will intelligently choose to output a JSON object containing arguments to call them - eg., to use your method `get_current_weather` to get the weather in a given location. Note that tool_choice is optional, but if you exclude it, the model will choose whether to use the function or not ([see here](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tool_choice)).
|
|
342
375
|
|
|
343
376
|
```ruby
|
|
377
|
+
|
|
344
378
|
def get_current_weather(location:, unit: "fahrenheit")
|
|
345
379
|
# use a weather api to fetch weather
|
|
346
380
|
end
|
|
@@ -348,7 +382,7 @@ end
|
|
|
348
382
|
response =
|
|
349
383
|
client.chat(
|
|
350
384
|
parameters: {
|
|
351
|
-
model: "gpt-3.5-turbo
|
|
385
|
+
model: "gpt-3.5-turbo",
|
|
352
386
|
messages: [
|
|
353
387
|
{
|
|
354
388
|
"role": "user",
|
|
@@ -378,16 +412,22 @@ response =
|
|
|
378
412
|
},
|
|
379
413
|
}
|
|
380
414
|
],
|
|
415
|
+
tool_choice: {
|
|
416
|
+
type: "function",
|
|
417
|
+
function: {
|
|
418
|
+
name: "get_current_weather"
|
|
419
|
+
}
|
|
420
|
+
}
|
|
381
421
|
},
|
|
382
422
|
)
|
|
383
423
|
|
|
384
424
|
message = response.dig("choices", 0, "message")
|
|
385
425
|
|
|
386
426
|
if message["role"] == "assistant" && message["tool_calls"]
|
|
387
|
-
function_name = message.dig("tool_calls", "function",
|
|
427
|
+
function_name = message.dig("tool_calls", 0, "function", "name")
|
|
388
428
|
args =
|
|
389
429
|
JSON.parse(
|
|
390
|
-
message.dig("tool_calls", "function", "arguments"),
|
|
430
|
+
message.dig("tool_calls", 0, "function", "arguments"),
|
|
391
431
|
{ symbolize_names: true },
|
|
392
432
|
)
|
|
393
433
|
|
|
@@ -399,20 +439,19 @@ end
|
|
|
399
439
|
# => "The weather is nice 🌞"
|
|
400
440
|
```
|
|
401
441
|
|
|
402
|
-
###
|
|
442
|
+
### Completions
|
|
403
443
|
|
|
404
|
-
|
|
444
|
+
Hit the OpenAI API for a completion using other GPT-3 models:
|
|
405
445
|
|
|
406
446
|
```ruby
|
|
407
|
-
response = client.
|
|
447
|
+
response = client.completions(
|
|
408
448
|
parameters: {
|
|
409
|
-
model: "
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
# => What day of the week is it?
|
|
449
|
+
model: "gpt-3.5-turbo",
|
|
450
|
+
prompt: "Once upon a time",
|
|
451
|
+
max_tokens: 5
|
|
452
|
+
})
|
|
453
|
+
puts response["choices"].map { |c| c["text"] }
|
|
454
|
+
# => [", there lived a great"]
|
|
416
455
|
```
|
|
417
456
|
|
|
418
457
|
### Embeddings
|
|
@@ -431,6 +470,94 @@ puts response.dig("data", 0, "embedding")
|
|
|
431
470
|
# => Vector representation of your embedding
|
|
432
471
|
```
|
|
433
472
|
|
|
473
|
+
### Batches
|
|
474
|
+
|
|
475
|
+
The Batches endpoint allows you to create and manage large batches of API requests to run asynchronously. Currently, only the `/v1/chat/completions` endpoint is supported for batches.
|
|
476
|
+
|
|
477
|
+
To use the Batches endpoint, you need to first upload a JSONL file containing the batch requests using the Files endpoint. The file must be uploaded with the purpose set to `batch`. Each line in the JSONL file represents a single request and should have the following format:
|
|
478
|
+
|
|
479
|
+
```json
|
|
480
|
+
{
|
|
481
|
+
"custom_id": "request-1",
|
|
482
|
+
"method": "POST",
|
|
483
|
+
"url": "/v1/chat/completions",
|
|
484
|
+
"body": {
|
|
485
|
+
"model": "gpt-3.5-turbo",
|
|
486
|
+
"messages": [
|
|
487
|
+
{ "role": "system", "content": "You are a helpful assistant." },
|
|
488
|
+
{ "role": "user", "content": "What is 2+2?" }
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
Once you have uploaded the JSONL file, you can create a new batch by providing the file ID, endpoint, and completion window:
|
|
495
|
+
|
|
496
|
+
```ruby
|
|
497
|
+
response = client.batches.create(
|
|
498
|
+
parameters: {
|
|
499
|
+
input_file_id: "file-abc123",
|
|
500
|
+
endpoint: "/v1/chat/completions",
|
|
501
|
+
completion_window: "24h"
|
|
502
|
+
}
|
|
503
|
+
)
|
|
504
|
+
batch_id = response["id"]
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
You can retrieve information about a specific batch using its ID:
|
|
508
|
+
|
|
509
|
+
```ruby
|
|
510
|
+
batch = client.batches.retrieve(id: batch_id)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
To cancel a batch that is in progress:
|
|
514
|
+
|
|
515
|
+
```ruby
|
|
516
|
+
client.batches.cancel(id: batch_id)
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
You can also list all the batches:
|
|
520
|
+
|
|
521
|
+
```ruby
|
|
522
|
+
client.batches.list
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Once the batch["completed_at"] is present, you can fetch the output or error files:
|
|
526
|
+
|
|
527
|
+
```ruby
|
|
528
|
+
batch = client.batches.retrieve(id: batch_id)
|
|
529
|
+
output_file_id = batch["output_file_id"]
|
|
530
|
+
output_response = client.files.content(id: output_file_id)
|
|
531
|
+
error_file_id = batch["error_file_id"]
|
|
532
|
+
error_response = client.files.content(id: error_file_id)
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
These files are in JSONL format, with each line representing the output or error for a single request. The lines can be in any order:
|
|
536
|
+
|
|
537
|
+
```json
|
|
538
|
+
{
|
|
539
|
+
"id": "response-1",
|
|
540
|
+
"custom_id": "request-1",
|
|
541
|
+
"response": {
|
|
542
|
+
"id": "chatcmpl-abc123",
|
|
543
|
+
"object": "chat.completion",
|
|
544
|
+
"created": 1677858242,
|
|
545
|
+
"model": "gpt-3.5-turbo-0301",
|
|
546
|
+
"choices": [
|
|
547
|
+
{
|
|
548
|
+
"index": 0,
|
|
549
|
+
"message": {
|
|
550
|
+
"role": "assistant",
|
|
551
|
+
"content": "2+2 equals 4."
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
]
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
If a request fails with a non-HTTP error, the error object will contain more information about the cause of the failure.
|
|
560
|
+
|
|
434
561
|
### Files
|
|
435
562
|
|
|
436
563
|
Put your data in a `.jsonl` file like this:
|
|
@@ -440,7 +567,7 @@ Put your data in a `.jsonl` file like this:
|
|
|
440
567
|
{"prompt":"@lakers disappoint for a third straight night ->", "completion":" negative"}
|
|
441
568
|
```
|
|
442
569
|
|
|
443
|
-
and pass the path to `client.files.upload` to upload it to OpenAI, and then interact with it:
|
|
570
|
+
and pass the path (or a StringIO object) to `client.files.upload` to upload it to OpenAI, and then interact with it:
|
|
444
571
|
|
|
445
572
|
```ruby
|
|
446
573
|
client.files.upload(parameters: { file: "path/to/sentiment.jsonl", purpose: "fine-tune" })
|
|
@@ -465,7 +592,7 @@ You can then use this file ID to create a fine tuning job:
|
|
|
465
592
|
response = client.finetunes.create(
|
|
466
593
|
parameters: {
|
|
467
594
|
training_file: file_id,
|
|
468
|
-
model: "gpt-3.5-turbo
|
|
595
|
+
model: "gpt-3.5-turbo"
|
|
469
596
|
})
|
|
470
597
|
fine_tune_id = response["id"]
|
|
471
598
|
```
|
|
@@ -504,9 +631,9 @@ client.finetunes.list_events(id: fine_tune_id)
|
|
|
504
631
|
|
|
505
632
|
### Assistants
|
|
506
633
|
|
|
507
|
-
Assistants
|
|
634
|
+
Assistants are stateful actors that can have many conversations and use tools to perform tasks (see [Assistant Overview](https://platform.openai.com/docs/assistants/overview)).
|
|
508
635
|
|
|
509
|
-
To create a new assistant
|
|
636
|
+
To create a new assistant:
|
|
510
637
|
|
|
511
638
|
```ruby
|
|
512
639
|
response = client.assistants.create(
|
|
@@ -590,17 +717,36 @@ client.messages.retrieve(thread_id: thread_id, id: message_id) # -> Fails after
|
|
|
590
717
|
|
|
591
718
|
### Runs
|
|
592
719
|
|
|
593
|
-
To submit a thread to be evaluated with the model of an assistant, create a `Run` as follows
|
|
720
|
+
To submit a thread to be evaluated with the model of an assistant, create a `Run` as follows:
|
|
594
721
|
|
|
595
722
|
```ruby
|
|
596
723
|
# Create run (will use instruction/model/tools from Assistant's definition)
|
|
597
724
|
response = client.runs.create(thread_id: thread_id,
|
|
598
725
|
parameters: {
|
|
599
|
-
assistant_id: assistant_id
|
|
726
|
+
assistant_id: assistant_id,
|
|
727
|
+
max_prompt_tokens: 256,
|
|
728
|
+
max_completion_tokens: 16
|
|
600
729
|
})
|
|
601
730
|
run_id = response['id']
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
You can stream the message chunks as they come through:
|
|
602
734
|
|
|
603
|
-
|
|
735
|
+
```ruby
|
|
736
|
+
client.runs.create(thread_id: thread_id,
|
|
737
|
+
parameters: {
|
|
738
|
+
assistant_id: assistant_id,
|
|
739
|
+
max_prompt_tokens: 256,
|
|
740
|
+
max_completion_tokens: 16,
|
|
741
|
+
stream: proc do |chunk, _bytesize|
|
|
742
|
+
print chunk.dig("delta", "content", 0, "text", "value") if chunk["object"] == "thread.message.delta"
|
|
743
|
+
end
|
|
744
|
+
})
|
|
745
|
+
```
|
|
746
|
+
|
|
747
|
+
To get the status of a Run:
|
|
748
|
+
|
|
749
|
+
```
|
|
604
750
|
response = client.runs.retrieve(id: run_id, thread_id: thread_id)
|
|
605
751
|
status = response['status']
|
|
606
752
|
```
|
|
@@ -609,23 +755,22 @@ The `status` response can include the following strings `queued`, `in_progress`,
|
|
|
609
755
|
|
|
610
756
|
```ruby
|
|
611
757
|
while true do
|
|
612
|
-
|
|
613
758
|
response = client.runs.retrieve(id: run_id, thread_id: thread_id)
|
|
614
759
|
status = response['status']
|
|
615
760
|
|
|
616
761
|
case status
|
|
617
762
|
when 'queued', 'in_progress', 'cancelling'
|
|
618
|
-
|
|
619
|
-
|
|
763
|
+
puts 'Sleeping'
|
|
764
|
+
sleep 1 # Wait one second and poll again
|
|
620
765
|
when 'completed'
|
|
621
|
-
|
|
766
|
+
break # Exit loop and report result to user
|
|
622
767
|
when 'requires_action'
|
|
623
|
-
|
|
768
|
+
# Handle tool calls (see below)
|
|
624
769
|
when 'cancelled', 'failed', 'expired'
|
|
625
|
-
|
|
626
|
-
|
|
770
|
+
puts response['last_error'].inspect
|
|
771
|
+
break # or `exit`
|
|
627
772
|
else
|
|
628
|
-
|
|
773
|
+
puts "Unknown status response: #{status}"
|
|
629
774
|
end
|
|
630
775
|
end
|
|
631
776
|
```
|
|
@@ -634,10 +779,10 @@ If the `status` response indicates that the `run` is `completed`, the associated
|
|
|
634
779
|
|
|
635
780
|
```ruby
|
|
636
781
|
# Either retrieve all messages in bulk again, or...
|
|
637
|
-
messages = client.messages.list(thread_id: thread_id
|
|
782
|
+
messages = client.messages.list(thread_id: thread_id, parameters: { order: 'asc' })
|
|
638
783
|
|
|
639
784
|
# Alternatively retrieve the `run steps` for the run which link to the messages:
|
|
640
|
-
run_steps = client.run_steps.list(thread_id: thread_id, run_id: run_id)
|
|
785
|
+
run_steps = client.run_steps.list(thread_id: thread_id, run_id: run_id, parameters: { order: 'asc' })
|
|
641
786
|
new_message_ids = run_steps['data'].filter_map { |step|
|
|
642
787
|
if step['type'] == 'message_creation'
|
|
643
788
|
step.dig('step_details', "message_creation", "message_id")
|
|
@@ -664,10 +809,33 @@ new_messages.each { |msg|
|
|
|
664
809
|
}
|
|
665
810
|
```
|
|
666
811
|
|
|
667
|
-
|
|
812
|
+
You can also update the metadata on messages, including messages that come from the assistant.
|
|
668
813
|
|
|
669
814
|
```ruby
|
|
670
|
-
|
|
815
|
+
metadata = {
|
|
816
|
+
user_id: "abc123"
|
|
817
|
+
}
|
|
818
|
+
message = client.messages.modify(id: message_id, thread_id: thread_id, parameters: { metadata: metadata })
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
At any time you can list all runs which have been performed on a particular thread or are currently running:
|
|
822
|
+
|
|
823
|
+
```ruby
|
|
824
|
+
client.runs.list(thread_id: thread_id, parameters: { order: "asc", limit: 3 })
|
|
825
|
+
```
|
|
826
|
+
|
|
827
|
+
#### Create and Run
|
|
828
|
+
|
|
829
|
+
You can also create a thread and run in one call like this:
|
|
830
|
+
|
|
831
|
+
```ruby
|
|
832
|
+
response = client.threads.create_and_run(
|
|
833
|
+
parameters: {
|
|
834
|
+
model: 'gpt-3.5-turbo',
|
|
835
|
+
messages: [{ role: 'user', content: "What's deep learning?"}]
|
|
836
|
+
})
|
|
837
|
+
run_id = response['id']
|
|
838
|
+
thread_id = response['thread_id']
|
|
671
839
|
```
|
|
672
840
|
|
|
673
841
|
#### Runs involving function tools
|
|
@@ -731,7 +899,7 @@ puts response.dig("data", 0, "url")
|
|
|
731
899
|
For DALL·E 3 the size of any generated images must be one of `1024x1024`, `1024x1792` or `1792x1024`. Additionally the quality of the image can be specified to either `standard` or `hd`.
|
|
732
900
|
|
|
733
901
|
```ruby
|
|
734
|
-
response = client.images.generate(parameters: { prompt: "A springer spaniel cooking pasta wearing a hat of some sort", size: "1024x1792", quality: "standard" })
|
|
902
|
+
response = client.images.generate(parameters: { prompt: "A springer spaniel cooking pasta wearing a hat of some sort", model: "dall-e-3", size: "1024x1792", quality: "standard" })
|
|
735
903
|
puts response.dig("data", 0, "url")
|
|
736
904
|
# => "https://oaidalleapiprodscus.blob.core.windows.net/private/org-Rf437IxKhh..."
|
|
737
905
|
```
|
|
@@ -830,7 +998,7 @@ HTTP errors can be caught like this:
|
|
|
830
998
|
|
|
831
999
|
```
|
|
832
1000
|
begin
|
|
833
|
-
OpenAI::Client.new.models.retrieve(id: "
|
|
1001
|
+
OpenAI::Client.new.models.retrieve(id: "gpt-3.5-turbo")
|
|
834
1002
|
rescue Faraday::Error => e
|
|
835
1003
|
raise "Got a Faraday error: #{e}"
|
|
836
1004
|
end
|
data/lib/openai/assistants.rb
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module OpenAI
|
|
2
|
+
class Batches
|
|
3
|
+
def initialize(client:)
|
|
4
|
+
@client = client.beta(assistants: "v1")
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def list
|
|
8
|
+
@client.get(path: "/batches")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def retrieve(id:)
|
|
12
|
+
@client.get(path: "/batches/#{id}")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(parameters: {})
|
|
16
|
+
@client.json_post(path: "/batches", parameters: parameters)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def cancel(id:)
|
|
20
|
+
@client.post(path: "/batches/#{id}/cancel")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/openai/client.rb
CHANGED
|
@@ -6,6 +6,7 @@ module OpenAI
|
|
|
6
6
|
api_type
|
|
7
7
|
api_version
|
|
8
8
|
access_token
|
|
9
|
+
log_errors
|
|
9
10
|
organization_id
|
|
10
11
|
uri_base
|
|
11
12
|
request_timeout
|
|
@@ -17,7 +18,10 @@ module OpenAI
|
|
|
17
18
|
CONFIG_KEYS.each do |key|
|
|
18
19
|
# Set instance variables like api_type & access_token. Fall back to global config
|
|
19
20
|
# if not present.
|
|
20
|
-
instance_variable_set(
|
|
21
|
+
instance_variable_set(
|
|
22
|
+
"@#{key}",
|
|
23
|
+
config[key].nil? ? OpenAI.configuration.send(key) : config[key]
|
|
24
|
+
)
|
|
21
25
|
end
|
|
22
26
|
@faraday_middleware = faraday_middleware
|
|
23
27
|
end
|
|
@@ -26,14 +30,14 @@ module OpenAI
|
|
|
26
30
|
json_post(path: "/chat/completions", parameters: parameters)
|
|
27
31
|
end
|
|
28
32
|
|
|
29
|
-
def edits(parameters: {})
|
|
30
|
-
json_post(path: "/edits", parameters: parameters)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
33
|
def embeddings(parameters: {})
|
|
34
34
|
json_post(path: "/embeddings", parameters: parameters)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
def completions(parameters: {})
|
|
38
|
+
json_post(path: "/completions", parameters: parameters)
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
def audio
|
|
38
42
|
@audio ||= OpenAI::Audio.new(client: self)
|
|
39
43
|
end
|
|
@@ -74,6 +78,10 @@ module OpenAI
|
|
|
74
78
|
@run_steps ||= OpenAI::RunSteps.new(client: self)
|
|
75
79
|
end
|
|
76
80
|
|
|
81
|
+
def batches
|
|
82
|
+
@batches ||= OpenAI::Batches.new(client: self)
|
|
83
|
+
end
|
|
84
|
+
|
|
77
85
|
def moderations(parameters: {})
|
|
78
86
|
json_post(path: "/moderations", parameters: parameters)
|
|
79
87
|
end
|
data/lib/openai/files.rb
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
module OpenAI
|
|
2
2
|
class Files
|
|
3
|
+
PURPOSES = %w[
|
|
4
|
+
assistants
|
|
5
|
+
batch
|
|
6
|
+
fine-tune
|
|
7
|
+
].freeze
|
|
8
|
+
|
|
3
9
|
def initialize(client:)
|
|
4
10
|
@client = client
|
|
5
11
|
end
|
|
@@ -9,12 +15,17 @@ module OpenAI
|
|
|
9
15
|
end
|
|
10
16
|
|
|
11
17
|
def upload(parameters: {})
|
|
12
|
-
|
|
18
|
+
file_input = parameters[:file]
|
|
19
|
+
file = prepare_file_input(file_input: file_input)
|
|
20
|
+
|
|
21
|
+
validate(file: file, purpose: parameters[:purpose], file_input: file_input)
|
|
13
22
|
|
|
14
23
|
@client.multipart_post(
|
|
15
24
|
path: "/files",
|
|
16
|
-
parameters: parameters.merge(file:
|
|
25
|
+
parameters: parameters.merge(file: file)
|
|
17
26
|
)
|
|
27
|
+
ensure
|
|
28
|
+
file.close if file.is_a?(File)
|
|
18
29
|
end
|
|
19
30
|
|
|
20
31
|
def retrieve(id:)
|
|
@@ -31,12 +42,33 @@ module OpenAI
|
|
|
31
42
|
|
|
32
43
|
private
|
|
33
44
|
|
|
34
|
-
def
|
|
35
|
-
|
|
45
|
+
def prepare_file_input(file_input:)
|
|
46
|
+
if file_input.is_a?(String)
|
|
47
|
+
File.open(file_input)
|
|
48
|
+
elsif file_input.respond_to?(:read) && file_input.respond_to?(:rewind)
|
|
49
|
+
file_input
|
|
50
|
+
else
|
|
51
|
+
raise ArgumentError, "Invalid file - must be a StringIO object or a path to a file."
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def validate(file:, purpose:, file_input:)
|
|
56
|
+
raise ArgumentError, "`file` is required" if file.nil?
|
|
57
|
+
unless PURPOSES.include?(purpose)
|
|
58
|
+
raise ArgumentError, "`purpose` must be one of `#{PURPOSES.join(',')}`"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
validate_jsonl(file: file) if file_input.is_a?(String) && file_input.end_with?(".jsonl")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def validate_jsonl(file:)
|
|
65
|
+
file.each_line.with_index do |line, index|
|
|
36
66
|
JSON.parse(line)
|
|
37
67
|
rescue JSON::ParserError => e
|
|
38
68
|
raise JSON::ParserError, "#{e.message} - found on line #{index + 1} of #{file}"
|
|
39
69
|
end
|
|
70
|
+
ensure
|
|
71
|
+
file.rewind
|
|
40
72
|
end
|
|
41
73
|
end
|
|
42
74
|
end
|
data/lib/openai/http.rb
CHANGED
|
@@ -6,8 +6,8 @@ module OpenAI
|
|
|
6
6
|
module HTTP
|
|
7
7
|
include HTTPHeaders
|
|
8
8
|
|
|
9
|
-
def get(path:)
|
|
10
|
-
parse_jsonl(conn.get(uri(path: path)) do |req|
|
|
9
|
+
def get(path:, parameters: nil)
|
|
10
|
+
parse_jsonl(conn.get(uri(path: path), parameters) do |req|
|
|
11
11
|
req.headers = headers
|
|
12
12
|
end&.body)
|
|
13
13
|
end
|
|
@@ -74,7 +74,7 @@ module OpenAI
|
|
|
74
74
|
connection = Faraday.new do |f|
|
|
75
75
|
f.options[:timeout] = @request_timeout
|
|
76
76
|
f.request(:multipart) if multipart
|
|
77
|
-
f.use MiddlewareErrors
|
|
77
|
+
f.use MiddlewareErrors if @log_errors
|
|
78
78
|
f.response :raise_error
|
|
79
79
|
f.response :json
|
|
80
80
|
end
|
|
@@ -88,6 +88,8 @@ module OpenAI
|
|
|
88
88
|
if azure?
|
|
89
89
|
base = File.join(@uri_base, path)
|
|
90
90
|
"#{base}?api-version=#{@api_version}"
|
|
91
|
+
elsif @uri_base.include?(@api_version)
|
|
92
|
+
File.join(@uri_base, path)
|
|
91
93
|
else
|
|
92
94
|
File.join(@uri_base, @api_version, path)
|
|
93
95
|
end
|
|
@@ -97,10 +99,14 @@ module OpenAI
|
|
|
97
99
|
parameters&.transform_values do |value|
|
|
98
100
|
next value unless value.respond_to?(:close) # File or IO object.
|
|
99
101
|
|
|
102
|
+
# Faraday::UploadIO does not require a path, so we will pass it
|
|
103
|
+
# only if it is available. This allows StringIO objects to be
|
|
104
|
+
# passed in as well.
|
|
105
|
+
path = value.respond_to?(:path) ? value.path : nil
|
|
100
106
|
# Doesn't seem like OpenAI needs mime_type yet, so not worth
|
|
101
107
|
# the library to figure this out. Hence the empty string
|
|
102
108
|
# as the second argument.
|
|
103
|
-
Faraday::UploadIO.new(value, "",
|
|
109
|
+
Faraday::UploadIO.new(value, "", path)
|
|
104
110
|
end
|
|
105
111
|
end
|
|
106
112
|
|
data/lib/openai/messages.rb
CHANGED
|
@@ -4,8 +4,8 @@ module OpenAI
|
|
|
4
4
|
@client = client.beta(assistants: "v1")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def list(thread_id:)
|
|
8
|
-
@client.get(path: "/threads/#{thread_id}/messages")
|
|
7
|
+
def list(thread_id:, parameters: {})
|
|
8
|
+
@client.get(path: "/threads/#{thread_id}/messages", parameters: parameters)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def retrieve(thread_id:, id:)
|
data/lib/openai/run_steps.rb
CHANGED
|
@@ -4,8 +4,8 @@ module OpenAI
|
|
|
4
4
|
@client = client.beta(assistants: "v1")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def list(thread_id:, run_id:)
|
|
8
|
-
@client.get(path: "/threads/#{thread_id}/runs/#{run_id}/steps")
|
|
7
|
+
def list(thread_id:, run_id:, parameters: {})
|
|
8
|
+
@client.get(path: "/threads/#{thread_id}/runs/#{run_id}/steps", parameters: parameters)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def retrieve(thread_id:, run_id:, id:)
|
data/lib/openai/runs.rb
CHANGED
|
@@ -4,8 +4,8 @@ module OpenAI
|
|
|
4
4
|
@client = client.beta(assistants: "v1")
|
|
5
5
|
end
|
|
6
6
|
|
|
7
|
-
def list(thread_id:)
|
|
8
|
-
@client.get(path: "/threads/#{thread_id}/runs")
|
|
7
|
+
def list(thread_id:, parameters: {})
|
|
8
|
+
@client.get(path: "/threads/#{thread_id}/runs", parameters: parameters)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def retrieve(thread_id:, id:)
|
|
@@ -24,6 +24,10 @@ module OpenAI
|
|
|
24
24
|
@client.post(path: "/threads/#{thread_id}/runs/#{id}/cancel")
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
def create_thread_and_run(parameters: {})
|
|
28
|
+
@client.json_post(path: "/threads/runs", parameters: parameters)
|
|
29
|
+
end
|
|
30
|
+
|
|
27
31
|
def submit_tool_outputs(thread_id:, run_id:, parameters: {})
|
|
28
32
|
@client.json_post(path: "/threads/#{thread_id}/runs/#{run_id}/submit_tool_outputs",
|
|
29
33
|
parameters: parameters)
|
data/lib/openai/version.rb
CHANGED
data/lib/openai.rb
CHANGED
|
@@ -14,6 +14,7 @@ require_relative "openai/runs"
|
|
|
14
14
|
require_relative "openai/run_steps"
|
|
15
15
|
require_relative "openai/audio"
|
|
16
16
|
require_relative "openai/version"
|
|
17
|
+
require_relative "openai/batches"
|
|
17
18
|
|
|
18
19
|
module OpenAI
|
|
19
20
|
class Error < StandardError; end
|
|
@@ -36,30 +37,30 @@ module OpenAI
|
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
class Configuration
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
attr_accessor :access_token,
|
|
41
|
+
:api_type,
|
|
42
|
+
:api_version,
|
|
43
|
+
:log_errors,
|
|
44
|
+
:organization_id,
|
|
45
|
+
:uri_base,
|
|
46
|
+
:request_timeout,
|
|
41
47
|
:extra_headers
|
|
42
48
|
|
|
43
49
|
DEFAULT_API_VERSION = "v1".freeze
|
|
44
50
|
DEFAULT_URI_BASE = "https://api.openai.com/".freeze
|
|
45
51
|
DEFAULT_REQUEST_TIMEOUT = 120
|
|
52
|
+
DEFAULT_LOG_ERRORS = false
|
|
46
53
|
|
|
47
54
|
def initialize
|
|
48
55
|
@access_token = nil
|
|
49
56
|
@api_type = nil
|
|
50
57
|
@api_version = DEFAULT_API_VERSION
|
|
58
|
+
@log_errors = DEFAULT_LOG_ERRORS
|
|
51
59
|
@organization_id = nil
|
|
52
60
|
@uri_base = DEFAULT_URI_BASE
|
|
53
61
|
@request_timeout = DEFAULT_REQUEST_TIMEOUT
|
|
54
62
|
@extra_headers = {}
|
|
55
63
|
end
|
|
56
|
-
|
|
57
|
-
def access_token
|
|
58
|
-
return @access_token if @access_token
|
|
59
|
-
|
|
60
|
-
error_text = "OpenAI access token missing! See https://github.com/alexrudall/ruby-openai#usage"
|
|
61
|
-
raise ConfigurationError, error_text
|
|
62
|
-
end
|
|
63
64
|
end
|
|
64
65
|
|
|
65
66
|
class << self
|
data/ruby-openai.gemspec
CHANGED
|
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.authors = ["Alex"]
|
|
7
7
|
spec.email = ["alexrudall@users.noreply.github.com"]
|
|
8
8
|
|
|
9
|
-
spec.summary = "OpenAI API + Ruby!
|
|
9
|
+
spec.summary = "OpenAI API + Ruby! 🤖❤️"
|
|
10
10
|
spec.homepage = "https://github.com/alexrudall/ruby-openai"
|
|
11
11
|
spec.license = "MIT"
|
|
12
12
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-openai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 7.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-04-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: event_stream_parser
|
|
@@ -89,6 +89,7 @@ files:
|
|
|
89
89
|
- lib/openai.rb
|
|
90
90
|
- lib/openai/assistants.rb
|
|
91
91
|
- lib/openai/audio.rb
|
|
92
|
+
- lib/openai/batches.rb
|
|
92
93
|
- lib/openai/client.rb
|
|
93
94
|
- lib/openai/compatibility.rb
|
|
94
95
|
- lib/openai/files.rb
|
|
@@ -129,8 +130,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
129
130
|
- !ruby/object:Gem::Version
|
|
130
131
|
version: '0'
|
|
131
132
|
requirements: []
|
|
132
|
-
rubygems_version: 3.
|
|
133
|
+
rubygems_version: 3.5.9
|
|
133
134
|
signing_key:
|
|
134
135
|
specification_version: 4
|
|
135
|
-
summary: "OpenAI API + Ruby! \U0001F916
|
|
136
|
+
summary: "OpenAI API + Ruby! \U0001F916❤️"
|
|
136
137
|
test_files: []
|