chatgpt-rb 0.1.0 → 0.1.1

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: 56bfd3ab0a5f56e05e8da9b5f59f7358383ebb1c78214d1afec32c6dd63fa140
4
- data.tar.gz: 3361ca43ea603a5634e95793cfff46215751a855e2836a92ba6161c4eb07d3fc
3
+ metadata.gz: 50e30e865ade9a6e20cad5680617972114a224bda8bf25d9969b9b57e6236763
4
+ data.tar.gz: e7d1714512f1696b9401018b11292a46ed220c650639521def9b4fa0290303a0
5
5
  SHA512:
6
- metadata.gz: '09ab2d88f40d4b00eed86b3fbab7ab8fcc9b454f98c6f1ab0ac3b7461f97324f9151563540c9700d6e24d2ba47491ada4e611394453bd9b093ed2c026254f4cb'
7
- data.tar.gz: ff8ba450b24f98564a455c5994e8e19a3ad8cc0e85e4e3f14530a65a669e2a964ae8484815c14098fa6160c48e61b24a69f8cb46de4da4b5874d8a191881bb60
6
+ metadata.gz: a42400a64dee74e93b7b27c8d04fc1f8c750bd0b90abc1ba37c33bdd58cbc9a494906c544b2bb0e02585807fffffbaae9ff3488d328b9bdb3051cc4fbfb59c0b
7
+ data.tar.gz: 4f187489399450e128b1f5f1634004be8de0a5f4b71516bff12ec234e3cf5cf3498102d6e44081e0e2bd00dc8ad14c1f75ca68770425eac0a7b1e32d284ee6e4
data/bin/watcher ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "listen"
4
+
5
+ directory_to_watch = Dir.pwd
6
+
7
+ listener = Listen.to(directory_to_watch) do |modified, added, removed|
8
+ system("rspec")
9
+ end
10
+
11
+ listener.start
12
+ puts "Watching #{directory_to_watch} for changes..."
13
+
14
+ # Stop the listener when the process is terminated
15
+ Signal.trap("INT") { listener.stop }
16
+ Signal.trap("TERM") { listener.stop }
17
+ sleep
@@ -1,12 +1,19 @@
1
1
  require "httparty"
2
+ require_relative "./function"
3
+ require_relative "./dsl/conversation"
2
4
 
3
5
  module ChatgptRb
4
6
  class Conversation
5
- attr_reader :api_key, :model, :functions, :temperature, :max_tokens, :top_p, :frequency_penalty, :presence_penalty, :messages
7
+ include HTTParty
8
+
9
+ base_uri "https://api.openai.com"
10
+
11
+ attr_accessor :api_key, :model, :functions, :temperature, :max_tokens, :top_p, :frequency_penalty, :presence_penalty, :prompt
12
+ attr_reader :messages
6
13
 
7
14
  # @param api_key [String]
8
15
  # @param model [String]
9
- # @param functions [Array<Hash>]
16
+ # @param functions [Array<Hash>, Array<ChatgptRb::Function>]
10
17
  # @param temperature [Float]
11
18
  # @param max_tokens [Integer]
12
19
  # @param top_p [Float]
@@ -14,25 +21,43 @@ module ChatgptRb
14
21
  # @param presence_penalty [Float]
15
22
  # @param messages [Array<Hash>]
16
23
  # @param prompt [String, nil] instructions that the model can use to inform its responses, for example: "Act like a sullen teenager."
17
- def initialize(api_key:, model: "gpt-3.5-turbo", functions: [], temperature: 0.7, max_tokens: 1024, top_p: 1.0, frequency_penalty: 0.0, presence_penalty: 0.0, messages: [], prompt: nil)
24
+ def initialize(api_key: nil, model: "gpt-3.5-turbo", functions: [], temperature: 0.7, max_tokens: 1024, top_p: 1.0, frequency_penalty: 0.0, presence_penalty: 0.0, messages: [], prompt: nil, &configuration)
18
25
  @api_key = api_key
19
26
  @model = model
20
- @functions = functions
27
+ @functions = functions.each_with_object({}) do |function, hash|
28
+ func = function.is_a?(ChatgptRb::Function) ? function : ChatgptRb::Function.new(**function)
29
+ hash[func.name] = func
30
+ end
21
31
  @temperature = temperature
22
32
  @max_tokens = max_tokens
