monadic-chat 0.3.4 → 0.3.5

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.
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MonadicChat
4
+ def self.open_readme
5
+ url = "https://github.com/yohasebe/monadic-chat/"
6
+ Launchy.open(url)
7
+ end
8
+
9
+ def self.mdprint(str)
10
+ print TTY::Markdown.parse(str, indent: 0)
11
+ end
12
+
13
+ def self.prompt_system
14
+ box_width = 8
15
+ name = "System".center(box_width, " ")
16
+ color = "green"
17
+ "\n#{PASTEL.send(:"on_#{color}", name)}"
18
+ end
19
+
20
+ def self.prompt_user
21
+ box_width = 6
22
+ color = "blue"
23
+ name = "User".center(box_width, " ")
24
+ "\n#{PASTEL.send(:"on_#{color}", name)}"
25
+ end
26
+
27
+ def self.prompt_assistant
28
+ box_width = 5
29
+ color = "red"
30
+ name = "GPT".center(box_width, " ")
31
+ "\n#{PASTEL.send(:"on_#{color}", name)}"
32
+ end
33
+
34
+ def self.tokenize(text)
35
+ BLINGFIRE.text_to_ids(text)
36
+ end
37
+
38
+ def self.create_app(app_name)
39
+ app_name = +app_name.downcase
40
+ user_apps_dir = File.join(HOME, "user_apps")
41
+ user_app_dir = File.join(user_apps_dir, app_name)
42
+ FileUtils.mkdir_p(user_app_dir)
43
+ # replace certain strings in boilerplate files (boilerplate.rb, boilerplate.json, boilerplate.md)
44
+ [".rb", ".json", ".md"].each do |ext|
45
+ file = File.join(HOME, "user_apps", "boilerplates", "boilerplate#{ext}")
46
+ content = File.read(file)
47
+ content.gsub!("{{APP_NAME}}", app_name)
48
+ content.gsub!("{{APP_CLASS_NAME}}", app_name.capitalize)
49
+ File.open(File.join(user_app_dir, "#{app_name}#{ext}"), "w") do |f|
50
+ f.write(content)
51
+ end
52
+ end
53
+ print PROMPT_SYSTEM.prefix, "Scaffolding of the app created successfully", "\n"
54
+ print "Edit the app files:", "\n"
55
+ print HOME, "\n"
56
+ print "user_apps", "\n"
57
+ print "└── #{app_name}", "\n"
58
+ print " ├── #{app_name}.json", "\n"
59
+ print " ├── #{app_name}.md", "\n"
60
+ print " └── #{app_name}.rb", "\n"
61
+ end
62
+
63
+ def self.delete_app(app_name)
64
+ app_name = +app_name.downcase
65
+ user_apps_dir = File.join(HOME, "user_apps")
66
+ user_app_dir = File.join(user_apps_dir, app_name)
67
+ # confirm user wants to delete the app
68
+ if PROMPT_SYSTEM.yes?("Are you sure you want to delete the app #{app_name}?")
69
+ FileUtils.rm_rf(user_app_dir)
70
+ print PROMPT_SYSTEM.prefix, "App deleted successfully", "\n"
71
+ else
72
+ print PROMPT_SYSTEM.prefix, "App deletion cancelled", "\n"
73
+ end
74
+ end
75
+ end
@@ -6,14 +6,9 @@ class MonadicApp
6
6
  ##################################################
7
7
 
8
8
  def user_input(text = "")
9
- # if count_lines_below < 1
10
- # ask_clear
11
- # user_input
12
- # else
13
9
  res = PROMPT_USER.readline(text)
14
10
  print TTY::Cursor.clear_line_after
15
11
  res == "" ? nil : res
16
- # end
17
12
  end
18
13
 
19
14
  def show_greet
@@ -32,7 +27,7 @@ class MonadicApp
32
27
  end
33
28
 
34
29
  def confirm_query(input)
