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 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: []