gpt-function 0.3.0 → 0.5.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: c103f09f18b5ef5a39f26b5ede8a3948dd4b2305fb754908c6b090c7f78d1e79
4
- data.tar.gz: 686b1a27e1f955b45827abedcd665662c07386eb0008d6ad012a81a0dff6aedd
3
+ metadata.gz: 4382f4c9861d57510b154ab5179854eee8fad548dd849f3b283d870f736e599e
4
+ data.tar.gz: 498b2499d3d6ecdb03847a6b5c15f9d2f99c231d59655f3cf8a602898d525102
5
5
  SHA512:
6
- metadata.gz: 2237aa77cb338408e6d237c07036d9d7998f356939e292e481305a760386c9282b34b683d6c3ba41b51b6fbb911802077804a563372beaab4c0bfcf48d357ee0
7
- data.tar.gz: 0573a13abda0ae4a58c5b5cdfa0bdbf4062a68aba8b04802773c0efc8192728ce0ffa0bf30b8feddd70b2fb910b3b5248f6f55b3d40da94352e261febb8c9771
6
+ metadata.gz: 6ba7a96725e99edb9d87f9467011357fbd8e8e40dc62f902420b480334af7b432bf071e1b63df7ce5e0645611bcb6355caff08d275e9905a21a638ec6033cc06
7
+ data.tar.gz: 680facff33d5f9737fb4dbc6cfc10a08e35f221245cb1e90c82a3e280c4ed32a0f1129d52561e471ca210f984a4c973b671aec01445d7776fdb5815e1d25339b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gpt-function (0.3.0)
4
+ gpt-function (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -27,27 +27,94 @@ gem 'gpt-function'
27
27
  require 'gpt-function'
28
28
 
29
29
  # 你需要設定你的 api key 和 model name
30
- Gpt::Function.configure(api_key: '...', model: 'gpt-3.5-turbo-1106')
30
+ GptFunction.configure(api_key: '...', model: 'gpt-4o-mini', batch_storage: MyBatchStorage)
31
31
 
32
32
  # 使用內建的翻譯方法
33
- p Gpt::Functions.翻譯成中文("banana") # "香蕉"
33
+ p GptFunctions.翻譯成中文.call("banana") # "香蕉"
34
34
 
35
35
  # 使用內建的擷取關鍵字方法
36
- p Gpt::Functions.擷取關鍵字("臺北市政府推動綠色交通計劃,鼓勵民眾使用公共運輸和自行車") # ["臺北市政府", "綠色交通計劃", "民眾", "公共運輸", "自行車"]
36
+ p GptFunctions.擷取關鍵字.call("臺北市政府推動綠色交通計劃,鼓勵民眾使用公共運輸和自行車") # ["臺北市政府", "綠色交通計劃", "民眾", "公共運輸", "自行車"]
37
37
 
38
38
  # 你也可以自己定義方法
39
- def 擷取關鍵字(input)
39
+ def 擷取關鍵字
40
40
  # 創建一個簡單的 GPT 函數,你需要描述這個函數的功能,以及提供一些範例
41
- Gpt::Function.new("Extract all keywords",
41
+ GptFunction.new("Extract all keywords",
42
42
  [
43
43
  [
44
44
  "臺灣最新5G網路覆蓋率達95%,推動智慧城市發展,領先亞洲多國",
45
45
  ["臺灣", "5G網路", "覆蓋率", "智慧城市", "亞洲"]
46
46
  ]
47
- ]).call(input)
47
+ ])
48
48
  end
