diff --git a/backend/igny8_core/ai/ai_core.py b/backend/igny8_core/ai/ai_core.py index 7c69a48f..cd105a65 100644 --- a/backend/igny8_core/ai/ai_core.py +++ b/backend/igny8_core/ai/ai_core.py @@ -43,33 +43,21 @@ class AICore: self._load_account_settings() def _load_account_settings(self): - """Load API keys from IntegrationSettings for account only - no fallbacks""" - def get_integration_key(integration_type: str, account): - if not account: - return None - try: - from igny8_core.modules.system.models import IntegrationSettings - settings_obj = IntegrationSettings.objects.filter( - integration_type=integration_type, - account=account, - is_active=True - ).first() - if settings_obj and settings_obj.config: - return settings_obj.config.get('apiKey') - except Exception as e: - logger.warning(f"Could not load {integration_type} settings for account {getattr(account, 'id', None)}: {e}", exc_info=True) - return None - - # Load account-specific keys only - configure via Django admin - if self.account: - self._openai_api_key = get_integration_key('openai', self.account) - self._runware_api_key = get_integration_key('runware', self.account) - - # Fallback to Django settings as last resort - if not self._openai_api_key: - self._openai_api_key = getattr(settings, 'OPENAI_API_KEY', None) - if not self._runware_api_key: - self._runware_api_key = getattr(settings, 'RUNWARE_API_KEY', None) + """Load API keys from GlobalIntegrationSettings (platform-wide, used by ALL accounts)""" + try: + from igny8_core.modules.system.global_settings_models import GlobalIntegrationSettings + + # Get global settings - single instance used by ALL accounts + global_settings = GlobalIntegrationSettings.get_instance() + + # Load API keys from global settings (platform-wide) + self._openai_api_key = global_settings.openai_api_key + self._runware_api_key = global_settings.runware_api_key + + except Exception as e: + logger.error(f"Could not load GlobalIntegrationSettings: {e}", exc_info=True) + self._openai_api_key = None + self._runware_api_key = None def get_api_key(self, integration_type: str = 'openai') -> Optional[str]: """Get API key for integration type""" diff --git a/backend/igny8_core/business/billing/services/credit_service.py b/backend/igny8_core/business/billing/services/credit_service.py index abfd9a48..660ae6cc 100644 --- a/backend/igny8_core/business/billing/services/credit_service.py +++ b/backend/igny8_core/business/billing/services/credit_service.py @@ -82,6 +82,62 @@ class CreditService: return credits + @staticmethod + def check_credits(account, operation_type, estimated_amount=None): + """ + Check if account has sufficient credits for an operation. + For token-based operations, this is an estimate check only. + Actual deduction happens after AI call with real token usage. + + Args: + account: Account instance + operation_type: Type of operation + estimated_amount: Optional estimated amount (for non-token operations) + + Raises: + InsufficientCreditsError: If account doesn't have enough credits + """ + from igny8_core.business.billing.models import CreditCostConfig + from igny8_core.business.billing.constants import CREDIT_COSTS + + # Get operation config + config = CreditCostConfig.objects.filter( + operation_type=operation_type, + is_active=True + ).first() + + if config: + # Use minimum credits as estimate for token-based operations + required = config.min_credits + else: + # Fallback to constants + required = CREDIT_COSTS.get(operation_type, 1) + + if account.credits < required: + raise InsufficientCreditsError( + f"Insufficient credits. Required: {required}, Available: {account.credits}" + ) + return True + + @staticmethod + def check_credits_legacy(account, amount): + """ + Legacy method to check credits for a known amount. + Used internally by deduct_credits. + + Args: + account: Account instance + amount: Required credits amount + + Raises: + InsufficientCreditsError: If account doesn't have enough credits + """ + if account.credits < amount: + raise InsufficientCreditsError( + f"Insufficient credits. Required: {amount}, Available: {account.credits}" + ) + return True + @staticmethod def check_credits_for_tokens(account, operation_type, estimated_tokens_input, estimated_tokens_output): """