35
- if input.size < MIN_LENGTH
30
+ if input.size < SETTINGS["min_query_size"]
36
31
  PROMPT_SYSTEM.yes?("Would you like to proceed with this (very short) prompt?")
37
32
  else
38
33
  true
@@ -59,6 +59,13 @@ class MonadicApp
59
59
  def prepare_params(input_role, input)
60
60
  params = @params.dup
61
61
 
62
+ delimited_input = case input_role
63
+ when "user"
64
+ "NEW PROMPT: ###\n#{input}\n###"
65
+ when "system" # i.e. search engine
66
+ "SEARCH SNIPPETS: ###\n#{input}\n###"
67
+ end
68
+
62
69
  case @mode
63
70
  when :research
64
71
  messages = +""
@@ -68,14 +75,16 @@ class MonadicApp
68
75
  content = mes["content"]
69
76
  case role
70
77
  when "system"
71
- system << "#{content}\n"
78
+ system << "#{content}\n" if system == ""
72
79
  else
73
80
  messages << "- #{mes["role"].strip}: #{content}\n"
74
81
  end
75
82
  end
83
+
84
+ delimited_messages = "MESSAGES: ###\n#{messages}\n###"
76
85
  template = @template.dup.sub("{{SYSTEM}}", system)
77
- .sub("{{PROMPT}}", input)
78
- .sub("{{MESSAGES}}", messages.strip)
86
+ .sub("{{PROMPT}}", delimited_input)
87
+ .sub("{{MESSAGES}}", delimited_messages.strip)
79
88
 
80
89
  @template_tokens = count_tokens(template)
81
90
 
@@ -104,27 +113,40 @@ class MonadicApp
104
113
  case @mode
105
114
  when :research
106
115
  @metadata = res
107
- @messages << { "role" => "assistant", "content" => @metadata["response"] }
116
+ @messages << { "role" => role, "content" => @metadata["response"] }
108
117
  json = @metadata.to_json.strip
109
118
  File.open(TEMP_JSON, "w") { |f| f.write json }
110
119
  @template.sub!(/JSON:\n+```json.+```\n\n/m, "JSON:\n\n```json\n#{json}\n```\n\n")
111
120
  when :normal
112
121
  @messages << { "role" => "assistant", "content" => res }
113
122
  end
114
- remove_intermediate_messages if role == "system"
115
123
  end
116
124
 
117
- def remove_intermediate_messages
118
- @messages = @messages.reject { |ele| ele["role"] == "assistant" && /SEARCH\(.+\)/m =~ ele["content"] }
119
- @messages = @messages.reject { |ele| ele["role"] == "system" && /^SEARCH SNIPPETS/ =~ ele["content"] }
125
+ ##################################################
126
+ # function to package plain text into a unit
127
+ ##################################################
128
+
129
+ def unit(input)
130
+ if input.instance_of?(Hash)
131
+ input
132
+ else
133
+ @metadata["response"] = input
134
+ @metadata
135
+ end
120
136
  end
121
137
 
122
138
  ##################################################
123
139
  # function to bind data
124
140
  ##################################################
125
141
 
126
- def bind(input, role: "user", num_retry: 0)
127
- @turns += 1 if role == "user"
142
+ def bind(input, role: "user", num_retrials: 0)
143
+ case role
144
+ when "user"
145
+ @turns += 1
146
+ when "system" # i.e. search engine
147
+ input = "\n\n#{input}"
148
+ end
149
+
128
150
  print PROMPT_ASSISTANT.prefix, "\n"
129
151
  params = prepare_params(role, input)
130
152
  research_mode = @mode == :research
@@ -132,7 +154,10 @@ class MonadicApp
132
154
  escaping = +""
133
155
  last_chunk = +""
134
156
 
135
- res = @completion.run(params, research_mode: research_mode, num_retry: num_retry) do |chunk|
157
+ res = @completion.run(params,
158
+ research_mode: research_mode,
159
+ timeout_sec: SETTINGS["timeout_sec"],
160
+ num_retrials: num_retrials) do |chunk|
136
161
  if escaping
