luogu 0.1.6 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -1
- data/README.md +8 -4
- data/lib/luogu/chatgpt.rb +42 -11
- data/lib/luogu/cli.rb +76 -44
- data/lib/luogu/init.rb +3 -1
- data/lib/luogu/plugin.rb +52 -0
- data/lib/luogu/version.rb +1 -1
- data/luogu.gemspec +1 -0
- metadata +17 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d415e44469be65939709764b50b5283da141d5e68663acf5e3c376044407970
|
4
|
+
data.tar.gz: 18846bbcd392e9581f6d9becff711b2e551983759460464b169824e14f3c05a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5eb13f0a6b90843366879a773f816d55dbcdba55f2cc6f06915f9e7f7dbc4a73ceb1916505d482a670755d8197519792d649f0731c12f53071fa87b131bcd62a
|
7
|
+
data.tar.gz: b25c5d0dfa8a2b4d4df66ec9695d226521551ddb77f674722d122ba8e9252546abcfa916d2d379a794f520fedf32247e1dcbeef575739675bdd84ddd705e78f5
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
luogu (0.1.
|
4
|
+
luogu (0.1.7)
|
5
5
|
dotenv (~> 2.8, >= 2.8.1)
|
6
|
+
dry-cli (~> 1.0)
|
6
7
|
ruby-openai (~> 3.7)
|
7
8
|
tty-prompt (~> 0.23.1)
|
8
9
|
|
@@ -10,6 +11,7 @@ GEM
|
|
10
11
|
remote: https://rubygems.org/
|
11
12
|
specs:
|
12
13
|
dotenv (2.8.1)
|
14
|
+
dry-cli (1.0.0)
|
13
15
|
httparty (0.21.0)
|
14
16
|
mini_mime (>= 1.0.0)
|
15
17
|
multi_xml (>= 0.5.2)
|
data/README.md
CHANGED
@@ -10,10 +10,14 @@
|
|
10
10
|
- 如果需要在终端显示markdown,需要 [glow](https://github.com/charmbracelet/glow)
|
11
11
|
|
12
12
|
### 使用
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
```Bash
|
14
|
+
Commands:
|
15
|
+
luogu build PROMPT_FILE [TARGET_FILE] # 编译 Prompt.md 成能够提交给 ChatGPT API 的 messages. 默认输出为 <同文件名>.json
|
16
|
+
luogu generate JSON_FILE [PROMPT_FILE] # 根据 ChatGPT messages JSON 来生成 Prompt.md
|
17
|
+
luogu run PROMPT_FILE # 编译 Prompt.md 成能够提交给 ChatGPT API 的 messages. 默认输出为 <同文件名>.json
|
18
|
+
luogu test [PROMPT_FILE] [TEST_FILE] # 测试 Prompt 文件
|
19
|
+
luogu version # 打印版本
|
20
|
+
```
|
17
21
|
|
18
22
|
你可以在项目目录的.env中设置下面的环境变量,或者直接系统设置
|
19
23
|
```
|
data/lib/luogu/chatgpt.rb
CHANGED
@@ -1,26 +1,50 @@
|
|
1
1
|
module Luogu
|
2
2
|
class ChatGPT
|
3
|
-
|
3
|
+
|
4
|
+
attr_accessor :template, :limit_history, :prompt, :row_history, :history, :temperature, :model_name
|
5
|
+
|
6
|
+
def initialize(file, history_path='.', plugin_file_path=nil)
|
7
|
+
@plugin_file_path = plugin_file_path || file.sub(File.extname(file), ".plugin.rb")
|
8
|
+
|
9
|
+
if File.exist?(@plugin_file_path)
|
10
|
+
@plugin = Plugin.new(@plugin_file_path).load()
|
11
|
+
else
|
12
|
+
@plugin = Plugin.new(@plugin_file_path)
|
13
|
+
end
|
14
|
+
|
4
15
|
@temperature = ENV.fetch('OPENAI_TEMPERATURE', '0.7').to_f
|
5
16
|
@limit_history = ENV.fetch('OPENAI_LIMIT_HISTORY', '6').to_i * 2
|
17
|
+
@model_name = "gpt-3.5-turbo"
|
6
18
|
|
19
|
+
@history_path = history_path
|
20
|
+
@prompt_file = file
|
21
|
+
|
7
22
|
@prompt = PromptParser.new(file)
|
8
23
|
@row_history = []
|
9
24
|
@history = HistoryQueue.new @limit_history
|
25
|
+
|
26
|
+
@plugin.setup_proc.call(self) if @plugin.setup_proc
|
10
27
|
end
|
11
28
|
|
12
29
|
def request(messages)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
30
|
+
params = {
|
31
|
+
model: @model_name,
|
32
|
+
messages: messages,
|
33
|
+
temperature: @temperature,
|
34
|
+
}
|
35
|
+
|
36
|
+
params = @plugin.before_request_proc.call(self, params) if @plugin.before_request_proc
|
37
|
+
response = client.chat(parameters: params)
|
38
|
+
@plugin.after_request_proc.call(self, response) if @plugin.after_request_proc
|
39
|
+
|
19
40
|
response.dig("choices", 0, "message", "content")
|
20
41
|
end
|
21
42
|
|
22
43
|
def chat(user_message)
|
44
|
+
user_message = @plugin.before_input_proc.call(self, user_message) if @plugin.before_input_proc
|
23
45
|
messages = (@prompt.render + @history.to_a) << {role: "user", content: user_message}
|
46
|
+
@plugin.after_input_proc.call(self, messages) if @plugin.after_input_proc
|
47
|
+
|
24
48
|
assistant_message = self.request(messages)
|
25
49
|
|
26
50
|
self.push_row_history(user_message, assistant_message)
|
@@ -28,6 +52,8 @@ module Luogu
|
|
28
52
|
if @prompt.ruby_code
|
29
53
|
puts "执行文档中的callback"
|
30
54
|
instance_eval @prompt.ruby_code, @prompt.file_path, @prompt.ruby_code_line
|
55
|
+
elsif @plugin.before_save_history_proc
|
56
|
+
@plugin.before_save_history_proc.call(self, user_message, assistant_message)
|
31
57
|
else
|
32
58
|
puts "执行默认的历史记录"
|
33
59
|
self.push_history(user_message, assistant_message)
|
@@ -44,6 +70,7 @@ module Luogu
|
|
44
70
|
def push_history(user_message, assistant_message)
|
45
71
|
@history.enqueue({role: "user", content: user_message})
|
46
72
|
@history.enqueue({role: "assistant", content: assistant_message})
|
73
|
+
@plugin.after_save_history_proc.call(self, user_message, assistant_message) if @plugin.after_save_history_proc
|
47
74
|
end
|
48
75
|
|
49
76
|
def ask(message)
|
@@ -70,8 +97,9 @@ module Luogu
|
|
70
97
|
# 根据用户输入执行相应的操作
|
71
98
|
case input
|
72
99
|
when "save"
|
73
|
-
|
74
|
-
self.class.save @
|
100
|
+
file_name = File.basename(@prompt_file, ".*")
|
101
|
+
self.class.save @row_history, File.join(@history_path, "#{file_name}.row_history.md")
|
102
|
+
self.class.save @history.to_a, File.join(@history_path, "#{file_name}.history.md")
|
75
103
|
when "row history"
|
76
104
|
p @row_history
|
77
105
|
when "history"
|
@@ -91,8 +119,10 @@ module Luogu
|
|
91
119
|
self.puts self.chat(message)
|
92
120
|
end
|
93
121
|
now = Time.now.to_i
|
94
|
-
|
95
|
-
|
122
|
+
file_name = File.basename(@prompt_file, ".*")
|
123
|
+
|
124
|
+
self.class.save @row_history, File.join(@history_path, "#{file_name}-#{now}.row_history.md")
|
125
|
+
self.class.save @history.to_a, File.join(@history_path, "#{file_name}-#{now}.history.md")
|
96
126
|
end
|
97
127
|
|
98
128
|
class << self
|
@@ -105,6 +135,7 @@ module Luogu
|
|
105
135
|
text += item[:content]
|
106
136
|
text += "\n\n"
|
107
137
|
end
|
138
|
+
FileUtils.mkdir_p(File.dirname(file_path))
|
108
139
|
File.open(file_path, 'w') do |f|
|
109
140
|
f.write(text)
|
110
141
|
end
|
data/lib/luogu/cli.rb
CHANGED
@@ -1,58 +1,90 @@
|
|
1
1
|
module Luogu
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
luogu build <file> -> 编译prompt
|
13
|
-
luogu run <file> -> 测试 prompt
|
14
|
-
luogu gen <file> <target> -> 根据 json 生成 prompt 文件
|
15
|
-
luogu test <file> <test_file.yml> -> 根据 yaml 来对 prompt 进行测试
|
16
|
-
"""
|
17
|
-
exit
|
2
|
+
module CLI
|
3
|
+
module Commands
|
4
|
+
extend Dry::CLI::Registry
|
5
|
+
|
6
|
+
class Version < Dry::CLI::Command
|
7
|
+
desc "打印版本"
|
8
|
+
|
9
|
+
def call(*)
|
10
|
+
puts Luogu::VERSION
|
11
|
+
end
|
18
12
|
end
|
19
13
|
|
20
|
-
|
14
|
+
class Build < Dry::CLI::Command
|
15
|
+
|
16
|
+
desc "编译 Prompt.md 成能够提交给 ChatGPT API 的 messages. 默认输出为 <同文件名>.json"
|
17
|
+
argument :prompt_file, type: :string, required: true, deec: "Prompt文件, 使用markdown书写"
|
18
|
+
argument :target_file, type: :string, required: false, deec: "输出 JSON 文件"
|
19
|
+
|
20
|
+
def call(prompt_file: nil, target_file: nil, **)
|
21
|
+
target_file ||= prompt_file.sub(File.extname(prompt_file), ".json")
|
22
|
+
data = PromptParser.new(prompt_file).to_json
|
23
|
+
File.open(target_file, 'w') do |f|
|
24
|
+
f.write(data)
|
25
|
+
end
|
26
|
+
end
|
21
27
|
|
22
|
-
|
23
|
-
subcommands['build'] = Proc.new do |args|
|
24
|
-
data = PromptParser.new(args.first).to_json
|
25
|
-
target_path = args[1] || "./prompt.json"
|
26
|
-
File.open(target_path, 'w') do |f|
|
27
|
-
f.write(data)
|
28
28
|
end
|
29
|
-
end
|
30
29
|
|
31
|
-
|
32
|
-
chatgpt = ChatGPT.new(args.first)
|
33
|
-
chatgpt.run
|
34
|
-
end
|
30
|
+
class Run < Dry::CLI::Command
|
35
31
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
32
|
+
desc "编译 Prompt.md 成能够提交给 ChatGPT API 的 messages. 默认输出为 <同文件名>.json"
|
33
|
+
argument :prompt_file, type: :string, required: true, desc: "Prompt文件, 使用markdown书写"
|
34
|
+
option :out, type: :string, default: ".", desc: "保存历史时存放的目录,默认为当前目录"
|
35
|
+
option :plugin, type: :string, desc: "运行的时候载入对应的插件"
|
40
36
|
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
def call(prompt_file: nil, **options)
|
38
|
+
chatgpt = ChatGPT.new(prompt_file, options.fetch(:out), options.fetch(:plugin, nil))
|
39
|
+
chatgpt.run
|
40
|
+
end
|
44
41
|
|
45
|
-
|
42
|
+
end
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
44
|
+
class Generate < Dry::CLI::Command
|
45
|
+
|
46
|
+
desc "根据 ChatGPT messages JSON 来生成 Prompt.md"
|
47
|
+
argument :json_file, type: :string, required: true, deec: "ChatGPT 生成的 messages json 文件"
|
48
|
+
argument :prompt_file, type: :string, required: false, deec: "要输出的Prompt文件路径, 默认生成 <同名>.md"
|
49
|
+
|
50
|
+
def call(json_file: nil, prompt_file: nil, **)
|
51
|
+
json = JSON.parse(File.read(json_file), symbolize_names: true)
|
52
|
+
prompt_file ||= json_file.sub(File.extname(json_file), ".md")
|
53
|
+
|
54
|
+
chatgpt = ChatGPT.save(json, prompt_file)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class Test < Dry::CLI::Command
|
60
|
+
|
61
|
+
desc "测试 Prompt 文件"
|
62
|
+
argument :prompt_file, type: :string, require: true, desc: "输出 Prompt 文件"
|
63
|
+
argument :test_file, type: :string, require: false, desc: "测试文件, 使用 YAML 文件, 一个字符串数组。默认为 同名.test.yml"
|
64
|
+
option :out, type: :string, default: ".", desc: "保存测试历史时存放的目录,默认为当前目录"
|
65
|
+
option :plugin, type: :string, desc: "运行的时候载入对应的插件"
|
66
|
+
|
67
|
+
def call(prompt_file: nil, test_file:nil, **options)
|
68
|
+
test_file ||= prompt_file.sub(File.extname(prompt_file), ".test.yml")
|
69
|
+
|
70
|
+
chatgpt = ChatGPT.new(prompt_file, options.fetch(:out), options.fetch(:plugin, nil))
|
71
|
+
messages = YAML.load_file(test_file)
|
72
|
+
chatgpt.playload messages
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
register "version", Version, aliases: ["v", "-v", "--version"]
|
78
|
+
register "build", Build, aliases: ["b"]
|
79
|
+
register "run", Run, aliases: ["r"]
|
80
|
+
register "generate", Generate, aliases: ["g"]
|
81
|
+
register "test", Test, aliases: ["t"]
|
50
82
|
|
51
|
-
if subcommands.key?(ARGV.first)
|
52
|
-
subcommands[ARGV.first].call(ARGV[1..-1])
|
53
|
-
else
|
54
|
-
puts "Invalid command. Use -h or --help for usage information."
|
55
83
|
end
|
84
|
+
end
|
56
85
|
|
86
|
+
module_function
|
87
|
+
def cli
|
88
|
+
Dry::CLI.new(Luogu::CLI::Commands).call
|
57
89
|
end
|
58
|
-
end
|
90
|
+
end
|
data/lib/luogu/init.rb
CHANGED
@@ -3,8 +3,10 @@ require 'dotenv/load'
|
|
3
3
|
require "tty-prompt"
|
4
4
|
require 'json'
|
5
5
|
require 'yaml'
|
6
|
-
require
|
6
|
+
require "dry/cli"
|
7
|
+
require 'fileutils'
|
7
8
|
|
9
|
+
require_relative 'plugin'
|
8
10
|
require_relative 'history_queue'
|
9
11
|
require_relative "prompt_parser"
|
10
12
|
require_relative "chatgpt"
|
data/lib/luogu/plugin.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Luogu
|
2
|
+
class Plugin
|
3
|
+
attr_reader :before_input_proc, :before_save_history_proc, :after_input_proc, :after_save_history_proc,
|
4
|
+
:setup_proc, :before_request_proc, :after_request_proc
|
5
|
+
|
6
|
+
def initialize(plugin_file_path)
|
7
|
+
@plugin_file_path = plugin_file_path
|
8
|
+
|
9
|
+
@before_input_proc = nil
|
10
|
+
@before_save_history_proc = nil
|
11
|
+
|
12
|
+
@after_input_proc = nil
|
13
|
+
@after_save_history_proc = nil
|
14
|
+
|
15
|
+
@setup_proc = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_input(&block)
|
19
|
+
@before_input_proc = block
|
20
|
+
end
|
21
|
+
|
22
|
+
def before_save_history(&block)
|
23
|
+
@before_save_history_proc = block
|
24
|
+
end
|
25
|
+
|
26
|
+
def after_input(&block)
|
27
|
+
@after_input_proc = block
|
28
|
+
end
|
29
|
+
|
30
|
+
def after_save_history(&block)
|
31
|
+
@after_save_history_proc = block
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup(&block)
|
35
|
+
@setup_proc = block
|
36
|
+
end
|
37
|
+
|
38
|
+
def before_request(&block)
|
39
|
+
@before_request_proc = block
|
40
|
+
end
|
41
|
+
|
42
|
+
def after_request(&block)
|
43
|
+
@after_request_proc = block
|
44
|
+
end
|
45
|
+
|
46
|
+
def load()
|
47
|
+
self.instance_eval File.read(@plugin_file_path)
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
data/lib/luogu/version.rb
CHANGED
data/luogu.gemspec
CHANGED
@@ -35,6 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency 'ruby-openai', '~> 3.7'
|
36
36
|
spec.add_dependency 'dotenv', '~> 2.8', '>= 2.8.1'
|
37
37
|
spec.add_dependency 'tty-prompt', '~> 0.23.1'
|
38
|
+
spec.add_dependency 'dry-cli', '~> 1.0'
|
38
39
|
|
39
40
|
# For more information and examples about making a new gem, check out our
|
40
41
|
# guide at: https://bundler.io/guides/creating_gem.html
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luogu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- MJ
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-openai
|
@@ -58,6 +58,20 @@ dependencies:
|
|
58
58
|
- - "~>"
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: 0.23.1
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: dry-cli
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '1.0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '1.0'
|
61
75
|
description: 使用markdown来快速实现 Prompt工程研发
|
62
76
|
email:
|
63
77
|
- tywf91@gmail.com
|
@@ -76,6 +90,7 @@ files:
|
|
76
90
|
- lib/luogu/cli.rb
|
77
91
|
- lib/luogu/history_queue.rb
|
78
92
|
- lib/luogu/init.rb
|
93
|
+
- lib/luogu/plugin.rb
|
79
94
|
- lib/luogu/prompt_parser.rb
|
80
95
|
- lib/luogu/version.rb
|
81
96
|
- luogu.gemspec
|