ask-ai 0.0.5 → 1.0.0

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: f43705932c791d2b495230b8ac87567a23dafddd7c76fbbdc9cd0d88d960aac7
4
- data.tar.gz: c8376477e6a4261f04ced1c99ccc07d433551e1613c317b51ab1b21b53e50b58
3
+ metadata.gz: 3d0033fda00a5a8399a6e9b71c75338b02269df54edb791bd82215e939492d15
4
+ data.tar.gz: 391d4cc9fe240289358f2489b61224b8d0706254174f9ad4a5ec7a109b7b3a89
5
5
  SHA512:
6
- metadata.gz: 26841ece9e0ee1cb05d1df0d6cbf1b20db94d18daf74be4decf82599bf3614f5a6823a2ae3398a26d9a4df480c9eedb51285934bd674d4f3b2eac5355b617da1
7
- data.tar.gz: 0ecfbc09c3944f62ef1cfdc3ddbef975d7b2cf3ea69913bff416ba25f6df063436bdbf7359bf40ca9b80fa4ce0d4dfc74d54d79b487f1f8c9b22365a2027c70e
6
+ metadata.gz: 6f749624e465e35a8ebcae8b7b9b312d1f4ffdbd8e390043a0fc87dae5eaf680931975eb87369eba855043eff52206c2daf47af95fc5136e7fb0134520275a28
7
+ data.tar.gz: 81d6f56f465808352087d5f53bab44b7a1af2d63292dbba4b5fab7f91b44fd3d78c6a591718d142f6348c6ab78bae8a54d84b2cba73e2164efd32dd3b27d4e1d
data/config/config.yml CHANGED
@@ -1,3 +0,0 @@
1
- ---
2
- TEMPERATURE: 0.7
3
- CONTEXT_LENGTH: 12
data/lib/config.rb CHANGED
@@ -1,65 +1,110 @@
1
1
  require_relative './files.rb'
2
2
 
3
3
  module Config
4
- include Files
5
- def self.load_key()
6
- config = YAML.load_file(Files.config_path)
4
+ extend Files
5
+ def load_key()
6
+ config = YAML.load_file(config_path)
7
7
  config['OPENAI_API_KEY']
8
8
  end
9
9
 
10
- def self.save_key(api_key)
11
- config = YAML.load_file(Files.config_path)
10
+ def save_key(api_key)
11
+ config = YAML.load_file(config_path)
12
+ if config == false
13
+ config = {}
14
+ end
12
15
  config['OPENAI_API_KEY'] = api_key
13
- File.open(Files.config_path, 'w') { |f| YAML.dump(config, f) }
16
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
14
17
  end
15
18
 
16
- def self.load_temperature
17
- config = YAML.load_file(Files.config_path)
18
- config['TEMPERATURE']
19
+ def load_temperature
20
+ config = YAML.load_file(config_path)
21
+ unless config == false
22
+ config['TEMPERATURE']
23
+ end
19
24
  end
20
25
 
21
- def self.save_temperature(temperature)
22
- config = YAML.load_file(Files.config_path)
26
+ def save_temperature(temperature)
27
+ config = YAML.load_file(config_path)
28
+ if config == false
29
+ config = {}
30
+ end
23
31
  config['TEMPERATURE'] = temperature.to_f
24
- File.open(Files.config_path, 'w') { |f| YAML.dump(config, f) }
32
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
25
33
  end
26
34
 
27
- def self.load_context_length
28
- config = YAML.load_file(Files.config_path)
29
- config['CONTEXT_LENGTH']
35
+ def load_context_length
36
+ config = YAML.load_file(config_path)
37
+ unless config == false
38
+ config['CONTEXT_LENGTH']
39
+ end
30
40
  end
31
41
 
32
- def self.save_context_length(context_length)
33
- config = YAML.load_file(Files.config_path)
42
+ def save_context_length(context_length)
43
+ config = YAML.load_file(config_path)
44
+ if config == false
45
+ config = {}
46
+ end
34
47
  config['CONTEXT_LENGTH'] = context_length.to_i
35
- File.open(Files.config_path, 'w') { |f| YAML.dump(config, f) }
48
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
36
49
  end
37
50
 
38
- def self.set_config(value)
39
- puts 'value',value
51
+ def set_config(value)
40
52
  if value.include?('key')