137
162
  chunk = escaping + chunk
138
163
  escaping = ""
@@ -152,13 +177,31 @@ class MonadicApp
152
177
  print last_chunk
153
178
  print "\n"
154
179
 
155
- webdata = use_tool(res)
156
- update_template(res, role) unless webdata
157
- if webdata && role != "system"
158
- bind(webdata, role: "system", num_retry: num_retry)
159
- elsif @html
160
- set_html
161
- end
180
+ message = case role
181
+ when "system" # i.e. search engine; the response given above should be by "assistant"
182
+ { role: "assistant", content: @mode == :research ? unit(res) : res }
183
+ when "user" # the response give above should be either "assistant"
184
+ searched = use_tool(res)
185
+ # but if the response is a search query, it should be by "system" (search engine)
186
+ if searched
187
+ @messages << { "role" => "assistant",
188
+ "content" => @mode == :research ? unit(res)["response"] : res }
189
+ if searched == "empty"
190
+ print PROMPT_SYSTEM.prefix, "Search results are empty", "\n"
191
+ return
192
+ else
193
+ bind(searched, role: "system")
194
+ return
195
+ end
196
+ # otherwise, it should be by "assistant"
197
+ else
198
+ { role: "assistant", content: @mode == :researh ? unit(res) : res }
199
+ end
200
+ end
201
+
202
+ update_template(message[:content], message[:role])
203
+
204
+ set_html if @html
162
205
  end
163
206
 
164
207
  ##################################################
@@ -174,19 +217,16 @@ class MonadicApp
174
217
  end
175
218
 
176
219
  case text
177
- when /\bSEARCH_WIKI\((.+?)\)/m
220
+ when /\bSEARCH_WIKI\("?(.+?)"?\)/m
221
+ @wiki_search_cache ||= {}
178
222
  search_key = Regexp.last_match(1)
179
- search_keys = search_key.split(",").map do |key|
180
- key.strip.sub(/^"(.+)"$/, '\1')
181
- end
182
- text = "SEARCH SNIPPETS\n#{wikipedia_search(*search_keys)}"
183
- return text
223
+ wikipedia_search(search_key, @wiki_search_cache)
184
224
  when /\bSEARCH_WEB\("?(.+?)"?\)/m
225
+ @web_search_cache ||= {}
185
226
  search_key = Regexp.last_match(1)
186
- text = "SEARCH SNIPPETS\n#{bing_search(search_key)}"
187
- return text
227
+ bing_search(search_key, @web_searh_cache)
228
+ else
229
+ false
188
230
  end
189
-
190
- false
191
231
  end
192
232
  end
@@ -12,7 +12,7 @@ Oj.mimic_JSON
12
12
  module OpenAI
13
13
  def self.default_model(research_mode: false)
14
14
  if research_mode
15
- "text-davinci-003"
15
+ "gpt-3.5-turbo"
16
16
  else
17
17
  "gpt-3.5-turbo"
18
18
  end
@@ -96,10 +96,10 @@ module OpenAI
96
96
  OpenAI.models(@access_token)
97
97
  end
98
98
 
99
- def run(params, research_mode: false, num_retry: 1, &block)
99
+ def run(params, research_mode: false, timeout_sec: 60, num_retrials: 1, &block)
100
100
  method = OpenAI.model_to_method(params["model"])
101
101
 
102
- response = OpenAI.query(@access_token, "post", method, 60, params, &block)
102
+ response = OpenAI.query(@access_token, "post", method, timeout_sec, params, &block)
103
103
  if response["error"]
104
104
  raise response["error"]["message"]
105
105
  elsif response["choices"][0]["finish_reason"] == "length"
@@ -112,11 +112,11 @@ module OpenAI
112
112
  response["choices"][0]["text"]
113
113
  end
114
114
  rescue StandardError => e
115
- case num_retry
115
+ case num_retrials
116
116
  when 0
