banko-ai-assistant 1.0.0__py3-none-any.whl

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.
Files changed (46) hide show
  1. banko_ai/__init__.py +19 -0
  2. banko_ai/__main__.py +10 -0
  3. banko_ai/ai_providers/__init__.py +18 -0
  4. banko_ai/ai_providers/aws_provider.py +337 -0
  5. banko_ai/ai_providers/base.py +175 -0
  6. banko_ai/ai_providers/factory.py +84 -0
  7. banko_ai/ai_providers/gemini_provider.py +340 -0
  8. banko_ai/ai_providers/openai_provider.py +295 -0
  9. banko_ai/ai_providers/watsonx_provider.py +591 -0
  10. banko_ai/cli.py +374 -0
  11. banko_ai/config/__init__.py +5 -0
  12. banko_ai/config/settings.py +216 -0
  13. banko_ai/static/Anallytics.png +0 -0
  14. banko_ai/static/Graph.png +0 -0
  15. banko_ai/static/Graph2.png +0 -0
  16. banko_ai/static/ai-status.png +0 -0
  17. banko_ai/static/banko-ai-assistant-watsonx.gif +0 -0
  18. banko_ai/static/banko-db-ops.png +0 -0
  19. banko_ai/static/banko-response.png +0 -0
  20. banko_ai/static/cache-stats.png +0 -0
  21. banko_ai/static/creditcard.png +0 -0
  22. banko_ai/static/profilepic.jpeg +0 -0
  23. banko_ai/static/query_watcher.png +0 -0
  24. banko_ai/static/roach-logo.svg +54 -0
  25. banko_ai/static/watsonx-icon.svg +1 -0
  26. banko_ai/templates/base.html +59 -0
  27. banko_ai/templates/dashboard.html +569 -0
  28. banko_ai/templates/index.html +1499 -0
  29. banko_ai/templates/login.html +41 -0
  30. banko_ai/utils/__init__.py +8 -0
  31. banko_ai/utils/cache_manager.py +525 -0
  32. banko_ai/utils/database.py +202 -0
  33. banko_ai/utils/migration.py +123 -0
  34. banko_ai/vector_search/__init__.py +18 -0
  35. banko_ai/vector_search/enrichment.py +278 -0
  36. banko_ai/vector_search/generator.py +329 -0
  37. banko_ai/vector_search/search.py +463 -0
  38. banko_ai/web/__init__.py +13 -0
  39. banko_ai/web/app.py +668 -0
  40. banko_ai/web/auth.py +73 -0
  41. banko_ai_assistant-1.0.0.dist-info/METADATA +414 -0
  42. banko_ai_assistant-1.0.0.dist-info/RECORD +46 -0
  43. banko_ai_assistant-1.0.0.dist-info/WHEEL +5 -0
  44. banko_ai_assistant-1.0.0.dist-info/entry_points.txt +2 -0
  45. banko_ai_assistant-1.0.0.dist-info/licenses/LICENSE +21 -0
  46. banko_ai_assistant-1.0.0.dist-info/top_level.txt +1 -0