41
53
  stript_value = value.sub(/^key/, '').strip
42
54
  if stript_value.empty?
43
- puts 'No API key given'
44
- exit
55
+ return 'No API key given'
45
56
  end
46
57
  save_key(stript_value)
58
+ return 'API key saved'
47
59
  elsif value.include?('temp')
48
- stript_value = value.sub(/^temp/, '').strip
49
- if stript_value.empty?
50
- puts 'No temperature given'
51
- exit
60
+ stript_value = value.sub(/^temp/, '').strip.to_f
61
+ if stript_value.to_f > 1.0 || stript_value.to_f < 0.1
62
+ return 'Temperature must be between 0.1 and 1.0'
52
63
  end
53
64
  save_temperature(stript_value)
65
+ return 'Temperature saved'
54
66
  elsif value.include?('context')
55
- stript_value = value.sub(/^context/, '').strip
56
- if stript_value.empty?
57
- puts 'No context length given'
58
- exit
67
+ stript_value = value.sub(/^context/, '').strip.to_i
68
+ if stript_value.to_i > 100 || stript_value.to_i < 1
69
+ return 'Context length must be between 1 and 100'
59
70
  end
60
71
  save_context_length(stript_value)
72
+ return 'Context length saved'
61
73
  else
62
- puts 'Invalid config value'
74
+ return 'Invalid config value'
63
75
  end
64
76
  end
77
+
78
+ def set_key(api_key: nil)
79
+ if api_key.nil?
80
+ log("Setting API key...")
81
+ log("Enter API key: (or press enter to exit)")
82
+
83
+ while input = Readline.readline("> ", true) do
84
+ if input.empty?
85
+ log("Exiting.")
86
+ exit
87
+ else
88
+ api_key = input.strip
89
+ break
90
+ end
91
+ end
92
+ log("Saving API key...")
93
+ end
94
+
95
+ FileUtils.mkdir_p(File.dirname(config_path))
96
+ File.open(config_path, "w") do |f|
97
+ f.write(YAML.dump({ "OPENAI_API_KEY" => api_key }))
98
+ end
99
+ log("API key saved.")
100
+ log("")
101
+ end
102
+
103
+ def load_env()
104
+ #Config.load_key()
105
+ YAML.load(File.read(config_path))
106
+
107
+ rescue Errno::ENOENT
108
+ log("No config.yml found.")
109
+ end
65
110
  end
data/lib/context.rb CHANGED
@@ -1,10 +1,10 @@
1
1
  require_relative './files.rb'
2
2
  require_relative './config.rb'
3
3
  class Context
4
- include Files, Config
4
+ extend Files, Config, Logging
5
5
  def self.load_context()
6
- if File.exist?(Files.context_path)
7
- conversation = File.readlines(Files.context_path).map { |line| JSON.parse(line) }
6
+ if File.exist?(context_path)
7
+ conversation = File.readlines(context_path).map { |line| JSON.parse(line) }
8
8
  else
9
9
  conversation = []
10
10
  end
@@ -27,30 +27,30 @@ class Context
27
27
  ## Here we save the context to a file.
28
28
  ## Max 10 previous Q / A to save tokens.
29
29
  def self.save_context(context)
30
+ return if context.nil?
30
31
  tmp_arr = []
31
- unless File.exist?(Files.context_path)
32
- File.open(Files.context_path, "w") {}
32
+ unless File.exist?(context_path)
33
+ File.open(context_path, "w") {}
33
34
  end
34
- File.readlines(Files.context_path).map { |line| tmp_arr.push(JSON.parse(line)) }
35
- length = Config.load_context_length().nil? ? 10 : Config.load_context_length()
35
+ File.readlines(context_path).map { |line| tmp_arr.push(JSON.parse(line)) }
36
+ length = load_context_length().nil? ? 10 : load_context_length()
36
37
  if tmp_arr.length > length
37
38
  tmp_arr.shift()
38
39
  end
39
- File.truncate(Files.context_path, 0)
40
- tmp_arr.each { |line| File.open(Files.context_path, "a") { |file| file.write("#{line.to_json}\n") } }
41
- File.open(Files.context_path, "a") { |file| file.write("#{context.to_json}\n") }
40
+ File.truncate(context_path, 0)
41
+ tmp_arr.each { |line| File.open(context_path, "a") { |file| file.write("#{line.to_json}\n") } }
42
+ File.open(context_path, "a") { |file| file.write("#{context.to_json}\n") }
42
43
  end
