From 4a840e9e6e9a0951e885d1f390b2ca1551c6a9ce Mon Sep 17 00:00:00 2001 From: Ida Date: Wed, 29 Apr 2026 14:16:52 +0200 Subject: [PATCH] added neutralization option to indexing new connections --- .../services/serviceAi/mainServiceAi.py | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/modules/serviceCenter/services/serviceAi/mainServiceAi.py b/modules/serviceCenter/services/serviceAi/mainServiceAi.py index 6428bed3..f3742356 100644 --- a/modules/serviceCenter/services/serviceAi/mainServiceAi.py +++ b/modules/serviceCenter/services/serviceAi/mainServiceAi.py @@ -164,12 +164,29 @@ class AiService: # SPEECH_TEAMS: Dedicated pipeline, bypasses standard model selection if request.options and request.options.operationType == OperationTypeEnum.SPEECH_TEAMS: return await self._handleSpeechTeams(request) - - # FAIL-SAFE: Pre-flight billing validation (like 0 CHF credit card check) - self._preflightBillingCheck() - - # Balance & provider permission checks - await self._checkBillingBeforeAiCall() + + _opType = request.options.operationType if request.options else None + _isNeutralizationCall = _opType in ( + OperationTypeEnum.NEUTRALIZATION_TEXT, + OperationTypeEnum.NEUTRALIZATION_IMAGE, + ) + + if not _isNeutralizationCall: + # FAIL-SAFE: Pre-flight billing validation (like 0 CHF credit card check) + self._preflightBillingCheck() + # Balance & provider permission checks + await self._checkBillingBeforeAiCall() + else: + # Neutralization calls are system-level operations (connector anonymization). + # They run without a mandate context (e.g. personal-scope connections) and + # are billed the same way as embedding calls: best-effort, skipped when no + # billing settings exist for an empty mandate. + logger.debug( + "callAi: skipping billing preflight for neutralization call " + "(operationType=%s, user=%s)", + _opType, + getattr(getattr(self.services, 'user', None), 'id', 'unknown'), + ) # Calculate effective allowedProviders: RBAC ∩ Workflow effectiveProviders = self._calculateEffectiveProviders() @@ -218,8 +235,15 @@ class AiService: Rehydration happens on the final AiCallResponse (not on individual str deltas). """ await self.ensureAiObjectsInitialized() - self._preflightBillingCheck() - await self._checkBillingBeforeAiCall() + + _streamOpType = request.options.operationType if request.options else None + _isNeutralizationStream = _streamOpType in ( + OperationTypeEnum.NEUTRALIZATION_TEXT, + OperationTypeEnum.NEUTRALIZATION_IMAGE, + ) + if not _isNeutralizationStream: + self._preflightBillingCheck() + await self._checkBillingBeforeAiCall() effectiveProviders = self._calculateEffectiveProviders() if effectiveProviders and request.options: