luogu 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0cd2a93255b9c6ed4fe776dab51414384fea23cad8d73c1e407acb5deb9bb382
4
+ data.tar.gz: e26cdfa7b3e748a580181f6a916a6fd07667fe6b0a3d3c713c454b9584b09eee
5
+ SHA512:
6
+ metadata.gz: f6ce3327ccd8824a59e5deda151876f1d6fc1b64247c5d5b1140ae4e1fd8455169b8c346f3101304f4b0dd01a5c201b43d5cbb8f322b91ab23a159d6285cf6c3
7
+ data.tar.gz: 3b6e68d717a10b7ca2feca6cf5b47760e0ab0d672b5cce34883e992a6fffa49caa0a69cd5f36f98cd51c49d1237d76f643f3ca50c241f328f1789ab803ac38ee
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in luogu.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
data/Gemfile.lock ADDED
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ luogu (0.1.0)
5
+ dotenv (~> 2.8, >= 2.8.1)
6
+ ruby-openai (~> 3.7)
7
+ tty-prompt (~> 0.23.1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ dotenv (2.8.1)
13
+ httparty (0.21.0)
14
+ mini_mime (>= 1.0.0)
15
+ multi_xml (>= 0.5.2)
16
+ mini_mime (1.1.2)
17
+ multi_xml (0.6.0)
18
+ pastel (0.8.0)
19
+ tty-color (~> 0.5)
20
+ rake (13.0.6)
21
+ ruby-openai (3.7.0)
22
+ httparty (>= 0.18.1)
23
+ tty-color (0.6.0)
24
+ tty-cursor (0.7.1)
25
+ tty-prompt (0.23.1)
26
+ pastel (~> 0.8)
27
+ tty-reader (~> 0.8)
28
+ tty-reader (0.9.0)
29
+ tty-cursor (~> 0.7)
30
+ tty-screen (~> 0.8)
31
+ wisper (~> 2.0)
32
+ tty-screen (0.8.1)
33
+ wisper (2.0.1)
34
+
35
+ PLATFORMS
36
+ arm64-darwin-22
37
+ ruby
38
+ x86_64-linux
39
+
40
+ DEPENDENCIES
41
+ luogu!
42
+ rake (~> 13.0)
43
+
44
+ BUNDLED WITH
45
+ 2.4.6
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # Luogu
2
+ > 锣鼓,现在的写代码就如古代的求神仪式一样,以前敲锣打鼓求天,现在敲锣打鼓求大模型
3
+
4
+ 用来开发 prompt 工程的工具
5
+
6
+ ### 安装
7
+ - 安装ruby,要求2.6以上,Mac自带不需要再安装
8
+ - gem install luogu
9
+ - 如果使用 mac 可能你需要使用sudu权限
10
+ - 如果需要在终端显示markdown,需要 [glow](https://github.com/charmbracelet/glow)
11
+
12
+ ### 使用
13
+ - luogu build <file> 编译成对应的json
14
+ - luogu run <file> 测试prompt
15
+
16
+ 你可以在项目目录的.env中设置下面的环境变量,或者直接系统设置
17
+ ```
18
+ OPENAI_ACCESS_TOKEN=zheshiyigetoken
19
+ OPENAI_TEMPERATURE=0.7
20
+ OPENAI_LIMIT_HISTORY=6
21
+ ```
22
+
23
+ prompt.md 示例
24
+ ```
25
+ @s
26
+ 你是一个罗纳尔多的球迷
27
+
28
+ @a
29
+ 好的
30
+
31
+ @u
32
+ 罗纳尔多是谁?
33
+
34
+ @a
35
+ 是大罗,不是C罗
36
+ ```
37
+
38
+ 如果需要处理历史记录的是否进入上下文可以使用,在 prompt.md写入
39
+
40
+
41
+ @callback
42
+ ```ruby
43
+ if assistant_message =~ /```ruby/
44
+ puts "记录本次记录"
45
+ self.push_history(user_message, assistant_message)
46
+ else
47
+ puts "抛弃本次记录"
48
+ end
49
+ ```
50
+
51
+
52
+ ### 进入run模式
53
+ - save 保存对话
54
+ - row history 查看对话历史
55
+ - history 查看当前上下文
56
+ - exit 退出
57
+
58
+ ## MIT 协议
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ task default: %i[]
data/exe/luogu ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require_relative "../lib/luogu"
6
+
7
+ Luogu.cli
@@ -0,0 +1,103 @@
1
+ module Luogu
2
+ class ChatGPT
3
+ def initialize(file)
4
+ @temperature = ENV.fetch('OPENAI_TEMPERATURE', '0.7').to_f
5
+ @limit_history = ENV.fetch('OPENAI_LIMIT_HISTORY', '6').to_i * 2
6
+
7
+ @prompt = PromptParser.new(file)
8
+ @row_history = []
9
+ @history = HistoryQueue.new @limit_history
10
+ end
11
+
12
+ def request(messages)
13
+ response = client.chat(
14
+ parameters: {
15
+ model: "gpt-3.5-turbo",
16
+ messages: messages,
17
+ temperature: 0.7,
18
+ })
19
+ response.dig("choices", 0, "message", "content")
20
+ end
21
+
22
+ def chat(user_message)
23
+ messages = (@prompt.render + @history.to_a) << {role: "user", content: user_message}
24
+ assistant_message = self.request(messages)
25
+
26
+ self.push_row_history(user_message, assistant_message)
27
+
28
+ if @prompt.ruby_code
29
+ puts "执行文档中的callback"
30
+ instance_eval @prompt.ruby_code, @prompt.file_path, @prompt.ruby_code_line
31
+ else
32
+ puts "执行默认的历史记录"
33
+ self.push_history(user_message, assistant_message)
34
+ end
35
+
36
+ assistant_message
37
+ end
38
+
39
+ def push_row_history(user_message, assistant_message)
40
+ @row_history << {role: "user", content: user_message}
41
+ @row_history << {role: "assistant", content: assistant_message}
42
+ end
43
+
44
+ def push_history(user_message, assistant_message)
45
+ @history.enqueue({role: "user", content: user_message})
46
+ @history.enqueue({role: "assistant", content: assistant_message})
47
+ end
48
+
49
+ def ask(message)
50
+ TTY::Prompt.new.ask(message)
51
+ end
52
+
53
+ def puts(message)
54
+ @_puts_method ||= if system("which glow > /dev/null 2>&1")
55
+ require 'shellwords'
56
+ -> (message) {
57
+ system("echo #{Shellwords.escape(message)} | glow -")
58
+ }
59
+ else
60
+ -> (message) { puts message }
61
+ end
62
+ @_puts_method.call message
63
+ end
64
+
65
+ def save(history, file_path)
66
+ text = ""
67
+ role_map = {"user" => "@u", "assistant" => "@a", "system" => "@s"}
68
+ history.each do |item|
69
+ text += role_map[item[:role]]
70
+ text += "\n"
71
+ text += item[:content]
72
+ text += "\n\n"
73
+ end
74
+ File.open(file_path, 'w') do |f|
75
+ f.write(text)
76
+ end
77
+ puts "已经保存文件到 #{file_path}"
78
+ end
79
+
80
+ def run
81
+ loop do
82
+ # 从命令行读取输入
83
+ input = self.ask("请输入你的指令>").cover_chinese
84
+
85
+ # 根据用户输入执行相应的操作
86
+ case input
87
+ when "save"
88
+ self.save @row_history, "./prompt.row_history.md"
89
+ self.save @history.to_a, "./prompt.history.md"
90
+ when "row history"
91
+ p @row_history
92
+ when "history"
93
+ p @history.to_a
94
+ when "exit"
95
+ puts "再见!"
96
+ break
97
+ else
98
+ self.puts self.chat(input)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
data/lib/luogu/cli.rb ADDED
@@ -0,0 +1,41 @@
1
+ module Luogu
2
+ module_function
3
+ def cli
4
+ options = {}
5
+ subcommands = {}
6
+
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: luogu [command]"
9
+
10
+ opts.on("-h", "--help", "Prints help") do
11
+ puts """
12
+ luogu build <file> -> 编译prompt
13
+ luogu run <file> -> 测试 prompt
14
+ """
15
+ exit
16
+ end
17
+
18
+ end.parse!
19
+
20
+
21
+ subcommands['build'] = Proc.new do |args|
22
+ data = PromptParser.new(args.first).to_json
23
+ target_path = args[1] || "./prompt.json"
24
+ File.open(target_path, 'w') do |f|
25
+ f.write(data)
26
+ end
27
+ end
28
+
29
+ subcommands['run'] = Proc.new do |args|
30
+ chatgpt = ChatGPT.new(args.first)
31
+ chatgpt.run
32
+ end
33
+
34
+ if subcommands.key?(ARGV.first)
35
+ subcommands[ARGV.first].call(ARGV[1..-1])
36
+ else
37
+ puts "Invalid command. Use -h or --help for usage information."
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,31 @@
1
+ module Luogu
2
+ class HistoryQueue
3
+ def initialize(max_size = 12)
4
+ @queue = []
5
+ @max_size = max_size
6
+ end
7
+
8
+ def enqueue(element)
9
+ if @queue.size == @max_size
10
+ @queue.shift
11
+ end
12
+ @queue << element
13
+ end
14
+
15
+ def dequeue
16
+ @queue.shift
17
+ end
18
+
19
+ def size
20
+ @queue.size
21
+ end
22
+
23
+ def to_a
24
+ @queue
25
+ end
26
+
27
+ def to_json
28
+ JSON.pretty_generate @queue
29
+ end
30
+ end
31
+ end
data/lib/luogu/init.rb ADDED
@@ -0,0 +1,20 @@
1
+ require "openai"
2
+ require 'dotenv/load'
3
+ require "tty-prompt"
4
+ require 'json'
5
+ require 'optparse'
6
+
7
+ require_relative 'history_queue'
8
+ require_relative "prompt_parser"
9
+ require_relative "chatgpt"
10
+ require_relative "cli"
11
+
12
+ def client
13
+ $client ||= OpenAI::Client.new
14
+ end
15
+
16
+ class String
17
+ def cover_chinese
18
+ self.gsub(/[\uFF01-\uFF0F]/) {|s| (s.ord-65248).chr}
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ module Luogu
2
+ class PromptParser
3
+ attr_reader :ruby_code, :ruby_code_line, :file_path
4
+ def initialize(file_path)
5
+ @file_path = file_path
6
+ @messages = []
7
+ @ruby_code = nil
8
+ @ruby_code_line = nil
9
+ end
10
+
11
+ def render
12
+ process_file
13
+ if @messages.length.even?
14
+ @messages
15
+ else
16
+ raise "prompt里面的问答对不对, 必须是一问一答, 当前存在单一问题或者答案"
17
+ end
18
+ end
19
+
20
+ def to_json
21
+ JSON.pretty_generate self.render
22
+ end
23
+
24
+ private
25
+ def process_file
26
+ @messages = []
27
+ file = File.read(@file_path)
28
+
29
+ if file =~ /@callback/
30
+ callback_regex = /@callback\n```ruby\n(.*?)\n```/m
31
+ @ruby_code = file[callback_regex, 1]
32
+ @ruby_code_line = self.find_line_number(file, "@callback") + 2
33
+ file = file.gsub(callback_regex, '')
34
+ end
35
+
36
+ file.split(/(?=@u|@a|@s)/).reject(&:empty?).each do |c|
37
+ role = if c =~ /^@s/
38
+ "system"
39
+ elsif c =~ /^@u/
40
+ "user"
41
+ elsif c =~ /^@a/
42
+ "assistant"
43
+ end
44
+ content = c.sub(/^@(u|a|s)\s+/, '').strip
45
+ @messages << {role: role, content: content}
46
+ end
47
+ end
48
+
49
+ def find_line_number(text, search_str)
50
+ lines = text.split("\n")
51
+ line_number = nil
52
+
53
+ lines.each_with_index do |line, index|
54
+ if line.include?(search_str)
55
+ line_number = index + 1
56
+ break
57
+ end
58
+ end
59
+
60
+ line_number
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Luogu
4
+ VERSION = "0.1.0"
5
+ end
data/lib/luogu.rb ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "luogu/version"
4
+ require_relative "luogu/init"
5
+
6
+ module Luogu
7
+ class Error < StandardError; end
8
+ # Your code goes here...
9
+
10
+ module_eval do
11
+ Dotenv.load
12
+
13
+ OpenAI.configure do |config|
14
+ config.access_token = ENV.fetch('OPENAI_ACCESS_TOKEN')
15
+ end
16
+ end
17
+ end
data/luogu.gemspec ADDED
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/luogu/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "luogu"
7
+ spec.version = Luogu::VERSION
8
+ spec.authors = ["MJ"]
9
+ spec.email = ["tywf91@gmail.com"]
10
+
11
+ spec.summary = "luogu 用于 Prompt 工程开发"
12
+ spec.description = "使用markdown来快速实现 Prompt工程研发"
13
+ spec.homepage = "https://github.com/mjason/luogu"
14
+ spec.required_ruby_version = ">= 2.6.0"
15
+
16
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
17
+
18
+ spec.metadata["homepage_uri"] = spec.homepage
19
+ spec.metadata["source_code_uri"] = "https://github.com/mjason/luogu"
20
+ spec.metadata["changelog_uri"] = "https://github.com/mjason/luogu"
21
+
22
+ # Specify which files should be added to the gem when it is released.
23
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
+ spec.files = Dir.chdir(__dir__) do
25
+ `git ls-files -z`.split("\x0").reject do |f|
26
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ # Uncomment to register a new dependency of your gem
34
+ # spec.add_dependency "example-gem", "~> 1.0"
35
+ spec.add_dependency 'ruby-openai', '~> 3.7'
36
+ spec.add_dependency 'dotenv', '~> 2.8', '>= 2.8.1'
37
+ spec.add_dependency 'tty-prompt', '~> 0.23.1'
38
+
39
+ # For more information and examples about making a new gem, check out our
40
+ # guide at: https://bundler.io/guides/creating_gem.html
41
+ end
data/sig/luogu.rbs ADDED
@@ -0,0 +1,4 @@
1
+ module Luogu
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: luogu
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - MJ
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-openai
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dotenv
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.8'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 2.8.1
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '2.8'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 2.8.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: tty-prompt
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: 0.23.1
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.23.1
61
+ description: 使用markdown来快速实现 Prompt工程研发
62
+ email:
63
+ - tywf91@gmail.com
64
+ executables:
65
+ - luogu
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - Gemfile
70
+ - Gemfile.lock
71
+ - README.md
72
+ - Rakefile
73
+ - exe/luogu
74
+ - lib/luogu.rb
75
+ - lib/luogu/chatgpt.rb
76
+ - lib/luogu/cli.rb
77
+ - lib/luogu/history_queue.rb
78
+ - lib/luogu/init.rb
79
+ - lib/luogu/prompt_parser.rb
80
+ - lib/luogu/version.rb
81
+ - luogu.gemspec
82
+ - sig/luogu.rbs
83
+ homepage: https://github.com/mjason/luogu
84
+ licenses: []
85
+ metadata:
86
+ homepage_uri: https://github.com/mjason/luogu
87
+ source_code_uri: https://github.com/mjason/luogu
88
+ changelog_uri: https://github.com/mjason/luogu
89
+ post_install_message:
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 2.6.0
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 3.4.6
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: luogu 用于 Prompt 工程开发
108
+ test_files: []