117
117
  raise e
118
118
  else
119
- run(params, research_mode: research_mode, num_retry: num_retry - 1, &block)
119
+ run(params, research_mode: research_mode, timeout_sec: timeout_sec, num_retrials: num_retrials - 1, &block)
120
120
  end
121
121
  end
122
122
 
@@ -134,7 +134,7 @@ module OpenAI
134
134
  res
135
135
  end
136
136
 
137
- def run_iteration(params, prompts, template, replace_key = "{{PROMPT}}", num_retry: 0)
137
+ def run_iteration(params, prompts, template, replace_key = "{{PROMPT}}", timeout_sec: 60, num_retrials: 0)
138
138
  bar = TTY::ProgressBar.new("[:bar] :current/:total :total_byte :percent ET::elapsed ETA::eta",
139
139
  total: prompts.size,
140
140
  bar_format: :box)
@@ -142,7 +142,7 @@ module OpenAI
142
142
  json = ""
143
143
  prompts.each do |prompt|
144
144
  params["prompt"] = template.sub(replace_key, prompt)
145
- res = run(params, num_retry: num_retry)
145
+ res = run(params, timeout_sec: timeout_sec, num_retrials: num_retrials)
146
146
  json = JSON.pretty_generate(get_json(res))
147
147
  bar.advance(1)
148
148
  template = template.sub(/JSON:\n+```json.+?```\n\n/m, "JSON:\n\n```json\n#{json}\n```\n\n")
@@ -5,24 +5,26 @@ class MonadicApp
5
5
  # method for web search
6
6
  ##################################################
7
7
 
8
- def bing_search(query, retrial: 5)
9
- uri = "https://www.bing.com/search"
8
+ def bing_search(query, num_retrial: 3)
9
+ base_uri = "https://www.bing.com/search?setlang=en"
10
10
  css_selector = "#b_results"
11
11
 
12
12
  q = URI.encode_www_form(q: query)
13
- doc = Nokogiri::HTML(URI.parse([uri, q].join("?")).read)
13
+ doc = Nokogiri::HTML(URI.parse([base_uri, q].join("&")).read)
14
14
  doc.css("script, link").each(&:remove)
15
15
  doc.css(css_selector).text.squeeze(" \n")
16
16
  rescue StandardError
17
- return "SEARCH ENGINE NOT AVAILABLE" if retrial.zero?
18
-
19
- sleep 1
20
- retrial -= 1
21
- bing_search(query, retrial: retrial)
17
+ num_retrial -= 1
18
+ if num_retrial.positive?
19
+ sleep 1
20
+ bing_search(keywords, num_retrial: num_retrial)
21
+ else
22
+ "empty"
23
+ end
22
24
  end
23
25
 