banko_ai/cli.py ADDED
@@ -0,0 +1,374 @@
1
+ """
2
+ Command-line interface for Banko AI Assistant.
3
+
4
+ This module provides CLI commands for running the application and managing data.
5
+ """
6
+
7
+ import click
8
+ import os
9
+ from .config.settings import get_config
10
+ from .vector_search.generator import EnhancedExpenseGenerator
11
+ from .web.app import create_app
12
+
13
+
14
+ @click.group()
15
+ def cli():
16
+ """Banko AI Assistant - AI-powered expense analysis and RAG system."""
17
+ pass
18
+
19
+
20
+ @cli.command()
21
+ @click.option('--host', default='0.0.0.0', help='Host to bind to')
22
+ @click.option('--port', default=5000, help='Port to bind to')
23
+ @click.option('--debug', is_flag=True, help='Enable debug mode')
24
+ @click.option('--generate-data', type=int, default=5000, help='Generate sample data before starting (default: 5000 records)')
25
+ @click.option('--no-data', is_flag=True, help='Skip data generation and start with empty database')
26
+ @click.option('--clear-data', is_flag=True, help='Clear existing data before generating new data')
27
+ @click.option('--background', is_flag=True, help='Run in background mode (suppress Flask output)')
28
+ def run(host, port, debug, generate_data, no_data, clear_data, background):
29
+ """Run the Banko AI Assistant web application."""
30
+ # Show beautiful startup banner
31
+ click.echo("🏦 === Banko AI Assistant Starting === 🏦")
32
+
33
+ # Load configuration and show AI service info
34
+ config = get_config()
35
+ ai_service = config.ai_service.upper()
36
+ click.echo(f"🤖 AI Service: {config.ai_service}")
37
+
38
+ # Check AI provider availability
39
+ try:
40
+ from .ai_providers.factory import AIProviderFactory
41
+ ai_config = config.get_ai_config()
42
+ ai_provider = AIProviderFactory.create_provider(
43
+ config.ai_service,
44
+ ai_config[config.ai_service]
45
+ )
46
+
47
+ # Test connection and show status
48
+ if ai_provider.test_connection():
49
+ click.echo(f"🔧 {ai_service} Available: True")
50
+ click.echo(f"✅ Active AI Service: {ai_service}")
51
+ else:
52
+ click.echo(f"🔧 {ai_service} Available: False")
53
+ click.echo(f"⚠️ {ai_service} running in demo mode")
54
+ except Exception as e:
55
+ click.echo(f"🔧 {ai_service} Available: False")
56
+ click.echo(f"⚠️ {ai_service} running in demo mode")
57
+
58
+ click.echo("=" * 44)
59
+
60
+ # Generate data if not explicitly disabled
61
+ if not no_data:
62
+ click.echo("🔍 Checking database setup...")
63
+ click.echo(f"Generating {generate_data} sample expense records...")
64
+ generator = EnhancedExpenseGenerator(config.database_url)
65
+
66
+ # Check if data already exists
67
+ try:
68
+ existing_count = generator.get_expense_count()
69
+ if existing_count > 0 and not clear_data:
70
+ click.echo(f"✅ Database already contains {existing_count} expense records")
71
+ else:
72
+ if clear_data:
73
+ click.echo("Clearing existing data...")
74
+ generator.clear_expenses()
75
+
76
+ generator.generate_and_save(generate_data)
77
+ click.echo(f"✅ Successfully generated {generate_data} expense records")
78
+ except Exception as e:
79
+ click.echo(f"❌ Error generating data: {e}")
80
+ return
81
+ else:
82
+ click.echo("Skipping data generation (--no-data flag used)")
83
+
84
+ # Show startup completion message
85
+ click.echo(f"🚀 Starting server on http://localhost:{port}")
86
+ click.echo("🎉 Banko AI is ready to help with your finances!")
87
+ click.echo("=" * 44)
88
+
89
+ # Create and run the app
90
+ app = create_app()
91
+
92
+ if background:
93
+ # Background mode - suppress Flask output
94
+ import logging
95
+ log = logging.getLogger('werkzeug')
96
+ log.setLevel(logging.ERROR)
97
+
98
+ # Show final message for background mode
99
+ click.echo(f"🚀 Banko AI running in background on http://localhost:{port}")
100
+ click.echo("💡 Use 'banko-ai status' to check if it's running")
101
+ click.echo("🛑 Use 'pkill -f banko-ai' to stop the background process")
102
+
103
+ app.run(host=host, port=port, debug=debug)
104
+
105
+
106
+ @cli.command()
107
+ @click.option('--count', default=1000, help='Number of records to generate')
108
+ @click.option('--user-id', help='User ID for generated records')
109
+ @click.option('--clear', is_flag=True, help='Clear existing data before generating')
110
+ def generate_data(count, user_id, clear):
111
+ """Generate sample expense data."""
112
+ config = get_config()
113
+ generator = EnhancedExpenseGenerator(config.database_url)
114
+
115
+ click.echo(f"Generating {count} expense records...")
116
+
117
+ generated_count = generator.generate_and_save(
118
+ count=count,
119
+ user_id=user_id,
120
+ clear_existing=clear
121
+ )
122
+
123
+ click.echo(f"Successfully generated {generated_count} expense records")
124
+
125
+
126
+ @cli.command()
127
+ def clear_data():
128
+ """Clear all expense data."""
129
+ config = get_config()
130
+ generator = EnhancedExpenseGenerator(config.database_url)
131
+
132
+ if generator.clear_expenses():
133
+ click.echo("Successfully cleared all expense data")
134
+ else:
135
+ click.echo("Failed to clear expense data")
136
+
137
+
138
+ @cli.command()
139
+ def status():
140
+ """Show application status."""
141
+ config = get_config()
142
+ generator = EnhancedExpenseGenerator(config.database_url)
143
+
144
+ # Check database connection
145
+ try:
146
+ count = generator.get_expense_count()
147
+ click.echo(f"✅ Database connected - {count} expense records")
148
+ except Exception as e:
149
+ click.echo(f"❌ Database error: {e}")
150
+ return
151
+
152
+ # Check AI provider
153
+ try:
154
+ from .ai_providers.factory import AIProviderFactory
155
+ ai_config = config.get_ai_config()
156
+ ai_provider = AIProviderFactory.create_provider(
157
+ config.ai_service,
158
+ ai_config[config.ai_service]
159
+ )
160
+
161
+ if ai_provider.test_connection():
162
+ click.echo(f"✅ AI provider ({config.ai_service}) connected")
163
+ else:
164
+ click.echo(f"❌ AI provider ({config.ai_service}) disconnected")
165
+ except Exception as e:
166
+ click.echo(f"❌ AI provider error: {e}")
167
+
168
+
169
+ @cli.command()
170
+ @click.option('--host', default='0.0.0.0', help='Host to bind to')
171
+ @click.option('--port', default=5000, help='Port to bind to')
172
+ @click.option('--generate-data', type=int, default=5000, help='Generate sample data before starting (default: 5000 records)')
173
+ @click.option('--no-data', is_flag=True, help='Skip data generation and start with empty database')
174
+ @click.option('--clear-data', is_flag=True, help='Clear existing data before generating new data')
175
+ def start(host, port, generate_data, no_data, clear_data):
176
+ """Start Banko AI in background mode (equivalent to 'run --background')."""
177
+ # Show beautiful startup banner
178
+ click.echo("🏦 === Banko AI Assistant Starting === 🏦")
179
+
180
+ # Load configuration and show AI service info
181
+ config = get_config()
182
+ ai_service = config.ai_service.upper()
183
+ click.echo(f"🤖 AI Service: {config.ai_service}")
184
+
185
+ # Check AI provider availability
186
+ try:
187
+ from .ai_providers.factory import AIProviderFactory
188
+ ai_config = config.get_ai_config()
189
+ ai_provider = AIProviderFactory.create_provider(
190
+ config.ai_service,
191
+ ai_config[config.ai_service]
192
+ )
193
+
194
+ # Test connection and show status
195
+ if ai_provider.test_connection():
196
+ click.echo(f"🔧 {ai_service} Available: True")
197
+ click.echo(f"✅ Active AI Service: {ai_service}")
198
+ else:
199
+ click.echo(f"🔧 {ai_service} Available: False")
200
+ click.echo(f"⚠️ {ai_service} running in demo mode")
201
+ except Exception as e:
202
+ click.echo(f"🔧 {ai_service} Available: False")
203
+ click.echo(f"⚠️ {ai_service} running in demo mode")
204
+
205
+ click.echo("=" * 44)
206
+
207
+ # Generate data if not explicitly disabled
208
+ if not no_data:
209
+ click.echo("🔍 Checking database setup...")
210
+ click.echo(f"Generating {generate_data} sample expense records...")
211
+ generator = EnhancedExpenseGenerator(config.database_url)
212
+
213
+ # Check if data already exists
214
+ try:
215
+ existing_count = generator.get_expense_count()
216
+ if existing_count > 0 and not clear_data:
217
+ click.echo(f"✅ Database already contains {existing_count} expense records")
218
+ else:
219
+ if clear_data:
220
+ click.echo("Clearing existing data...")
221
+ generator.clear_expenses()
222
+
223
+ generator.generate_and_save(generate_data)
224
+ click.echo(f"✅ Successfully generated {generate_data} expense records")
225
+ except Exception as e:
226
+ click.echo(f"❌ Error generating data: {e}")
227
+ return
228
+ else:
229
+ click.echo("Skipping data generation (--no-data flag used)")
230
+
231
+ # Show startup completion message
232
+ click.echo(f"🚀 Starting server on http://localhost:{port}")
233
+ click.echo("🎉 Banko AI is ready to help with your finances!")
234
+ click.echo("=" * 44)
235
+
236
+ # Create and run the app in background mode
237
+ app = create_app()
238
+
239
+ # Background mode - suppress Flask output
240
+ import logging
241
+ log = logging.getLogger('werkzeug')
242
+ log.setLevel(logging.ERROR)
243
+
244
+ # Show final message for background mode
245
+ click.echo(f"🚀 Banko AI running in background on http://localhost:{port}")
246
+ click.echo("💡 Use 'banko-ai status' to check if it's running")
247
+ click.echo("🛑 Use 'pkill -f banko-ai' to stop the background process")
248
+
249
+ app.run(host=host, port=port, debug=False)
250
+
251
+
252
+ @cli.command()
253
+ def help():
254
+ """Show detailed help and setup instructions."""
255
+ click.echo("""
256
+ 🤖 Banko AI Assistant - Setup Guide
257
+ ====================================
258
+
259
+ This is a modern AI-powered expense analysis application with RAG capabilities.
260
+
261
+ QUICK START:
262
+ -----------
263
+ 1. Set up your environment variables:
264
+ export AI_SERVICE="watsonx" # or "openai", "aws", "gemini"
265
+ export DATABASE_URL="postgresql://root@localhost:26257/banko_ai?sslmode=disable"
266
+
267
+ 2. Configure your AI provider:
268
+
269
+ For Watsonx (IBM):
270
+ export WATSONX_API_KEY="your_api_key_here"
271
+ export WATSONX_PROJECT_ID="your_project_id_here"
272
+ export WATSONX_MODEL="meta-llama/llama-2-70b-chat"
273
+
274
+ For OpenAI:
275
+ export OPENAI_API_KEY="your_api_key_here"
276
+ export OPENAI_MODEL="gpt-3.5-turbo"
277
+
278
+ For AWS Bedrock:
279
+ export AWS_ACCESS_KEY_ID="your_access_key"
280
+ export AWS_SECRET_ACCESS_KEY="your_secret_key"
281
+ export AWS_REGION="us-east-1"
282
+ export AWS_MODEL="anthropic.claude-3-sonnet-20240229-v1:0"
283
+
284
+ For Google Gemini:
285
+ export GOOGLE_APPLICATION_CREDENTIALS="path/to/service-account.json"
286
+ export GOOGLE_MODEL="gemini-1.5-pro"
287
+
288
+ 3. Start the application:
289
+ banko-ai run # Normal mode with full output
290
+ banko-ai start # Background mode (quiet) - same as run --background
291
+ banko-ai run --background # Background mode (quiet)
292
+ banko-ai run --no-data # Skip data generation
293
+ banko-ai run --debug # Enable debug mode
294
+
295
+ COMMANDS:
296
+ ---------
297
+ run Run the web application (normal mode)
298
+ start Start the web application (background mode)
299
+ generate-data Generate sample expense data
300
+ clear-data Clear all expense data
301
+ status Show application status
302
+ search Search expenses using vector similarity
303
+ help Show this help message
304
+
305
+ FEATURES:
306
+ ---------
307
+ ✅ Multi-AI Provider Support (OpenAI, AWS Bedrock, IBM Watsonx, Google Gemini)
308
+ ✅ Dynamic Model Switching (switch models without restart)
309
+ ✅ User Authentication & User-Specific Vector Indexing
310
+ ✅ Enhanced Vector Search with Data Enrichment
311
+ ✅ Modern PyPI-Ready Package Structure
312
+ ✅ Real-time Chat Interface
313
+ ✅ Expense Analysis & Categorization
314
+ ✅ Multi-language Support
315
+
316
+ ENDPOINTS:
317
+ ----------
318
+ Web Interface: http://localhost:5000
319
+ API Health: http://localhost:5000/api/health
320
+ AI Providers: http://localhost:5000/api/ai-providers
321
+ Models: http://localhost:5000/api/models
322
+ Search: POST http://localhost:5000/api/search (JSON: {"query": "your search", "limit": 10})
323
+ RAG: POST http://localhost:5000/api/rag (JSON: {"query": "your question", "limit": 5})
324
+
325
+ TROUBLESHOOTING:
326
+ ---------------
327
+ - Database connection issues: Check DATABASE_URL
328
+ - AI provider errors: Verify API keys and configuration
329
+ - Model switching: Use the Settings tab in the web interface
330
+ - Vector search: Ensure database has expense data
331
+
332
+ For more information, visit: https://github.com/your-repo/banko-ai-assistant
333
+ """)
334
+
335
+
336
+ @cli.command()
337
+ @click.argument('query')
338
+ @click.option('--user-id', help='User ID to filter results')
339
+ @click.option('--limit', default=10, help='Maximum number of results')
340
+ def search(query, user_id, limit):
341
+ """Search expenses using vector similarity."""
342
+ config = get_config()
343
+ from .vector_search.search import VectorSearchEngine
344
+
345
+ search_engine = VectorSearchEngine(config.database_url)
346
+ results = search_engine.search_expenses(
347
+ query=query,
348
+ user_id=user_id,
349
+ limit=limit
350
+ )
351
+
352
+ if not results:
353
+ click.echo("No results found")
354
+ return
355
+
356
+ click.echo(f"Found {len(results)} results for '{query}':")
357
+ click.echo()
358
+
359
+ for i, result in enumerate(results, 1):
360
+ click.echo(f"{i}. {result.description}")
361
+ click.echo(f" Merchant: {result.merchant}")
362
+ click.echo(f" Amount: ${result.amount:.2f}")
363
+ click.echo(f" Date: {result.date}")
364
+ click.echo(f" Similarity: {result.similarity_score:.3f}")
365
+ click.echo()
366
+
367
+
368
+ def main():
369
+ """Main CLI entry point."""
370
+ cli()
371
+
372
+
373
+ if __name__ == '__main__':
374
+ main()
@@ -0,0 +1,5 @@
1
+ """Configuration management for Banko AI Assistant."""
2
+
3
+ from .settings import Config, get_config
4
+
5
+ __all__ = ["Config", "get_config"]
@@ -0,0 +1,216 @@
1
+ """
2
+ Configuration management using environment variables.
3
+
4
+ This module provides a centralized configuration system that reads from environment
5
+ variables with sensible defaults, making the application easy to configure and deploy.
6
+ """
7
+
8
+ import os
9
+ from typing import Optional, Dict, Any, List
10
+ from dataclasses import dataclass
11
+
12
+
13
+ @dataclass
14
+ class Config:
15
+ """Application configuration loaded from environment variables."""
16
+
17
+ # Database Configuration
18
+ database_url: str
19
+ database_host: str = "localhost"
20
+ database_port: int = 26257
21
+ database_name: str = "defaultdb"
22
+ database_user: str = "root"
23
+ database_password: str = ""
24
+ ssl_mode: str = "disable"
25
+
26
+ # AI Service Configuration
27
+ ai_service: str = "watsonx" # openai, aws, watsonx, gemini
28
+ openai_api_key: Optional[str] = None
29
+ openai_model: str = "gpt-3.5-turbo" # gpt-3.5-turbo, gpt-4, gpt-4-turbo
30
+ aws_access_key_id: Optional[str] = None
31
+ aws_secret_access_key: Optional[str] = None
32
+ aws_region: str = "us-east-1"
33
+ aws_model: str = "us.anthropic.claude-3-5-sonnet-20241022-v2:0" # Claude models
34
+ watsonx_api_key: Optional[str] = None
35
+ watsonx_project_id: Optional[str] = None
36
+ watsonx_model: str = "openai/gpt-oss-120b" # IBM models
37
+ google_project_id: Optional[str] = None
38
+ google_location: str = "us-central1"
39
+ google_model: str = "gemini-1.5-pro" # Gemini models
40
+
41
+ # Application Configuration
42
+ secret_key: str = "your-secret-key-change-in-production"
43
+ debug: bool = False
44
+ host: str = "0.0.0.0"
45
+ port: int = 5000
46
+
47
+ # Vector Search Configuration
48
+ embedding_model: str = "all-MiniLM-L6-v2"
49
+ vector_dimensions: int = 384
50
+ similarity_threshold: float = 0.7
51
+
52
+ # Cache Configuration
53
+ cache_enabled: bool = True
54
+ cache_ttl: int = 3600 # 1 hour
55
+
56
+ # Data Generation Configuration
57
+ default_record_count: int = 10000
58
+ default_user_count: int = 100
59
+
60
+ @classmethod
61
+ def from_env(cls) -> "Config":
62
+ """Create configuration from environment variables."""
63
+ # Database configuration
64
+ database_url = os.getenv("DATABASE_URL", "cockroachdb://root@localhost:26257/banko_ai?sslmode=disable")
65
+
66
+ # Parse database URL for individual components
67
+ db_host = os.getenv("DATABASE_HOST", "localhost")
68
+ db_port = int(os.getenv("DATABASE_PORT", "26257"))
69
+ db_name = os.getenv("DATABASE_NAME", "banko_ai")
70
+ db_user = os.getenv("DATABASE_USER", "root")
71
+ db_password = os.getenv("DATABASE_PASSWORD", "")
72
+ ssl_mode = os.getenv("DATABASE_SSL_MODE", "disable")
73
+
74
+ # AI Service configuration
75
+ ai_service = os.getenv("AI_SERVICE", "watsonx").lower()
76
+
77
+ return cls(
78
+ # Database
79
+ database_url=database_url,
80
+ database_host=db_host,
81
+ database_port=db_port,
82
+ database_name=db_name,
83
+ database_user=db_user,
84
+ database_password=db_password,
85
+ ssl_mode=ssl_mode,
86
+
87
+ # AI Services
88
+ ai_service=ai_service,
89
+ openai_api_key=os.getenv("OPENAI_API_KEY"),
90
+ openai_model=os.getenv("OPENAI_MODEL", "gpt-3.5-turbo"),
91
+ aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
92
+ aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
93
+ aws_region=os.getenv("AWS_REGION", "us-east-1"),
94
+ aws_model=os.getenv("AWS_MODEL", "us.anthropic.claude-3-5-sonnet-20241022-v2:0"),
95
+ watsonx_api_key=os.getenv("WATSONX_API_KEY"),
96
+ watsonx_project_id=os.getenv("WATSONX_PROJECT_ID"),
97
+ watsonx_model=os.getenv("WATSONX_MODEL", "openai/gpt-oss-120b"),
98
+ google_project_id=os.getenv("GOOGLE_PROJECT_ID"),
99
+ google_location=os.getenv("GOOGLE_LOCATION", "us-central1"),
100
+ google_model=os.getenv("GOOGLE_MODEL", "gemini-1.5-pro"),
101
+
102
+ # Application
103
+ secret_key=os.getenv("SECRET_KEY", "your-secret-key-change-in-production"),
104
+ debug=os.getenv("DEBUG", "false").lower() == "true",
105
+ host=os.getenv("HOST", "0.0.0.0"),
106
+ port=int(os.getenv("PORT", "5000")),
107
+
108
+ # Vector Search
109
+ embedding_model=os.getenv("EMBEDDING_MODEL", "all-MiniLM-L6-v2"),
110
+ vector_dimensions=int(os.getenv("VECTOR_DIMENSIONS", "384")),
111
+ similarity_threshold=float(os.getenv("SIMILARITY_THRESHOLD", "0.7")),
112
+
113
+ # Cache
114
+ cache_enabled=os.getenv("CACHE_ENABLED", "true").lower() == "true",
115
+ cache_ttl=int(os.getenv("CACHE_TTL", "3600")),
116
+
117
+ # Data Generation
118
+ default_record_count=int(os.getenv("DEFAULT_RECORD_COUNT", "10000")),
119
+ default_user_count=int(os.getenv("DEFAULT_USER_COUNT", "100")),
120
+ )
121
+
122
+ def get_ai_config(self) -> Dict[str, Any]:
123
+ """Get AI service specific configuration."""
124
+ config = {
125
+ "service": self.ai_service,
126
+ "openai": {
127
+ "api_key": self.openai_api_key,
128
+ "model": self.openai_model,
129
+ },
130
+ "aws": {
131
+ "access_key_id": self.aws_access_key_id,
132
+ "secret_access_key": self.aws_secret_access_key,
133
+ "region": self.aws_region,
134
+ "model": self.aws_model,
135
+ },
136
+ "watsonx": {
137
+ "api_key": self.watsonx_api_key,
138
+ "project_id": self.watsonx_project_id,
139
+ "model": self.watsonx_model,
140
+ },
141
+ "gemini": {
142
+ "project_id": self.google_project_id,
143
+ "location": self.google_location,
144
+ "model": self.google_model,
145
+ }
146
+ }
147
+ return config
148
+
149
+ def get_available_models(self) -> Dict[str, List[str]]:
150
+ """Get available models for each AI provider."""
151
+ return {
152
+ "openai": [
153
+ "gpt-3.5-turbo",
154
+ "gpt-3.5-turbo-16k",
155
+ "gpt-4",
156
+ "gpt-4-turbo",
157
+ "gpt-4o",
158
+ "gpt-4o-mini"
159
+ ],
160
+ "aws": [
161
+ "us.anthropic.claude-3-5-sonnet-20241022-v2:0",
162
+ "us.anthropic.claude-3-5-haiku-20241022-v1:0",
163
+ "us.anthropic.claude-3-opus-20240229-v1:0",
164
+ "us.anthropic.claude-3-sonnet-20240229-v1:0",
165
+ "us.anthropic.claude-3-haiku-20240307-v1:0"
166
+ ],
167
+ "watsonx": [
168
+ "openai/gpt-oss-120b",
169
+ "ibm/granite-13b-chat-v2",
170
+ "ibm/granite-13b-instruct-v2",
171
+ "ibm/granite-8b-chat-v2",
172
+ "ibm/granite-8b-instruct-v2",
173
+ "meta-llama/llama-2-70b-chat",
174
+ "meta-llama/llama-2-13b-chat"
175
+ ],
176
+ "gemini": [
177
+ "gemini-1.5-pro",
178
+ "gemini-1.5-flash",
179
+ "gemini-1.0-pro"
180
+ ]
181
+ }
182
+
183
+ def validate(self) -> None:
184
+ """Validate configuration and raise errors for missing required values."""
185
+ if not self.database_url:
186
+ raise ValueError("DATABASE_URL is required")
187
+
188
+ # Validate AI service specific requirements
189
+ if self.ai_service == "openai" and not self.openai_api_key:
190
+ raise ValueError("OPENAI_API_KEY is required for OpenAI service")
191
+ elif self.ai_service == "aws" and (not self.aws_access_key_id or not self.aws_secret_access_key):
192
+ raise ValueError("AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY are required for AWS service")
193
+ elif self.ai_service == "watsonx" and not self.watsonx_api_key:
194
+ # For demo purposes, make Watsonx API key optional
195
+ print("Warning: WATSONX_API_KEY not provided. AI features will be limited.")
196
+ elif self.ai_service == "gemini" and not self.google_project_id:
197
+ raise ValueError("GOOGLE_PROJECT_ID is required for Gemini service")
198
+
199
+
200
+ # Global configuration instance
201
+ _config: Optional[Config] = None
202
+
203
+
204
+ def get_config() -> Config:
205
+ """Get the global configuration instance."""
206
+ global _config
207
+ if _config is None:
208
+ _config = Config.from_env()
209
+ _config.validate()
210
+ return _config
211
+
212
+
213
+ def set_config(config: Config) -> None:
214
+ """Set the global configuration instance (useful for testing)."""
215
+ global _config
216
+ _config = config
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file