49
49
  ```
50
50
 
51
+ Batch Storage 是一個用來儲存 GPT 函數的結果的類別,你可以自己定義一個類似的類別,並且在 `GptFunction.configure` 中設定。
52
+
53
+ ```ruby
54
+ class MyBatchStorage
55
+ def initialize
56
+ @queue = []
57
+ end
58
+
59
+ def enqueue(value)
60
+ @queue << value
61
+ true
62
+ end
63
+
64
+ def dequeue
65
+ @queue.shift
66
+ end
67
+ end
68
+
69
+ GptFunction.configure(api_key: '...', model: 'gpt-4o-mini', batch_storage: MyBatchStorage)
70
+ ```
71
+
72
+ 你可以用 Batch.create 建立一個新的 Batch, 在 create 成功時,會自動將 Batch 存入 BatchStorage 中。
73
+
74
+ ```ruby
75
+ request1 = GptFunctions.翻譯成中文.to_request_body("apple")
76
+ request2 = GptFunctions.翻譯成中文.to_request_body("tesla")
77
+ batch = GptFunction::Batch.create([request1, request2])
78
+ ```
79
+
80
+ 你可以用 Batch.process 來處理 Batch,如果 Batch 的 status 在 "failed", "completed", "expired", "cancelled" 當中,Batch 會被從 queue 中移除,如果是其他狀態,Batch 會自動重新加入 queue 中,你只需要定期持續呼叫 process 就可以。
81
+
82
+ ```ruby
83
+ GptFunction::Batch.process do |batch|
84
+ puts "batch id: #{batch.id}, status: #{batch.status}, progress: #{batch.request_counts_completed}/#{batch.request_counts_total}"
85
+ batch.pairs.each do |input, output|
86
+ puts "input: #{input}, output: #{output}"
87
+ end
88
+ end
89
+ ```
90
+
91
+ 可以用 count 參數來限制每次處理的數量,預設值為 1。
92
+
93
+ ```ruby
94
+ GptFunction::Batch.process(count: 2) do |batch|
95
+ ...
96
+ end
97
+ ```
98
+
99
+ Batch Storage 整合 Active Record 的範例:
100
+
101
+ ```ruby
102
+ class Model < ApplicationRecord
103
+ class << self
104
+ def enqueue(hash)
105
+ create!(hash)
106
+ true
107
+ end
108
+
109
+ def dequeue
110
+ first&.destroy
111
+ end
112
+ end
113
+ end
114
+
115
+ GptFunction.configure(api_key: '...', model: 'gpt-4o-mini', batch_storage: Model)
116
+ ```
117
+
51
118
  ## License
52
119
 
53
120
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/lib/gpt-function.rb CHANGED
@@ -5,6 +5,8 @@ require "json"
5
5
 
6
6
  require_relative "gpt_function/version"
7
7
  require_relative "gpt_function/file"
8
+ require_relative "gpt_function/storage"
9
+ require_relative "gpt_function/simple_queue"
8
10
  require_relative "gpt_function/batch"
9
11
  require_relative "gpt_functions"
10
12
 
@@ -17,9 +19,10 @@ class GptFunction
17
19
  class << self
18
20
  attr_accessor :api_key, :model
19
21
 
20
- def configure(api_key:, model:)
22
+ def configure(api_key:, model:, batch_storage: GptFunction::SimpleQueue.new)
21
23
  @api_key = api_key
22
24
  @model = model
25
+ GptFunction::Storage.batch_storage = batch_storage
23
26
  end
24
27
  end
25
28
 
@@ -1,9 +1,7 @@
1
- # lib/gpt_function/batch.rb
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require "net/http"
5
4
  require "json"
6
- require "byebug"
7
5
 
8
6
  class GptFunction
9
7
  class Batch
@@ -30,8 +28,7 @@ class GptFunction
30
28
  attr_reader :request_counts_completed
31
29
  attr_reader :request_counts_failed
32
30
 
33
- attr_reader :metadata_customer_id
34
- attr_reader :metadata_batch_description
31
+ attr_reader :metadata
35
32
 
36
33
  def initialize(hash)
37
34
  @id = hash["id"]
@@ -57,8 +54,7 @@ class GptFunction
57
54
  @request_counts_completed = hash.dig("request_counts", "completed")
58
55
  @request_counts_failed = hash.dig("request_counts", "failed")
59
56
 
60
- @metadata_customer_id = hash.dig("metadata", "customer_id")
61
- @metadata_batch_description = hash.dig("metadata", "batch_description")
57
+ @metadata = hash.dig("metadata")
62
58
  end
63
59
 
64
60
  def to_hash
@@ -84,8 +80,7 @@ class GptFunction
84
80
  request_counts_total: request_counts_total,
85
81
  request_counts_completed: request_counts_completed,
86
82
  request_counts_failed: request_counts_failed,
87
- metadata_customer_id: metadata_customer_id,
88
- metadata_batch_description: metadata_batch_description,
83
+ metadata: metadata
89
84
  }
90
85
  end
91
86
 
@@ -98,19 +93,21 @@ class GptFunction
98
93
  end
99
94
 
100
95
  def input_file
96
+ return nil if input_file_id.nil?
101
97
  @input_file ||= File.from_id(input_file_id)
102
98
  end
103
99
 
104
100
  def output_file
101
+ return nil if output_file_id.nil?
105
102
  @output_file ||= File.from_id(output_file_id)
106
103
  end
107
104
 
108
105
  def input_jsonl
109
- @input_jsonl ||= input_file.jsonl
106
+ @input_jsonl ||= input_file&.jsonl || []
110
107
  end
111
108
 
112
109
  def output_jsonl
113
- @output_jsonl ||= output_file.jsonl
110
+ @output_jsonl ||= output_file&.jsonl || []
114
111
  end
115
112
 
116
113
  def inputs
@@ -135,14 +132,16 @@ class GptFunction
135
132
 
136
133
  def pairs
137
134
  hash = {}
138
- inputs.each do |input|
139
- hash[input["custom_id"]] = {
140
- "input" => input["content"],
141
- }
142
- end
135
+
143
136
  outputs.each do |output|
144
- hash[output["custom_id"]]["output"] = output["content"]
137
+ hash[output["custom_id"]] = [nil ,output["content"]]
138
+ end
139
+
140
+ inputs.each do |input|
141
+ next if hash[input["custom_id"]].nil?
142
+ hash[input["custom_id"]][0] = input["content"]
145
143
  end
144
+
146
145
  hash.values
147
146
  end
148
147
 
@@ -150,6 +149,24 @@ class GptFunction
150
149
  Batch.cancel(id)
151
150
  end
152
151
 
152
+ def enqueue
153
+ return false if GptFunction::Storage.batch_storage.nil?
154
+
155
+ GptFunction::Storage.batch_storage.enqueue(self.to_hash)
156
+ end
157
+
158
+ # validating the input file is being validated before the batch can begin
159
+ # failed the input file has failed the validation process
160
+ # in_progress the input file was successfully validated and the batch is currently being run
161
+ # finalizing the batch has completed and the results are being prepared
162
+ # completed the batch has been completed and the results are ready
163
+ # expired the batch was not able to be completed within the 24-hour time window
164
+ # cancelling the batch is being cancelled (may take up to 10 minutes)
165
+ # cancelled the batch was cancelled
166
+ def is_processed
167
+ ["failed", "completed", "expired", "cancelled"].include? status
168
+ end
169
+
153
170
  class << self
154
171
  def list(limit: 20, after: nil)
155
172
  # 創建批次請求
@@ -169,7 +186,7 @@ class GptFunction
169
186
  end
170
187
  end
171
188
 
172
- def create(requests)
189
+ def create(requests, metadata: nil)
173
190
  requests = requests.each_with_index.map do |request, index|
174
191
  {
175
192
  custom_id: "request-#{index + 1}",
@@ -186,11 +203,13 @@ class GptFunction
186
203
  uri = URI('https://api.openai.com/v1/batches')
187
204
  request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
188
205
  request['Authorization'] = "Bearer #{GptFunction.api_key}"
189
- request.body = {
206
+ body = {
190
207
  input_file_id: file.id,
191
208
  endpoint: '/v1/chat/completions',
192
209
  completion_window: '24h'
193
- }.to_json
210
+ }
211
+ body[:metadata] = metadata unless metadata.nil?
212
+ request.body = body.to_json
194
213
 
195
214
  response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
196
215
  http.request(request)
@@ -199,7 +218,9 @@ class GptFunction
199
218
  raise "Batch creation failed: #{response.body}" unless response.is_a?(Net::HTTPSuccess)
200
219
 
201
220
  hash = JSON.parse(response.body)
202
- Batch.new(hash)
221
+ batch = Batch.new(hash)
222
+ batch.enqueue
223
+ batch
203
224
  rescue => e
204
225
  file&.delete
205
226
  raise e
@@ -245,6 +266,32 @@ class GptFunction
245
266
  response.body
246
267
  end
247
268
 
269
+ def dequeue
270
+ hash = GptFunction::Storage.batch_storage&.dequeue
271
+ id = hash&.dig("id") || hash&.dig(:id)
272
+ from_id(id) if id
273
+ end
274
+
275
+ # 進行批次請求處理
276
+ # count: 處理批次請求的數量
277
+ # block: 處理批次請求的 block
278
+ # 返回值: 是否還有批次請求需要處理
279
+ def process(count: 1, &block)
280
+ # 從 Storage 取出 count 個批次請求
281
+ count.times do
282
+ batch = dequeue
283
+
284
+ # 如果沒有批次請求,則跳出迴圈
285
+ return false if batch.nil?
286
+
287
+ yield batch
288
+
289
+ # 如果 batch 還未處理完成,將批次請求重新加入 Storage
290
+ batch.enqueue unless batch.is_processed
291
+ end
292
+
293
+ true
294
+ end
248
295
  end
249
296
  end
250
297
  end
@@ -1,4 +1,3 @@
1
- # lib/gpt_function/batch.rb
2
1
  # frozen_string_literal: true
3
2
 
4
3
  require "net/http"
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GptFunction
4
+ class SimpleQueue
5
+ def initialize
6
+ @queue = []
7
+ end
8
+
9
+ def enqueue(value)
10
+ @queue << value
11
+ true
12
+ end
13
+
14
+ def dequeue
15
+ @queue.shift
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GptFunction
4
+ module Storage
5
+ class << self
6
+ def batch_storage=(value)
7
+ # 檢查 value 有實作 enqueue 方法
8
+ raise "Invalid batch storage: should respond to #enqueue" unless value.respond_to?(:enqueue)
9
+
10
+ # 檢查 value 有實作 dequeue 方法
11
+ raise "Invalid batch storage: should respond to #dequeue" unless value.respond_to?(:dequeue)
12
+ @batch_storage = value
13
+ end
14
+
15
+ def batch_storage
16
+ @batch_storage
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GptFunction
4
- VERSION = "0.3.0"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gpt-function
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - etrex kuo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-02 00:00:00.000000000 Z
11
+ date: 2024-08-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -41,9 +41,10 @@ files:
41
41
  - Rakefile
42
42
  - gpt-function.gemspec
43
43
  - lib/gpt-function.rb
44
- - lib/gpt/function.rb
45
44
  - lib/gpt_function/batch.rb
46
45
  - lib/gpt_function/file.rb
46
+ - lib/gpt_function/simple_queue.rb
47
+ - lib/gpt_function/storage.rb
47
48
  - lib/gpt_function/version.rb
48
49
  - lib/gpt_functions.rb
49
50
  - workflows/main.yml
data/lib/gpt/function.rb DELETED
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "net/http"
4
- require "json"
5
- require_relative "function/batch"
6
-
7
- module Gpt
8
- # 這是一個簡單的 GPT 函數類別
9
-
10
- end