23
33
  @top_p = top_p
24
34
  @frequency_penalty = frequency_penalty
25
35
  @presence_penalty = presence_penalty
26
36
  @messages = messages
37
+ @prompt = prompt
38
+ ChatgptRb::DSL::Conversation.configure(self, &configuration) if block_given?
27
39
  @messages << { role: "system", content: prompt } if prompt
28
40
  end
29
41
 
30
42
  # @param content [String]
43
+ # @yieldparam [String] the response, but streamed
44
+ # @return [String] the response
31
45
  def ask(content, &block)
32
46
  @messages << { role: "user", content: }
33
47
  get_next_response(&block)
34
48
  end
35
49
 
50
+ # @param content [String]
51
+ # @param function [ChatgptRb::Function] temporarily enhance the next response with the provided function
52
+ # @yieldparam [String] the response, but streamed
53
+ # @return [String] the response
54
+ def ask_with_function(content, function, &block)
55
+ function_was = functions[function.name]
56
+ functions[function.name] = function
57
+ get_next_response(content, &block)
58
+ functions[function.name] = function_was
59
+ end
60
+
36
61
  private
37
62
 
38
63
  def <<(message)
@@ -46,23 +71,29 @@ module ChatgptRb
46
71
  streamed_function = ""
47
72
  error_buffer = []
48
73
 
