rails_ai 0.1.7 → 0.1.9
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/lib/rails_ai/version.rb +1 -1
- data/lib/rails_ai/web_search.rb +115 -0
- data/lib/rails_ai.rb +3 -0
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59f6834d30b4cf06108297201d34f4c51de26e46162d1a19290217d3e4219f17
|
4
|
+
data.tar.gz: e0b01802d3f3ce93e74fce16fdb307d063c77d0dff3a62c30992185adb8c27ce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f04449c3223b6d793fb32cae60cbd78e122dd81a148cdd9452d53e8b2d3419ca5204c931cd937a25fbd5a5bbe5364b30654843e3aecc0be78de1eb2e1e082c99
|
7
|
+
data.tar.gz: e08d1b8bf4cf29a087c81d6a7b32f3e94778f31484fcb62d53e5fd99e91e8e7ae95f88b9d70c649ec786737a13d10860221c115c76ca2078656a93c21e82c905
|
data/lib/rails_ai/version.rb
CHANGED
@@ -0,0 +1,115 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'json'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
module RailsAi
|
8
|
+
module WebSearch
|
9
|
+
class SearchError < StandardError; end
|
10
|
+
|
11
|
+
class GoogleSearch
|
12
|
+
def initialize(api_key: nil, search_engine_id: nil)
|
13
|
+
@api_key = api_key || ENV['GOOGLE_SEARCH_API_KEY']
|
14
|
+
@search_engine_id = search_engine_id || ENV['GOOGLE_SEARCH_ENGINE_ID']
|
15
|
+
@base_url = 'https://www.googleapis.com/customsearch/v1'
|
16
|
+
end
|
17
|
+
|
18
|
+
def search(query, num_results: 5)
|
19
|
+
raise SearchError, "Google Search API key not configured" unless @api_key
|
20
|
+
raise SearchError, "Google Search Engine ID not configured" unless @search_engine_id
|
21
|
+
|
22
|
+
uri = URI(@base_url)
|
23
|
+
params = {
|
24
|
+
key: @api_key,
|
25
|
+
cx: @search_engine_id,
|
26
|
+
q: query,
|
27
|
+
num: num_results
|
28
|
+
}
|
29
|
+
uri.query = URI.encode_www_form(params)
|
30
|
+
|
31
|
+
response = Net::HTTP.get_response(uri)
|
32
|
+
raise SearchError, "Search failed: #{response.code}" unless response.code == '200'
|
33
|
+
|
34
|
+
data = JSON.parse(response.body)
|
35
|
+
format_results(data)
|
36
|
+
rescue => e
|
37
|
+
raise SearchError, "Web search error: #{e.message}"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def format_results(data)
|
43
|
+
results = data['items'] || []
|
44
|
+
results.map do |item|
|
45
|
+
{
|
46
|
+
title: item['title'],
|
47
|
+
link: item['link'],
|
48
|
+
snippet: item['snippet']
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class DuckDuckGoSearch
|
55
|
+
def search(query, num_results: 5)
|
56
|
+
# Simple web scraping approach (for demo purposes)
|
57
|
+
# In production, you'd want to use a proper API
|
58
|
+
uri = URI("https://html.duckduckgo.com/html/?q=#{URI.encode_www_form_component(query)}")
|
59
|
+
|
60
|
+
response = Net::HTTP.get_response(uri)
|
61
|
+
raise SearchError, "Search failed: #{response.code}" unless response.code == '200'
|
62
|
+
|
63
|
+
# Parse HTML and extract results (simplified)
|
64
|
+
parse_duckduckgo_results(response.body, num_results)
|
65
|
+
rescue => e
|
66
|
+
raise SearchError, "Web search error: #{e.message}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def parse_duckduckgo_results(html, num_results)
|
72
|
+
# This is a simplified parser - in production you'd use Nokogiri
|
73
|
+
results = []
|
74
|
+
lines = html.split("\n")
|
75
|
+
|
76
|
+
lines.each_with_index do |line, index|
|
77
|
+
if line.include?('class="result__title"') && results.length < num_results
|
78
|
+
title_line = lines[index + 1] rescue ""
|
79
|
+
snippet_line = lines[index + 3] rescue ""
|
80
|
+
|
81
|
+
results << {
|
82
|
+
title: title_line.strip,
|
83
|
+
link: "https://duckduckgo.com",
|
84
|
+
snippet: snippet_line.strip
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
results
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class WebSearch
|
94
|
+
def initialize(provider: :google, **options)
|
95
|
+
@provider = case provider
|
96
|
+
when :google
|
97
|
+
GoogleSearch.new(**options)
|
98
|
+
when :duckduckgo
|
99
|
+
DuckDuckGoSearch.new(**options)
|
100
|
+
else
|
101
|
+
raise SearchError, "Unsupported search provider: #{provider}"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def search(query, **options)
|
106
|
+
@provider.search(query, **options)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Convenience method
|
111
|
+
def self.search(query, provider: :google, **options)
|
112
|
+
WebSearch.new(provider: provider, **options).search(query)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/lib/rails_ai.rb
CHANGED
@@ -502,6 +502,8 @@ end
|
|
502
502
|
end
|
503
503
|
require_relative "rails_ai/web_search"
|
504
504
|
|
505
|
+
# Web-enhanced chat with real-time information
|
506
|
+
|
505
507
|
# Web-enhanced chat with real-time information
|
506
508
|
def self.chat_with_web_search(prompt, model: config.default_model, **opts)
|
507
509
|
# Check if the prompt needs web search
|
@@ -532,3 +534,4 @@ require_relative "rails_ai/web_search"
|
|
532
534
|
chat(prompt, model: model, **opts)
|
533
535
|
end
|
534
536
|
end
|
537
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_ai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Amah
|
@@ -339,6 +339,7 @@ files:
|
|
339
339
|
- lib/rails_ai/security/secure_file_handler.rb
|
340
340
|
- lib/rails_ai/security/secure_http_client.rb
|
341
341
|
- lib/rails_ai/version.rb
|
342
|
+
- lib/rails_ai/web_search.rb
|
342
343
|
- lib/rails_ai/window_context.rb
|
343
344
|
- monitoring/ci_setup_guide.md
|
344
345
|
- monitoring/enhanced_monitoring_script.rb
|