chatgpt-rb 0.1.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 +7 -0
- data/bin/chatgpt-rb +34 -0
- data/lib/chatgpt_rb/conversation.rb +126 -0
- data/lib/chatgpt_rb.rb +1 -0
- metadata +104 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 56bfd3ab0a5f56e05e8da9b5f59f7358383ebb1c78214d1afec32c6dd63fa140
|
4
|
+
data.tar.gz: 3361ca43ea603a5634e95793cfff46215751a855e2836a92ba6161c4eb07d3fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: '09ab2d88f40d4b00eed86b3fbab7ab8fcc9b454f98c6f1ab0ac3b7461f97324f9151563540c9700d6e24d2ba47491ada4e611394453bd9b093ed2c026254f4cb'
|
7
|
+
data.tar.gz: ff8ba450b24f98564a455c5994e8e19a3ad8cc0e85e4e3f14530a65a669e2a964ae8484815c14098fa6160c48e61b24a69f8cb46de4da4b5874d8a191881bb60
|
data/bin/chatgpt-rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "dotenv/load"
|
4
|
+
require "colorize"
|
5
|
+
require "reline"
|
6
|
+
require_relative "./../lib/chatgpt_rb"
|
7
|
+
|
8
|
+
begin
|
9
|
+
stty_save = `stty -g`.chomp
|
10
|
+
rescue
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
conversation = ChatgptRb::Conversation.new(api_key: ENV.fetch("OPEN_AI_KEY"), model: ENV.fetch("OPEN_AI_MODEL", "gpt-3.5-turbo"))
|
15
|
+
|
16
|
+
puts "Type any message to talk with ChatGPT. Type 'exit' to quit. Type 'dump' to dump this conversation to JSON."
|
17
|
+
|
18
|
+
while message = Reline.readline("me> ".colorize(:red), true) do
|
19
|
+
case message.chomp
|
20
|
+
when "exit", "quit", "q", "\\q"
|
21
|
+
exit
|
22
|
+
when "dump"
|
23
|
+
puts "dump> ".colorize(:blue) + conversation.messages.to_json
|
24
|
+
else
|
25
|
+
print("ai> ".colorize(:yellow))
|
26
|
+
conversation.ask(message) { |fragment| print(fragment) }
|
27
|
+
puts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
rescue Interrupt
|
31
|
+
puts "^C"
|
32
|
+
`stty #{stty_save}` if stty_save
|
33
|
+
exit
|
34
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "httparty"
|
2
|
+
|
3
|
+
module ChatgptRb
|
4
|
+
class Conversation
|
5
|
+
attr_reader :api_key, :model, :functions, :temperature, :max_tokens, :top_p, :frequency_penalty, :presence_penalty, :messages
|
6
|
+
|
7
|
+
# @param api_key [String]
|
8
|
+
# @param model [String]
|
9
|
+
# @param functions [Array<Hash>]
|
10
|
+
# @param temperature [Float]
|
11
|
+
# @param max_tokens [Integer]
|
12
|
+
# @param top_p [Float]
|
13
|
+
# @param frequency_penalty [Float]
|
14
|
+
# @param presence_penalty [Float]
|
15
|
+
# @param messages [Array<Hash>]
|
16
|
+
# @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)
|
18
|
+
@api_key = api_key
|
19
|
+
@model = model
|
20
|
+
@functions = functions
|
21
|
+
@temperature = temperature
|
22
|
+
@max_tokens = max_tokens
|
23
|
+
@top_p = top_p
|
24
|
+
@frequency_penalty = frequency_penalty
|
25
|
+
@presence_penalty = presence_penalty
|
26
|
+
@messages = messages
|
27
|
+
@messages << { role: "system", content: prompt } if prompt
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param content [String]
|
31
|
+
def ask(content, &block)
|
32
|
+
@messages << { role: "user", content: }
|
33
|
+
get_next_response(&block)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def <<(message)
|
39
|
+
@messages << message
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_next_response(&block)
|
43
|
+
streamed_content = ""
|
44
|
+
streamed_arguments = ""
|
45
|
+
streamed_role = ""
|
46
|
+
streamed_function = ""
|
47
|
+
error_buffer = []
|
48
|
+
|
49
|
+
response = HTTParty.post(
|
50
|
+
"https://api.openai.com/v1/chat/completions",
|
51
|
+
steam_body: block_given?,
|
52
|
+
headers: {
|
53
|
+
"Content-Type": "application/json",
|
54
|
+
"Authorization": "Bearer #{api_key}",
|
55
|
+
},
|
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,
|
66
|
+
) do |fragment|
|
67
|
+
if block_given?
|
68
|
+
fragment.each_line do |line|
|
69
|
+
next if line.nil?
|
70
|
+
next if line == "\n"
|
71
|
+
break if line == "data: [DONE]\n"
|
72
|
+
|
73
|
+
line_without_prefix = line.gsub(/^data: /, "")
|
74
|
+
json = JSON.parse(line_without_prefix)
|
75
|
+
|
76
|
+
break if json.dig("choices", 0, "finish_reason")
|
77
|
+
|
78
|
+
if (function_name = json.dig("choices", 0, "delta", "function_call", "name"))
|
79
|
+
streamed_function = function_name
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
if (role = json.dig("choices", 0, "delta", "role"))
|
84
|
+
streamed_role = role
|
85
|
+
next
|
86
|
+
end
|
87
|
+
|
88
|
+
if content = json.dig("choices", 0, "delta", "content")
|
89
|
+
yield content unless line_without_prefix.empty?
|
90
|
+
streamed_content << content
|
91
|
+
elsif arguments = json.dig("choices", 0, "delta", "function_call", "arguments")
|
92
|
+
streamed_arguments << arguments
|
93
|
+
end
|
94
|
+
rescue => e
|
95
|
+
error_buffer << "Error: #{e}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
error_buffer.each { |e| $stderr.puts("Error: #{e}") }
|
101
|
+
|
102
|
+
@messages << if block_given? && streamed_content != ""
|
103
|
+
{ "content" => streamed_content, "role" => streamed_role }
|
104
|
+
elsif block_given? && streamed_arguments != ""
|
105
|
+
{ "role" => "assistant", "content" => nil, "function_call" => { "name" => streamed_function, "arguments" => streamed_arguments } }
|
106
|
+
else
|
107
|
+
response.dig("choices", 0, "message")
|
108
|
+
end
|
109
|
+
|
110
|
+
if @messages.last["content"]
|
111
|
+
@messages.last["content"]
|
112
|
+
elsif @messages.last["function_call"]
|
113
|
+
function_args = @messages.last["function_call"]
|
114
|
+
function_name = function_args.fetch("name")
|
115
|
+
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))
|
119
|
+
|
120
|
+
@messages << { role: "function", name: function_name, content: content.to_json }
|
121
|
+
|
122
|
+
get_next_response(functions:, api_key:, model:, temperature:, max_tokens:, top_p:, frequency_penalty:, presence_penalty:, &block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/chatgpt_rb.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "./chatgpt_rb/conversation"
|
metadata
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chatgpt-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Breckenridge
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-07-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.21'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.21'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: colorize
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dotenv
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.8'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: reline
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.3'
|
69
|
+
description: Provides libraries for interacting with the ChatGPT API and a CLI program
|
70
|
+
`chatgpt-rb` for live conversations.
|
71
|
+
email:
|
72
|
+
- aaron@breckridge.dev
|
73
|
+
executables:
|
74
|
+
- chatgpt-rb
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- bin/chatgpt-rb
|
79
|
+
- lib/chatgpt_rb.rb
|
80
|
+
- lib/chatgpt_rb/conversation.rb
|
81
|
+
homepage: https://github.com/breckenedge/chatgpt-rb
|
82
|
+
licenses:
|
83
|
+
- MIT
|
84
|
+
metadata: {}
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
require_paths:
|
88
|
+
- lib
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
requirements: []
|
100
|
+
rubygems_version: 3.4.10
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: A gem for interacting with the ChatGPT API
|
104
|
+
test_files: []
|