monadic-chat 0.2.2 → 0.3.1
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 +4 -4
- data/Gemfile.lock +4 -1
- data/README.md +90 -114
- data/apps/chat/chat.json +5 -1
- data/apps/chat/chat.md +4 -5
- data/apps/chat/chat.rb +13 -18
- data/apps/code/code.md +2 -4
- data/apps/code/code.rb +13 -18
- data/apps/linguistic/linguistic.json +1 -1
- data/apps/linguistic/linguistic.md +2 -4
- data/apps/linguistic/linguistic.rb +13 -18
- data/apps/novel/novel.md +2 -4
- data/apps/novel/novel.rb +13 -18
- data/apps/translate/translate.md +2 -4
- data/apps/translate/translate.rb +13 -18
- data/lib/monadic_app.rb +7 -22
- data/lib/monadic_chat/formatting.rb +1 -4
- data/lib/monadic_chat/interaction.rb +12 -12
- data/lib/monadic_chat/internals.rb +35 -181
- data/lib/monadic_chat/menu.rb +8 -8
- data/lib/monadic_chat/open_ai.rb +25 -14
- data/lib/monadic_chat/parameters.rb +12 -10
- data/lib/monadic_chat/version.rb +1 -1
- data/lib/monadic_chat.rb +43 -13
- data/monadic_chat.gemspec +1 -0
- metadata +16 -4
- data/doc/img/extra-template-json.png +0 -0
- data/doc/img/langacker-2001.svg +0 -41
@@ -39,35 +39,15 @@ class MonadicApp
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def wait
|
43
|
-
return self if @threads.empty?
|
44
|
-
|
45
|
-
print TTY::Cursor.save
|
46
|
-
message = PASTEL.red "Processing contextual data #{SPINNER} "
|
47
|
-
print message
|
48
|
-
|
49
|
-
TIMEOUT_SEC.times do |i|
|
50
|
-
raise MonadicError, "Error: something went wrong" if i + 1 == TIMEOUT_SEC
|
51
|
-
|
52
|
-
break if @threads.empty?
|
53
|
-
|
54
|
-
sleep 1
|
55
|
-
end
|
56
|
-
print TTY::Cursor.restore
|
57
|
-
print TTY::Cursor.clear_char(message.size)
|
58
|
-
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
42
|
def objectify
|
63
|
-
case @
|
64
|
-
when
|
65
|
-
m =
|
43
|
+
case @mode
|
44
|
+
when :research
|
45
|
+
m = /JSON:\n+```json\s*(\{.+\})\s*```\n\n/m.match(@template)
|
66
46
|
json = m[1].gsub(/(?!\\\\\\)\\\\"/) { '\\\"' }
|
67
47
|
res = JSON.parse(json)
|
68
48
|
res["messages"] = @messages
|
69
49
|
res
|
70
|
-
when
|
50
|
+
when :normal
|
71
51
|
@messages
|
72
52
|
end
|
73
53
|
end
|
@@ -76,8 +56,9 @@ class MonadicApp
|
|
76
56
|
params = @params.dup
|
77
57
|
|
78
58
|
@update_proc.call
|
79
|
-
|
80
|
-
|
59
|
+
|
60
|
+
case @mode
|
61
|
+
when :research
|
81
62
|
messages = +""
|
82
63
|
system = +""
|
83
64
|
@messages.each do |mes|
|
@@ -87,20 +68,28 @@ class MonadicApp
|
|
87
68
|
when "system"
|
88
69
|
system << "#{content}\n"
|
89
70
|
when "assistant", "gpt"
|
90
|
-
|
71
|
+
messages << "- #{mes["role"].strip}: #{content}\n"
|
91
72
|
else
|
92
|
-
messages << "- #{mes["role"].strip}: #{mes["content"]}"
|
73
|
+
messages << "- #{mes["role"].strip}: #{mes["content"]}\n"
|
93
74
|
end
|
94
75
|
end
|
95
76
|
template = @template.dup.sub("{{SYSTEM}}", system)
|
96
77
|
.sub("{{PROMPT}}", input)
|
97
78
|
.sub("{{MESSAGES}}", messages.strip)
|
98
79
|
|
99
|
-
|
80
|
+
File.open(TEMP_MD, "w") { |f| f.write template }
|
81
|
+
|
100
82
|
@messages << { "role" => "user", "content" => input }
|
101
|
-
|
83
|
+
|
84
|
+
case @method
|
85
|
+
when "completions"
|
86
|
+
params["prompt"] = template
|
87
|
+
when "chat/completions"
|
88
|
+
params["messages"] = [{ "role" => "system", "content" => template }]
|
89
|
+
end
|
90
|
+
|
91
|
+
when :normal
|
102
92
|
@messages << { "role" => "user", "content" => input }
|
103
|
-
@update_proc.call
|
104
93
|
params["messages"] = @messages
|
105
94
|
end
|
106
95
|
|
@@ -108,36 +97,31 @@ class MonadicApp
|
|
108
97
|
end
|
109
98
|
|
110
99
|
def update_template(res)
|
111
|
-
case @
|
112
|
-
when
|
100
|
+
case @mode
|
101
|
+
when :research
|
113
102
|
@metadata = res
|
114
|
-
@messages << { "role" => "assistant", "content" =>
|
115
|
-
json =
|
116
|
-
|
117
|
-
|
103
|
+
@messages << { "role" => "assistant", "content" => @metadata["response"] }
|
104
|
+
json = @metadata.to_json.strip
|
105
|
+
File.open(TEMP_JSON, "w") { |f| f.write json }
|
106
|
+
@template.sub!(/JSON:\n+```json.+```\n\n/m, "JSON:\n\n```json\n#{json}\n```\n\n")
|
107
|
+
when :normal
|
118
108
|
@messages << { "role" => "assistant", "content" => res }
|
119
109
|
end
|
120
110
|
end
|
121
111
|
|
122
112
|
##################################################
|
123
|
-
#
|
113
|
+
# function to bind data
|
124
114
|
##################################################
|
125
115
|
|
126
|
-
def
|
116
|
+
def bind(input, num_retry: 0)
|
127
117
|
print PROMPT_ASSISTANT.prefix, "\n"
|
128
|
-
print TTY::Cursor.save
|
129
|
-
|
130
|
-
wait
|
131
|
-
|
132
118
|
params = prepare_params(input)
|
133
|
-
|
134
|
-
print TTY::Cursor.save
|
119
|
+
research_mode = @mode == :research
|
135
120
|
|
136
121
|
escaping = +""
|
137
122
|
last_chunk = +""
|
138
|
-
|
139
|
-
|
140
|
-
res = @completion.run(params, num_retry: num_retry) do |chunk|
|
123
|
+
|
124
|
+
res = @completion.run(params, research_mode: research_mode, num_retry: num_retry) do |chunk|
|
141
125
|
if escaping
|
142
126
|
chunk = escaping + chunk
|
143
127
|
escaping = ""
|
@@ -147,147 +131,17 @@ class MonadicApp
|
|
147
131
|
escaping += chunk
|
148
132
|
next
|
149
133
|
else
|
150
|
-
chunk = chunk.gsub('\\n'
|
151
|
-
response << chunk
|
152
|
-
end
|
153
|
-
|
154
|
-
if count_lines_below > 1
|
155
|
-
print PASTEL.magenta(last_chunk)
|
156
|
-
elsif !spinning
|
157
|
-
print PASTEL.red SPINNER
|
158
|
-
spinning = true
|
134
|
+
chunk = chunk.gsub('\\n') { "\n" }
|
159
135
|
end
|
160
136
|
|
137
|
+
print last_chunk
|
161
138
|
last_chunk = chunk
|
162
139
|
end
|
163
140
|
|
164
|
-
print
|
165
|
-
print TTY::Cursor.clear_screen_down
|
166
|
-
|
167
|
-
text = response.gsub(/(?<![\\>\s])(?!\n[\n<])\n/m) { "{{NEWLINE}}\n" }
|
168
|
-
text = text.gsub(/```(.+?)```/m) do
|
169
|
-
m = Regexp.last_match
|
170
|
-
"```#{m[1].gsub("{{NEWLINE}}\n") { "\n" }}```"
|
171
|
-
end
|
172
|
-
text = text.gsub(/`(.+?)`/) do
|
173
|
-
m = Regexp.last_match
|
174
|
-
"`#{m[1].gsub("{{NEWLINE}}\n") { "\n" }}`"
|
175
|
-
end
|
176
|
-
|
177
|
-
text = text.gsub(/(?!\\\\)\\/) { "" }
|
178
|
-
print TTY::Markdown.parse(text).gsub("{{NEWLINE}}") { "\n" }.strip
|
141
|
+
print last_chunk
|
179
142
|
print "\n"
|
180
143
|
|
181
144
|
update_template(res)
|
182
145
|
set_html if @html
|
183
146
|
end
|
184
|
-
|
185
|
-
def bind_research_mode(input, num_retry: 0)
|
186
|
-
print PROMPT_ASSISTANT.prefix, "\n"
|
187
|
-
|
188
|
-
wait
|
189
|
-
|
190
|
-
params = prepare_params(input)
|
191
|
-
|
192
|
-
print TTY::Cursor.save
|
193
|
-
|
194
|
-
@threads << true
|
195
|
-
Thread.new do
|
196
|
-
response_all_shown = false
|
197
|
-
key_start = /"#{@prop_newdata}":\s*"/
|
198
|
-
key_finish = /\s+###\s*"/m
|
199
|
-
started = false
|
200
|
-
escaping = +""
|
201
|
-
last_chunk = +""
|
202
|
-
finished = false
|
203
|
-
response = +""
|
204
|
-
spinning = false
|
205
|
-
res = @completion.run(params, num_retry: num_retry, tmp_json_file: TEMP_JSON, tmp_md_file: TEMP_MD) do |chunk|
|
206
|
-
if finished && !response_all_shown
|
207
|
-
response_all_shown = true
|
208
|
-
@responses << response.sub(/\s+###\s*".*/m, "")
|
209
|
-
if spinning
|
210
|
-
TTY::Cursor.backword(" ▹▹▹▹▹ ".size)
|
211
|
-
TTY::Cursor.clear_char(" ▹▹▹▹▹ ".size)
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
unless finished
|
216
|
-
if escaping
|
217
|
-
chunk = escaping + chunk
|
218
|
-
escaping = ""
|
219
|
-
end
|
220
|
-
|
221
|
-
if /(?:\\\z)/ =~ chunk
|
222
|
-
escaping += chunk
|
223
|
-
next
|
224
|
-
else
|
225
|
-
chunk = chunk.gsub('\\n', "\n")
|
226
|
-
response << chunk
|
227
|
-
end
|
228
|
-
|
229
|
-
if started && !finished
|
230
|
-
if key_finish =~ response
|
231
|
-
finished = true
|
232
|
-
else
|
233
|
-
if count_lines_below > 1
|
234
|
-
print PASTEL.magenta(last_chunk)
|
235
|
-
elsif !spinning
|
236
|
-
print PASTEL.red SPINNER
|
237
|
-
spinning = true
|
238
|
-
end
|
239
|
-
last_chunk = chunk
|
240
|
-
end
|
241
|
-
elsif !started && !finished && key_start =~ response
|
242
|
-
started = true
|
243
|
-
response = +""
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
unless response_all_shown
|
249
|
-
if spinning
|
250
|
-
TTY::Cursor.backword(SPINNER.size)
|
251
|
-
TTY::Cursor.clear_char(SPINNER.size)
|
252
|
-
end
|
253
|
-
@responses << response.sub(/\s+###\s*".*/m, "")
|
254
|
-
end
|
255
|
-
|
256
|
-
update_template(res)
|
257
|
-
@threads.clear
|
258
|
-
rescue StandardError => e
|
259
|
-
@threads.clear
|
260
|
-
@responses << <<~ERROR
|
261
|
-
Error: something went wrong in a thread"
|
262
|
-
#{e.message}
|
263
|
-
#{e.backtrace}
|
264
|
-
ERROR
|
265
|
-
end
|
266
|
-
|
267
|
-
loop do
|
268
|
-
if @responses.empty?
|
269
|
-
sleep 1
|
270
|
-
else
|
271
|
-
print TTY::Cursor.restore
|
272
|
-
print TTY::Cursor.clear_screen_down
|
273
|
-
text = @responses.pop
|
274
|
-
|
275
|
-
text = text.gsub(/(?<![\\>\s])(?!\n[\n<])\n/m) { "{{NEWLINE}}\n" }
|
276
|
-
text = text.gsub(/```(.+?)```/m) do
|
277
|
-
m = Regexp.last_match
|
278
|
-
"```#{m[1].gsub("{{NEWLINE}}\n") { "\n" }}```"
|
279
|
-
end
|
280
|
-
text = text.gsub(/`(.+?)`/) do
|
281
|
-
m = Regexp.last_match
|
282
|
-
"`#{m[1].gsub("{{NEWLINE}}\n") { "\n" }}`"
|
283
|
-
end
|
284
|
-
|
285
|
-
text = text.gsub(/(?!\\\\)\\/) { "" }
|
286
|
-
print TTY::Markdown.parse(text).gsub("{{NEWLINE}}") { "\n" }.strip
|
287
|
-
print "\n"
|
288
|
-
break
|
289
|
-
end
|
290
|
-
end
|
291
|
-
set_html if @html
|
292
|
-
end
|
293
147
|
end
|
data/lib/monadic_chat/menu.rb
CHANGED
@@ -127,13 +127,13 @@ class MonadicApp
|
|
127
127
|
|
128
128
|
begin
|
129
129
|
File.open(filepath, "w") do |f|
|
130
|
-
case @
|
131
|
-
when
|
132
|
-
m =
|
130
|
+
case @mode
|
131
|
+
when :research
|
132
|
+
m = /JSON:\n+```json\s*(\{.+\})\s*```\n\n/m.match(@template)
|
133
133
|
data = JSON.parse(m[1])
|
134
134
|
data["messages"] = @messages
|
135
135
|
f.write JSON.pretty_generate(data)
|
136
|
-
when
|
136
|
+
when :normal
|
137
137
|
f.write JSON.pretty_generate({ "messages" => @messages })
|
138
138
|
end
|
139
139
|
|
@@ -167,15 +167,15 @@ class MonadicApp
|
|
167
167
|
filepath = File.expand_path(input.strip)
|
168
168
|
json = File.read(filepath)
|
169
169
|
data = JSON.parse(json)
|
170
|
-
case @
|
171
|
-
when
|
170
|
+
case @mode
|
171
|
+
when :research
|
172
172
|
self.class.name.downcase.split("::")[-1]
|
173
173
|
|
174
174
|
raise unless data["mode"] == self.class.name.downcase.split("::")[-1]
|
175
175
|
|
176
176
|
@messages = data.delete "messages"
|
177
|
-
@template = @template.sub(
|
178
|
-
when
|
177
|
+
@template = @template.sub(/JSON:\n+```json\s*\{.+\}\s*```\n\n/m, "JSON:\n\n```json\n#{JSON.pretty_generate(data).strip}\n```\n\n")
|
178
|
+
when :normal
|
179
179
|
raise unless data["messages"] && data["messages"][0]["role"]
|
180
180
|
|
181
181
|
@messages = data["messages"]
|
data/lib/monadic_chat/open_ai.rb
CHANGED
@@ -12,7 +12,11 @@ Oj.mimic_JSON
|
|
12
12
|
|
13
13
|
module OpenAI
|
14
14
|
def self.model_name(research_mode: false)
|
15
|
-
research_mode
|
15
|
+
if research_mode
|
16
|
+
"text-davinci-003"
|
17
|
+
else
|
18
|
+
"gpt-3.5-turbo"
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def self.model_to_method(model)
|
@@ -85,15 +89,25 @@ module OpenAI
|
|
85
89
|
class Completion
|
86
90
|
attr_reader :access_token
|
87
91
|
|
88
|
-
def initialize(access_token)
|
92
|
+
def initialize(access_token, normal_mode_model = nil, research_mode_model = nil)
|
89
93
|
@access_token = access_token
|
94
|
+
@normal_mode_model = normal_mode_model || OpenAI.model_name(research_mode: false)
|
95
|
+
@research_mode_model = research_mode_model || OpenAI.model_name(research_mode: true)
|
96
|
+
end
|
97
|
+
|
98
|
+
def model_name(research_mode: false)
|
99
|
+
if research_mode
|
100
|
+
@research_mode_model
|
101
|
+
else
|
102
|
+
@normal_mode_model
|
103
|
+
end
|
90
104
|
end
|
91
105
|
|
92
106
|
def models
|
93
107
|
OpenAI.models(@access_token)
|
94
108
|
end
|
95
109
|
|
96
|
-
def run(params,
|
110
|
+
def run(params, research_mode: false, num_retry: 1, &block)
|
97
111
|
method = OpenAI.model_to_method(params["model"])
|
98
112
|
|
99
113
|
response = OpenAI.query(@access_token, "post", method, 60, params, &block)
|
@@ -103,12 +117,10 @@ module OpenAI
|
|
103
117
|
raise "finished because of length"
|
104
118
|
end
|
105
119
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
when "chat/completions"
|
111
|
-
response ["choices"][0]["text"]
|
120
|
+
if research_mode
|
121
|
+
get_json response["choices"][0]["text"]
|
122
|
+
else
|
123
|
+
response["choices"][0]["text"]
|
112
124
|
end
|
113
125
|
rescue StandardError => e
|
114
126
|
case num_retry
|
@@ -119,9 +131,9 @@ module OpenAI
|
|
119
131
|
end
|
120
132
|
end
|
121
133
|
|
122
|
-
def get_json(data
|
134
|
+
def get_json(data)
|
123
135
|
case data
|
124
|
-
when %r{<JSON>\n*(\{
|
136
|
+
when %r{<JSON>\n*(\{.+?\})\n*</JSON>}m
|
125
137
|
json = Regexp.last_match(1).gsub(/\r\n?/, "\n").gsub(/\r\n/) { "\n" }
|
126
138
|
res = JSON.parse(json)
|
127
139
|
when /(\{.+\})/m
|
@@ -130,7 +142,6 @@ module OpenAI
|
|
130
142
|
else
|
131
143
|
res = data
|
132
144
|
end
|
133
|
-
File.open(tmp_json_file, "w") { |f| f.write json } if tmp_json_file
|
134
145
|
res
|
135
146
|
end
|
136
147
|
|
@@ -143,9 +154,9 @@ module OpenAI
|
|
143
154
|
prompts.each do |prompt|
|
144
155
|
params["prompt"] = template.sub(replace_key, prompt)
|
145
156
|
res = run(params, num_retry: num_retry)
|
146
|
-
json = JSON.pretty_generate(res)
|
157
|
+
json = JSON.pretty_generate(get_json(res))
|
147
158
|
bar.advance(1)
|
148
|
-
template = template.sub(
|
159
|
+
template = template.sub(/JSON:\n+```json.+?```\n\n/m, "JSON:\n\n```json\n#{json}\n```\n\n")
|
149
160
|
end
|
150
161
|
bar.finish
|
151
162
|
JSON.parse(json)
|
@@ -20,11 +20,7 @@ class MonadicApp
|
|
20
20
|
case parameter
|
21
21
|
when "model"
|
22
22
|
value = change_model
|
23
|
-
@
|
24
|
-
case @method
|
25
|
-
when RESEARCH_MODE
|
26
|
-
@template = @template_initial.dup
|
27
|
-
end
|
23
|
+
@method = OpenAI.model_to_method(value)
|
28
24
|
when "max_tokens"
|
29
25
|
value = change_max_tokens
|
30
26
|
when "temperature"
|
@@ -79,13 +75,19 @@ class MonadicApp
|
|
79
75
|
model = PROMPT_SYSTEM.select("Select a model:", per_page: 10, cycle: false, show_help: :never, filter: true, default: 1) do |menu|
|
80
76
|
menu.choice "#{BULLET} Cancel", "cancel"
|
81
77
|
TTY::Cursor.save
|
82
|
-
|
78
|
+
SPINNER.auto_spin
|
83
79
|
models = @completion.models
|
84
|
-
|
85
|
-
TTY::Cursor.restore
|
80
|
+
SPINNER.stop
|
86
81
|
TTY::Cursor.restore
|
87
|
-
|
88
|
-
|
82
|
+
case @mode
|
83
|
+
when :research
|
84
|
+
models.filter { |m| ["completions", "chat/completions"].include? OpenAI.model_to_method(m["id"]) }.sort_by { |m| -m["created"] }.each do |m|
|
85
|
+
menu.choice "#{BULLET} #{m["id"]}", m["id"]
|
86
|
+
end
|
87
|
+
when :normal
|
88
|
+
models.filter { |m| OpenAI.model_to_method(m["id"]) == "chat/completions" }.sort_by { |m| -m["created"] }.each do |m|
|
89
|
+
menu.choice "#{BULLET} #{m["id"]}", m["id"]
|
90
|
+
end
|
89
91
|
end
|
90
92
|
end
|
91
93
|
if model == "cancel"
|
data/lib/monadic_chat/version.rb
CHANGED
data/lib/monadic_chat.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "tty-cursor"
|
4
4
|
require "tty-screen"
|
5
5
|
require "tty-markdown"
|
6
|
+
require "tty-spinner"
|
6
7
|
require "tty-prompt"
|
7
8
|
require "tty-box"
|
8
9
|
require "pastel"
|
@@ -25,8 +26,6 @@ module MonadicChat
|
|
25
26
|
MIN_LENGTH = 5
|
26
27
|
TIMEOUT_SEC = 120
|
27
28
|
TITLE_WIDTH = 72
|
28
|
-
NORMAL_MODE = "chat/completions"
|
29
|
-
RESEARCH_MODE = "completions"
|
30
29
|
|
31
30
|
APPS_DIR = File.absolute_path(File.join(__dir__, "..", "apps"))
|
32
31
|
APPS_DIR_LIST = Dir.entries(APPS_DIR)
|
@@ -123,15 +122,37 @@ module MonadicChat
|
|
123
122
|
end
|
124
123
|
|
125
124
|
def self.authenticate(overwrite: false)
|
126
|
-
check = lambda do |token|
|
127
|
-
print "Checking configuration
|
125
|
+
check = lambda do |token, normal_mode_model, research_mode_model|
|
126
|
+
print "Checking configuration\n"
|
127
|
+
SPINNER.auto_spin
|
128
128
|
begin
|
129
|
-
|
129
|
+
models = OpenAI.models(token)
|
130
|
+
raise if models.empty?
|
130
131
|
|
131
|
-
|
132
|
-
|
132
|
+
SPINNER.stop
|
133
|
+
|
134
|
+
print "Success\n"
|
135
|
+
|
136
|
+
if normal_mode_model && !models.map { |m| m["id"] }.index(normal_mode_model)
|
137
|
+
SPINNER.stop
|
138
|
+
print "Normal mode model set in config file not available.\n"
|
139
|
+
normal_mode_model = false
|
140
|
+
end
|
141
|
+
normal_mode_model ||= OpenAI.model_name(research_mode: false)
|
142
|
+
print "Normal mode model: #{normal_mode_model}\n"
|
143
|
+
|
144
|
+
if research_mode_model && !models.map { |m| m["id"] }.index(research_mode_model)
|
145
|
+
SPINNER.stop
|
146
|
+
print "Normal mode model set in config file not available.\n"
|
147
|
+
print "Fallback to the default model (#{OpenAI.model_name(research_mode: true)}).\n"
|
148
|
+
end
|
149
|
+
research_mode_model ||= OpenAI.model_name(research_mode: true)
|
150
|
+
print "Research mode model: #{research_mode_model}\n"
|
151
|
+
|
152
|
+
OpenAI::Completion.new(token, normal_mode_model, research_mode_model)
|
133
153
|
rescue StandardError
|
134
|
-
|
154
|
+
SPINNER.stop
|
155
|
+
print "Authentication: failure.\n"
|
135
156
|
false
|
136
157
|
end
|
137
158
|
end
|
@@ -142,7 +163,7 @@ module MonadicChat
|
|
142
163
|
access_token = PROMPT_SYSTEM.ask(" Input your OpenAI access token:")
|
143
164
|
return false if access_token.to_s == ""
|
144
165
|
|
145
|
-
completion = check.call(access_token)
|
166
|
+
completion = check.call(access_token, nil, nil)
|
146
167
|
|
147
168
|
if completion
|
148
169
|
File.open(CONFIG, "w") do |f|
|
@@ -153,12 +174,19 @@ module MonadicChat
|
|
153
174
|
end
|
154
175
|
elsif File.exist?(CONFIG)
|
155
176
|
json = File.read(CONFIG)
|
156
|
-
|
177
|
+
begin
|
178
|
+
config = JSON.parse(json)
|
179
|
+
rescue JSON::ParserError
|
180
|
+
puts "Error: config file does not contain a valid JSON object."
|
181
|
+
exit
|
182
|
+
end
|
157
183
|
access_token = config["access_token"]
|
158
|
-
|
184
|
+
normal_mode_model = config["normal_mode_model"]
|
185
|
+
research_mode_model = config["research_mode_model"]
|
186
|
+
completion = check.call(access_token, normal_mode_model, research_mode_model)
|
159
187
|
else
|
160
188
|
access_token ||= PROMPT_SYSTEM.ask(" Input your OpenAI access token:")
|
161
|
-
completion = check.call(access_token)
|
189
|
+
completion = check.call(access_token, nil, nil)
|
162
190
|
if completion
|
163
191
|
File.open(CONFIG, "w") do |f|
|
164
192
|
config = { "access_token" => access_token }
|
@@ -194,6 +222,8 @@ module MonadicChat
|
|
194
222
|
PROMPT_USER = TTY::PromptX.new(active_color: :blue, prefix: prompt_user)
|
195
223
|
PROMPT_SYSTEM = TTY::PromptX.new(active_color: :blue, prefix: "#{prompt_system} ")
|
196
224
|
PROMPT_ASSISTANT = TTY::PromptX.new(active_color: :red, prefix: "#{prompt_assistant} ")
|
197
|
-
|
225
|
+
|
226
|
+
SPINNER = TTY::Spinner.new(format: :arrow_pulse, clear: true)
|
227
|
+
|
198
228
|
BULLET = "\e[33m●\e[0m"
|
199
229
|
end
|
data/monadic_chat.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monadic-chat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- yohasebe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-03-
|
11
|
+
date: 2023-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -234,6 +234,20 @@ dependencies:
|
|
234
234
|
- - ">="
|
235
235
|
- !ruby/object:Gem::Version
|
236
236
|
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: tty-spinner
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - ">="
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '0'
|
244
|
+
type: :runtime
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - ">="
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
237
251
|
description: 'Monadic Chat is a command-line client application program that uses
|
238
252
|
OpenAI''s Text Completion API and Chat API to enable chat-style conversations with
|
239
253
|
OpenAI''s artificial intelligence system in a ChatGPT-like style.
|
@@ -275,10 +289,8 @@ files:
|
|
275
289
|
- doc/img/code-example-time-html.png
|
276
290
|
- doc/img/code-example-time.png
|
277
291
|
- doc/img/example-translation.png
|
278
|
-
- doc/img/extra-template-json.png
|
279
292
|
- doc/img/how-research-mode-works.svg
|
280
293
|
- doc/img/input-acess-token.png
|
281
|
-
- doc/img/langacker-2001.svg
|
282
294
|
- doc/img/linguistic-html.png
|
283
295
|
- doc/img/monadic-chat.svg
|
284
296
|
- doc/img/readme-example-beatles-html.png
|
Binary file
|