ask-ai 0.0.4 → 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: b9aac9c44ecfb8fd4a68b1329f7dc48e37b09910011b7a1d1ad085f2afd48407
4
- data.tar.gz: c3b58592fce1e23ae7184a3b6d37d58451b8da82992c90dd503c4705a1fb94ff
3
+ metadata.gz: 3d0033fda00a5a8399a6e9b71c75338b02269df54edb791bd82215e939492d15
4
+ data.tar.gz: 391d4cc9fe240289358f2489b61224b8d0706254174f9ad4a5ec7a109b7b3a89
5
5
  SHA512:
6
- metadata.gz: f075fc93f55659c6f8d9331f5e508dcc6ac9f77e52cf4a8e2df2d25e3e727a8bef5f8f253588a4de06b8c67f7f2704792ed62f7c7e98d4337b5df0b843f34652
7
- data.tar.gz: 4d74731c56a046231dc11bd889c37c42e591dfcaebef7e1aaba11d6a0dd64c4942e01474e67f526b2a061a1681d806befa9934f60c070d2b0ead4fa45bc75d8e
6
+ metadata.gz: 6f749624e465e35a8ebcae8b7b9b312d1f4ffdbd8e390043a0fc87dae5eaf680931975eb87369eba855043eff52206c2daf47af95fc5136e7fb0134520275a28
7
+ data.tar.gz: 81d6f56f465808352087d5f53bab44b7a1af2d63292dbba4b5fab7f91b44fd3d78c6a591718d142f6348c6ab78bae8a54d84b2cba73e2164efd32dd3b27d4e1d
data/lib/config.rb ADDED
@@ -0,0 +1,110 @@
1
+ require_relative './files.rb'
2
+
3
+ module Config
4
+ extend Files
5
+ def load_key()
6
+ config = YAML.load_file(config_path)
7
+ config['OPENAI_API_KEY']
8
+ end
9
+
10
+ def save_key(api_key)
11
+ config = YAML.load_file(config_path)
12
+ if config == false
13
+ config = {}
14
+ end
15
+ config['OPENAI_API_KEY'] = api_key
16
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
17
+ end
18
+
19
+ def load_temperature
20
+ config = YAML.load_file(config_path)
21
+ unless config == false
22
+ config['TEMPERATURE']
23
+ end
24
+ end
25
+
26
+ def save_temperature(temperature)
27
+ config = YAML.load_file(config_path)
28
+ if config == false
29
+ config = {}
30
+ end
31
+ config['TEMPERATURE'] = temperature.to_f
32
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
33
+ end
34
+
35
+ def load_context_length
36
+ config = YAML.load_file(config_path)
37
+ unless config == false
38
+ config['CONTEXT_LENGTH']
39
+ end
40
+ end
41
+
42
+ def save_context_length(context_length)
43
+ config = YAML.load_file(config_path)
44
+ if config == false
45
+ config = {}
46
+ end
47
+ config['CONTEXT_LENGTH'] = context_length.to_i
48
+ File.open(config_path, 'w') { |f| YAML.dump(config, f) }
49
+ end
50
+
51
+ def set_config(value)
52
+ if value.include?('key')
53
+ stript_value = value.sub(/^key/, '').strip
54
+ if stript_value.empty?
55
+ return 'No API key given'
56
+ end
57
+ save_key(stript_value)
58
+ return 'API key saved'
59
+ elsif value.include?('temp')
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'
63
+ end
64
+ save_temperature(stript_value)
65
+ return 'Temperature saved'
66
+ elsif value.include?('context')
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'
70
+ end
71
+ save_context_length(stript_value)
72
+ return 'Context length saved'
73
+ else
74
+ return 'Invalid config value'
75
+ end
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
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
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,46 +27,51 @@ 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
- if tmp_arr.length > 9
35
+ File.readlines(context_path).map { |line| tmp_arr.push(JSON.parse(line)) }
36
+ length = load_context_length().nil? ? 10 : load_context_length()
37
+ if tmp_arr.length > length
36
38
  tmp_arr.shift()
37
39
  end
38
- File.truncate(Files.context_path, 0)
39
- tmp_arr.each { |line| File.open(Files.context_path, "a") { |file| file.write("#{line.to_json}\n") } }
40
- 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") }
41
43
  end
42
44
 
43
45
  def self.delete_context()
44
- Logging.log("Deleting previous context.")
45
- File.truncate(Files.context_path, 0)
46
+ log("Deleting previous context.")
47
+ File.truncate(context_path, 0)
46
48
  end
47
49
 
48
50
  def self.save_context_file(file_path)
49
51
  unless file_path.nil?
