chatgpt-rb 0.1.0

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