43
44
 
44
45
  def self.delete_context()
45
- Logging.log("Deleting previous context.")
46
- File.truncate(Files.context_path, 0)
46
+ log("Deleting previous context.")
47
+ File.truncate(context_path, 0)
47
48
  end
48
49
 
49
50
  def self.save_context_file(file_path)
50
- puts "File path: #{file_path}"
51
51
  unless file_path.nil?
52
52
  file_in = File.open(file_path, 'r')
53
- file_out = File.open(Files.context_file_path, 'w')
53
+ file_out = File.open(context_file_path, 'w')
54
54
  char_count = 0
55
55
  file_in.each do |line|
56
56
  puts "Line: #{line}"
@@ -61,17 +61,17 @@ class Context
61
61
  file_out.close
62
62
 
63
63
  if char_count > 10000
64
- Logging.log("Warning: The file you are trying to feed to the API is #{char_count} characters long. This consumes a lot of tokens.")
64
+ log("Warning: The file you are trying to feed to the API is #{char_count} characters long. This consumes a lot of tokens.")
65
65
  end
66
66
  else
67
- Logging.log("No file path given.")
67
+ log("No file path given.")
68
68
  end
69
69
  rescue Errno::ENOENT
70
- Logging.log("No file at '#{file_path}' found.")
70
+ log("No file at '#{file_path}' found.")
71
71
  end
72
72
 
73
73
  def self.load_context_file()
74
- file = File.open(Files.context_file_path, 'r')
74
+ file = File.open(context_file_path, 'r')
75
75
  file_as_string = ""
76
76
  file.each do |line|
77
77
  file_as_string += line
@@ -79,8 +79,8 @@ class Context
79
79
 
80
80
  return file_as_string
81
81
  rescue Errno::ENOENT
82
- Logging.log("No file at '#{Files.context_file_path}' found.")
83
- Logging.log("Load a file with 'aa -lf <file_path>'")
82
+ log("No file at '#{context_file_path}' found.")
83
+ log("Load a file with 'aa -lf <file_path>'")
84
84
  return ""
85
85
  end
86
86
 
data/lib/files.rb CHANGED
@@ -1,21 +1,21 @@
1
1
  module Files
2
- def self.root
2
+ def root
3
3
  File.expand_path("./../", __dir__)
4
4
  end
5
5
 
6
- def self.file_path
6
+ def file_path
7
7
  File.expand_path("./../files/", __dir__)
8
8
  end
9
9
 
10
- def self.context_path
10
+ def context_path
11
11
  File.expand_path("./../files/context.jsonl", __dir__)
12
12
  end
13
13
 
14
- def self.config_path
14
+ def config_path
15
15
  File.expand_path("./../config/config.yml", __dir__)
16
16
  end
17
17
 
18
- def self.context_file_path
18
+ def context_file_path
19
19
  File.expand_path("./../files/context_file.txt", __dir__)
20
20
  end
21
21
  end
data/lib/help.rb CHANGED
@@ -1,85 +1,49 @@
1
1
  require 'rubygems'
2
2
 
3
- class Help
4
- def self.display_help()
5
- Logging.log("Usage: aa [options] [input]")
6
- Logging.log(" -lf, --loadfile <path>: Load file into context")
7
- Logging.log(" -f, --file: Read from context file")
8
- Logging.log(" -c, --conversation: Append to conversation (max 10 Questions / Answers pairs saved)")
9
- Logging.log(" -d, --delete: Delete conversation")
10
- Logging.log(" -i, --interactive: Interactive mode, always a conversation. Clear context with 'clear' (exit with 'exit' or 'quit')")
11
- Logging.log(" -w, --whisper <path>: Transcribe audio file")
12
- Logging.log(" -t, --translate <path>: Translate audio file")
13
- Logging.log("\n Options:")
14
- Logging.log(" --config: Edit config file")
15
- Logging.log(" -v, --version: Display version")
16
- Logging.log(" -h, --help: Display this help message")
17
-
18
- end
19
-
20
- def self.display_api_key()
21
- Logging.log("You need to set your API key in the file: ./config/config.yml")
22
- Logging.log("Create the file if it doesn't exist.")
23
- Logging.log("Add the following line to the file:")
24
- Logging.log(" OPENAI_API_KEY: <your API key>")
25
- Logging.log("You can get your API key from: https://openai.com/")
26
- end
27
-
28
- ## This don't work yet. Need to rework the way we handle args.
29
- def self.display_help_file()
30
- ## TODO: How to work with files
31
- end
32
3
 