50
52
  file_in = File.open(file_path, 'r')
51
- file_out = File.open(Files.context_file_path, 'w')
53
+ file_out = File.open(context_file_path, 'w')
52
54
  char_count = 0
53
55
  file_in.each do |line|
56
+ puts "Line: #{line}"
54
57
  char_count += line.length
55
58
  file_out.write(line)
56
59
  end
60
+ file_in.close
61
+ file_out.close
57
62
 
58
63
  if char_count > 10000
59
- 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.")
60
65
  end
61
66
  else
62
- Logging.log("No file path given.")
67
+ log("No file path given.")
63
68
  end
64
69
  rescue Errno::ENOENT
65
- Logging.log("No file at '#{file_path}' found.")
70
+ log("No file at '#{file_path}' found.")
66
71
  end
67
72
 
68
73
  def self.load_context_file()
69
- file = File.open(Files.context_file_path, 'r')
74
+ file = File.open(context_file_path, 'r')
70
75
  file_as_string = ""
71
76
  file.each do |line|
72
77
  file_as_string += line
@@ -74,8 +79,8 @@ class Context
74
79
 
75
80
  return file_as_string
76
81
  rescue Errno::ENOENT
77
- Logging.log("No file at '#{Files.context_file_path}' found.")
78
- 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>'")
79
84
  return ""
80
85
  end
81
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,48 +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
3
 
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
4
+ class Help
5
+ extend Logging
27
6
 
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
7
+ def self.display_version()
8
+ ## Without using gemspec
9
+ spec = Gem::Specification::find_by_name("ask-ai")
10
+ log("Version: ask-ai-#{spec.version}")
31
11
  end
32
12
 
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
13
+ def self.interactive_help(command)
14
+ case command
15
+ when '-w'
16
+ log("Ex: -w /home/name/sound_file.m4a")
17
+ log("Will transcribe the audio file.")
18
+ when '-t'
19
+ log("Ex: -t /home/name/sound_file.m4a")
20
+ log("Will translate the audio file to English.")
21
+ when '-lf'
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.")
25
+ when '-f'
26
+ log("Ex: -f Can you describe the file i provided?")
27
+ when 'config'
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.")
32
+ else
33
+ log("No help for: #{command}")
34
+ end
37
35
 
38
- def self.display_version()
39
- spec = Gem::Specification::load("ask-ai.gemspec")
40
- Logging.log("Version: #{spec.version}")
41
36
  end
42
37
 
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.")
38
+ def self.interactive_desc()
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.")
47
48
  end
48
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,175 +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'
12
+ require_relative './config.rb'
13
13
 
14
14
  class Main
15
- include Logging
16
- include Files
17
- def self.run()
18
- config = load_env()
19
-
20
- ## This does not work. Need to fix this.
21
- if config == false
22
- Logging.log("No API key found.")
23
- Help.display_api_key()
24
- Logging.log('If you want to set your API key now, type (y)es and press enter.')
25
- while input = Readline.readline("> ", true) do
26
- if input.empty?
27
- Logging.log("Exiting.")
28
- exit
29
- elsif input == "y" || input == "yes" || input == "Y" || input == "Yes"
30
- set_key()
31
- exit
32
- else
33
- Logging.log('Invalid input (y)es or press enter to exit.')
34
- end
35
- end
36
- end
37
-
38
- context = Context.load_context()
39
- options_and_input = HandleArgs.handle_args()
40
- options = options_and_input.select { |k, v| k.start_with?("option_") }
41
- input = options_and_input["input"]
15
+ extend Logging, Files, Config
16
+ LIST = [
17
+ "exit", "quit", "version", "clear", "help", "show",
18
+ "-w", "-t", "-lf", "-f", "config", "temp", "context"
19
+ ].sort
42
20
 
43
- halt_options = ["-h", "--help", "-v", "--version", "--key"]
21
+ def self.run()
44
22
 
45
- ## Hack... Need to fix this.
46
- if options.empty?
47
- options = { "option_0" => "simple" }
48
- 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
49
29
 
50
- options.each do |k, v|
51
- if halt_options.include?(v)
52
- ## Options that halt the program.
53
- case v
54
- when "-h", "--help"
55
- Help.display_help()
56
- exit
57
- when "-v", "--version"
58
- Help.display_version()
59
- exit
60
-
61
- when "--key"
62
- set_key(api_key: nil)
63
- else
64
- Help.display_help()
65
- 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
66
64
  end