49
- response = HTTParty.post(
50
- "https://api.openai.com/v1/chat/completions",
74
+ body = {
75
+ model:,
76
+ messages: @messages,
77
+ temperature:,
78
+ max_tokens:,
79
+ top_p:,
80
+ frequency_penalty:,
81
+ presence_penalty:,
82
+ stream: block_given?,
83
+ }.tap do |hash|
84
+ hash[:functions] = functions.values.map(&:as_json) unless functions.empty?
85
+ end
86
+
87
+ response = self.class.post(
88
+ "/v1/chat/completions",
51
89
  steam_body: block_given?,
52
90
  headers: {
53
- "Content-Type": "application/json",
54
- "Authorization": "Bearer #{api_key}",
91
+ "Content-Type" => "application/json",
92
+ "Authorization" => "Bearer #{api_key}",
93
+ "Accept" => "application/json",
94
+ "User-Agent" => "Ruby/chatgpt-rb",
55
95
  },
56
- body: {
57
- model:,
58
- messages: @messages,
59
- temperature:,
60
- max_tokens:,
61
- top_p:,
62
- frequency_penalty:,
63
- presence_penalty:,
64
- stream: block_given?,
65
- }.tap { |hash| hash[:functions] = functions.map { |hash| hash.except(:implementation) } unless functions.empty? }.to_json,
96
+ body: body.to_json,
66
97
  ) do |fragment|
67
98
  if block_given?
68
99
  fragment.each_line do |line|
@@ -113,13 +144,12 @@ module ChatgptRb
113
144
  function_args = @messages.last["function_call"]
114
145
  function_name = function_args.fetch("name")
115
146
  arguments = JSON.parse(function_args.fetch("arguments"))
116
-
117
- function = functions.find { |function| function[:name] == function_name }
118
- content = function.fetch(:implementation).call(**arguments.transform_keys(&:to_sym))
147
+ function = functions[function_name]
148
+ content = function.implementation.call(**arguments.transform_keys(&:to_sym))
119
149
 
120
150
  @messages << { role: "function", name: function_name, content: content.to_json }
121
151
 
122
- get_next_response(functions:, api_key:, model:, temperature:, max_tokens:, top_p:, frequency_penalty:, presence_penalty:, &block)
152
+ get_next_response(&block)
123
153
  end
124
154
  end
125
155
  end
@@ -0,0 +1,29 @@
1
+ module ChatgptRb
2
+ module DSL
3
+ class Base
4
+ # @param object [Chatgpt::Conversation, ChatgptRb::Function, ChatgptRb::Parameter]
5
+ # @param configuration [Block]
6
+ # @return [Chatgpt::Conversation, ChatgptRb::Function, ChatgptRb::Parameter]
7
+ def self.configure(object, &configuration)
8
+ new(object).instance_eval(&configuration)
9
+ object
10
+ end
11
+
12
+ attr_reader :object
13
+
14
+ # @param object [Chatgpt::Conversation, ChatgptRb::Function, ChatgptRb::Parameter]
15
+ def initialize(object)
16
+ @object = object
17
+ end
18
+
19
+ # @param [Array<Symbol>] shorthand for allowing the DSL to set iVars
20
+ def self.supported_fields(fields)
21
+ fields.each do |method_name|
22
+ define_method method_name do |value|
23
+ object.public_send("#{method_name}=", value)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "./base"
2
+ require_relative "./function"
3
+ require_relative "../function"
4
+
5
+ module ChatgptRb
6
+ module DSL
7
+ class Conversation < Base
8
+ supported_fields %i[api_key model functions temperature max_tokens top_p frequency_penalty presence_penalty prompt]
9
+
10
+ # @param name [String] the name of the function
11
+ # @param configuration [Block]
12
+ def function(name, &configuration)
13
+ object.functions[name] = ChatgptRb::DSL::Function.configure(ChatgptRb::Function.new(name:), &configuration)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ require_relative "../parameter"
2
+ require_relative "./parameter"
3
+
4
+ module ChatgptRb
5
+ module DSL
6
+ class Function < Base
7
+ supported_fields %i[description implementation parameters]
8
+
9
+ def parameter(name, &configuration)
10
+ object.parameters << ChatgptRb::DSL::Parameter.configure(ChatgptRb::Parameter.new(name:), &configuration)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "./base"
2
+
3
+ module ChatgptRb
4
+ module DSL
5
+ class Parameter < Base
6
+ supported_fields %i[description type enum required]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ module ChatgptRb
2
+ class Function
3
+ attr_accessor :name, :description, :parameters, :implementation
4
+
5
+ # @param name [String]
6
+ # @param description [String, nil]
7
+ # @param parameters [Array<ChatgptRb::Parameter>]
8
+ # @param implementation [Lambda, nil]
9
+ def initialize(name:, description: nil, parameters: [], implementation: nil)
10
+ @name = name
11
+ @description = description
12
+ @parameters = parameters
13
+ @implementation = implementation
14
+ end
15
+
16
+ # @return [Hash]
17
+ def as_json
18
+ {
19
+ name:,
20
+ description:,
21
+ parameters: {
22
+ type: "object",
23
+ properties: parameters.each_with_object({}) do |parameter, hash|
24
+ hash[parameter.name] = parameter.as_json
25
+ end,
26
+ },
27
+ required: parameters.select(&:required?).map(&:name),
28
+ }.compact
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ module ChatgptRb
2
+ class Parameter
3
+ attr_accessor :name, :enum, :type, :description, :required
4
+
5
+ # @param name [String]
6
+ # @param enum
7
+ # @param type
8
+ # @param description
9
+ # @param required [true, false] whether or not this parameter is required
10
+ def initialize(name:, enum: nil, type: nil, description: nil, required: false)
11
+ @name = name
12
+ @enum = enum
13
+ @type = type
14
+ @description = description
15
+ @required = required
16
+ end
17
+
18
+ def required?
19
+ !!required
20
+ end
21
+
22
+ # @return Hash
23
+ def as_json
24
+ {
25
+ enum:,
26
+ type:,
27
+ description:,
28
+ }.compact
29
+ end
30
+ end
31
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chatgpt-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Breckenridge
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-07 00:00:00.000000000 Z
11
+ date: 2023-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -66,6 +66,48 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: listen
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
69
111
  description: Provides libraries for interacting with the ChatGPT API and a CLI program
70
112
  `chatgpt-rb` for live conversations.
71
113
  email:
@@ -76,8 +118,15 @@ extensions: []
76
118
  extra_rdoc_files: []
77
119
  files:
78
120
  - bin/chatgpt-rb
121
+ - bin/watcher
79
122
  - lib/chatgpt_rb.rb
80
123
  - lib/chatgpt_rb/conversation.rb
124
+ - lib/chatgpt_rb/dsl/base.rb
125
+ - lib/chatgpt_rb/dsl/conversation.rb
126
+ - lib/chatgpt_rb/dsl/function.rb
127
+ - lib/chatgpt_rb/dsl/parameter.rb
128
+ - lib/chatgpt_rb/function.rb
129
+ - lib/chatgpt_rb/parameter.rb
81
130
  homepage: https://github.com/breckenedge/chatgpt-rb
82
131
  licenses:
83
132
  - MIT