33
- ## This don't work yet. Need to rework the way we handle args.
34
- def self.display_help_conversation()
35
- ## TODO: How to work with conversation
36
- end
4
+ class Help
5
+ extend Logging
37
6
 
38
7
  def self.display_version()
39
- spec = Gem::Specification::load("ask-ai.gemspec")
40
- Logging.log("Version: #{spec.version}")
41
- end
42
-
43
- def self.display_usage()
44
- Logging.log("Usage: ./main.rb [options] [input]")
45
-
46
- Logging.log("There are two types of options, flags and arguments.")
8
+ ## Without using gemspec
9
+ spec = Gem::Specification::find_by_name("ask-ai")
10
+ log("Version: ask-ai-#{spec.version}")
47
11
  end
48
12
 
49
13
  def self.interactive_help(command)
50
14
  case command
51
15
  when '-w'
52
- Logging.log("Ex: -w /home/name/sound_file.m4a")
53
- Logging.log("Will transcribe the audio file.")
16
+ log("Ex: -w /home/name/sound_file.m4a")
17
+ log("Will transcribe the audio file.")
54
18
  when '-t'
55
- Logging.log("Ex: -t /home/name/sound_file.m4a")
56
- Logging.log("Will translate the audio file to English.")
19
+ log("Ex: -t /home/name/sound_file.m4a")
20
+ log("Will translate the audio file to English.")
57
21
  when '-lf'
58
- Logging.log("Ex: -lf /home/name/some_text_file.txt'")
59
- Logging.log("Will load the file into context.")
60
- Logging.log("The file should a [txt, CSV]. More formats coming soon.")
22
+ log("Ex: -lf /home/name/some_text_file.txt'")
23
+ log("Will load the file into context.")
24
+ log("The file should a [txt, CSV]. More formats coming soon.")
61
25
  when '-f'
62
- Logging.log("Ex: -f Can you describe the file i provided?")
26
+ log("Ex: -f Can you describe the file i provided?")
63
27
  when 'config'
64
- Logging.log("Ex: config key <your API key>")
65
- Logging.log("Ex: config temp <0.0 - 1.0>")
66
- Logging.log("Ex: config context <0 - 100>")
67
- Logging.log("Beaware that the more context you use, the more expensive it will be.")
28
+ log("Ex: config key <your API key>")
29
+ log("Ex: config temp <0.0 - 1.0>")
30
+ log("Ex: config context <0 - 100>")
31
+ log("Beaware that the more context you use, the more expensive it will be.")
68
32
  else
69
- Logging.log("No help for: #{command}")
33
+ log("No help for: #{command}")
70
34
  end
71
35
 
72
36
  end
73
37
 
74
38
  def self.interactive_desc()
75
- Logging.log("Type 'exit' or 'quit' to exit.")
76
- Logging.log("Type 'clear' to clear context.")
77
- Logging.log("Type 'show' to show context.")
78
- Logging.log("Type 'help' to show help.")
79
- Logging.log("Type 'config [key, temp, context]' to change config.")
80
- Logging.log("Type '-w <filepath>' to whisper transcribe.")
81
- Logging.log("Type '-t' <filepath> to whisper translate.")
82
- Logging.log("Type '-lf' <filepath> to load file.")
83
- Logging.log("Type '-f' to use loaded file as context.")
39
+ log("Type 'exit' or 'quit' to exit.")
40
+ log("Type 'clear' to clear context.")
41
+ log("Type 'show' to show context.")
42
+ log("Type 'help' to show help.")
43
+ log("Type 'config [key, temp, context]' to change config.")
44
+ log("Type '-w <filepath>' to whisper transcribe.")
45
+ log("Type '-t' <filepath> to whisper translate.")
46
+ log("Type '-lf' <filepath> to load file.")
47
+ log("Type '-f' to use loaded file as context.")
84
48
  end
85
49
  end
data/lib/logging.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'logger'
2
2
 
3
3
  module Logging
4
- def self.log(msg)
4
+ def log(msg)
5
5
  logger = Logger.new(STDOUT)