24
- def wikipedia_search(keywords, base_url = nil)
25
- base_url ||= "https://en.wikipedia.org/w/api.php"
26
+ def wikipedia_search(keywords, cache = {}, num_retrial: 10)
27
+ base_url = "https://en.wikipedia.org/w/api.php"
26
28
  search_params = {
27
29
  action: "query",
28
30
  list: "search",
@@ -41,6 +43,8 @@ class MonadicApp
41
43
 
42
44
  title = search_data["query"]["search"][0]["title"]
43
45
 
46
+ return cache[title] if cache.keys.include?(title)
47
+
44
48
  content_params = {
45
49
  action: "query",
46
50
  prop: "extracts",
@@ -56,8 +60,28 @@ class MonadicApp
56
60
  content_response = Net::HTTP.get(content_uri)
57
61
  content_data = JSON.parse(content_response)
58
62
 
59
- content_data["query"]["pages"][0]["extract"][0..1000]
63
+ result_data = content_data["query"]["pages"][0]["extract"]
64
+ tokenized = BLINGFIRE.text_to_ids(result_data)
65
+ if tokenized.size > SETTINGS["max_tokens_wiki"].to_i
66
+ ratio = SETTINGS["max_tokens_wiki"].to_f / tokenized.size
67
+ result_data = result_data[0..(result_data.size * ratio).to_i]
68
+ end
69
+
70
+ text = <<~TEXT
71
+ ```MediaWiki
72
+ #{result_data}
73
+ ```
74
+ TEXT
75
+ cache[title] = text
76
+
77
+ text
60
78
  rescue StandardError
61
- "SEARCH RESULTS EMPTY"
79
+ num_retrial -= 1
80
+ if num_retrial.positive?
81
+ sleep 1
82
+ wikipedia_search(keywords, num_retrial: num_retrial)
83
+ else
84
+ "empty"
85
+ end
62
86
  end
63
87
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MonadicChat
4
- VERSION = "0.3.4"
4
+ VERSION = "0.3.5"
5
5
  end
data/lib/monadic_chat.rb CHANGED
@@ -16,29 +16,43 @@ require "io/console"
16
16
  require "readline"
17
17
  require "nokogiri"
18
18
  require "open-uri"
19
- require "wikipedia"
20
19
 
21
20
  require_relative "./monadic_chat/version"
22
21
  require_relative "./monadic_chat/open_ai"
22
+ require_relative "./monadic_chat/authenticate"
23
+ require_relative "./monadic_chat/commands"
23
24
  require_relative "./monadic_chat/helper"
24
25
 
25
26
  Oj.mimic_JSON
26
27
 
27
28
  module MonadicChat
28
- SETTINGS = {}
29
- MAX_CHARS_WIKI = 1000
29
+ SETTINGS = {
30
+ "normal_model" => "gpt-3.5-turbo",
31
+ "research_model" => "gpt-3.5-turbo",
32
+ "max_tokens_wiki" => 1000,
33
+ "num_retrials" => 2,
34
+ "min_query_size" => 5,
35
+ "timeout_sec" => 120
36
+ }
30
37
  gpt2model_path = File.absolute_path(File.join(__dir__, "..", "assets", "gpt2.bin"))
38
+
31
39
  BLINGFIRE = BlingFire.load_model(gpt2model_path)
32
40
  CONFIG = File.join(Dir.home, "monadic_chat.conf")
33
- NUM_RETRY = 2
34
- MIN_LENGTH = 5
35
- TIMEOUT_SEC = 120
36
41
  TITLE_WIDTH = 72
37
-
38
42
  APPS_DIR = File.absolute_path(File.join(__dir__, "..", "apps"))
39
- APPS_DIR_LIST = Dir.entries(APPS_DIR)
43
+ USER_APPS_DIR = File.absolute_path(File.join(__dir__, "..", "user_apps"))
44
+
45
+ apps_dir_list = Dir.entries(APPS_DIR)
40
46
  .reject { |entry| /\A\./ =~ entry || /\A_/ =~ entry.split("/").last }
41
47
  .map { |entry| File.join(APPS_DIR, entry) }
48
+
49
+ user_apps_dir_list = Dir.entries(USER_APPS_DIR)
50
+ .reject { |entry| /\A\./ =~ entry || /\A_/ =~ entry.split("/").last }
51
+ .reject { |entry| /\Aboilerplates/ =~ entry }
52
+ .map { |entry| File.join(USER_APPS_DIR, entry) }
53
+
54
+ APPS_DIR_LIST = apps_dir_list + user_apps_dir_list
55
+
42
56
  templates = {}
43
57
  APPS_DIR_LIST.each do |app|
44
58
  basename = File.basename(app, ".*")
@@ -89,6 +103,14 @@ module MonadicChat
89
103
  background-color: #c4ffcb;
90
104
  margin-bottom: 0.5em;
91
105
  }
106
+ .monadic_search_engine {
107
+ display:inline-block;
108
+ padding-left: 0.5em;
109
+ padding-right: 0.5em;
110
+ font-weight: bold;
111
+ background-color: #ffe9c4;
112
+ margin-bottom: 0.5em;
113
+ }
92
114
  .monadic_gray {
93
115
  display:inline-block;
94
116
  font-weight: bold;
@@ -102,7 +124,14 @@ module MonadicChat
102
124
  margin-bottom: 0.5em;
103
125
  }
104
126
  CSS
127
+
105
128
  GITHUB_STYLE = style
129
+ PROMPT_USER = TTY::PromptX.new(active_color: :blue, prefix: prompt_user)
130
+ PROMPT_SYSTEM = TTY::PromptX.new(active_color: :blue, prefix: "#{prompt_system} ")
131
+ PROMPT_ASSISTANT = TTY::PromptX.new(active_color: :red, prefix: "#{prompt_assistant} ")
132
+ SPINNER = TTY::Spinner.new(format: :arrow_pulse, clear: true)
133
+ BULLET = "\e[33m●\e[0m"
134
+ HOME = File.expand_path(File.join(__dir__, ".."))
106
135
 
107
136
  def self.require_apps
108
137
  MonadicChat::APPS_DIR_LIST.each do |app_dir|
@@ -110,162 +139,4 @@ module MonadicChat
110
139
  require "#{app_dir}/#{basename}"
111
140
  end
112
141
  end
113
-
114
- def self.open_readme
115
- url = "https://github.com/yohasebe/monadic-chat/"
116
- Launchy.open(url)
117
- end
118
-
119
- def self.mdprint(str)
120
- print TTY::Markdown.parse(str, indent: 0)
121
- end
122
-
123
- def self.authenticate(overwrite: false, message: true)
124
- check = lambda do |token|
125
- if message
126
- print TTY::Cursor.restore
127
- print TTY::Cursor.clear_screen_down
128
- print "\n"
129
- SPINNER.auto_spin
130
- end
131
-
132
- if !token || token.strip == ""
133
- if message
134
- SPINNER.stop
135
- print TTY::Cursor.restore
136
- print "\n"
137
- mdprint "- Authentication: #{PASTEL.bold.red("Failure")}\n" if message
138
- end
139
- return false
140
- end
141
-
142
- begin
143
- models = OpenAI.models(token)
144
- raise if models.empty?
145
-
146
- if message
147
- SPINNER.stop
148
- print TTY::Cursor.restore, "\n"
149
- mdprint "#{PASTEL.on_green(" System ")} Config file: `#{CONFIG}`\n"
150
- print "\n"
151
- mdprint "- Authentication: #{PASTEL.bold.green("Success")}\n"
152
- end
153
-
154
- if SETTINGS["normal_model"] && !models.map { |m| m["id"] }.index(SETTINGS["normal_model"])
155
- if message
156
- SPINNER.stop
157
- mdprint "- Normal mode model specified in config file not available\n"
158
- mdprint "- Fallback to the default model (`#{OpenAI.default_model(research_mode: false)}`)\n"
159
- end
160
- SETTINGS["normal_model"] = false
161
- end
162
- SETTINGS["normal_model"] ||= OpenAI.default_model(research_mode: false)
163
- mdprint "- Normal mode model: `#{SETTINGS["normal_model"]}`\n" if message
164
-
165
- if SETTINGS["research_model"] && !models.map { |m| m["id"] }.index(SETTINGS["research_model"])
166
- if message
167
- SPINNER.stop
168
- mdprint "- Research mode model specified in config file not available\n"
169
- mdprint "- Fallback to the default model (`#{OpenAI.default_model(research_mode: true)}`)\n"
170
- end
171
- SETTINGS["research_model"] = false
172
- end
173
- SETTINGS["research_model"] ||= OpenAI.default_model(research_mode: true)
174
- mdprint "- Research mode model: `#{SETTINGS["research_model"]}`\n" if message
175
-
176
- OpenAI::Completion.new(token)
177
- rescue StandardError
178
- if message
179
- SPINNER.stop
180
- print TTY::Cursor.restore
181
- print "\n"
182
- mdprint "- Authentication: #{PASTEL.bold.red("Failure")}\n" if message
183
- end
184
- false
185
- end
186
- end
187
-
188
- completion = nil
189
-
190
- if overwrite
191
- access_token = PROMPT_SYSTEM.ask("Input your OpenAI access token:")
192
- return false if access_token.to_s == ""
193
-
194
- completion = check.call(access_token)
195
-
196
- if completion
197
- File.open(CONFIG, "w") do |f|
198
- config = {
199
- "access_token" => access_token,
200
- "normal_model" => SETTINGS["normal_model"],
201
- "research_model" => SETTINGS["research_model"]
202
- }
203
- f.write(JSON.pretty_generate(config))
204
- print "New access token has been saved to #{CONFIG}\n" if message
205
- end
206
- end
207
- elsif File.exist?(CONFIG)
208
- json = File.read(CONFIG)
209
- begin
210
- config = JSON.parse(json)
211
- rescue JSON::ParserError
212
- puts "Error: config file does not contain a valid JSON object."
213
- exit
214
- end
215
- SETTINGS["normal_model"] = config["normal_model"] if config["normal_model"]
216
- SETTINGS["research_model"] = config["research_model"] if config["research_model"]
217
- access_token = config["access_token"]
218
- completion = check.call(access_token)
219
- else
220
- access_token ||= PROMPT_SYSTEM.ask("Input your OpenAI access token:")
221
- return false if access_token.to_s == ""
222
-
223
- completion = check.call(access_token)
224
- if completion
225
- File.open(CONFIG, "w") do |f|
226
- config = {
227
- "access_token" => access_token,
228
- "normal_model" => SETTINGS["normal_model"],
229
- "research_model" => SETTINGS["research_model"]
230
- }
231
- f.write(JSON.pretty_generate(config))
232
- end
233
- print "Access token has been saved to #{CONFIG}\n" if message
234
- end
235
- end
236
- completion || authenticate(overwrite: true)
237
- end
238
-
239
- def self.prompt_system
240
- box_width = 8
241
- name = "System".center(box_width, " ")
242
- color = "green"
243
- "\n#{PASTEL.send(:"on_#{color}", name)}"
244
- end
245
-
246
- def self.prompt_user
247
- box_width = 6
248
- color = "blue"
249
- name = "User".center(box_width, " ")
250
- "\n#{PASTEL.send(:"on_#{color}", name)}"
251
- end
252
-
253
- def self.prompt_assistant
254
- box_width = 5
255
- color = "red"
256
- name = "GPT".center(box_width, " ")
257
- "\n#{PASTEL.send(:"on_#{color}", name)}"
258
- end
259
-
260
- def self.tokenize(text)
261
- BLINGFIRE.text_to_ids(text)
262
- end
263
-
264
- PROMPT_USER = TTY::PromptX.new(active_color: :blue, prefix: prompt_user)
265
- PROMPT_SYSTEM = TTY::PromptX.new(active_color: :blue, prefix: "#{prompt_system} ")
266
- PROMPT_ASSISTANT = TTY::PromptX.new(active_color: :red, prefix: "#{prompt_assistant} ")
267
-
268
- SPINNER = TTY::Spinner.new(format: :arrow_pulse, clear: true)
269
-
270
- BULLET = "\e[33m●\e[0m"
271
142
  end
data/monadic_chat.gemspec CHANGED
@@ -51,5 +51,4 @@ Gem::Specification.new do |spec|
51
51
  spec.add_dependency "tty-prompt"
52
52
  spec.add_dependency "tty-screen"
53
53
  spec.add_dependency "tty-spinner"
54
- spec.add_dependency "wikipedia-client"
55
54
  end
@@ -0,0 +1,5 @@
1
+ {"messages": [
2
+ {"role": "system", "content": ""},
3
+ {"role": "user", "content": ""},
4
+ {"role": "assistant", "content": ""}
5
+ ]}