pedicab 0.1.5 → 0.1.6
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/#README.md# +51 -0
- data/Gemfile.lock +49 -0
- data/books/Arnold_Bennett-How_to_Live_on_24_Hours_a_Day.txt +1247 -0
- data/books/Edward_L_Bernays-crystallizing_public_opinion.txt +4422 -0
- data/books/Emma_Goldman-Anarchism_and_Other_Essays.txt +7654 -0
- data/books/Office_of_Strategic_Services-Simple_Sabotage_Field_Manual.txt +1057 -0
- data/books/Sigmund_Freud-Group_Psychology_and_The_Analysis_of_The_Ego.txt +2360 -0
- data/books/Steve_Hassan-The_Bite_Model.txt +130 -0
- data/books/Steve_Hassan-The_Bite_Model.txt~ +132 -0
- data/books/Sun_Tzu-Art_of_War.txt +159 -0
- data/books/Sun_Tzu-Art_of_War.txt~ +166 -0
- data/books/US-Constitution.txt +502 -0
- data/books/US-Constitution.txt~ +502 -0
- data/books/cia-kubark.txt +4637 -0
- data/books/machiavelli-the_prince.txt +4599 -0
- data/books/sun_tzu-art_of_war.txt +1017 -0
- data/books/us_army-bayonette.txt +843 -0
- data/lib/pedicab/calc.rb~ +8 -0
- data/lib/pedicab/link.rb +38 -0
- data/lib/pedicab/link.rb~ +14 -0
- data/lib/pedicab/mark.rb +9 -0
- data/lib/pedicab/mark.rb~ +5 -0
- data/lib/pedicab/on.rb +6 -0
- data/lib/pedicab/on.rb~ +6 -0
- data/lib/pedicab/poke.rb +14 -0
- data/lib/pedicab/poke.rb~ +15 -0
- data/lib/pedicab/query.rb +92 -0
- data/lib/pedicab/query.rb~ +93 -0
- data/lib/pedicab/rank.rb +92 -0
- data/lib/pedicab/rank.rb~ +89 -0
- data/lib/pedicab/ride.rb +109 -0
- data/lib/pedicab/ride.rb~ +101 -0
- data/lib/pedicab/version.rb +1 -1
- data/pedicab-0.1.0.gem +0 -0
- data/pedicab-0.1.1.gem +0 -0
- data/pedicab-0.1.2.gem +0 -0
- data/pedicab-0.1.3.gem +0 -0
- data/pedicab-0.1.4.gem +0 -0
- data/pedicab-0.1.5.gem +0 -0
- metadata +39 -1
data/lib/pedicab/link.rb
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module LINK
|
|
2
|
+
@@L = {}
|
|
3
|
+
def self.on
|
|
4
|
+
@@L
|
|
5
|
+
end
|
|
6
|
+
def self.each_pair &b
|
|
7
|
+
@@L.each_pair { |k,v| b.call(k,v) }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
LINK.on["named entites which need to be defined or calculated"] = lambda { |s,e|
|
|
12
|
+
s.each("each named entity", e) { |ee|
|
|
13
|
+
if s.gate "The following has a calculatable formula:\n#{ee}"
|
|
14
|
+
s.prompt("Respond with only the bare mathmatical formula to be calculated by the ruby eqn gem for the following:\n#{ee}")
|
|
15
|
+
else
|
|
16
|
+
s.prompt("Define the following in the simplest terms:\n#{ee}")
|
|
17
|
+
end
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
LINK.on["a single fact based answer"] = lambda { |s,e| s.prompt("Respond with the fact needed to correctly respond to the following:\n#{e}") }
|
|
22
|
+
|
|
23
|
+
LINK.on["a step by step plan"] = lambda { |s,e| s.prompt("Respond with only a plan for the following without repeating yourself:\n#{e}").gsub(/\n\n+/,"\n") }
|
|
24
|
+
|
|
25
|
+
LINK.on["an answer by logical progression of thought"] = lambda { |s,e| s.prompt("Outline your thinking about the following without repeating yourself:\n#{e}").gsub(/\n\n+/,"\n") }
|
|
26
|
+
|
|
27
|
+
#LINK.on["goals which need to be achieved"] = lambda { |s,e|
|
|
28
|
+
# s.each("all goals which need to be achieved", e) { |ee|
|
|
29
|
+
# s.prompt("Outline the steps necessary to accomplish the following:\n#{ee}")
|
|
30
|
+
# }
|
|
31
|
+
#}
|
|
32
|
+
|
|
33
|
+
#LINK.on["decisions which need to be made"] = lambda { |s,e|
|
|
34
|
+
# s.each("all decisions which need to be made", e) { |ee|
|
|
35
|
+
# s.prompt("Decide the following:\n#{ee}")
|
|
36
|
+
# }
|
|
37
|
+
#}
|
|
38
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module LINK
|
|
2
|
+
@@L = {}
|
|
3
|
+
def self.on
|
|
4
|
+
@@L
|
|
5
|
+
end
|
|
6
|
+
def self.each_pair &b
|
|
7
|
+
@@L.each_pair { |k,v| b.call(k,v) }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
LINK.on["calculating a mathmatical formula"] = lambda { |s,e| s.dispatch("Define the mathmatical formula equal to the following:\n#{e} = ") }
|
|
12
|
+
LINK.on["abstract or complex planning"] = lambda { |s,e| s.dispatch("Create a plan for the following:\n#{e}") }
|
|
13
|
+
LINK.on["an answer by logical progression of thought"] = lambda { |s,e| s.dispath("Outline your thinking about the following:\n#{e}") }
|
|
14
|
+
#LINK.on["fact based knowledge from known and trusted sources"] = lambda { |s,e| s.prompt("Respond with only the answer to the following with no formatting or punctuation in as few words as possible:\n#{e}") }
|
data/lib/pedicab/mark.rb
ADDED
data/lib/pedicab/on.rb
ADDED
data/lib/pedicab/on.rb~
ADDED
data/lib/pedicab/poke.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module POKE
|
|
2
|
+
@@POKE = {}
|
|
3
|
+
def self.on
|
|
4
|
+
@@POKE
|
|
5
|
+
end
|
|
6
|
+
def self.[] q
|
|
7
|
+
a = [ q ]
|
|
8
|
+
@@POKE.each_pair { |r,b| if m = Regexp.new(r).match(q); a << b.call(q, m); end; }
|
|
9
|
+
return a.reverse.join("\n")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
POKE.on[" time "] = lambda { |q, m| t = Time.now; %[The current time is #{t.strftime('%T')}.] }
|
|
14
|
+
POKE.on[" date "] = lambda { |q, m| t = Time.now; %[The current date is #{t.strftime('%D')}.] }
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module POKE
|
|
2
|
+
@@POKE = {}
|
|
3
|
+
def self.on
|
|
4
|
+
@@POKE
|
|
5
|
+
end
|
|
6
|
+
def self.[] q
|
|
7
|
+
a = [ q ]
|
|
8
|
+
@@POKE.each_pair { |r,b| if m = Regexp.new(r).match(q); a << b.call(q, m); end; }
|
|
9
|
+
return a.reverse.join("\n")
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
POKE.on["time"] = lambda { |q, m| t = Time.now; %[The current time is #{t.strftime('%T')}.] }
|
|
14
|
+
POKE.on["date"] = lambda { |q, m| t = Time.now; %[The current date is #{t.strftime('%D')}.] }
|
|
15
|
+
POKE.on[/ (\d+)d(\d+) /] = lambda { |q, m| a, t = [], 0; m[1].to_i.times { x = rand(m[2].to_i) + 1; t += x; a << x }; %[Rolling #{m[1]}d#{m[2]} gave #{a.join(', ')} for a total of #{t}.] }
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
class RedditQuery
|
|
3
|
+
include HTTParty
|
|
4
|
+
base_uri 'https://www.reddit.com'
|
|
5
|
+
|
|
6
|
+
# Set a custom user agent (Reddit requires this)
|
|
7
|
+
headers 'User-Agent' => 'Ruby Reddit Client/1.0'
|
|
8
|
+
|
|
9
|
+
def initialize(topic)
|
|
10
|
+
@topic = topic
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Search for posts about the topic
|
|
14
|
+
def search(limit: 25, sort: 'relevance', time: 'all')
|
|
15
|
+
options = {
|
|
16
|
+
query: {
|
|
17
|
+
q: @topic,
|
|
18
|
+
limit: limit,
|
|
19
|
+
sort: sort,
|
|
20
|
+
t: time,
|
|
21
|
+
raw_json: 1
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
response = self.class.get('/search.json', options)
|
|
26
|
+
parse_response(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get posts from a specific subreddit about the topic
|
|
30
|
+
def search_subreddit(subreddit, limit: 25, sort: 'hot')
|
|
31
|
+
options = {
|
|
32
|
+
query: {
|
|
33
|
+
limit: limit,
|
|
34
|
+
raw_json: 1
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
response = self.class.get("/r/#{subreddit}/search.json?q=#{@topic}&restrict_sr=1", options)
|
|
39
|
+
parse_response(response)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get hot posts from a subreddit
|
|
43
|
+
def get_subreddit_posts(subreddit, limit: 25, sort: 'hot')
|
|
44
|
+
options = {
|
|
45
|
+
query: {
|
|
46
|
+
limit: limit,
|
|
47
|
+
raw_json: 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
response = self.class.get("/r/#{subreddit}/#{sort}.json", options)
|
|
52
|
+
parse_response(response)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def parse_response(response)
|
|
58
|
+
if response.success?
|
|
59
|
+
data = response.parsed_response
|
|
60
|
+
posts = data.dig('data', 'children') || []
|
|
61
|
+
|
|
62
|
+
posts.map do |post|
|
|
63
|
+
post_data = post['data']
|
|
64
|
+
{
|
|
65
|
+
title: post_data['title'],
|
|
66
|
+
author: post_data['author'],
|
|
67
|
+
subreddit: post_data['subreddit'],
|
|
68
|
+
score: post_data['score'],
|
|
69
|
+
url: post_data['url'],
|
|
70
|
+
permalink: "https://www.reddit.com#{post_data['permalink']}",
|
|
71
|
+
created_utc: Time.at(post_data['created_utc']),
|
|
72
|
+
num_comments: post_data['num_comments'],
|
|
73
|
+
selftext: post_data['selftext']
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
puts "Error: #{response.code} - #{response.message}"
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Example usage:
|
|
84
|
+
def self.reddit q
|
|
85
|
+
qq = RedditQuery.new(q).search(limit: 10, sort: 'hot', time: 'week').map { |post|
|
|
86
|
+
p = post[:selftext];
|
|
87
|
+
if p.length > 0;
|
|
88
|
+
p;
|
|
89
|
+
end;
|
|
90
|
+
}.flatten.compact
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
class RedditQuery
|
|
3
|
+
include HTTParty
|
|
4
|
+
base_uri 'https://www.reddit.com'
|
|
5
|
+
|
|
6
|
+
# Set a custom user agent (Reddit requires this)
|
|
7
|
+
headers 'User-Agent' => 'Ruby Reddit Client/1.0'
|
|
8
|
+
|
|
9
|
+
def initialize(topic)
|
|
10
|
+
@topic = topic
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Search for posts about the topic
|
|
14
|
+
def search(limit: 25, sort: 'relevance', time: 'all')
|
|
15
|
+
options = {
|
|
16
|
+
query: {
|
|
17
|
+
q: @topic,
|
|
18
|
+
limit: limit,
|
|
19
|
+
sort: sort,
|
|
20
|
+
t: time,
|
|
21
|
+
raw_json: 1
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
response = self.class.get('/search.json', options)
|
|
26
|
+
parse_response(response)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Get posts from a specific subreddit about the topic
|
|
30
|
+
def search_subreddit(subreddit, limit: 25, sort: 'hot')
|
|
31
|
+
options = {
|
|
32
|
+
query: {
|
|
33
|
+
limit: limit,
|
|
34
|
+
raw_json: 1
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
response = self.class.get("/r/#{subreddit}/search.json?q=#{@topic}&restrict_sr=1", options)
|
|
39
|
+
parse_response(response)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Get hot posts from a subreddit
|
|
43
|
+
def get_subreddit_posts(subreddit, limit: 25, sort: 'hot')
|
|
44
|
+
options = {
|
|
45
|
+
query: {
|
|
46
|
+
limit: limit,
|
|
47
|
+
raw_json: 1
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
response = self.class.get("/r/#{subreddit}/#{sort}.json", options)
|
|
52
|
+
parse_response(response)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def parse_response(response)
|
|
58
|
+
if response.success?
|
|
59
|
+
data = response.parsed_response
|
|
60
|
+
posts = data.dig('data', 'children') || []
|
|
61
|
+
|
|
62
|
+
posts.map do |post|
|
|
63
|
+
post_data = post['data']
|
|
64
|
+
{
|
|
65
|
+
title: post_data['title'],
|
|
66
|
+
author: post_data['author'],
|
|
67
|
+
subreddit: post_data['subreddit'],
|
|
68
|
+
score: post_data['score'],
|
|
69
|
+
url: post_data['url'],
|
|
70
|
+
permalink: "https://www.reddit.com#{post_data['permalink']}",
|
|
71
|
+
created_utc: Time.at(post_data['created_utc']),
|
|
72
|
+
num_comments: post_data['num_comments'],
|
|
73
|
+
selftext: post_data['selftext']
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
puts "Error: #{response.code} - #{response.message}"
|
|
78
|
+
[]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Example usage:
|
|
84
|
+
def self.reddit q
|
|
85
|
+
qq = RedditQuery.new(q).search(limit: 10, sort: 'hot', time: 'week').map { |post|
|
|
86
|
+
p = post[:selftext];
|
|
87
|
+
if p.length > 0;
|
|
88
|
+
p;
|
|
89
|
+
end;
|
|
90
|
+
}.flatten.compact.join("\n")
|
|
91
|
+
return %[#{q}:\n#{qq}]
|
|
92
|
+
end
|
|
93
|
+
end
|
data/lib/pedicab/rank.rb
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
module RANK
|
|
3
|
+
class KNN
|
|
4
|
+
# Initialize with a collection of strings
|
|
5
|
+
def initialize(strings)
|
|
6
|
+
@strings = strings
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Find k nearest neighbors to the query string
|
|
10
|
+
# Returns array of hashes with :string, :distance, and :similarity
|
|
11
|
+
def rank(id, query, k = 5, method: :levenshtein)
|
|
12
|
+
a, t = id.split("-")
|
|
13
|
+
return [] if @strings.empty?
|
|
14
|
+
|
|
15
|
+
# Calculate distances for all strings
|
|
16
|
+
distances = @strings.map do |str|
|
|
17
|
+
dist = levenshtein_distance(query, str)
|
|
18
|
+
{
|
|
19
|
+
book: id,
|
|
20
|
+
author: a,
|
|
21
|
+
title: t,
|
|
22
|
+
string: str.strip,
|
|
23
|
+
distance: dist,
|
|
24
|
+
similarity: 1.0 / (1.0 + dist)
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Sort by distance (ascending) and take k nearest
|
|
29
|
+
distances.sort_by { |d| d[:distance] }.take([k, @strings.length].min)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
# Calculate Levenshtein distance between two strings
|
|
35
|
+
def levenshtein_distance(s1, s2)
|
|
36
|
+
s1_lower = s1.downcase
|
|
37
|
+
s2_lower = s2.downcase
|
|
38
|
+
|
|
39
|
+
return s2_lower.length if s1_lower.empty?
|
|
40
|
+
return s1_lower.length if s2_lower.empty?
|
|
41
|
+
|
|
42
|
+
# Create distance matrix
|
|
43
|
+
d = Array.new(s1_lower.length + 1) { Array.new(s2_lower.length + 1) }
|
|
44
|
+
|
|
45
|
+
(0..s1_lower.length).each { |i| d[i][0] = i }
|
|
46
|
+
(0..s2_lower.length).each { |j| d[0][j] = j }
|
|
47
|
+
|
|
48
|
+
(1..s1_lower.length).each do |i|
|
|
49
|
+
(1..s2_lower.length).each do |j|
|
|
50
|
+
cost = s1_lower[i - 1] == s2_lower[j - 1] ? 0 : 1
|
|
51
|
+
|
|
52
|
+
d[i][j] = [
|
|
53
|
+
d[i - 1][j] + 1, # deletion
|
|
54
|
+
d[i][j - 1] + 1, # insertion
|
|
55
|
+
d[i - 1][j - 1] + cost # substitution
|
|
56
|
+
].min
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
d[s1_lower.length][s2_lower.length]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Generate character n-grams from string
|
|
64
|
+
def generate_ngrams(str, n)
|
|
65
|
+
return {} if str.length < n
|
|
66
|
+
|
|
67
|
+
ngrams = Hash.new(0)
|
|
68
|
+
(0..str.length - n).each do |i|
|
|
69
|
+
ngrams[str[i, n]] += 1
|
|
70
|
+
end
|
|
71
|
+
ngrams
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
@@Rank = Hash.new { |h,k| h[k] = Rank.new(k) }
|
|
75
|
+
class Rank
|
|
76
|
+
attr_accessor :data
|
|
77
|
+
def initialize k
|
|
78
|
+
@id = k
|
|
79
|
+
@data = []
|
|
80
|
+
end
|
|
81
|
+
def << i
|
|
82
|
+
@data << i
|
|
83
|
+
end
|
|
84
|
+
def [] k
|
|
85
|
+
KNN.new(@data.to_a).rank(@id, k, 5)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
def self.[] k
|
|
89
|
+
@@Rank[k]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
module RANK
|
|
3
|
+
class KNN
|
|
4
|
+
# Initialize with a collection of strings
|
|
5
|
+
def initialize(strings)
|
|
6
|
+
@strings = strings
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Find k nearest neighbors to the query string
|
|
10
|
+
# Returns array of hashes with :string, :distance, and :similarity
|
|
11
|
+
def rank(id, query, k = 5, method: :levenshtein)
|
|
12
|
+
return [] if @strings.empty?
|
|
13
|
+
|
|
14
|
+
# Calculate distances for all strings
|
|
15
|
+
distances = @strings.map do |str|
|
|
16
|
+
dist = levenshtein_distance(query, str)
|
|
17
|
+
{
|
|
18
|
+
book: id,
|
|
19
|
+
string: str,
|
|
20
|
+
distance: dist,
|
|
21
|
+
similarity: 1.0 / (1.0 + dist)
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Sort by distance (ascending) and take k nearest
|
|
26
|
+
distances.sort_by { |d| d[:distance] }.take([k, @strings.length].min)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
# Calculate Levenshtein distance between two strings
|
|
32
|
+
def levenshtein_distance(s1, s2)
|
|
33
|
+
s1_lower = s1.downcase
|
|
34
|
+
s2_lower = s2.downcase
|
|
35
|
+
|
|
36
|
+
return s2_lower.length if s1_lower.empty?
|
|
37
|
+
return s1_lower.length if s2_lower.empty?
|
|
38
|
+
|
|
39
|
+
# Create distance matrix
|
|
40
|
+
d = Array.new(s1_lower.length + 1) { Array.new(s2_lower.length + 1) }
|
|
41
|
+
|
|
42
|
+
(0..s1_lower.length).each { |i| d[i][0] = i }
|
|
43
|
+
(0..s2_lower.length).each { |j| d[0][j] = j }
|
|
44
|
+
|
|
45
|
+
(1..s1_lower.length).each do |i|
|
|
46
|
+
(1..s2_lower.length).each do |j|
|
|
47
|
+
cost = s1_lower[i - 1] == s2_lower[j - 1] ? 0 : 1
|
|
48
|
+
|
|
49
|
+
d[i][j] = [
|
|
50
|
+
d[i - 1][j] + 1, # deletion
|
|
51
|
+
d[i][j - 1] + 1, # insertion
|
|
52
|
+
d[i - 1][j - 1] + cost # substitution
|
|
53
|
+
].min
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
d[s1_lower.length][s2_lower.length]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Generate character n-grams from string
|
|
61
|
+
def generate_ngrams(str, n)
|
|
62
|
+
return {} if str.length < n
|
|
63
|
+
|
|
64
|
+
ngrams = Hash.new(0)
|
|
65
|
+
(0..str.length - n).each do |i|
|
|
66
|
+
ngrams[str[i, n]] += 1
|
|
67
|
+
end
|
|
68
|
+
ngrams
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
@@Rank = Hash.new { |h,k| h[k] = Rank.new(k) }
|
|
72
|
+
class Rank
|
|
73
|
+
attr_accessor :data, :outline
|
|
74
|
+
def initialize k
|
|
75
|
+
@id = k
|
|
76
|
+
@data = []
|
|
77
|
+
end
|
|
78
|
+
def << i
|
|
79
|
+
@data << i
|
|
80
|
+
end
|
|
81
|
+
def [] k
|
|
82
|
+
KNN.new(@data.to_a).rank(@id, k, 3)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
def self.[] k
|
|
86
|
+
@@Rank[k]
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
data/lib/pedicab/ride.rb
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
module Pedicab
|
|
2
|
+
@@Ride = Hash.new { |h,k| h[k] = Ride.new(k) }
|
|
3
|
+
class Ride
|
|
4
|
+
attr_accessor :state, :action, :goal, :ride, :info, :tale, :path, :model
|
|
5
|
+
def initialize k
|
|
6
|
+
@id = k
|
|
7
|
+
@model = 'model'
|
|
8
|
+
reset!
|
|
9
|
+
end
|
|
10
|
+
def reset!
|
|
11
|
+
@state = {}
|
|
12
|
+
@ride = []
|
|
13
|
+
@path = []
|
|
14
|
+
@info = ""
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# tell the "tale" of the ride.
|
|
19
|
+
def tale
|
|
20
|
+
a = []
|
|
21
|
+
if @ride.length > 0
|
|
22
|
+
h = @ride[-1]
|
|
23
|
+
@ride.shift
|
|
24
|
+
return %[#{h[:input]}\n#{h[:output]}\n]
|
|
25
|
+
else
|
|
26
|
+
return ""
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# process input.
|
|
32
|
+
def go i
|
|
33
|
+
@path << "go #{i}"
|
|
34
|
+
@state[:action] = "go"
|
|
35
|
+
@state[:input] = i
|
|
36
|
+
puts %[#===============[work]>\n#{i}\n#===============[work]];
|
|
37
|
+
Pedicab.on[:work].call(self)
|
|
38
|
+
@state[:output] = rider(role: 'user', model: 'work', content: "#{@info}#{tale}#{i}")
|
|
39
|
+
@ride << @state
|
|
40
|
+
@state[:output].gsub(/\n+/, "\n")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
##
|
|
44
|
+
# process condition
|
|
45
|
+
def go? i
|
|
46
|
+
@path << "go? #{i}"
|
|
47
|
+
@state[:action] = "go?"
|
|
48
|
+
@state[:input] = i
|
|
49
|
+
@state[:yes] = false
|
|
50
|
+
puts %[#>>>>>[gate]>\n#{i}\n#>>>>>[gate]];
|
|
51
|
+
Pedicab.on[:gate].call(self)
|
|
52
|
+
if rider(role: 'system', model: 'gate', content: %[#{@info}#{tale}if the following statement is true respond 'yes', otherwise respond 'no':\n#{i}], response: 'bool' ) == 'yes'
|
|
53
|
+
@state[:yes] = true
|
|
54
|
+
Pedicab.on[:go].call(self)
|
|
55
|
+
end
|
|
56
|
+
@ride << @state
|
|
57
|
+
@state[:yes]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
##
|
|
61
|
+
# process list
|
|
62
|
+
def go! i, p, &b
|
|
63
|
+
@path << "with #{i} of #{p}"
|
|
64
|
+
@state[:action] = "go! fork"
|
|
65
|
+
@state[:input] = %[#{@info}#{tale}List only #{i} without repeating yourself:\n#{p}]
|
|
66
|
+
Pedicab.on[:fork].call(self)
|
|
67
|
+
@state[:list] = rider(role: 'user', model: 'fork', content: @state[:input]).split("\n").uniq.map { |e|
|
|
68
|
+
if e.strip.length > 0;
|
|
69
|
+
puts %[#----------[fork]>\nfor: #{i}\nin: #{p}\nat: #{e}\n#----------[fork]];
|
|
70
|
+
Pedicab.on[:with].call(self);
|
|
71
|
+
b.call(e.strip);
|
|
72
|
+
end;
|
|
73
|
+
}
|
|
74
|
+
@ride << @state
|
|
75
|
+
@state[:list]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def rider h={}, &b
|
|
81
|
+
@state[:content] = "I don't know."
|
|
82
|
+
puts %[#====[ #{@ride.length} ][#{@state[:action]}]\n#{@state[:input]}]
|
|
83
|
+
Pedicab.on[:before].call(self)
|
|
84
|
+
@state[:took] = Benchmark.realtime do
|
|
85
|
+
Open3.popen3("sudo python3 bin/pedicab.py /models/#{h[:model]}.gguf") do |stdin, stdout, stderr, wait_thread|
|
|
86
|
+
x = lambda { stdin.puts(JSON.generate(h)); stdout.gets }
|
|
87
|
+
begin
|
|
88
|
+
xx = x.call()
|
|
89
|
+
if "#{xx}".strip.length > 0
|
|
90
|
+
@state[:content] = JSON.parse("#{xx}")['content']
|
|
91
|
+
end
|
|
92
|
+
rescue => e
|
|
93
|
+
@state[:content] = "Error: #{e}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
Pedicab.on[:after].call(self)
|
|
98
|
+
puts %[#====[ #{@ride.length} ] took: #{@state[:took]} seconds.\n#{@state[:content].gsub(/\n+/,"\n")}]
|
|
99
|
+
if block_given?
|
|
100
|
+
return b.call(self).gsub(/\n+/, "\n")
|
|
101
|
+
else
|
|
102
|
+
return @state[:content].gsub(/\n+/, "\n")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
def self.ride
|
|
107
|
+
@@Ride
|
|
108
|
+
end
|
|
109
|
+
end
|