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.
- banko_ai/__init__.py +19 -0
- banko_ai/__main__.py +10 -0
- banko_ai/ai_providers/__init__.py +18 -0
- banko_ai/ai_providers/aws_provider.py +337 -0
- banko_ai/ai_providers/base.py +175 -0
- banko_ai/ai_providers/factory.py +84 -0
- banko_ai/ai_providers/gemini_provider.py +340 -0
- banko_ai/ai_providers/openai_provider.py +295 -0
- banko_ai/ai_providers/watsonx_provider.py +591 -0
- banko_ai/cli.py +374 -0
- banko_ai/config/__init__.py +5 -0
- banko_ai/config/settings.py +216 -0
- banko_ai/static/Anallytics.png +0 -0
- banko_ai/static/Graph.png +0 -0
- banko_ai/static/Graph2.png +0 -0
- banko_ai/static/ai-status.png +0 -0
- banko_ai/static/banko-ai-assistant-watsonx.gif +0 -0
- banko_ai/static/banko-db-ops.png +0 -0
- banko_ai/static/banko-response.png +0 -0
- banko_ai/static/cache-stats.png +0 -0
- banko_ai/static/creditcard.png +0 -0
- banko_ai/static/profilepic.jpeg +0 -0
- banko_ai/static/query_watcher.png +0 -0
- banko_ai/static/roach-logo.svg +54 -0
- banko_ai/static/watsonx-icon.svg +1 -0
- banko_ai/templates/base.html +59 -0
- banko_ai/templates/dashboard.html +569 -0
- banko_ai/templates/index.html +1499 -0
- banko_ai/templates/login.html +41 -0
- banko_ai/utils/__init__.py +8 -0
- banko_ai/utils/cache_manager.py +525 -0
- banko_ai/utils/database.py +202 -0
- banko_ai/utils/migration.py +123 -0
- banko_ai/vector_search/__init__.py +18 -0
- banko_ai/vector_search/enrichment.py +278 -0
- banko_ai/vector_search/generator.py +329 -0
- banko_ai/vector_search/search.py +463 -0
- banko_ai/web/__init__.py +13 -0
- banko_ai/web/app.py +668 -0
- banko_ai/web/auth.py +73 -0
- banko_ai_assistant-1.0.0.dist-info/METADATA +414 -0
- banko_ai_assistant-1.0.0.dist-info/RECORD +46 -0
- banko_ai_assistant-1.0.0.dist-info/WHEEL +5 -0
- banko_ai_assistant-1.0.0.dist-info/entry_points.txt +2 -0
- banko_ai_assistant-1.0.0.dist-info/licenses/LICENSE +21 -0
- 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,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
|
Binary file
|