6
6
  logger.formatter = proc { |_severity, _datetime, _progname, msg| "#{msg}\n" }
7
7
  logger.info(msg)
data/lib/main.rb CHANGED
@@ -6,192 +6,80 @@ require 'readline'
6
6
  require 'io/console'
7
7
  require_relative './logging.rb'
8
8
  require_relative './prompt.rb'
9
- require_relative './handle_args.rb'
10
9
  require_relative './help.rb'
11
10
  require_relative './context.rb'
12
11
  require_relative './files.rb'
13
12
  require_relative './config.rb'
14
13
 
15
14
  class Main
16
- include Logging, Files, Config
15
+ extend Logging, Files, Config
16
+ LIST = [
17
+ "exit", "quit", "version", "clear", "help", "show",
18
+ "-w", "-t", "-lf", "-f", "config", "temp", "context"
19
+ ].sort
17
20
 
18
21
  def self.run()
19
- config = load_env()
20
22
 
21
- ## This does not work. Need to fix this.
22
- if (config == false || config.nil?)
23
- Logging.log("No API key found.")
24
- Help.display_api_key()
25
- Logging.log('If you want to set your API key now, type (y)es and press enter.')
26
- while input = Readline.readline("> ", true) do
27
- if input.empty?
28
- Logging.log("Exiting.")
29
- exit
30
- elsif input == "y" || input == "yes" || input == "Y" || input == "Yes"
31
- set_key()
32
- break
33
- else
34
- Logging.log('Invalid input (y)es or press enter to exit.')
35
- end
36
- end
37
- end
23
+ ## When using Readline, TAB will auto-complete
24
+ ## But it will only auto-complete from the LIST
25
+ ## Need to handle directories and files when -lf, -w, -t are used
26
+ #comp = proc { |s| LIST.grep(/^#{Regexp.escape(s)}/) }
27
+ #Readline.completion_append_character = ""
28
+ #Readline.completion_proc = comp
38
29
 
39
- context = Context.load_context()
40
- options_and_input = HandleArgs.handle_args()
41
- options = options_and_input.select { |k, v| k.start_with?("option_") }
42
- input = options_and_input["input"]
43
-
44
- halt_options = ["-h", "--help", "-v", "--version", "--key"]
45
-
46
- ## Hack... Need to fix this.
47
- if options.empty?
48
- options = { "option_0" => "simple" }
49
- end
50
-
51
- options.each do |k, v|
52
- if halt_options.include?(v)
53
- ## Options that halt the program.
54
- case v
55
- when "-h", "--help"
56
- Help.display_help()
57
- exit
58
- when "-v", "--version"
59
- Help.display_version()
60
- exit
61
-
62
- when "--key"
63
- set_key(api_key: nil)
64
- else
65
- Help.display_help()
66
- exit
30
+ Help.interactive_desc()
31
+ while input = Readline.readline("\n> ", true) do
32
+ case input
33
+ when "exit", "quit"
34
+ break
35
+ when "version"
36
+ Help.display_version()
37
+ when "clear"
38
+ log("Clearing context...")
39
+ Context.delete_context()
40
+ when 'help'
41
+ Help.interactive_desc()
42
+ when /^help/
43
+ strip_input = input.sub(/^help/, "").strip
44
+ Help.interactive_help(strip_input)
45
+ when "show"
46
+ log("\n")
47
+ log(Context.load_context())
48
+ when /^-w/
49
+ stript_input = input.sub(/^-w/, "").strip
50
+ log(Prompt.whisper_transcribe(stript_input, interactive: true))
51
+ when /^-t/
52
+ stript_input = input.sub(/^-t/, "").strip
53
+ log(Prompt.whisper_translate(stript_input, interactive: true))
54
+ when /^-lf/
55
+ stript_input = input.sub(/^-lf/, "").strip
56
+ log("Loading File #{stript_input}")
57
+ Context.save_context_file(stript_input)
58
+ when /^-f/
59
+ stript_input = input.sub(/^-f/, "").strip
60
+ file_as_string = Context.load_context_file()
61
+ if file_as_string.empty?
62
+ log("No file loaded.")
63
+ next
67
64
  end