67
- else
68
- ## Options that don't halt the program.
69
- case v
70
- when "-f", "--file"
71
- file_as_string = Context.load_context_file()
72
- if file_as_string.empty?
73
- exit
74
- end
75
- Prompt.stream_prompt(input, file_as_string)
76
- when "-lf", "--loadfile"
77
- Logging.log("Loading File #{input}")
78
- Context.save_context_file(input)
79
- when "-d", "--delete"
80
- if input.nil?
81
- Context.delete_context()
82
- else
83
- Context.delete_context()
84
- Context.save_context(Prompt.stream_prompt(input, context))
85
- end
86
- when "-c", "--conversation"
87
- Logging.log(input)
88
- Context.save_context(Prompt.stream_prompt(input, context))
89
- when "-w", "--whisper"
90
- Logging.log(Prompt.whisper_transcribe(input))
91
- when "-t", "--translate"
92
- Logging.log(Prompt.whisper_translate(input))
93
- when "-i", "--interactive"
94
- Logging.log("Interactive mode...")
95
- Logging.log("Type 'exit' or 'quit' to exit.")
96
- Logging.log("Type 'clear' to clear context.")
97
- Logging.log("Type 'show' to show context.")
98
- Logging.log("Type 'help' to show help.")
99
- Logging.log("Type 'config' to change config.")
100
- Logging.log("Type '-w' to whisper transcribe.")
101
- Logging.log("Type '-t' to whisper translate.")
102
-
103
- while input = Readline.readline("\n> ", true) do
104
- case input
105
- when "exit", "quit"
106
- break
107
- when "clear"
108
- Logging.log("Clearing context...")
109
- Context.delete_context()
110
- when "help"
111
- #TODO: This should be a specific help for interactive.
112
- Help.display_help()
113
- when "show"
114
- Logging.log("\n")
115
- Logging.log(Context.load_context())
116
- when /^-w/
117
- stript_input = input.sub(/^-w/, "").strip
118
- Logging.log(Prompt.whisper_transcribe(stript_input, interactive: true))
119
- when /^-t/
120
- stript_input = input.sub(/^-t/, "").strip
121
- Logging.log(Prompt.whisper_translate(stript_input, interactive: true))
122
- when "config"
123
- set_key(api_key: nil)
124
- else
125
- #options_and_input = HandleArgs.handle_args()
126
- context = Context.load_context()
127
- Logging.log("")
128
- Context.save_context(Prompt.stream_prompt(input, context))
129
- Logging.log("")
130
- end
131
- end
132
- Logging.log("Exiting...")
133
- when "simple"
134
- if !input.nil?
135
- Prompt.stream_prompt(input)
136
- else
137
- Logging.log("No input given.")
138
- Help.display_help()
139
- end
140
- else
141
- Help.display_help()
142
- end
143
- end
144
- end
145
- end
146
-
147
- private
148
-
149
- def self.set_key(api_key: nil)
150
- if api_key.nil?
151
- Logging.log("Setting API key...")
152
- Logging.log("Enter API key: (or press enter to exit)")
153
-
154
- while input = Readline.readline("> ", true) do
155
- if input.empty?
156
- Logging.log("Exiting.")
157
- exit
158
- else
159
- api_key = input.strip
160
- 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)
161
75
  end
76
+ else
77
+ context = Context.load_context()
78
+ log("")
79
+ Context.save_context(Prompt.stream_prompt(input, context))
80
+ log("")
162
81
  end
163
- Logging.log("Saving API key...")
164
82
  end
165
-
166
- FileUtils.mkdir_p(File.dirname(Files.config_path))
167
- File.open(Files.config_path, "w") do |f|
168
- f.write(YAML.dump({ "OPENAI_API_KEY" => api_key }))
169
- end
170
- Logging.log("API key saved.")
171
- end
172
-
173
- def self.load_env()
174
- YAML.load(File.read(Files.config_path))
175
-
176
- rescue Errno::ENOENT
177
- Logging.log("No config.yml found.")
178
83
  end
179
84
  end
180
85
 
data/lib/prompt.rb CHANGED
@@ -1,33 +1,39 @@
1
1
  require "openai"
2
2
  require_relative './files.rb'
3
+ require_relative './config.rb'
3
4
 
4
5
  class Prompt
5
- include Files
6
+ extend Files, Config, Logging
6
7
  ## Streams the response, VERY NICE
7
- def self.stream_prompt(input, conversation = '', temp = 0.7)
8
+ def self.stream_prompt(input, conversation = '', temp = load_temperature())
9
+ if temp.nil?
10
+ temp = 0.7
11
+ end
8
12
  if conversation.length == 0
9
13
  conversation += input
10
14
  else
11
15
  conversation += "\n My question: #{input}"
12
16
  end
