matheus 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72cfeba7ddd84ef4fd7c7c80144a1a8821eb4c3d03fd33f3d718109b08d39bae
4
- data.tar.gz: add8482702c9e6af603e6ea2ba5cb7cefa589c57bf133385f2682db7532b8324
3
+ metadata.gz: 8f0188994d160b9cfc3ce6ab06610e4f42102ddf828dc01e1c917cdf02ac77c6
4
+ data.tar.gz: 0cf90a3177f25047f2b15fcf5198eb0de8ea3439116107576b7fdd7daab5bddf
5
5
  SHA512:
6
- metadata.gz: 222e09a48119ad9aa15daa86b26f8159dd45dc9f7b1a8743e6bc8e1255399562e4a4ed2ee3a8ac2539b61c15d61b5d79532913cd2710b2a9f1657dae82de4a44
7
- data.tar.gz: c46798f32fc8a73cd99fb47372bdb61060718e1f0366f5d1623215e397bdb0ae5074666fc145a7957350f80bcdd4eeb459fe47809f4e656fa242423d07e28d9c
6
+ metadata.gz: 364f6273dfdbc464d491b3ce29d670351c5c4c007524c0aa6ad46e1d44e810bf4e7dfa083821a20ae2f0058d01e45a601f7b68c70b9d42ed156df3e6205af895
7
+ data.tar.gz: d8c641cbaeca884aff2d5782b0abbe720ddaf08af0057676d85ea9bdb9bb0adff33f81c8b158d8a18ba32879dd2f7e30f667c9e400ca4e9862befcae44409366
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.2.0
1
+ ruby 3.3.4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0]
4
+
5
+ _Released 2024-10-02_
6
+
7
+ - Save past questions with `q` and retrieve them with the `qs` command.
8
+ - Reuse answers for the same questions.
9
+
10
+ ## [0.3.0]
11
+
12
+ _Released 2024-08-27_
13
+
14
+ - Add `alert-me` command.
15
+
3
16
  ## [0.2.0]
4
17
 
5
18
  _Released 2024-08-26_
data/README.md CHANGED
@@ -6,6 +6,48 @@ A bunch of CLI tools I made for my own use.
6
6
 
7
7
  $ gem install matheus
8
8
 
9
+ ## Usage
10
+
11
+ ### `alert-me`
12
+
13
+ ```sh
14
+ $ alert-me 'sleep 1 && echo "Done!"'
15
+ Done!
16
+ # plays a sound after the command finishes
17
+ ```
18
+
19
+ ### `date-of-last`
20
+
21
+ Prints the date of the last week day.
22
+
23
+ ```sh
24
+ $ date-of-last monday
25
+ 2024-02-12
26
+
27
+ $ date-of-last sun
28
+ 2024-02-11
29
+ ```
30
+
31
+ ### `q`
32
+
33
+ It expects a OPENAI_API_KEY environment variable to be set. It will try to load
34
+ it from a `.env` file at `~/.env`.
35
+
36
+ ```sh
37
+ $ q "What is the capital of France?"
38
+ The capital of France is **Paris**
39
+ ```
40
+
41
+ ### `puts`
42
+
43
+ It evaluates the given Ruby code and prints the result. Active Support is
44
+ available.
45
+
46
+ ```sh
47
+ $ puts 10.days.ago
48
+ 2024-08-17 15:50:11 -0300
49
+ ```
50
+
9
51
  ## Contributing
10
52
 
11
53
  Probably not accepting contributions at the moment, but feel free to open an issue if you have any ideas or suggestions.
data/Rakefile CHANGED
@@ -45,3 +45,5 @@ end
45
45
 
46
46
  # Ensure the generate_executables task runs before the build task
47
47
  task build: :generate_executables
48
+ # Ensure tests are run before releasing the gem
49
+ task release: :spec
data/exe/alert-me ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+
5
+ require "matheus"
6
+
7
+ Matheus::AlertMe.call ARGV
data/exe/qs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
4
+
5
+ require "matheus"
6
+
7
+ Matheus::Qs.call ARGV
@@ -0,0 +1,16 @@
1
+ module Matheus
2
+ class AlertMe < Command
3
+ # Usage:
4
+ # $ alert-me "sleep 1 && echo 'Done!'"
5
+ # Runs the command and plays a sound based on its success or failure after it finishes.
6
+ def call(*args)
7
+ if system(args.join(" "))
8
+ system("afplay /System/Library/Sounds/Glass.aiff")
9
+ else
10
+ system("afplay /System/Library/Sounds/Sosumi.aiff")
11
+ end
12
+ rescue => e
13
+ Failure(e.message)
14
+ end
15
+ end
16
+ end
data/lib/matheus/q.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require "openai"
2
2
  require "tty-markdown"
3
+ require "tty-prompt"
4
+ require "json"
3
5
 
4
6
  module Matheus
5
7
  # Usage:
@@ -9,7 +11,17 @@ module Matheus
9
11
  BASE_PROMPT = "Answer this question in a short and concise way. You can use markdown in the response: "
10
12
 
11
13
  def call(question)
12
- ask_llm(question).then { print_markdown _1 }
14
+ question = question.join(" ")
15
+ existing_entry = search_question_in_history(question)
16
+
17
+ if existing_entry && use_existing_answer?
18
+ answer = existing_entry['answer']
19
+ else
20
+ answer = ask_llm(question)
21
+ save_qa(question, answer)
22
+ end
23
+
24
+ print_markdown(answer)
13
25
  rescue => e
