rails_ai 0.1.0
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 +7 -0
- data/.rspec_status +96 -0
- data/AGENT_GUIDE.md +513 -0
- data/Appraisals +49 -0
- data/COMMERCIAL_LICENSE_TEMPLATE.md +92 -0
- data/FEATURES.md +204 -0
- data/LEGAL_PROTECTION_GUIDE.md +222 -0
- data/LICENSE +62 -0
- data/LICENSE_SUMMARY.md +74 -0
- data/MIT-LICENSE +62 -0
- data/PERFORMANCE.md +300 -0
- data/PROVIDERS.md +495 -0
- data/README.md +454 -0
- data/Rakefile +11 -0
- data/SPEED_OPTIMIZATIONS.md +217 -0
- data/STRUCTURE.md +139 -0
- data/USAGE_GUIDE.md +288 -0
- data/app/channels/ai_stream_channel.rb +33 -0
- data/app/components/ai/prompt_component.rb +25 -0
- data/app/controllers/concerns/ai/context_aware.rb +77 -0
- data/app/controllers/concerns/ai/streaming.rb +41 -0
- data/app/helpers/ai_helper.rb +164 -0
- data/app/jobs/ai/generate_embedding_job.rb +25 -0
- data/app/jobs/ai/generate_summary_job.rb +25 -0
- data/app/models/concerns/ai/embeddable.rb +38 -0
- data/app/views/rails_ai/dashboard/index.html.erb +51 -0
- data/config/routes.rb +19 -0
- data/lib/generators/rails_ai/install/install_generator.rb +38 -0
- data/lib/rails_ai/agents/agent_manager.rb +258 -0
- data/lib/rails_ai/agents/agent_team.rb +243 -0
- data/lib/rails_ai/agents/base_agent.rb +331 -0
- data/lib/rails_ai/agents/collaboration.rb +238 -0
- data/lib/rails_ai/agents/memory.rb +116 -0
- data/lib/rails_ai/agents/message_bus.rb +95 -0
- data/lib/rails_ai/agents/specialized_agents.rb +391 -0
- data/lib/rails_ai/agents/task_queue.rb +111 -0
- data/lib/rails_ai/cache.rb +14 -0
- data/lib/rails_ai/config.rb +40 -0
- data/lib/rails_ai/context.rb +7 -0
- data/lib/rails_ai/context_analyzer.rb +86 -0
- data/lib/rails_ai/engine.rb +48 -0
- data/lib/rails_ai/events.rb +9 -0
- data/lib/rails_ai/image_context.rb +110 -0
- data/lib/rails_ai/performance.rb +231 -0
- data/lib/rails_ai/provider.rb +8 -0
- data/lib/rails_ai/providers/anthropic_adapter.rb +256 -0
- data/lib/rails_ai/providers/base.rb +60 -0
- data/lib/rails_ai/providers/dummy_adapter.rb +29 -0
- data/lib/rails_ai/providers/gemini_adapter.rb +509 -0
- data/lib/rails_ai/providers/openai_adapter.rb +535 -0
- data/lib/rails_ai/providers/secure_anthropic_adapter.rb +206 -0
- data/lib/rails_ai/providers/secure_openai_adapter.rb +284 -0
- data/lib/rails_ai/railtie.rb +48 -0
- data/lib/rails_ai/redactor.rb +12 -0
- data/lib/rails_ai/security/api_key_manager.rb +82 -0
- data/lib/rails_ai/security/audit_logger.rb +46 -0
- data/lib/rails_ai/security/error_handler.rb +62 -0
- data/lib/rails_ai/security/input_validator.rb +176 -0
- data/lib/rails_ai/security/secure_file_handler.rb +45 -0
- data/lib/rails_ai/security/secure_http_client.rb +177 -0
- data/lib/rails_ai/security.rb +0 -0
- data/lib/rails_ai/version.rb +5 -0
- data/lib/rails_ai/window_context.rb +103 -0
- data/lib/rails_ai.rb +502 -0
- data/monitoring/ci_setup_guide.md +214 -0
- data/monitoring/enhanced_monitoring_script.rb +237 -0
- data/monitoring/google_alerts_setup.md +42 -0
- data/monitoring_log_20250921.txt +0 -0
- data/monitoring_script.rb +161 -0
- data/rails_ai.gemspec +54 -0
- data/scripts/security_scanner.rb +353 -0
- data/setup_monitoring.sh +163 -0
- data/wiki/API-Documentation.md +734 -0
- data/wiki/Architecture-Overview.md +672 -0
- data/wiki/Contributing-Guide.md +407 -0
- data/wiki/Development-Setup.md +532 -0
- data/wiki/Home.md +278 -0
- data/wiki/Installation-Guide.md +527 -0
- data/wiki/Quick-Start.md +186 -0
- data/wiki/README.md +135 -0
- data/wiki/Release-Process.md +467 -0
- metadata +385 -0
data/lib/rails_ai.rb
ADDED
@@ -0,0 +1,502 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
require "concurrent-ruby"
|
5
|
+
require "zlib"
|
6
|
+
require "digest"
|
7
|
+
require "net/http"
|
8
|
+
require "json"
|
9
|
+
require "base64"
|
10
|
+
require "securerandom"
|
11
|
+
require_relative "rails_ai/version"
|
12
|
+
require_relative "rails_ai/config"
|
13
|
+
require_relative "rails_ai/context"
|
14
|
+
require_relative "rails_ai/cache"
|
15
|
+
require_relative "rails_ai/redactor"
|
16
|
+
require_relative "rails_ai/events"
|
17
|
+
require_relative "rails_ai/provider"
|
18
|
+
require_relative "rails_ai/engine"
|
19
|
+
require_relative "rails_ai/railtie"
|
20
|
+
require_relative "rails_ai/providers/base"
|
21
|
+
require_relative "rails_ai/providers/secure_openai_adapter"
|
22
|
+
require_relative "rails_ai/providers/secure_anthropic_adapter"
|
23
|
+
require_relative "rails_ai/providers/gemini_adapter"
|
24
|
+
require_relative "rails_ai/providers/dummy_adapter"
|
25
|
+
require_relative "rails_ai/context_analyzer"
|
26
|
+
require_relative "rails_ai/window_context"
|
27
|
+
require_relative "rails_ai/image_context"
|
28
|
+
require_relative "rails_ai/performance"
|
29
|
+
require_relative "rails_ai/agents/base_agent"
|
30
|
+
require_relative "rails_ai/agents/memory"
|
31
|
+
require_relative "rails_ai/agents/agent_manager"
|
32
|
+
require_relative "rails_ai/agents/message_bus"
|
33
|
+
require_relative "rails_ai/agents/task_queue"
|
34
|
+
require_relative "rails_ai/agents/agent_team"
|
35
|
+
require_relative "rails_ai/agents/collaboration"
|
36
|
+
require_relative "rails_ai/agents/specialized_agents"
|
37
|
+
require_relative "rails_ai/security"
|
38
|
+
|
39
|
+
module RailsAi
|
40
|
+
# Performance optimizations
|
41
|
+
@connection_pool = nil
|
42
|
+
@batch_processor = nil
|
43
|
+
@smart_cache = nil
|
44
|
+
@request_deduplicator = nil
|
45
|
+
@performance_monitor = nil
|
46
|
+
@agent_manager = nil
|
47
|
+
|
48
|
+
class << self
|
49
|
+
# Version compatibility helpers
|
50
|
+
def rails_version
|
51
|
+
Rails.version.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
def rails_8?
|
55
|
+
Rails.version >= "8.0"
|
56
|
+
end
|
57
|
+
|
58
|
+
def rails_7?
|
59
|
+
Rails.version >= "7.0" && Rails.version < "8.0"
|
60
|
+
end
|
61
|
+
|
62
|
+
def rails_6?
|
63
|
+
Rails.version >= "6.0" && Rails.version < "7.0"
|
64
|
+
end
|
65
|
+
|
66
|
+
def rails_5?
|
67
|
+
Rails.version >= "5.2" && Rails.version < "6.0"
|
68
|
+
end
|
69
|
+
|
70
|
+
# Performance-optimized provider with lazy loading
|
71
|
+
def provider
|
72
|
+
@provider ||= Performance::LazyProvider.new do
|
73
|
+
case config.provider.to_sym
|
74
|
+
when :openai then Providers::SecureOpenAIAdapter.new
|
75
|
+
when :anthropic then Providers::SecureAnthropicAdapter.new
|
76
|
+
when :gemini then Providers::GeminiAdapter.new
|
77
|
+
when :dummy then Providers::DummyAdapter.new
|
78
|
+
else Providers::DummyAdapter.new
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Agent management
|
84
|
+
def agent_manager
|
85
|
+
@agent_manager ||= Agents::AgentManager.new
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_agent(name:, role:, capabilities: [], **opts)
|
89
|
+
agent = Agents::BaseAgent.new(
|
90
|
+
name: name,
|
91
|
+
role: role,
|
92
|
+
capabilities: capabilities,
|
93
|
+
**opts
|
94
|
+
)
|
95
|
+
agent_manager.register_agent(agent)
|
96
|
+
agent
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_research_agent(name: "ResearchAgent", **opts)
|
100
|
+
agent = Agents::ResearchAgent.new(name: name, **opts)
|
101
|
+
agent_manager.register_agent(agent)
|
102
|
+
agent
|
103
|
+
end
|
104
|
+
|
105
|
+
def create_creative_agent(name: "CreativeAgent", **opts)
|
106
|
+
agent = Agents::CreativeAgent.new(name: name, **opts)
|
107
|
+
agent_manager.register_agent(agent)
|
108
|
+
agent
|
109
|
+
end
|
110
|
+
|
111
|
+
def create_technical_agent(name: "TechnicalAgent", **opts)
|
112
|
+
agent = Agents::TechnicalAgent.new(name: name, **opts)
|
113
|
+
agent_manager.register_agent(agent)
|
114
|
+
agent
|
115
|
+
end
|
116
|
+
|
117
|
+
def create_coordinator_agent(name: "CoordinatorAgent", **opts)
|
118
|
+
agent = Agents::CoordinatorAgent.new(name: name, **opts)
|
119
|
+
agent_manager.register_agent(agent)
|
120
|
+
agent
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_agent(name)
|
124
|
+
agent_manager.get_agent(name)
|
125
|
+
end
|
126
|
+
|
127
|
+
def list_agents
|
128
|
+
agent_manager.list_agents
|
129
|
+
end
|
130
|
+
|
131
|
+
def start_agents!
|
132
|
+
agent_manager.start!
|
133
|
+
end
|
134
|
+
|
135
|
+
def stop_agents!
|
136
|
+
agent_manager.stop!
|
137
|
+
end
|
138
|
+
|
139
|
+
# Task management
|
140
|
+
def submit_task(task)
|
141
|
+
agent_manager.submit_task(task)
|
142
|
+
end
|
143
|
+
|
144
|
+
def assign_task(task, agent_name)
|
145
|
+
agent_manager.assign_task_to_agent(task, agent_name)
|
146
|
+
end
|
147
|
+
|
148
|
+
def auto_assign_task(task)
|
149
|
+
agent_manager.auto_assign_task(task)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Agent teams
|
153
|
+
def create_agent_team(name, agents, strategy: :round_robin)
|
154
|
+
agent_manager.create_agent_team(name, agents, strategy: strategy)
|
155
|
+
end
|
156
|
+
|
157
|
+
def orchestrate_collaboration(task, agent_names)
|
158
|
+
agent_manager.orchestrate_collaboration(task, agent_names)
|
159
|
+
end
|
160
|
+
|
161
|
+
# Agent communication
|
162
|
+
def send_agent_message(from_agent, to_agent, message)
|
163
|
+
agent_manager.send_message(from_agent, to_agent, message)
|
164
|
+
end
|
165
|
+
|
166
|
+
def broadcast_agent_message(from_agent, message, exclude: [])
|
167
|
+
agent_manager.broadcast_message(from_agent, message, exclude: exclude)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Agent monitoring
|
171
|
+
def agent_system_status
|
172
|
+
agent_manager.system_status
|
173
|
+
end
|
174
|
+
|
175
|
+
def agent_health_check
|
176
|
+
agent_manager.health_check
|
177
|
+
end
|
178
|
+
|
179
|
+
# Performance monitoring
|
180
|
+
def performance_monitor
|
181
|
+
@performance_monitor ||= Performance::PerformanceMonitor.new
|
182
|
+
end
|
183
|
+
|
184
|
+
def metrics
|
185
|
+
performance_monitor.metrics
|
186
|
+
end
|
187
|
+
|
188
|
+
# Connection pool for HTTP requests
|
189
|
+
def connection_pool
|
190
|
+
@connection_pool ||= Performance::ConnectionPool.new(size: config.connection_pool_size)
|
191
|
+
end
|
192
|
+
|
193
|
+
# Smart caching with compression
|
194
|
+
def smart_cache
|
195
|
+
@smart_cache ||= Performance::SmartCache.new(
|
196
|
+
compression_threshold: config.compression_threshold
|
197
|
+
)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Request deduplication
|
201
|
+
def request_deduplicator
|
202
|
+
@request_deduplicator ||= Performance::RequestDeduplicator.new
|
203
|
+
end
|
204
|
+
|
205
|
+
# Batch processor for multiple operations
|
206
|
+
def batch_processor
|
207
|
+
@batch_processor ||= Performance::BatchProcessor.new(
|
208
|
+
batch_size: config.batch_size,
|
209
|
+
flush_interval: config.flush_interval
|
210
|
+
)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Optimized text-based AI operations with performance monitoring
|
214
|
+
def chat(prompt_or_messages, model: config.default_model, **opts)
|
215
|
+
performance_monitor.measure(:chat) do
|
216
|
+
messages = normalize_messages(prompt_or_messages)
|
217
|
+
cache_key = [:chat, model, messages.hash]
|
218
|
+
|
219
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
220
|
+
request_deduplicator.deduplicate(cache_key) do
|
221
|
+
provider.chat!(messages: messages, model: model, **opts)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def stream(prompt_or_messages, model: config.default_model, **opts, &block)
|
228
|
+
performance_monitor.measure(:stream) do
|
229
|
+
messages = normalize_messages(prompt_or_messages)
|
230
|
+
|
231
|
+
# Use connection pool for streaming
|
232
|
+
connection_pool.with_connection do |connection|
|
233
|
+
provider.stream_chat!(messages: messages, model: model, **opts, &block)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def embed(texts, model: config.default_model, **opts)
|
239
|
+
performance_monitor.measure(:embed) do
|
240
|
+
texts = Array(texts)
|
241
|
+
cache_key = [:embed, model, texts.hash]
|
242
|
+
|
243
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
244
|
+
request_deduplicator.deduplicate(cache_key) do
|
245
|
+
provider.embed!(texts: texts, model: model, **opts)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# Optimized image operations
|
252
|
+
def generate_image(prompt, model: "dall-e-3", size: "1024x1024", quality: "standard", **opts)
|
253
|
+
performance_monitor.measure(:generate_image) do
|
254
|
+
cache_key = [:image, model, prompt.hash, size, quality]
|
255
|
+
|
256
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
257
|
+
request_deduplicator.deduplicate(cache_key) do
|
258
|
+
provider.generate_image!(prompt: prompt, model: model, size: size, quality: quality, **opts)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def edit_image(image, prompt, mask: nil, size: "1024x1024", **opts)
|
265
|
+
performance_monitor.measure(:edit_image) do
|
266
|
+
cache_key = [:image_edit, prompt.hash, image.hash, size]
|
267
|
+
|
268
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
269
|
+
request_deduplicator.deduplicate(cache_key) do
|
270
|
+
provider.edit_image!(image: image, prompt: prompt, mask: mask, size: size, **opts)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def create_variation(image, size: "1024x1024", **opts)
|
277
|
+
performance_monitor.measure(:create_variation) do
|
278
|
+
cache_key = [:image_variation, image.hash, size]
|
279
|
+
|
280
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
281
|
+
request_deduplicator.deduplicate(cache_key) do
|
282
|
+
provider.create_variation!(image: image, size: size, **opts)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# Optimized video operations
|
289
|
+
def generate_video(prompt, model: "sora", duration: 5, **opts)
|
290
|
+
performance_monitor.measure(:generate_video) do
|
291
|
+
cache_key = [:video, model, prompt.hash, duration]
|
292
|
+
|
293
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
294
|
+
request_deduplicator.deduplicate(cache_key) do
|
295
|
+
provider.generate_video!(prompt: prompt, model: model, duration: duration, **opts)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
def edit_video(video, prompt, **opts)
|
302
|
+
performance_monitor.measure(:edit_video) do
|
303
|
+
cache_key = [:video_edit, prompt.hash, video.hash]
|
304
|
+
|
305
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
306
|
+
request_deduplicator.deduplicate(cache_key) do
|
307
|
+
provider.edit_video!(video: video, prompt: prompt, **opts)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
# Optimized audio operations
|
314
|
+
def generate_speech(text, model: "tts-1", voice: "alloy", **opts)
|
315
|
+
performance_monitor.measure(:generate_speech) do
|
316
|
+
cache_key = [:speech, model, text.hash, voice]
|
317
|
+
|
318
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
319
|
+
request_deduplicator.deduplicate(cache_key) do
|
320
|
+
provider.generate_speech!(text: text, model: model, voice: voice, **opts)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def transcribe_audio(audio, model: "whisper-1", **opts)
|
327
|
+
performance_monitor.measure(:transcribe_audio) do
|
328
|
+
cache_key = [:transcription, model, audio.hash]
|
329
|
+
|
330
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
331
|
+
request_deduplicator.deduplicate(cache_key) do
|
332
|
+
provider.transcribe_audio!(audio: audio, model: model, **opts)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
# Optimized multimodal analysis
|
339
|
+
def analyze_image(image, prompt, model: "gpt-4o", **opts)
|
340
|
+
performance_monitor.measure(:analyze_image) do
|
341
|
+
cache_key = [:image_analysis, model, prompt.hash, image.hash]
|
342
|
+
|
343
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
344
|
+
request_deduplicator.deduplicate(cache_key) do
|
345
|
+
provider.analyze_image!(image: image, prompt: prompt, model: model, **opts)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def analyze_video(video, prompt, model: "gpt-4o", **opts)
|
352
|
+
performance_monitor.measure(:analyze_video) do
|
353
|
+
cache_key = [:video_analysis, model, prompt.hash, video.hash]
|
354
|
+
|
355
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
356
|
+
request_deduplicator.deduplicate(cache_key) do
|
357
|
+
provider.analyze_video!(video: video, prompt: prompt, model: model, **opts)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# Batch operations for multiple requests
|
364
|
+
def batch_chat(requests)
|
365
|
+
performance_monitor.measure(:batch_chat) do
|
366
|
+
requests.map do |request|
|
367
|
+
batch_processor.add_operation(-> { chat(request[:prompt], **request.except(:prompt)) })
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
def batch_embed(texts_array)
|
373
|
+
performance_monitor.measure(:batch_embed) do
|
374
|
+
texts_array.map do |texts|
|
375
|
+
batch_processor.add_operation(-> { embed(texts) })
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Context-aware AI operations (optimized)
|
381
|
+
def analyze_image_with_context(image, prompt, user_context: {}, window_context: {}, image_context: {}, **opts)
|
382
|
+
performance_monitor.measure(:analyze_image_with_context) do
|
383
|
+
cache_key = [:context_image_analysis, prompt.hash, image.hash, user_context.hash, window_context.hash, image_context.hash]
|
384
|
+
|
385
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
386
|
+
analyzer = ContextAnalyzer.new(
|
387
|
+
user_context: user_context,
|
388
|
+
window_context: window_context,
|
389
|
+
image_context: image_context
|
390
|
+
)
|
391
|
+
analyzer.analyze_with_context(image, prompt, **opts)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def generate_with_context(prompt, user_context: {}, window_context: {}, **opts)
|
397
|
+
performance_monitor.measure(:generate_with_context) do
|
398
|
+
cache_key = [:context_generate, prompt.hash, user_context.hash, window_context.hash]
|
399
|
+
|
400
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
401
|
+
analyzer = ContextAnalyzer.new(
|
402
|
+
user_context: user_context,
|
403
|
+
window_context: window_context
|
404
|
+
)
|
405
|
+
analyzer.generate_with_context(prompt, **opts)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
def generate_image_with_context(prompt, user_context: {}, window_context: {}, **opts)
|
411
|
+
performance_monitor.measure(:generate_image_with_context) do
|
412
|
+
cache_key = [:context_image_generate, prompt.hash, user_context.hash, window_context.hash]
|
413
|
+
|
414
|
+
smart_cache.fetch(cache_key, expires_in: config.cache_ttl) do
|
415
|
+
analyzer = ContextAnalyzer.new(
|
416
|
+
user_context: user_context,
|
417
|
+
window_context: window_context
|
418
|
+
)
|
419
|
+
analyzer.generate_image_with_context(prompt, **opts)
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
# Convenience methods for common AI tasks (optimized)
|
425
|
+
def summarize(content, **opts)
|
426
|
+
chat("Summarize the following content: #{content}", **opts)
|
427
|
+
end
|
428
|
+
|
429
|
+
def translate(content, target_language, **opts)
|
430
|
+
chat("Translate the following content to #{target_language}: #{content}", **opts)
|
431
|
+
end
|
432
|
+
|
433
|
+
def classify(content, categories, **opts)
|
434
|
+
chat("Classify the following content into one of these categories: #{categories.join(", ")}. Content: #{content}", **opts)
|
435
|
+
end
|
436
|
+
|
437
|
+
def extract_entities(content, **opts)
|
438
|
+
chat("Extract named entities from the following content: #{content}", **opts)
|
439
|
+
end
|
440
|
+
|
441
|
+
def generate_code(prompt, language: "ruby", **opts)
|
442
|
+
chat("Generate #{language} code for: #{prompt}", **opts)
|
443
|
+
end
|
444
|
+
|
445
|
+
def explain_code(code, language: "ruby", **opts)
|
446
|
+
chat("Explain this #{language} code: #{code}", **opts)
|
447
|
+
end
|
448
|
+
|
449
|
+
# Performance utilities
|
450
|
+
def warmup!
|
451
|
+
# Pre-initialize components for faster first requests
|
452
|
+
provider
|
453
|
+
connection_pool
|
454
|
+
smart_cache
|
455
|
+
request_deduplicator
|
456
|
+
batch_processor
|
457
|
+
agent_manager
|
458
|
+
end
|
459
|
+
|
460
|
+
def clear_cache!
|
461
|
+
Rails.cache.delete_matched("rails_ai:*") if defined?(Rails) && Rails.cache
|
462
|
+
end
|
463
|
+
|
464
|
+
def reset_performance_metrics!
|
465
|
+
@performance_monitor = Performance::PerformanceMonitor.new
|
466
|
+
end
|
467
|
+
|
468
|
+
private
|
469
|
+
|
470
|
+
def normalize_messages(prompt_or_messages)
|
471
|
+
messages = prompt_or_messages.is_a?(Array) ? prompt_or_messages : [{role: "user", content: prompt_or_messages}]
|
472
|
+
text = RailsAi::Redactor.call(messages.last[:content])
|
473
|
+
messages[-1] = messages.last.merge(content: text)
|
474
|
+
messages
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
# Security methods
|
480
|
+
def self.validate_input(input, type: :text)
|
481
|
+
Security::InputValidator.send("validate_#{type}_input", input)
|
482
|
+
end
|
483
|
+
|
484
|
+
def self.sanitize_content(content)
|
485
|
+
Security::ContentSanitizer.sanitize_content(content)
|
486
|
+
end
|
487
|
+
|
488
|
+
def self.secure_api_key(env_var, required: true)
|
489
|
+
Security::APIKeyManager.secure_fetch(env_var, required: required)
|
490
|
+
end
|
491
|
+
|
492
|
+
def self.mask_api_key(key)
|
493
|
+
Security::APIKeyManager.mask_key(key)
|
494
|
+
end
|
495
|
+
|
496
|
+
def self.log_security_event(event_type, details = {})
|
497
|
+
Security::AuditLogger.log_security_event(event_type, details)
|
498
|
+
end
|
499
|
+
|
500
|
+
def self.handle_security_error(error, context = {})
|
501
|
+
Security::ErrorHandler.handle_security_error(error, context)
|
502
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# CI Monitoring Setup Guide
|
2
|
+
|
3
|
+
## 🚀 Continuous Monitoring via GitHub Actions
|
4
|
+
|
5
|
+
Your Rails AI gem now has automated monitoring that runs continuously!
|
6
|
+
|
7
|
+
## 📋 What's Set Up
|
8
|
+
|
9
|
+
### 1. Daily Monitoring Workflow (`.github/workflows/monitoring.yml`)
|
10
|
+
- **Runs**: Every day at 9 AM UTC
|
11
|
+
- **Manual**: Can be triggered manually
|
12
|
+
- **Triggers**: On pushes to main branch
|
13
|
+
- **Checks**: RubyGems, GitHub, Google searches
|
14
|
+
- **Outputs**: Monitoring reports and logs
|
15
|
+
|
16
|
+
### 2. Security Monitoring Workflow (`.github/workflows/security-monitoring.yml`)
|
17
|
+
- **Runs**: Every 6 hours
|
18
|
+
- **Focus**: Security and plagiarism detection
|
19
|
+
- **Checks**: Code similarity, package conflicts
|
20
|
+
- **Outputs**: Security reports
|
21
|
+
|
22
|
+
## 🔧 Setup Steps
|
23
|
+
|
24
|
+
### Step 1: Enable GitHub Actions
|
25
|
+
1. Go to your GitHub repository
|
26
|
+
2. Click "Actions" tab
|
27
|
+
3. Enable GitHub Actions if not already enabled
|
28
|
+
|
29
|
+
### Step 2: Add API Keys (Optional but Recommended)
|
30
|
+
1. Go to repository Settings → Secrets and variables → Actions
|
31
|
+
2. Add these secrets:
|
32
|
+
- `GOOGLE_API_KEY`: For Google search monitoring
|
33
|
+
- `GITHUB_PAT`: For GitHub API access
|
34
|
+
- `RUBYGEMS_API_KEY`: For RubyGems API access
|
35
|
+
|
36
|
+
### Step 3: Test the Workflows
|
37
|
+
1. Go to Actions tab
|
38
|
+
2. Click "Rails AI Monitoring"
|
39
|
+
3. Click "Run workflow" to test manually
|
40
|
+
|
41
|
+
## �� Monitoring Outputs
|
42
|
+
|
43
|
+
### Daily Reports
|
44
|
+
- **Location**: Actions → Artifacts
|
45
|
+
- **Files**: `monitoring-results-{run_number}`
|
46
|
+
- **Content**: Detailed monitoring logs
|
47
|
+
|
48
|
+
### Security Reports
|
49
|
+
- **Location**: Actions → Artifacts
|
50
|
+
- **Files**: `security-report-{run_number}`
|
51
|
+
- **Content**: Security and plagiarism checks
|
52
|
+
|
53
|
+
## 🔔 Notifications
|
54
|
+
|
55
|
+
### Email Notifications
|
56
|
+
- GitHub will email you when workflows fail
|
57
|
+
- Set up email notifications in GitHub settings
|
58
|
+
|
59
|
+
### Slack/Discord Integration (Optional)
|
60
|
+
Add this to your workflow for Slack notifications:
|
61
|
+
|
62
|
+
```yaml
|
63
|
+
- name: Notify Slack
|
64
|
+
if: failure()
|
65
|
+
uses: 8398a7/action-slack@v3
|
66
|
+
with:
|
67
|
+
status: failure
|
68
|
+
text: "Rails AI monitoring found potential issues!"
|
69
|
+
env:
|
70
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
71
|
+
```
|
72
|
+
|
73
|
+
## 📈 Monitoring Schedule
|
74
|
+
|
75
|
+
### Daily (9 AM UTC)
|
76
|
+
- RubyGems package monitoring
|
77
|
+
- GitHub repository searches
|
78
|
+
- Google search monitoring
|
79
|
+
- Generate monitoring report
|
80
|
+
|
81
|
+
### Every 6 Hours
|
82
|
+
- Security checks
|
83
|
+
- Code plagiarism detection
|
84
|
+
- Package conflict detection
|
85
|
+
- Generate security report
|
86
|
+
|
87
|
+
## 🛠️ Customization
|
88
|
+
|
89
|
+
### Change Schedule
|
90
|
+
Edit the cron expressions in the workflow files:
|
91
|
+
```yaml
|
92
|
+
schedule:
|
93
|
+
- cron: '0 9 * * *' # Daily at 9 AM UTC
|
94
|
+
- cron: '0 */6 * * *' # Every 6 hours
|
95
|
+
```
|
96
|
+
|
97
|
+
### Add More Checks
|
98
|
+
Add new monitoring steps to the workflow:
|
99
|
+
```yaml
|
100
|
+
- name: Check specific website
|
101
|
+
run: |
|
102
|
+
curl -s "https://example.com/search?q=rails_ai" | grep -i "commercial"
|
103
|
+
```
|
104
|
+
|
105
|
+
### Add More APIs
|
106
|
+
Add API keys to repository secrets and use them:
|
107
|
+
```yaml
|
108
|
+
env:
|
109
|
+
CUSTOM_API_KEY: ${{ secrets.CUSTOM_API_KEY }}
|
110
|
+
```
|
111
|
+
|
112
|
+
## 📱 Mobile Monitoring
|
113
|
+
|
114
|
+
### GitHub Mobile App
|
115
|
+
- Get notifications on your phone
|
116
|
+
- View monitoring results anywhere
|
117
|
+
- Respond to alerts immediately
|
118
|
+
|
119
|
+
### Email Alerts
|
120
|
+
- Set up email notifications for failures
|
121
|
+
- Get daily monitoring summaries
|
122
|
+
- Receive security alerts
|
123
|
+
|
124
|
+
## 🔍 What Gets Monitored
|
125
|
+
|
126
|
+
### RubyGems
|
127
|
+
- New packages with similar names
|
128
|
+
- Commercial usage in descriptions
|
129
|
+
- Download statistics
|
130
|
+
- Package dependencies
|
131
|
+
|
132
|
+
### GitHub
|
133
|
+
- Repositories using your gem
|
134
|
+
- Forks of your code
|
135
|
+
- Similar project names
|
136
|
+
- Commercial usage indicators
|
137
|
+
|
138
|
+
### Google Search
|
139
|
+
- Web mentions of your gem
|
140
|
+
- Commercial usage discussions
|
141
|
+
- Competitor analysis
|
142
|
+
- Brand monitoring
|
143
|
+
|
144
|
+
## 🚨 Alert Conditions
|
145
|
+
|
146
|
+
### High Priority
|
147
|
+
- Direct code copying
|
148
|
+
- Commercial use without license
|
149
|
+
- Trademark infringement
|
150
|
+
- Patent violations
|
151
|
+
|
152
|
+
### Medium Priority
|
153
|
+
- Similar package names
|
154
|
+
- Competitive analysis
|
155
|
+
- Usage discussions
|
156
|
+
- Feature requests
|
157
|
+
|
158
|
+
### Low Priority
|
159
|
+
- General mentions
|
160
|
+
- Educational usage
|
161
|
+
- Open source contributions
|
162
|
+
- Community discussions
|
163
|
+
|
164
|
+
## 📊 Monitoring Dashboard
|
165
|
+
|
166
|
+
### GitHub Actions Tab
|
167
|
+
- View all monitoring runs
|
168
|
+
- See success/failure status
|
169
|
+
- Download monitoring reports
|
170
|
+
- View detailed logs
|
171
|
+
|
172
|
+
### Artifacts
|
173
|
+
- Download monitoring results
|
174
|
+
- View security reports
|
175
|
+
- Analyze trends over time
|
176
|
+
- Share reports with legal team
|
177
|
+
|
178
|
+
## 🔧 Troubleshooting
|
179
|
+
|
180
|
+
### Common Issues
|
181
|
+
1. **Workflow not running**: Check if GitHub Actions is enabled
|
182
|
+
2. **API errors**: Verify API keys are set correctly
|
183
|
+
3. **Permission errors**: Check repository permissions
|
184
|
+
4. **Rate limiting**: Add delays between API calls
|
185
|
+
|
186
|
+
### Debug Mode
|
187
|
+
Add this to see detailed logs:
|
188
|
+
```yaml
|
189
|
+
- name: Debug monitoring
|
190
|
+
run: |
|
191
|
+
echo "Debug information:"
|
192
|
+
echo "Date: $(date)"
|
193
|
+
echo "Ruby version: $(ruby --version)"
|
194
|
+
echo "Working directory: $(pwd)"
|
195
|
+
```
|
196
|
+
|
197
|
+
## 📞 Support
|
198
|
+
|
199
|
+
### GitHub Actions Documentation
|
200
|
+
- https://docs.github.com/en/actions
|
201
|
+
|
202
|
+
### Monitoring Script Issues
|
203
|
+
- Check the monitoring_script.rb file
|
204
|
+
- Review the monitoring logs
|
205
|
+
- Test locally first
|
206
|
+
|
207
|
+
### Legal Questions
|
208
|
+
- Contact your IP lawyer
|
209
|
+
- Review the legal protection guide
|
210
|
+
- Use the cease and desist template
|
211
|
+
|
212
|
+
---
|
213
|
+
|
214
|
+
**Your Rails AI gem is now continuously monitored! 🛡️**
|