13
17
  response = ''
14
- client.chat(
15
- parameters: {
16
- model: "gpt-3.5-turbo",
17
- messages: [{ role: "user", content: conversation}],
18
- temperature: temp, ## Should be a parameter
19
- stream: proc do |chunk, _bytesize|
20
- response += chunk.dig("choices", 0, "delta", "content") unless chunk.dig("choices", 0, "delta", "content").nil?
21
- print chunk.dig("choices", 0, "delta", "content")
22
- 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,
23
33
  }
24
- )
25
- context = {
26
- "input" => input,
27
- "response" => response,
28
- }
29
34
 
30
- return context
35
+ return context
36
+ end
31
37
  end
32
38
 
33
39
  ## Not implemented only scaffolding
@@ -42,7 +48,7 @@ class Prompt
42
48
 
43
49
  def self.whisper_translate(file_path, interactive = false)
44
50
  if (file_path.nil? || !file_path.end_with?(*['.mp3', '.wav', '.m4a', '.webm', '.mpeg', '.mpga']))
45
- Logging.log("No file given or wrong file type")
51
+ log("No file given or wrong file type")
46
52
  unless interactive
47
53
  exit
48
54
  end
@@ -54,27 +60,29 @@ class Prompt
54
60
  exit
55
61
  end
56
62
  else
57
- response = client.audio.translate(
58
- parameters: {
59
- model: "whisper-1",
60
- file: File.open(file_path, "rb"),
61
- })
62
- if (response["text"].nil? || response["text"].empty?)
63
- Logging.log("No text found")
64
- unless interactive
65
- 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
66
74
  end
75
+ return response["text"]
67
76
  end
68
- return response["text"]
69
77
  end
70
78
  end
71
79
  rescue Errno::ENOENT => e
72
- Logging.log(e)
80
+ log(e)
73
81
  end
74
82
 
75
83
  def self.whisper_transcribe(file_path, interactive = false)
76
84
  if (file_path.nil? || !file_path.end_with?(*['.mp3', '.wav', '.m4a', '.webm', '.mpeg', '.mpga']))
77
- Logging.log("No file given")
85
+ log("No file given")
78
86
  unless interactive
79
87
  exit
80
88
  end
@@ -86,31 +94,40 @@ class Prompt
86
94
  exit
87
95
  end
88
96
  else
89
- response = client.audio.transcribe(
90
- parameters: {
91
- model: "whisper-1",
92
- file: File.open(file_path, "rb"),
93
- })
94
- if (response["text"].nil? || response["text"].empty?)
95
- Logging.log("No text found")
96
- unless interactive
97
- 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
98
108
  end
109
+ return response["text"]
99
110
  end
100
- return response["text"]
101
111
  end
102
112
  end
103
113
  rescue Errno::ENOENT => e
104
114
  #Logging.log("File not found")
105
- Logging.log(e)
115
+ log(e)
106
116
  end
107
117
 
108
118
  private
109
119
 
110
120
  def self.client()
111
- conf = YAML.load(File.read(Files.config_path))
112
- 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
113
125
 
114
- 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
115
132
  end
116
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.4
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-03 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
@@ -36,13 +36,12 @@ files:
36
36
  - config/config.yml
37
37
  - files/context.jsonl
38
38
  - files/context_file.txt
39
+ - lib/config.rb
39
40
  - lib/context.rb
40
41
  - lib/files.rb
41
- - lib/handle_args.rb
42
42
  - lib/help.rb
43
43
  - lib/logging.rb
44
44
  - lib/main.rb
45
- - lib/paths.rb
46
45
  - lib/prompt.rb
47
46
  homepage: https://github.com/OskarFranck/terminal_chat
48
47
  licenses:
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
data/lib/paths.rb DELETED
@@ -1,26 +0,0 @@
1
-
2
- module Files
3
- def self.root
4
- File.expand_path("./../", __dir__)
5
- end
6
-
7
- def self.context
8
- File.expand_path("./../files/context.jsonl", __dir__)
9
- end
10
-
11
- def self.files
12
- FILE_PATH
13
- end
14
-
15
- def self.config
16
- CONFIG_PATH
17
- end
18
-
19
- def self.context_file
20
- CONTEXT_FILE_PATH
21
- end
22
- end
23
- CONTEXT_PATH = File.expand_path("./../files/context.jsonl", __dir__)
24
- FILE_PATH = File.expand_path("./../files/", __dir__)
25
- CONFIG_PATH = File.expand_path("./../config/config.yml", __dir__)
26
- CONTEXT_FILE_PATH = File.expand_path("./../files/context_file.txt", __dir__)