14
26
  Failure(e.message)
15
27
  end
@@ -21,7 +33,7 @@ module Matheus
21
33
 
22
34
  response = client.chat(
23
35
  parameters: {
24
- model: "gpt-4o-mini", # using gpt-4o model
36
+ model: "gpt-4o-mini",
25
37
  messages: [{role: "user", content: "#{BASE_PROMPT}#{question}"}]
26
38
  }
27
39
  )
@@ -29,6 +41,8 @@ module Matheus
29
41
  raise response["error"]["message"] if response.has_key?("error")
30
42
 
31
43
  response.dig("choices", 0, "message", "content")
44
+ rescue Faraday::ClientError => error
45
+ raise error.response_body.dig("error", "message") || error
32
46
  end
33
47
 
34
48
  def print_markdown(text)
@@ -38,5 +52,26 @@ module Matheus
38
52
  def client
39
53
  OpenAI::Client.new(access_token: ENV.fetch("OPENAI_API_KEY"))
40
54
  end
55
+
56
+ def save_qa(question, answer)
57
+ history = load_history
58
+ history << { question:, answer:, timestamp: Time.now.to_s }
59
+ File.write(QUESTION_HISTORY_FILE, JSON.pretty_generate(history))
60
+ end
61
+
62
+ def load_history
63
+ File.exist?(QUESTION_HISTORY_FILE) ? JSON.parse(File.read(QUESTION_HISTORY_FILE)) : []
64
+ end
65
+
66
+ def search_question_in_history(question)
67
+ load_history.reverse.find { |entry| entry['question'].downcase.strip == question.downcase.strip }
68
+ end
69
+
70
+ def use_existing_answer?
71
+ prompt = TTY::Prompt.new
72
+ prompt.yes?("An existing answer was found. Do you want to use it?") do |q|
73
+ q.default true
74
+ end
75
+ end
41
76
  end
42
77
  end
data/lib/matheus/qs.rb ADDED
@@ -0,0 +1,40 @@
1
+ require "json"
2
+ require "tty-prompt"
3
+ require "tty-markdown"
4
+
5
+ module Matheus
6
+ # Usage:
7
+ # $ qs
8
+ # Lists the questions asked and their answers.
9
+ class Qs < Command
10
+ def call(_)
11
+ return puts "No questions found in history." if history.empty?
12
+
13
+ answer = prompt.select("Question:", choices, per_page: 10)
14
+ print_markdown(answer)
15
+ rescue => e
16
+ Failure(e.message)
17
+ end
18
+
19
+ private
20
+ def choices
21
+ history.map do |entry|
22
+ {entry['question'] => entry['answer'] }
23
+ end
24
+ end
25
+
26
+
27
+ def history
28
+ @history ||= File.exist?(QUESTION_HISTORY_FILE) ? JSON.parse(File.read(QUESTION_HISTORY_FILE)) : []
29
+ end
30
+
31
+ def prompt
32
+ @prompt ||= TTY::Prompt.new(interrupt: :exit)
33
+ end
34
+
35
+ def print_markdown(answer)
36
+ puts
37
+ puts TTY::Markdown.parse(answer)
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Matheus
4
- VERSION = "0.2.1"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/matheus.rb CHANGED
@@ -9,4 +9,5 @@ Dotenv.load("~/.env")
9
9
  Zeitwerk::Loader.for_gem.setup
10
10
 
11
11
  module Matheus
12
+ QUESTION_HISTORY_FILE = File.expand_path("~/.qa_history.json")
12
13
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: matheus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matheus Richard
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-26 00:00:00.000000000 Z
11
+ date: 2024-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.7.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: tty-table
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.12.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.12.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: tty-prompt
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.23.1
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.23.1
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: dotenv
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -84,9 +112,11 @@ description: A bunch of CLI tools I made for my own use.
84
112
  email:
85
113
  - matheusrichardt@gmail.com
86
114
  executables:
115
+ - alert-me
87
116
  - date-of-last
88
117
  - puts
89
118
  - q
119
+ - qs
90
120
  extensions: []
91
121
  extra_rdoc_files: []
92
122
  files:
@@ -96,14 +126,18 @@ files:
96
126
  - LICENSE.txt
97
127
  - README.md
98
128
  - Rakefile
129
+ - exe/alert-me
99
130
  - exe/date-of-last
100
131
  - exe/puts
101
132
  - exe/q
133
+ - exe/qs
102
134
  - lib/matheus.rb
135
+ - lib/matheus/alert_me.rb
103
136
  - lib/matheus/command.rb
104
137
  - lib/matheus/date_of_last.rb
105
138
  - lib/matheus/puts.rb
106
139
  - lib/matheus/q.rb
140
+ - lib/matheus/qs.rb
107
141
  - lib/matheus/result.rb
108
142
  - lib/matheus/string_format.rb
109
143
  - lib/matheus/version.rb
@@ -129,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
163
  - !ruby/object:Gem::Version
130
164
  version: '0'
131
165
  requirements: []
132
- rubygems_version: 3.5.17
166
+ rubygems_version: 3.5.11
133
167
  signing_key:
134
168
  specification_version: 4
135
169
  summary: A bunch of CLI tools I made for my own use.