n2b 0.2.3 → 0.2.4
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 +15 -2
- data/lib/n2b/base.rb +15 -10
- data/lib/n2b/irb.rb +24 -3
- data/lib/n2b/llm/claude.rb +1 -1
- data/lib/n2b/llm/gemini.rb +69 -0
- data/lib/n2b/version.rb +1 -1
- data/lib/n2b.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf304be008b27bf4336085ec39f75fc8ac5207c6e17d442d5129a366795629eb
|
4
|
+
data.tar.gz: f436a7dc4a59f2840b023d7e406aa5fa2aa02dee7ebb10f48c982efaaf489546
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 770f49a5df340f3f9eae3f9072eafcbd9e8de6e2a5a227da3a96c67ebb22ca998411d1098921a375a9203fe446593ac8b15cfc3b6c6e6d13503a48957fed29c9
|
7
|
+
data.tar.gz: 88720e0bae3adf499830681214c142ea96787f3fbae01fcfe276593ce3860f65127783293cf2c1c993725747ad54165e260473f84d172fb290490165cd587708
|
data/README.md
CHANGED
@@ -56,16 +56,29 @@ n2rscrum "Create a user authentication system"
|
|
56
56
|
|
57
57
|
## Configuration
|
58
58
|
|
59
|
-
Create a config file at `~/.n2b/config.yml` with your API keys:
|
59
|
+
Create a config file at `~/.n2b/config.yml` with your API keys. You can also use a custom config file by setting the `N2B_CONFIG_FILE` environment variable:
|
60
60
|
|
61
|
+
```bash
|
62
|
+
export N2B_CONFIG_FILE=/path/to/your/config.yml
|
63
|
+
```
|
64
|
+
|
65
|
+
Example config file:
|
61
66
|
```yaml
|
62
|
-
llm: claude # or openai
|
67
|
+
llm: claude # or openai, gemini
|
63
68
|
claude:
|
64
69
|
key: your-anthropic-api-key
|
65
70
|
model: claude-3-opus-20240229 # or opus, haiku, sonnet
|
66
71
|
openai:
|
67
72
|
key: your-openai-api-key
|
68
73
|
model: gpt-4 # or gpt-3.5-turbo
|
74
|
+
gemini:
|
75
|
+
key: your-google-api-key
|
76
|
+
model: gemini-flash # uses gemini-2.0-flash model
|
77
|
+
```
|
78
|
+
|
79
|
+
You can also set the history file location using the `N2B_HISTORY_FILE` environment variable:
|
80
|
+
```bash
|
81
|
+
export N2B_HISTORY_FILE=/path/to/your/history
|
69
82
|
```
|
70
83
|
|
71
84
|
## Quick Example N2B
|
data/lib/n2b/base.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module N2B
|
2
2
|
class Base
|
3
3
|
|
4
|
-
CONFIG_FILE = File.expand_path('~/.n2b/config.yml')
|
5
|
-
HISTORY_FILE = File.expand_path('~/.n2b/history')
|
4
|
+
CONFIG_FILE = ENV['N2B_CONFIG_FILE'] || File.expand_path('~/.n2b/config.yml')
|
5
|
+
HISTORY_FILE = ENV['N2B_HISTORY_FILE'] || File.expand_path('~/.n2b/history')
|
6
6
|
|
7
7
|
def load_config
|
8
8
|
if File.exist?(CONFIG_FILE)
|
@@ -18,16 +18,24 @@ module N2B
|
|
18
18
|
model = config['model'] || 'sonnet35'
|
19
19
|
|
20
20
|
if api_key.nil? || api_key == '' || reconfigure
|
21
|
-
print "choose a language model to use (1:claude, 2:openai) #{ config['llm'] }: "
|
21
|
+
print "choose a language model to use (1:claude, 2:openai, 3:gemini) #{ config['llm'] }: "
|
22
22
|
llm = $stdin.gets.chomp
|
23
23
|
llm = config['llm'] if llm.empty?
|
24
|
-
unless ['claude', 'openai','1','2'].include?(llm)
|
25
|
-
puts "Invalid language model. Choose from: claude, openai"
|
24
|
+
unless ['claude', 'openai', 'gemini', '1', '2', '3'].include?(llm)
|
25
|
+
puts "Invalid language model. Choose from: claude, openai, gemini"
|
26
26
|
exit 1
|
27
27
|
end
|
28
28
|
llm = 'claude' if llm == '1'
|
29
29
|
llm = 'openai' if llm == '2'
|
30
|
-
|
30
|
+
llm = 'gemini' if llm == '3'
|
31
|
+
llm_class = case llm
|
32
|
+
when 'openai'
|
33
|
+
N2M::Llm::OpenAi
|
34
|
+
when 'gemini'
|
35
|
+
N2M::Llm::Gemini
|
36
|
+
else
|
37
|
+
N2M::Llm::Claude
|
38
|
+
end
|
31
39
|
|
32
40
|
print "Enter your #{llm} API key: #{ api_key.nil? || api_key.empty? ? '' : '(leave blank to keep the current key '+api_key[0..10]+'...)' }"
|
33
41
|
api_key = $stdin.gets.chomp
|
@@ -50,11 +58,8 @@ module N2B
|
|
50
58
|
config['append_to_shell_history'] = false
|
51
59
|
puts "Current configuration: #{config['privacy']}"
|
52
60
|
FileUtils.mkdir_p(File.dirname(CONFIG_FILE)) unless File.exist?(File.dirname(CONFIG_FILE))
|
53
|
-
File.
|
54
|
-
f.write(config.to_yaml )
|
55
|
-
end
|
61
|
+
File.write(CONFIG_FILE, config.to_yaml)
|
56
62
|
end
|
57
|
-
|
58
63
|
config
|
59
64
|
end
|
60
65
|
end
|
data/lib/n2b/irb.rb
CHANGED
@@ -17,7 +17,14 @@ module N2B
|
|
17
17
|
|
18
18
|
def n2r(input_string='', files: [], exception: nil, log: false)
|
19
19
|
config = N2B::Base.new.get_config
|
20
|
-
llm = config['llm']
|
20
|
+
llm = case config['llm']
|
21
|
+
when 'openai'
|
22
|
+
N2M::Llm::OpenAi.new(config)
|
23
|
+
when 'gemini'
|
24
|
+
N2M::Llm::Gemini.new(config)
|
25
|
+
else
|
26
|
+
N2M::Llm::Claude.new(config)
|
27
|
+
end
|
21
28
|
# detect if inside rails console
|
22
29
|
console = case
|
23
30
|
when defined?(Rails) && Rails.respond_to?(:application)
|
@@ -586,7 +593,14 @@ module N2B
|
|
586
593
|
|
587
594
|
def analyze_error(error_info, related_files)
|
588
595
|
config = N2B::Base.new.get_config
|
589
|
-
llm = config['llm']
|
596
|
+
llm = case config['llm']
|
597
|
+
when 'openai'
|
598
|
+
N2M::Llm::OpenAi.new(config)
|
599
|
+
when 'gemini'
|
600
|
+
N2M::Llm::Gemini.new(config)
|
601
|
+
else
|
602
|
+
N2M::Llm::Claude.new(config)
|
603
|
+
end
|
590
604
|
|
591
605
|
# Build file content section, showing context if available
|
592
606
|
file_content_section = related_files.map do |file_path, content|
|
@@ -651,7 +665,14 @@ module N2B
|
|
651
665
|
|
652
666
|
def generate_error_ticket(error_info, related_files = {}, url = nil)
|
653
667
|
config = N2B::Base.new.get_config
|
654
|
-
llm = config['llm']
|
668
|
+
llm = case config['llm']
|
669
|
+
when 'openai'
|
670
|
+
N2M::Llm::OpenAi.new(config)
|
671
|
+
when 'gemini'
|
672
|
+
N2M::Llm::Gemini.new(config)
|
673
|
+
else
|
674
|
+
N2M::Llm::Claude.new(config)
|
675
|
+
end
|
655
676
|
|
656
677
|
# Build file content section, showing context if available
|
657
678
|
file_content_section = related_files.map do |file_path, content|
|
data/lib/n2b/llm/claude.rb
CHANGED
@@ -2,7 +2,7 @@ module N2M
|
|
2
2
|
module Llm
|
3
3
|
class Claude
|
4
4
|
API_URI = URI.parse('https://api.anthropic.com/v1/messages')
|
5
|
-
MODELS = { 'haiku' => 'claude-3-haiku-20240307', 'sonnet' => 'claude-3-sonnet-20240229', 'sonnet35' => 'claude-3-5-sonnet-20240620' }
|
5
|
+
MODELS = { 'haiku' => 'claude-3-haiku-20240307', 'sonnet' => 'claude-3-sonnet-20240229', 'sonnet35' => 'claude-3-5-sonnet-20240620', "sonnet37" => "claude-3-7-sonnet-20250219" }
|
6
6
|
|
7
7
|
def initialize(config)
|
8
8
|
@config = config
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module N2M
|
6
|
+
module Llm
|
7
|
+
class Gemini
|
8
|
+
API_URI = URI.parse('https://generativelanguage.googleapis.com/v1beta/models')
|
9
|
+
MODELS = {
|
10
|
+
'gemini-flash' => 'gemini-2.0-flash'
|
11
|
+
}
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@config = config
|
15
|
+
end
|
16
|
+
|
17
|
+
def make_request(content)
|
18
|
+
model = MODELS[@config['model']] || 'gemini-flash'
|
19
|
+
uri = URI.parse("#{API_URI}/#{model}:generateContent?key=#{@config['access_key']}")
|
20
|
+
|
21
|
+
request = Net::HTTP::Post.new(uri)
|
22
|
+
request.content_type = 'application/json'
|
23
|
+
|
24
|
+
request.body = JSON.dump({
|
25
|
+
"contents" => [{
|
26
|
+
"parts" => [{
|
27
|
+
"text" => content
|
28
|
+
}]
|
29
|
+
}]
|
30
|
+
})
|
31
|
+
|
32
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
|
33
|
+
http.request(request)
|
34
|
+
end
|
35
|
+
|
36
|
+
# check for errors
|
37
|
+
if response.code != '200'
|
38
|
+
puts "Error: #{response.code} #{response.message}"
|
39
|
+
puts response.body
|
40
|
+
puts "Config: #{@config.inspect}"
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
parsed_response = JSON.parse(response.body)
|
45
|
+
answer = parsed_response['candidates'].first['content']['parts'].first['text']
|
46
|
+
|
47
|
+
begin
|
48
|
+
# Try to parse as JSON if it looks like JSON
|
49
|
+
if answer.strip.start_with?('{') && answer.strip.end_with?('}')
|
50
|
+
answer = JSON.parse(answer)
|
51
|
+
else
|
52
|
+
# If not JSON, wrap it in our expected format
|
53
|
+
answer = {
|
54
|
+
'explanation' => answer,
|
55
|
+
'code' => nil
|
56
|
+
}
|
57
|
+
end
|
58
|
+
rescue JSON::ParserError
|
59
|
+
# If JSON parsing fails, wrap the text in our expected format
|
60
|
+
answer = {
|
61
|
+
'explanation' => answer,
|
62
|
+
'code' => nil
|
63
|
+
}
|
64
|
+
end
|
65
|
+
answer
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/n2b/version.rb
CHANGED
data/lib/n2b.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: n2b
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stefan Nothegger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/n2b/cli.rb
|
70
70
|
- lib/n2b/irb.rb
|
71
71
|
- lib/n2b/llm/claude.rb
|
72
|
+
- lib/n2b/llm/gemini.rb
|
72
73
|
- lib/n2b/llm/open_ai.rb
|
73
74
|
- lib/n2b/version.rb
|
74
75
|
homepage: https://github.com/stefan-kp/n2b
|