68
- else
69
- ## Options that don't halt the program.
70
- case v
71
- when "-f", "--file"
72
- file_as_string = Context.load_context_file()
73
- if file_as_string.empty?
74
- exit
75
- end
76
- Prompt.stream_prompt(input, file_as_string)
77
- when "-lf", "--loadfile"
78
- Logging.log("Loading File #{input}")
79
- Context.save_context_file(input)
80
- when "-d", "--delete"
81
- if input.nil?
82
- Context.delete_context()
83
- else
84
- Context.delete_context()
85
- Context.save_context(Prompt.stream_prompt(input, context))
86
- end
87
- when "-c", "--conversation"
88
- Logging.log(input)
89
- Context.save_context(Prompt.stream_prompt(input, context))
90
- when "-w", "--whisper"
91
- Logging.log(Prompt.whisper_transcribe(input))
92
- when "-t", "--translate"
93
- Logging.log(Prompt.whisper_translate(input))
94
- when "-i", "--interactive"
95
- Logging.log("Interactive mode...")
96
- Help.interactive_desc()
97
- while input = Readline.readline("\n> ", true) do
98
- case input
99
- when "exit", "quit"
100
- break
101
- when "clear"
102
- Logging.log("Clearing context...")
103
- Context.delete_context()
104
- when 'help'
105
- Help.interactive_desc()
106
- when /^help/
107
- strip_input = input.sub(/^help/, "").strip
108
- #TODO: This should be a specific help for interactive.
109
- Help.interactive_help(strip_input)
110
- when "show"
111
- Logging.log("\n")
112
- Logging.log(Context.load_context())
113
- when /^-w/
114
- stript_input = input.sub(/^-w/, "").strip
115
- Logging.log(Prompt.whisper_transcribe(stript_input, interactive: true))
116
- when /^-t/
117
- stript_input = input.sub(/^-t/, "").strip
118
- Logging.log(Prompt.whisper_translate(stript_input, interactive: true))
119
- when /^-lf/
120
- stript_input = input.sub(/^-lf/, "").strip
121
- Logging.log("Loading File #{stript_input}")
122
- Context.save_context_file(stript_input)
123
- when /^-f/
124
- stript_input = input.sub(/^-f/, "").strip
125
- file_as_string = Context.load_context_file()
126
- if file_as_string.empty?
127
- Logging.log("No file loaded.")
128
- next
129
- end
130
- Logging.log("")
131
- Prompt.stream_prompt(stript_input, file_as_string)
132
- Logging.log("")
133
- when ""
134
- Logging.log("No input given.")
135
- when /^config/
136
- strip_input = input.sub(/^config/, "").strip
137
- Config.set_config(strip_input)
138
- #set_key(api_key: nil)
139
- else
140
- #options_and_input = HandleArgs.handle_args()
141
- context = Context.load_context()
142
- Logging.log("")
143
- Context.save_context(Prompt.stream_prompt(input, context))
144
- Logging.log("")
145
- end
146
- end
147
- Logging.log("Exiting...")
148
- when "simple"
149
- if !input.nil?
150
- Prompt.stream_prompt(input)
151
- else
152
- Logging.log("No input given.")
153
- Help.display_help()
154
- end
155
- else
156
- Help.display_help()
157
- end
158
- end
159
- end
160
- end
161
-
162
- private
163
-
164
- def self.set_key(api_key: nil)
165
- if api_key.nil?
166
- Logging.log("Setting API key...")
167
- Logging.log("Enter API key: (or press enter to exit)")
168
-
169
- while input = Readline.readline("> ", true) do
170
- if input.empty?
171
- Logging.log("Exiting.")
172
- exit
173
- else
174
- api_key = input.strip
175
- break
65
+ log("")
66
+ Prompt.stream_prompt(stript_input, file_as_string)
67
+ log("")
68
+ when ""
69
+ log("No input given.")
70
+ when /^config/
71
+ strip_input = input.sub(/^config/, "").strip
72
+ res = set_config(strip_input)
73
+ if res.is_a?(String)
74
+ log(res)
176
75
  end
76
+ else
77
+ context = Context.load_context()
78
+ log("")
79
+ Context.save_context(Prompt.stream_prompt(input, context))
80
+ log("")
177
81
  end
178
- Logging.log("Saving API key...")
179
82
  end
