prescient 0.0.0 → 0.2.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.
@@ -0,0 +1,363 @@
1
+ # AI Providers Integration Guide
2
+
3
+ This guide explains how to integrate the AI Providers gem into your existing Rails AI application.
4
+
5
+ ## Integration Steps
6
+
7
+ ### 1. Update Your Gemfile
8
+
9
+ ```ruby
10
+ # Add to your Gemfile
11
+ gem 'prescient', path: './prescient_gem' # Local development
12
+ # OR when published:
13
+ # gem 'prescient', '~> 0.1.0'
14
+ ```
15
+
16
+ ### 2. Replace Existing AI Service
17
+
18
+ **Before (Original OllamaService):**
19
+
20
+ ```ruby
21
+ # app/services/ollama_service.rb
22
+ class OllamaService
23
+ def generate_embedding(text)
24
+ # Direct Ollama API calls
25
+ end
26
+
27
+ def generate_response(prompt, context_items)
28
+ # Direct Ollama API calls
29
+ end
30
+ end
31
+ ```
32
+
33
+ **After (Using AI Providers Gem):**
34
+
35
+ ```ruby
36
+ # app/services/ai_service.rb
37
+ class AIService
38
+ def self.client(provider = nil)
39
+ @clients ||= {}
40
+ provider_name = provider || Rails.application.config.default_ai_provider
41
+ @clients[provider_name] ||= Prescient.client(provider_name)
42
+ end
43
+
44
+ def self.generate_embedding(text, provider: nil)
45
+ client(provider).generate_embedding(text)
46
+ rescue Prescient::Error => e
47
+ Rails.logger.error "AI embedding generation failed: #{e.message}"
48
+ raise
49
+ end
50
+
51
+ def self.generate_response(prompt, context_items = [], provider: nil, **options)
52
+ client(provider).generate_response(prompt, context_items, **options)
53
+ rescue Prescient::Error => e
54
+ Rails.logger.error "AI response generation failed: #{e.message}"
55
+ raise
56
+ end
57
+
58
+ def self.health_check(provider: nil)
59
+ client(provider).health_check
60
+ rescue Prescient::Error => e
61
+ { status: 'unhealthy', error: e.message }
62
+ end
63
+ end
64
+ ```
65
+
66
+ ### 3. Configuration
67
+
68
+ **Create initializer:**
69
+
70
+ ```ruby
71
+ # config/initializers/prescient.rb
72
+ Prescient.configure do |config|
73
+ config.default_provider = Rails.env.production? ? :openai : :ollama
74
+ config.timeout = 60
75
+ config.retry_attempts = 3
76
+ config.retry_delay = 1.0
77
+
78
+ # Ollama (Local/Development)
79
+ config.add_provider(:ollama, Prescient::Ollama::Provider,
80
+ url: ENV.fetch('OLLAMA_URL', 'http://localhost:11434'),
81
+ embedding_model: ENV.fetch('OLLAMA_EMBEDDING_MODEL', 'nomic-embed-text'),
82
+ chat_model: ENV.fetch('OLLAMA_CHAT_MODEL', 'llama3.1:8b'),
83
+ timeout: 120
84
+ )
85
+
86
+ # OpenAI (Production)
87
+ if ENV['OPENAI_API_KEY'].present?
88
+ config.add_provider(:openai, Prescient::OpenAI::Provider,
89
+ api_key: ENV['OPENAI_API_KEY'],
90
+ embedding_model: ENV.fetch('OPENAI_EMBEDDING_MODEL', 'text-embedding-3-small'),
91
+ chat_model: ENV.fetch('OPENAI_CHAT_MODEL', 'gpt-3.5-turbo')
92
+ )
93
+ end
94
+
95
+ # Anthropic (Alternative)
96
+ if ENV['ANTHROPIC_API_KEY'].present?
97
+ config.add_provider(:anthropic, Prescient::Anthropic::Provider,
98
+ api_key: ENV['ANTHROPIC_API_KEY'],
99
+ model: ENV.fetch('ANTHROPIC_MODEL', 'claude-3-haiku-20240307')
100
+ )
101
+ end
102
+
103
+ # HuggingFace (Research/Open Source)
104
+ if ENV['HUGGINGFACE_API_KEY'].present?
105
+ config.add_provider(:huggingface, Prescient::HuggingFace::Provider,
106
+ api_key: ENV['HUGGINGFACE_API_KEY'],
107
+ embedding_model: ENV.fetch('HUGGINGFACE_EMBEDDING_MODEL', 'sentence-transformers/all-MiniLM-L6-v2'),
108
+ chat_model: ENV.fetch('HUGGINGFACE_CHAT_MODEL', 'microsoft/DialoGPT-medium')
109
+ )
110
+ end
111
+ end
112
+
113
+ # Set default provider for Rails
114
+ Rails.application.config.default_ai_provider = :ollama
115
+ ```
116
+
117
+ ### 4. Update Environment Variables
118
+
119
+ ```bash
120
+ # .env or environment configuration
121
+
122
+ # Ollama (Local)
123
+ OLLAMA_URL=http://localhost:11434
124
+ OLLAMA_EMBEDDING_MODEL=nomic-embed-text
125
+ OLLAMA_CHAT_MODEL=llama3.1:8b
126
+
127
+ # OpenAI (Production)
128
+ OPENAI_API_KEY=your_openai_api_key
129
+ OPENAI_EMBEDDING_MODEL=text-embedding-3-small
130
+ OPENAI_CHAT_MODEL=gpt-3.5-turbo
131
+
132
+ # Anthropic (Alternative)
133
+ ANTHROPIC_API_KEY=your_anthropic_api_key
134
+ ANTHROPIC_MODEL=claude-3-haiku-20240307
135
+
136
+ # HuggingFace (Research)
137
+ HUGGINGFACE_API_KEY=your_huggingface_api_key
138
+ HUGGINGFACE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
139
+ HUGGINGFACE_CHAT_MODEL=microsoft/DialoGPT-medium
140
+ ```
141
+
142
+ ### 5. Update Controllers
143
+
144
+ **Before:**
145
+
146
+ ```ruby
147
+ class Api::V1::AiQueriesController < ApplicationController
148
+ def create
149
+ embedding = OllamaService.new.generate_embedding(params[:query])
150
+ # ... rest of the logic
151
+ end
152
+ end
153
+ ```
154
+
155
+ **After:**
156
+
157
+ ```ruby
158
+ class Api::V1::AiQueriesController < ApplicationController
159
+ def create
160
+ # Use default provider or specify one
161
+ embedding = AIService.generate_embedding(params[:query])
162
+
163
+ # Or use specific provider
164
+ # embedding = AIService.generate_embedding(params[:query], provider: :openai)
165
+
166
+ # ... rest of the logic remains the same
167
+ end
168
+
169
+ private
170
+
171
+ def generate_ai_response(query, context_items)
172
+ # Automatically uses configured provider with fallback
173
+ response = AIService.generate_response(
174
+ query,
175
+ context_items,
176
+ max_tokens: 2000,
177
+ temperature: 0.7
178
+ )
179
+
180
+ response[:response]
181
+ rescue Prescient::Error => e
182
+ Rails.logger.error "AI response failed: #{e.message}"
183
+ "I apologize, but I'm currently unable to generate a response. Please try again later."
184
+ end
185
+ end
186
+ ```
187
+
188
+ ### 6. Health Check Integration
189
+
190
+ ```ruby
191
+ # app/controllers/api/v1/system/health_controller.rb
192
+ class Api::V1::System::HealthController < ApplicationController
193
+ def show
194
+ health_status = {
195
+ database: database_health,
196
+ prescient: prescient_health,
197
+ overall: 'healthy'
198
+ }
199
+
200
+ # Set overall status based on critical components
201
+ if health_status[:prescient][:primary][:status] != 'healthy'
202
+ health_status[:overall] = 'degraded'
203
+ end
204
+
205
+ render json: health_status
206
+ end
207
+
208
+ private
209
+
210
+ def prescient_health
211
+ providers = {}
212
+
213
+ # Check primary provider
214
+ primary_provider = Rails.application.config.default_ai_provider
215
+ providers[:primary] = {
216
+ name: primary_provider,
217
+ **AIService.health_check(provider: primary_provider)
218
+ }
219
+
220
+ # Check backup providers
221
+ backup_providers = [:openai, :anthropic, :huggingface] - [primary_provider]
222
+ providers[:backups] = backup_providers.map do |provider|
223
+ {
224
+ name: provider,
225
+ **AIService.health_check(provider: provider)
226
+ }
227
+ end
228
+
229
+ providers
230
+ end
231
+
232
+ def database_health
233
+ ActiveRecord::Base.connection.execute('SELECT 1')
234
+ { status: 'healthy' }
235
+ rescue StandardError => e
236
+ { status: 'unhealthy', error: e.message }
237
+ end
238
+ end
239
+ ```
240
+
241
+ ### 7. Migration Strategy
242
+
243
+ 1. **Phase 1: Side-by-side deployment**
244
+
245
+ - Keep existing OllamaService
246
+ - Add AI Providers gem alongside
247
+ - Test thoroughly in development
248
+
249
+ 2. **Phase 2: Gradual migration**
250
+
251
+ - Update one controller at a time
252
+ - Use feature flags to switch between old/new systems
253
+ - Monitor performance and error rates
254
+
255
+ 3. **Phase 3: Complete migration**
256
+ - Remove old OllamaService
257
+ - Update all controllers to use AIService
258
+ - Clean up unused code
259
+
260
+ ### 8. Testing Updates
261
+
262
+ ```ruby
263
+ # spec/services/ai_service_spec.rb
264
+ RSpec.describe AIService do
265
+ before do
266
+ Prescient.configure do |config|
267
+ config.add_provider(:test, Prescient::Ollama::Provider,
268
+ url: 'http://localhost:11434',
269
+ embedding_model: 'test-embed',
270
+ chat_model: 'test-chat'
271
+ )
272
+ config.default_provider = :test
273
+ end
274
+ end
275
+
276
+ describe '.generate_embedding' do
277
+ it 'returns embedding vector' do
278
+ # Mock the provider response
279
+ allow_any_instance_of(Prescient::Ollama::Provider)
280
+ .to receive(:generate_embedding)
281
+ .and_return([0.1, 0.2, 0.3])
282
+
283
+ result = described_class.generate_embedding('test text')
284
+ expect(result).to eq([0.1, 0.2, 0.3])
285
+ end
286
+ end
287
+ end
288
+ ```
289
+
290
+ ### 9. Monitoring and Logging
291
+
292
+ ```ruby
293
+ # config/initializers/prescient_monitoring.rb
294
+ class PrescientMonitoring
295
+ def self.setup!
296
+ ActiveSupport::Notifications.subscribe('prescient.request') do |name, start, finish, id, payload|
297
+ duration = finish - start
298
+
299
+ Rails.logger.info "AI Provider Request: #{payload[:provider]} - #{payload[:operation]} - #{duration.round(3)}s"
300
+
301
+ # Send metrics to your monitoring system
302
+ # StatsD.increment('prescient.requests', tags: [
303
+ # "provider:#{payload[:provider]}",
304
+ # "operation:#{payload[:operation]}",
305
+ # "status:#{payload[:status]}"
306
+ # ])
307
+ end
308
+ end
309
+ end
310
+
311
+ PrescientMonitoring.setup! if Rails.env.production?
312
+ ```
313
+
314
+ ### 10. Performance Optimization
315
+
316
+ ```ruby
317
+ # app/services/ai_service.rb (enhanced)
318
+ class AIService
319
+ # Connection pooling for providers
320
+ def self.client(provider = nil)
321
+ @clients ||= {}
322
+ provider_name = provider || Rails.application.config.default_ai_provider
323
+
324
+ @clients[provider_name] ||= begin
325
+ # Use connection pooling for high-traffic applications
326
+ Prescient.client(provider_name)
327
+ end
328
+ end
329
+
330
+ # Caching for embeddings (optional)
331
+ def self.generate_embedding(text, provider: nil)
332
+ cache_key = "ai_embedding:#{ Digest::SHA256.hexdigest(text)}:#{ provider}"
333
+
334
+ Rails.cache.fetch(cache_key, expires_in: 1.hour) do
335
+ client(provider).generate_embedding(text)
336
+ end
337
+ rescue Prescient::Error => e
338
+ Rails.logger.error "AI embedding generation failed: #{e.message}"
339
+ raise
340
+ end
341
+ end
342
+ ```
343
+
344
+ ## Benefits of Migration
345
+
346
+ 1. **Provider Flexibility**: Easy switching between AI providers
347
+ 2. **Fallback Support**: Automatic fallback to backup providers
348
+ 3. **Better Error Handling**: Comprehensive error classification
349
+ 4. **Monitoring**: Built-in health checks and metrics
350
+ 5. **Testing**: Easier mocking and testing
351
+ 6. **Scalability**: Better support for different deployment scenarios
352
+ 7. **Cost Optimization**: Use local models for development, cloud for production
353
+
354
+ ## Rollback Plan
355
+
356
+ If issues arise, quickly rollback by:
357
+
358
+ 1. Revert initializer changes
359
+ 2. Switch controllers back to OllamaService
360
+ 3. Deploy previous version
361
+ 4. Debug issues separately
362
+
363
+ The gem structure allows for easy rollback since it's designed as a drop-in replacement.