chatgpt-rb 0.1.0 → 0.1.2
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/bin/chatgpt-rb +71 -4
- data/bin/watcher +17 -0
- data/lib/chatgpt_rb/conversation.rb +73 -32
- data/lib/chatgpt_rb/dsl/base.rb +29 -0
- data/lib/chatgpt_rb/dsl/conversation.rb +17 -0
- data/lib/chatgpt_rb/dsl/function.rb +14 -0
- data/lib/chatgpt_rb/dsl/parameter.rb +9 -0
- data/lib/chatgpt_rb/function.rb +31 -0
- data/lib/chatgpt_rb/parameter.rb +31 -0
- metadata +65 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2dcefe52467b8bae3bc12c17e1f36a20b7a5a8a207f21c20d3db413b19f0a15e
|
4
|
+
data.tar.gz: 0cde2181779a22b431d8afd59dc89a80a1a5c58634fd02f7795cc31a9ee874be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ba3dd8cf78ef49ca4df7ed0521c309b8cc44bc837a0fd14aed5a7f346cced3a5204c56581514b19761d0f081b82edae25298a871eba7dfc409a226819f3a1b5
|
7
|
+
data.tar.gz: 73f97ff7857d9947cfd60036eb8c0b455e603fe73b84d02624ff693f969cfcdef47c8e078c3e7a95cb78fde9ca70fccffc3d2b52c36c9465220adfa4e3e8aa95
|
data/bin/chatgpt-rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "dotenv/load"
|
4
4
|
require "colorize"
|
5
5
|
require "reline"
|
6
|
+
require "optparse"
|
6
7
|
require_relative "./../lib/chatgpt_rb"
|
7
8
|
|
8
9
|
begin
|
@@ -10,17 +11,83 @@ begin
|
|
10
11
|
rescue
|
11
12
|
end
|
12
13
|
|
14
|
+
options = {
|
15
|
+
key: ENV["OPEN_AI_KEY"],
|
16
|
+
model: "gpt-3.5-turbo",
|
17
|
+
base_uri: "https://api.openai.com/v1",
|
18
|
+
functions_files: [],
|
19
|
+
}
|
20
|
+
|
21
|
+
OptionParser.new do |opts|
|
22
|
+
opts.banner = "Usage: chatgpt-rb [options]"
|
23
|
+
|
24
|
+
opts.on("-f", "--file FILE", "Load a previous conversation from FILE") do |file|
|
25
|
+
options[:file] = file
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-k", "--api-key KEY", "Use the provided API key for authentication") do |key|
|
29
|
+
options[:key] = key
|
30
|
+
end
|
31
|
+
|
32
|
+
opts.on("-m", "--model MODEL", "Use the provided MODEL (Default: #{options[:model]})") do |model|
|
33
|
+
options[:model] = model
|
34
|
+
end
|
35
|
+
|
36
|
+
opts.on("-b", "--base-uri URI", "Use the provided base URI (Default: #{options[:base_uri]})") do |uri|
|
37
|
+
options[:base_uri] = uri
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on("-u", "--functions-file FILE", "Add functions defined in FILE to your conversation") do |functions_file|
|
41
|
+
options[:functions_files] << functions_file
|
42
|
+
end
|
43
|
+
|
44
|
+
opts.on("-p", "--prompt PROMPT", "Declare the PROMPT for your conversation") do |prompt|
|
45
|
+
options[:prompt] = prompt
|
46
|
+
end
|
47
|
+
end.parse!
|
48
|
+
|
13
49
|
begin
|
14
|
-
|
50
|
+
puts "Type any message to talk with ChatGPT. Type '\\help' for a list of commands."
|
51
|
+
|
52
|
+
functions = options[:functions_files].map do |function_file|
|
53
|
+
puts "Loading functions from #{function_file}"
|
54
|
+
|
55
|
+
ChatgptRb::DSL::Conversation.new(ChatgptRb::Conversation.new).instance_eval(File.read(function_file))
|
56
|
+
end
|
57
|
+
|
58
|
+
messages = if options[:file]
|
59
|
+
JSON.parse(File.read(options[:file])).map { |hash| hash.transform_keys(&:to_sym) }
|
60
|
+
else
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
|
64
|
+
if options[:prompt]
|
65
|
+
puts "prompt> ".colorize(:blue) + options[:prompt]
|
66
|
+
end
|
15
67
|
|
16
|
-
|
68
|
+
conversation = ChatgptRb::Conversation.new(api_key: options.fetch(:key), model: options.fetch(:model), base_uri: options.fetch(:base_uri), messages:, functions:, prompt: options[:prompt])
|
17
69
|
|
18
70
|
while message = Reline.readline("me> ".colorize(:red), true) do
|
19
71
|
case message.chomp
|
20
|
-
when "
|
72
|
+
when "\\help", "\\h"
|
73
|
+
puts <<~COMMANDS.colorize(:blue)
|
74
|
+
- `\\quit` Exit
|
75
|
+
- `\\save <filename>` Save this conversation to a JSON file that can be reloaded later with the `-f` argument
|
76
|
+
- `\\functions` Get a list of configured functions
|
77
|
+
COMMANDS
|
78
|
+
when "\\q", "\\quit", "\\exit"
|
21
79
|
exit
|
22
|
-
when "dump"
|
80
|
+
when "\\dump"
|
23
81
|
puts "dump> ".colorize(:blue) + conversation.messages.to_json
|
82
|
+
when "\\functions"
|
83
|
+
puts "available functions:".colorize(:blue)
|
84
|
+
functions.each do |function|
|
85
|
+
puts "- `#{function.name}` #{function.description}".colorize(:blue)
|
86
|
+
end
|
87
|
+
when /^\\save .+/
|
88
|
+
filename = /^\\save (.+)/.match(message)[1]
|
89
|
+
File.open(filename, "w") { |f| f.write(conversation.messages.to_json) }
|
90
|
+
puts "saved to #{filename} ".colorize(:blue)
|
24
91
|
else
|
25
92
|
print("ai> ".colorize(:yellow))
|
26
93
|
conversation.ask(message) { |fragment| print(fragment) }
|
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,16 @@
|
|
1
1
|
require "httparty"
|
2
|
+
require "json-schema"
|
3
|
+
require_relative "./function"
|
4
|
+
require_relative "./dsl/conversation"
|
2
5
|
|
3
6
|
module ChatgptRb
|
4
7
|
class Conversation
|
5
|
-
|
8
|
+
attr_accessor :api_key, :model, :functions, :temperature, :max_tokens, :top_p, :frequency_penalty, :presence_penalty, :prompt, :base_uri
|
9
|
+
attr_reader :messages
|
6
10
|
|
7
11
|
# @param api_key [String]
|
8
12
|
# @param model [String]
|
9
|
-
# @param functions [Array<Hash>]
|
13
|
+
# @param functions [Array<Hash>, Array<ChatgptRb::Function>]
|
10
14
|
# @param temperature [Float]
|
11
15
|
# @param max_tokens [Integer]
|
12
16
|
# @param top_p [Float]
|
@@ -14,63 +18,101 @@ module ChatgptRb
|
|
14
18
|
# @param presence_penalty [Float]
|
15
19
|
# @param messages [Array<Hash>]
|
16
20
|
# @param prompt [String, nil] instructions that the model can use to inform its responses, for example: "Act like a sullen teenager."
|
17
|
-
|
21
|
+
# @param base_uri [String]
|
22
|
+
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, base_uri: "https://api.openai.com/v1", &configuration)
|
18
23
|
@api_key = api_key
|
19
24
|
@model = model
|
20
|
-
@functions = functions
|
25
|
+
@functions = functions.each_with_object({}) do |function, hash|
|
26
|
+
func = function.is_a?(ChatgptRb::Function) ? function : ChatgptRb::Function.new(**function)
|
27
|
+
hash[func.name] = func
|
28
|
+
end
|
21
29
|
@temperature = temperature
|
22
30
|
@max_tokens = max_tokens
|
23
31
|
@top_p = top_p
|
24
32
|
@frequency_penalty = frequency_penalty
|
25
33
|
@presence_penalty = presence_penalty
|
26
|
-
@messages = messages
|
34
|
+
@messages = messages.map { |message| message.transform_keys(&:to_sym) }
|
35
|
+
@prompt = prompt
|
36
|
+
@base_uri = base_uri
|
37
|
+
ChatgptRb::DSL::Conversation.configure(self, &configuration) if block_given?
|
27
38
|
@messages << { role: "system", content: prompt } if prompt
|
28
39
|
end
|
29
40
|
|
30
41
|
# @param content [String]
|
42
|
+
# @yieldparam [String] the response, but streamed
|
43
|
+
# @return [String] the response
|
31
44
|
def ask(content, &block)
|
32
45
|
@messages << { role: "user", content: }
|
33
46
|
get_next_response(&block)
|
34
47
|
end
|
35
48
|
|
49
|
+
# @param content [String]
|
50
|
+
# @param function [ChatgptRb::Function] temporarily enhance the next response with the provided function
|
51
|
+
# @yieldparam [String] the response, but streamed
|
52
|
+
# @return [String] the response
|
53
|
+
def ask_with_function(content, function, &block)
|
54
|
+
function_was = functions[function.name]
|
55
|
+
functions[function.name] = function
|
56
|
+
get_next_response(content, &block)
|
57
|
+
functions[function.name] = function_was
|
58
|
+
end
|
59
|
+
|
36
60
|
private
|
37
61
|
|
38
62
|
def <<(message)
|
39
63
|
@messages << message
|
40
64
|
end
|
41
65
|
|
66
|
+
# Ensure that each function's argument declarations conform to the JSON Schema
|
67
|
+
# See https://github.com/voxpupuli/json-schema/
|
68
|
+
def validate_functions!
|
69
|
+
metaschema = JSON::Validator.validator_for_name("draft4").metaschema
|
70
|
+
functions.values.each do |function|
|
71
|
+
raise ArgumentError, "Invalid function declaration for #{function.name}: #{function.as_json}" unless JSON::Validator.validate(metaschema, function.as_json)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
42
75
|
def get_next_response(&block)
|
76
|
+
validate_functions!
|
77
|
+
|
43
78
|
streamed_content = ""
|
44
79
|
streamed_arguments = ""
|
45
80
|
streamed_role = ""
|
46
81
|
streamed_function = ""
|
47
82
|
error_buffer = []
|
48
83
|
|
84
|
+
body = {
|
85
|
+
model:,
|
86
|
+
messages: @messages,
|
87
|
+
temperature:,
|
88
|
+
max_tokens:,
|
89
|
+
top_p:,
|
90
|
+
frequency_penalty:,
|
91
|
+
presence_penalty:,
|
92
|
+
stream: block_given?,
|
93
|
+
}.tap do |hash|
|
94
|
+
hash[:functions] = functions.values.map(&:as_json) unless functions.empty?
|
95
|
+
end
|
96
|
+
|
49
97
|
response = HTTParty.post(
|
50
|
-
"
|
98
|
+
"#{base_uri}/chat/completions",
|
51
99
|
steam_body: block_given?,
|
52
100
|
headers: {
|
53
|
-
"Content-Type"
|
54
|
-
"Authorization"
|
101
|
+
"Content-Type" => "application/json",
|
102
|
+
"Authorization" => "Bearer #{api_key}",
|
103
|
+
"Accept" => "application/json",
|
104
|
+
"User-Agent" => "Ruby/chatgpt-rb",
|
55
105
|
},
|
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,
|
106
|
+
body: body.to_json,
|
66
107
|
) do |fragment|
|
67
108
|
if block_given?
|
68
109
|
fragment.each_line do |line|
|
69
|
-
next if line.nil?
|
70
|
-
next if line == "\n"
|
71
110
|
break if line == "data: [DONE]\n"
|
72
111
|
|
73
|
-
line_without_prefix = line.gsub(/^data: /, "")
|
112
|
+
line_without_prefix = line.gsub(/^data: /, "").rstrip
|
113
|
+
|
114
|
+
next if line_without_prefix.empty?
|
115
|
+
|
74
116
|
json = JSON.parse(line_without_prefix)
|
75
117
|
|
76
118
|
break if json.dig("choices", 0, "finish_reason")
|
@@ -100,26 +142,25 @@ module ChatgptRb
|
|
100
142
|
error_buffer.each { |e| $stderr.puts("Error: #{e}") }
|
101
143
|
|
102
144
|
@messages << if block_given? && streamed_content != ""
|
103
|
-
{
|
145
|
+
{ content: streamed_content, role: streamed_role }
|
104
146
|
elsif block_given? && streamed_arguments != ""
|
105
|
-
{
|
147
|
+
{ role: "assistant", content: nil, function_call: { "name" => streamed_function, "arguments" => streamed_arguments } }
|
106
148
|
else
|
107
|
-
response.dig("choices", 0, "message")
|
149
|
+
response.dig("choices", 0, "message").transform_keys(&:to_sym)
|
108
150
|
end
|
109
151
|
|
110
|
-
if @messages.last[
|
111
|
-
@messages.last[
|
112
|
-
elsif @messages.last[
|
113
|
-
function_args = @messages.last[
|
152
|
+
if @messages.last[:content]
|
153
|
+
@messages.last[:content]
|
154
|
+
elsif @messages.last[:function_call]
|
155
|
+
function_args = @messages.last[:function_call]
|
114
156
|
function_name = function_args.fetch("name")
|
115
157
|
arguments = JSON.parse(function_args.fetch("arguments"))
|
116
|
-
|
117
|
-
|
118
|
-
content = function.fetch(:implementation).call(**arguments.transform_keys(&:to_sym))
|
158
|
+
function = functions[function_name]
|
159
|
+
content = function.implementation.call(**arguments.transform_keys(&:to_sym))
|
119
160
|
|
120
161
|
@messages << { role: "function", name: function_name, content: content.to_json }
|
121
162
|
|
122
|
-
get_next_response(
|
163
|
+
get_next_response(&block)
|
123
164
|
end
|
124
165
|
end
|
125
166
|
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,31 @@
|
|
1
|
+
module ChatgptRb
|
2
|
+
class Function
|
3
|
+
attr_accessor :name, :description, :parameters, :implementation
|
4
|
+
|
5
|
+
# @param name [String, nil]
|
6
|
+
# @param description [String, nil]
|
7
|
+
# @param parameters [Array<ChatgptRb::Parameter>]
|
8
|
+
# @param implementation [Lambda, nil]
|
9
|
+
def initialize(name: nil, 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.
|
4
|
+
version: 0.1.2
|
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-
|
11
|
+
date: 2023-07-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -66,6 +66,62 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: json-schema
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '4.0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '4.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
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: listen
|
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'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
69
125
|
description: Provides libraries for interacting with the ChatGPT API and a CLI program
|
70
126
|
`chatgpt-rb` for live conversations.
|
71
127
|
email:
|
@@ -76,8 +132,15 @@ extensions: []
|
|
76
132
|
extra_rdoc_files: []
|
77
133
|
files:
|
78
134
|
- bin/chatgpt-rb
|
135
|
+
- bin/watcher
|
79
136
|
- lib/chatgpt_rb.rb
|
80
137
|
- lib/chatgpt_rb/conversation.rb
|
138
|
+
- lib/chatgpt_rb/dsl/base.rb
|
139
|
+
- lib/chatgpt_rb/dsl/conversation.rb
|
140
|
+
- lib/chatgpt_rb/dsl/function.rb
|
141
|
+
- lib/chatgpt_rb/dsl/parameter.rb
|
142
|
+
- lib/chatgpt_rb/function.rb
|
143
|
+
- lib/chatgpt_rb/parameter.rb
|
81
144
|
homepage: https://github.com/breckenedge/chatgpt-rb
|
82
145
|
licenses:
|
83
146
|
- MIT
|