180
-
181
- FileUtils.mkdir_p(File.dirname(Files.config_path))
182
- File.open(Files.config_path, "w") do |f|
183
- f.write(YAML.dump({ "OPENAI_API_KEY" => api_key }))
184
- end
185
- Logging.log("API key saved.")
186
- Logging.log("")
187
- end
188
-
189
- def self.load_env()
190
- #Config.load_key()
191
- YAML.load(File.read(Files.config_path))
192
-
193
- rescue Errno::ENOENT
194
- Logging.log("No config.yml found.")
195
83
  end
196
84
  end
197
85
 
data/lib/prompt.rb CHANGED
@@ -3,10 +3,9 @@ require_relative './files.rb'
3
3
  require_relative './config.rb'
4
4
 
5
5
  class Prompt
6
- include Files
7
- include Config
6
+ extend Files, Config, Logging
8
7
  ## Streams the response, VERY NICE
9
- def self.stream_prompt(input, conversation = '', temp = Config.load_temperature())
8
+ def self.stream_prompt(input, conversation = '', temp = load_temperature())
10
9
  if temp.nil?
11
10
  temp = 0.7
12
11
  end
@@ -16,23 +15,25 @@ class Prompt
16
15
  conversation += "\n My question: #{input}"
17
16
  end
18
17
  response = ''
