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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d669156f98a861c284f95d3f56f9fdad92b5820d288e8f3227e885ed5d13b2a
4
- data.tar.gz: e20b7578ff3ca46d9062137a930656e7598c4b613329da1984df09b80adffceb
3
+ metadata.gz: bf304be008b27bf4336085ec39f75fc8ac5207c6e17d442d5129a366795629eb
4
+ data.tar.gz: f436a7dc4a59f2840b023d7e406aa5fa2aa02dee7ebb10f48c982efaaf489546
5
5
  SHA512:
6
- metadata.gz: ee2d6aaceaea02c667e03f5ff30e6f08c88e27cd9fa3b3fba97f9cd90b1410684d253bf729993a769ef1b3151839cde6f08f7fa99636001027c8e2cfc1713b59
7
- data.tar.gz: f10b4515f9191e9f8adb4cacbc6096384f9b6be1697b94f2304130ede32a4360d81f90b9808c4462b8024aeff1982cd54842be64d22085938dbe7cd0b81bd5ab
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
- llm_class = llm == 'openai' ? N2M::Llm::OpenAi : N2M::Llm::Claude
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.open(CONFIG_FILE, 'w+') do |f|
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'] == 'openai' ? N2M::Llm::OpenAi.new(config) : N2M::Llm::Claude.new(config)
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'] == 'openai' ? N2M::Llm::OpenAi.new(config) : N2M::Llm::Claude.new(config)
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'] == 'openai' ? N2M::Llm::OpenAi.new(config) : N2M::Llm::Claude.new(config)
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|
@@ -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
@@ -1,4 +1,4 @@
1
1
  # lib/n2b/version.rb
2
2
  module N2B
3
- VERSION = "0.2.3"
3
+ VERSION = "0.2.4"
4
4
  end
data/lib/n2b.rb CHANGED
@@ -8,6 +8,7 @@ require 'fileutils'
8
8
  require 'n2b/version'
9
9
  require 'n2b/llm/claude'
10
10
  require 'n2b/llm/open_ai'
11
+ require 'n2b/llm/gemini'
11
12
  require 'n2b/base'
12
13
  require 'n2b/cli'
13
14
 
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.3
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-20 00:00:00.000000000 Z
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