pedicab 0.1.4 → 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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/#README.md# +51 -0
  3. data/Gemfile.lock +49 -0
  4. data/books/Arnold_Bennett-How_to_Live_on_24_Hours_a_Day.txt +1247 -0
  5. data/books/Edward_L_Bernays-crystallizing_public_opinion.txt +4422 -0
  6. data/books/Emma_Goldman-Anarchism_and_Other_Essays.txt +7654 -0
  7. data/books/Office_of_Strategic_Services-Simple_Sabotage_Field_Manual.txt +1057 -0
  8. data/books/Sigmund_Freud-Group_Psychology_and_The_Analysis_of_The_Ego.txt +2360 -0
  9. data/books/Steve_Hassan-The_Bite_Model.txt +130 -0
  10. data/books/Steve_Hassan-The_Bite_Model.txt~ +132 -0
  11. data/books/Sun_Tzu-Art_of_War.txt +159 -0
  12. data/books/Sun_Tzu-Art_of_War.txt~ +166 -0
  13. data/books/US-Constitution.txt +502 -0
  14. data/books/US-Constitution.txt~ +502 -0
  15. data/books/cia-kubark.txt +4637 -0
  16. data/books/machiavelli-the_prince.txt +4599 -0
  17. data/books/sun_tzu-art_of_war.txt +1017 -0
  18. data/books/us_army-bayonette.txt +843 -0
  19. data/lib/pedicab/calc.rb~ +8 -0
  20. data/lib/pedicab/link.rb +38 -0
  21. data/lib/pedicab/link.rb~ +14 -0
  22. data/lib/pedicab/mark.rb +9 -0
  23. data/lib/pedicab/mark.rb~ +5 -0
  24. data/lib/pedicab/on.rb +6 -0
  25. data/lib/pedicab/on.rb~ +6 -0
  26. data/lib/pedicab/poke.rb +14 -0
  27. data/lib/pedicab/poke.rb~ +15 -0
  28. data/lib/pedicab/query.rb +92 -0
  29. data/lib/pedicab/query.rb~ +93 -0
  30. data/lib/pedicab/rank.rb +92 -0
  31. data/lib/pedicab/rank.rb~ +89 -0
  32. data/lib/pedicab/ride.rb +109 -0
  33. data/lib/pedicab/ride.rb~ +101 -0
  34. data/lib/pedicab/version.rb +1 -1
  35. data/lib/pedicab.rb +2 -2
  36. data/pedicab-0.1.0.gem +0 -0
  37. data/pedicab-0.1.1.gem +0 -0
  38. data/pedicab-0.1.2.gem +0 -0
  39. data/pedicab-0.1.3.gem +0 -0
  40. data/pedicab-0.1.4.gem +0 -0
  41. data/pedicab-0.1.5.gem +0 -0
  42. metadata +39 -1
@@ -0,0 +1,8 @@
1
+ module Pedicab
2
+ class Calc
3
+ def initialize
4
+
5
+ end
6
+
7
+ end
8
+ end
@@ -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}") }
@@ -0,0 +1,9 @@
1
+ module Pedicab
2
+ def self.mark x
3
+ Nokogiri::HTML(Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true).render(x)).css('p').map { |e|
4
+ if !/http.*/.match(e.text)
5
+ e.text
6
+ end
7
+ }.flatten.compact
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Pedicab
2
+ def self.mark x
3
+ Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true).render(x)
4
+ end
5
+ end
data/lib/pedicab/on.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Pedicab
2
+ @@ON = Hash.new { |h,k| h[k] = lambda() { |ride| ride } }
3
+ def self.on
4
+ @@ON
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Pedicab
2
+ @@ON = Hash.new { |h,k| h[k] = lambda() { |ride| ride } }
3
+ def self.on
4
+ @@ON
5
+ end
6
+ end
@@ -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
@@ -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
@@ -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