19
- client.chat(
20
- parameters: {
21
- model: "gpt-3.5-turbo",
22
- messages: [{ role: "user", content: conversation}],
23
- temperature: temp, ## Should be a parameter
24
- stream: proc do |chunk, _bytesize|
25
- response += chunk.dig("choices", 0, "delta", "content") unless chunk.dig("choices", 0, "delta", "content").nil?
26
- print chunk.dig("choices", 0, "delta", "content")
27
- end
18
+ unless client.nil?
19
+ client.chat(
20
+ parameters: {
21
+ model: "gpt-3.5-turbo",
22
+ messages: [{ role: "user", content: conversation}],
23
+ temperature: temp, ## Should be a parameter
24
+ stream: proc do |chunk, _bytesize|
25
+ response += chunk.dig("choices", 0, "delta", "content") unless chunk.dig("choices", 0, "delta", "content").nil?
26
+ print chunk.dig("choices", 0, "delta", "content")
27
+ end
28
+ }
29
+ )
30
+ context = {
31
+ "input" => input,
32
+ "response" => response,
28
33
  }
29
- )
30
- context = {
31
- "input" => input,
32
- "response" => response,
33
- }
34
34
 
35
- return context
35
+ return context
36
+ end
36
37
  end
37
38
 
38
39
  ## Not implemented only scaffolding
@@ -47,7 +48,7 @@ class Prompt
47
48
 
48
49
  def self.whisper_translate(file_path, interactive = false)
49
50
  if (file_path.nil? || !file_path.end_with?(*['.mp3', '.wav', '.m4a', '.webm', '.mpeg', '.mpga']))
50
- Logging.log("No file given or wrong file type")
51
+ log("No file given or wrong file type")
51
52
  unless interactive
52
53
  exit
53
54
  end
@@ -59,27 +60,29 @@ class Prompt
59
60
  exit
60
61
  end
61
62
  else
62
- response = client.audio.translate(
63
- parameters: {
64
- model: "whisper-1",
65
- file: File.open(file_path, "rb"),
66
- })
67
- if (response["text"].nil? || response["text"].empty?)
68
- Logging.log("No text found")
69
- unless interactive
70
- exit
63
+ unless client.nil?
64
+ response = client.audio.translate(
65
+ parameters: {
66
+ model: "whisper-1",
67
+ file: File.open(file_path, "rb"),
68
+ })
69
+ if (response["text"].nil? || response["text"].empty?)
70
+ log("No text found")
71
+ unless interactive
72
+ exit
73
+ end
71
74
  end
75
+ return response["text"]
72
76
  end
73
- return response["text"]
74
77
  end
75
78
  end
76
79
  rescue Errno::ENOENT => e
77
- Logging.log(e)
80
+ log(e)
78
81
  end
79
82
 
80
83
  def self.whisper_transcribe(file_path, interactive = false)
81
84
  if (file_path.nil? || !file_path.end_with?(*['.mp3', '.wav', '.m4a', '.webm', '.mpeg', '.mpga']))
82
- Logging.log("No file given")
85
+ log("No file given")
83
86
  unless interactive
84
87
  exit
85
88
  end
@@ -91,31 +94,40 @@ class Prompt
91
94
  exit
92
95
  end
93
96
  else
94
- response = client.audio.transcribe(
95
- parameters: {
96
- model: "whisper-1",
97
- file: File.open(file_path, "rb"),
98
- })
99
- if (response["text"].nil? || response["text"].empty?)
100
- Logging.log("No text found")
101
- unless interactive
102
- exit
97
+ unless client.nil?
98
+ response = client.audio.transcribe(
99
+ parameters: {
100
+ model: "whisper-1",
101
+ file: File.open(file_path, "rb"),
102
+ })
103
+ if (response["text"].nil? || response["text"].empty?)
104
+ log("No text found")
105
+ unless interactive
106
+ exit
107
+ end
103
108
  end
109
+ return response["text"]
104
110
  end
105
- return response["text"]
106
111
  end
107
112
  end
108
113
  rescue Errno::ENOENT => e
109
114
  #Logging.log("File not found")
110
- Logging.log(e)
115
+ log(e)
111
116
  end
112
117
 
113
118
  private
114
119
 
115
120
  def self.client()
116
- conf = YAML.load(File.read(Files.config_path))
117
- key = conf["OPENAI_API_KEY"]
121
+ conf = YAML.load(File.read(config_path))
122
+ unless conf == false
123
+ key = conf["OPENAI_API_KEY"]
124
+ end
118
125
 
119
- OpenAI::Client.new(access_token: key)
126
+ begin
127
+ OpenAI::Client.new(access_token: key)
128
+ rescue OpenAI::ConfigurationError => e
129
+ log("OpenAI API key not found, run 'config key' to set it")
130
+ return nil
131
+ end
120
132
  end
121
133
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ask-ai
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oskar Franck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-04 00:00:00.000000000 Z
11
+ date: 2023-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-openai
@@ -39,7 +39,6 @@ files:
39
39
  - lib/config.rb
40
40
  - lib/context.rb
41
41
  - lib/files.rb
42
- - lib/handle_args.rb
43
42
  - lib/help.rb
44
43
  - lib/logging.rb
45
44
  - lib/main.rb
@@ -63,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
62
  - !ruby/object:Gem::Version
64
63
  version: '0'
65
64
  requirements: []
66
- rubygems_version: 3.3.7
65
+ rubygems_version: 3.2.33
67
66
  signing_key:
68
67
  specification_version: 4
69
68
  summary: A simple CLI for OpenAI's GPT-3 API.
data/lib/handle_args.rb DELETED
@@ -1,61 +0,0 @@
1
- class HandleArgs
2
- def self.permitted_options()
3
- ## TODO: Add more options.
4
- ## -t --translate
5
- ## -temp --temperature (need to handle value after input)
6
-
7
- [
8
- '-h',
9
- '--help',
10
- '-v',
11
- '--version',
12
- '-f',
13
- '--file',
14
- '-lf',
15
- '--loadfile',
16
- '-d',
17
- '--delete',
18
- '-c',
19
- '--conversation',
20
- '--finetune',
21
- '-w', '--whisper',
22
- '-t', '--translate',
23
- '-i', '--interactive',
24
- '--key',
25
- ]
26
- end
27
-
28
- def self.handle_args()
29
- p_args = HandleArgs.permitted_options()
30
- ## This is the hash that will be returned.
31
- args_hash = {}
32
-
33
- ## This handles args then called as ruby script.
34
- ARGV.each_with_index do |arg, i|
35
- #Logging.log("Arg: #{arg}")
36
-
37
- if arg.start_with?('-')
38
- ## This is an option.
39
- if p_args.include?(arg)
40
- ## This is a permitted / available option.
41
- #Logging.log("Option: #{arg}")
42
- args_hash["option_#{i}"] = arg
43
- else
44
- ## This is an unknown option.
45
- ## TODO: Handle unknown option. display help? discard?
46
- Logging.log("Unknown option: #{arg}")
47
- args_hash["option_#{i}"] = arg
48
- end
49
- else
50
- ## This is input.
51
- ## This if statement append all 'input' args to one string.
52
- if args_hash["input"].nil?
53
- args_hash["input"] = arg
54
- else
55
- args_hash["input"] = "#{args_hash['input']} #{arg}"
56
- end
57
- end
58
- end
59
- return args_hash
60
- end
61
- end