gpt-function 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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