Underground-Digital/Workflow-Engine
0
1import json2from collections import defaultdict3from json import JSONDecodeError4from typing import Optional5 6from sqlalchemy.exc import IntegrityError7 8from configs import dify_config9from core.entities.model_entities import DefaultModelEntity, DefaultModelProviderEntity10from core.entities.provider_configuration import ProviderConfiguration, ProviderConfigurations, ProviderModelBundle11from core.entities.provider_entities import (12 CustomConfiguration,13 CustomModelConfiguration,14 CustomProviderConfiguration,15 ModelLoadBalancingConfiguration,16 ModelSettings,17 QuotaConfiguration,18 SystemConfiguration,19)20from core.helper import encrypter21from core.helper.model_provider_cache import ProviderCredentialsCache, ProviderCredentialsCacheType22from core.helper.position_helper import is_filtered23from core.model_runtime.entities.model_entities import ModelType24from core.model_runtime.entities.provider_entities import CredentialFormSchema, FormType, ProviderEntity25from core.model_runtime.model_providers import model_provider_factory26from extensions import ext_hosting_provider27from extensions.ext_database import db28from extensions.ext_redis import redis_client29from models.provider import (30 LoadBalancingModelConfig,31 Provider,32 ProviderModel,33 ProviderModelSetting,34 ProviderQuotaType,35 ProviderType,36 TenantDefaultModel,37 TenantPreferredModelProvider,38)39from services.feature_service import FeatureService40 41 42class ProviderManager:43 """44 ProviderManager is a class that manages the model providers includes Hosting and Customize Model Providers.45 """46 47 def __init__(self) -> None:48 self.decoding_rsa_key = None49 self.decoding_cipher_rsa = None50 51 def get_configurations(self, tenant_id: str) -> ProviderConfigurations:52 """53 Get model provider configurations.54 55 Construct ProviderConfiguration objects for each provider56 Including:57 1. Basic information of the provider58 2. Hosting configuration information, including:59 (1. Whether to enable (support) hosting type, if enabled, the following information exists60 (2. List of hosting type provider configurations61 (including quota type, quota limit, current remaining quota, etc.)62 (3. The current hosting type in use (whether there is a quota or not)63 paid quotas > provider free quotas > hosting trial quotas64 (4. Unified credentials for hosting providers65 3. Custom configuration information, including:66 (1. Whether to enable (support) custom type, if enabled, the following information exists67 (2. Custom provider configuration (including credentials)68 (3. List of custom provider model configurations (including credentials)69 4. Hosting/custom preferred provider type.70 Provide methods:71 - Get the current configuration (including credentials)72 - Get the availability and status of the hosting configuration: active available,73 quota_exceeded insufficient quota, unsupported hosting74 - Get the availability of custom configuration75 Custom provider available conditions:76 (1. custom provider credentials available77 (2. at least one custom model credentials available78 - Verify, update, and delete custom provider configuration79 - Verify, update, and delete custom provider model configuration80 - Get the list of available models (optional provider filtering, model type filtering)81 Append custom provider models to the list82 - Get provider instance83 - Switch selection priority84 85 :param tenant_id:86 :return:87 """88 # Get all provider records of the workspace89 provider_name_to_provider_records_dict = self._get_all_providers(tenant_id)90 91 # Initialize trial provider records if not exist92 provider_name_to_provider_records_dict = self._init_trial_provider_records(93 tenant_id, provider_name_to_provider_records_dict94 )95 96 # Get all provider model records of the workspace97 provider_name_to_provider_model_records_dict = self._get_all_provider_models(tenant_id)98 99 # Get all provider entities100 provider_entities = model_provider_factory.get_providers()101 102 # Get All preferred provider types of the workspace103 provider_name_to_preferred_model_provider_records_dict = self._get_all_preferred_model_providers(tenant_id)104 105 # Get All provider model settings106 provider_name_to_provider_model_settings_dict = self._get_all_provider_model_settings(tenant_id)107 108 # Get All load balancing configs109 provider_name_to_provider_load_balancing_model_configs_dict = self._get_all_provider_load_balancing_configs(110 tenant_id111 )112 113 provider_configurations = ProviderConfigurations(tenant_id=tenant_id)114 115 # Construct ProviderConfiguration objects for each provider116 for provider_entity in provider_entities:117 # handle include, exclude118 if is_filtered(119 include_set=dify_config.POSITION_PROVIDER_INCLUDES_SET,120 exclude_set=dify_config.POSITION_PROVIDER_EXCLUDES_SET,121 data=provider_entity,122 name_func=lambda x: x.provider,123 ):124 continue125 126 provider_name = provider_entity.provider127 provider_records = provider_name_to_provider_records_dict.get(provider_entity.provider, [])128 provider_model_records = provider_name_to_provider_model_records_dict.get(provider_entity.provider, [])129 130 # Convert to custom configuration131 custom_configuration = self._to_custom_configuration(132 tenant_id, provider_entity, provider_records, provider_model_records133 )134 135 # Convert to system configuration136 system_configuration = self._to_system_configuration(tenant_id, provider_entity, provider_records)137 138 # Get preferred provider type139 preferred_provider_type_record = provider_name_to_preferred_model_provider_records_dict.get(provider_name)140 141 if preferred_provider_type_record:142 preferred_provider_type = ProviderType.value_of(preferred_provider_type_record.preferred_provider_type)143 elif custom_configuration.provider or custom_configuration.models:144 preferred_provider_type = ProviderType.CUSTOM145 elif system_configuration.enabled:146 preferred_provider_type = ProviderType.SYSTEM147 else:148 preferred_provider_type = ProviderType.CUSTOM149 150 using_provider_type = preferred_provider_type151 has_valid_quota = any(quota_conf.is_valid for quota_conf in system_configuration.quota_configurations)152 153 if preferred_provider_type == ProviderType.SYSTEM:154 if not system_configuration.enabled or not has_valid_quota:155 using_provider_type = ProviderType.CUSTOM156 157 else:158 if not custom_configuration.provider and not custom_configuration.models:159 if system_configuration.enabled and has_valid_quota:160 using_provider_type = ProviderType.SYSTEM161 162 # Get provider load balancing configs163 provider_model_settings = provider_name_to_provider_model_settings_dict.get(provider_name)164 165 # Get provider load balancing configs166 provider_load_balancing_configs = provider_name_to_provider_load_balancing_model_configs_dict.get(167 provider_name168 )169 170 # Convert to model settings171 model_settings = self._to_model_settings(172 provider_entity=provider_entity,173 provider_model_settings=provider_model_settings,174 load_balancing_model_configs=provider_load_balancing_configs,175 )176 177 provider_configuration = ProviderConfiguration(178 tenant_id=tenant_id,179 provider=provider_entity,180 preferred_provider_type=preferred_provider_type,181 using_provider_type=using_provider_type,182 system_configuration=system_configuration,183 custom_configuration=custom_configuration,184 model_settings=model_settings,185 )186 187 provider_configurations[provider_name] = provider_configuration188 189 # Return the encapsulated object190 return provider_configurations191 192 def get_provider_model_bundle(self, tenant_id: str, provider: str, model_type: ModelType) -> ProviderModelBundle:193 """194 Get provider model bundle.195 :param tenant_id: workspace id196 :param provider: provider name197 :param model_type: model type198 :return:199 """200 provider_configurations = self.get_configurations(tenant_id)201 202 # get provider instance203 provider_configuration = provider_configurations.get(provider)204 if not provider_configuration:205 raise ValueError(f"Provider {provider} does not exist.")206 207 provider_instance = provider_configuration.get_provider_instance()208 model_type_instance = provider_instance.get_model_instance(model_type)209 210 return ProviderModelBundle(211 configuration=provider_configuration,212 provider_instance=provider_instance,213 model_type_instance=model_type_instance,214 )215 216 def get_default_model(self, tenant_id: str, model_type: ModelType) -> Optional[DefaultModelEntity]:217 """218 Get default model.219 220 :param tenant_id: workspace id221 :param model_type: model type222 :return:223 """224 # Get the corresponding TenantDefaultModel record225 default_model = (226 db.session.query(TenantDefaultModel)227 .filter(228 TenantDefaultModel.tenant_id == tenant_id,229 TenantDefaultModel.model_type == model_type.to_origin_model_type(),230 )231 .first()232 )233 234 # If it does not exist, get the first available provider model from get_configurations235 # and update the TenantDefaultModel record236 if not default_model:237 # Get provider configurations238 provider_configurations = self.get_configurations(tenant_id)239 240 # get available models from provider_configurations241 available_models = provider_configurations.get_models(model_type=model_type, only_active=True)242 243 if available_models:244 available_model = next(245 (model for model in available_models if model.model == "gpt-4"), available_models[0]246 )247 248 default_model = TenantDefaultModel(249 tenant_id=tenant_id,250 model_type=model_type.to_origin_model_type(),251 provider_name=available_model.provider.provider,252 model_name=available_model.model,253 )254 db.session.add(default_model)255 db.session.commit()256 257 if not default_model:258 return None259 260 provider_instance = model_provider_factory.get_provider_instance(default_model.provider_name)261 provider_schema = provider_instance.get_provider_schema()262 263 return DefaultModelEntity(264 model=default_model.model_name,265 model_type=model_type,266 provider=DefaultModelProviderEntity(267 provider=provider_schema.provider,268 label=provider_schema.label,269 icon_small=provider_schema.icon_small,270 icon_large=provider_schema.icon_large,271 supported_model_types=provider_schema.supported_model_types,272 ),273 )274 275 def get_first_provider_first_model(self, tenant_id: str, model_type: ModelType) -> tuple[str, str]:276 """277 Get names of first model and its provider278 279 :param tenant_id: workspace id280 :param model_type: model type281 :return: provider name, model name282 """283 provider_configurations = self.get_configurations(tenant_id)284 285 # get available models from provider_configurations286 all_models = provider_configurations.get_models(model_type=model_type, only_active=False)287 288 return all_models[0].provider.provider, all_models[0].model289 290 def update_default_model_record(291 self, tenant_id: str, model_type: ModelType, provider: str, model: str292 ) -> TenantDefaultModel:293 """294 Update default model record.295 296 :param tenant_id: workspace id297 :param model_type: model type298 :param provider: provider name299 :param model: model name300 :return:301 """302 provider_configurations = self.get_configurations(tenant_id)303 if provider not in provider_configurations:304 raise ValueError(f"Provider {provider} does not exist.")305 306 # get available models from provider_configurations307 available_models = provider_configurations.get_models(model_type=model_type, only_active=True)308 309 # check if the model is exist in available models310 model_names = [model.model for model in available_models]311 if model not in model_names:312 raise ValueError(f"Model {model} does not exist.")313 314 # Get the list of available models from get_configurations and check if it is LLM315 default_model = (316 db.session.query(TenantDefaultModel)317 .filter(318 TenantDefaultModel.tenant_id == tenant_id,319 TenantDefaultModel.model_type == model_type.to_origin_model_type(),320 )321 .first()322 )323 324 # create or update TenantDefaultModel record325 if default_model:326 # update default model327 default_model.provider_name = provider328 default_model.model_name = model329 db.session.commit()330 else:331 # create default model332 default_model = TenantDefaultModel(333 tenant_id=tenant_id,334 model_type=model_type.value,335 provider_name=provider,336 model_name=model,337 )338 db.session.add(default_model)339 db.session.commit()340 341 return default_model342 343 @staticmethod344 def _get_all_providers(tenant_id: str) -> dict[str, list[Provider]]:345 """346 Get all provider records of the workspace.347 348 :param tenant_id: workspace id349 :return:350 """351 providers = db.session.query(Provider).filter(Provider.tenant_id == tenant_id, Provider.is_valid == True).all()352 353 provider_name_to_provider_records_dict = defaultdict(list)354 for provider in providers:355 provider_name_to_provider_records_dict[provider.provider_name].append(provider)356 357 return provider_name_to_provider_records_dict358 359 @staticmethod360 def _get_all_provider_models(tenant_id: str) -> dict[str, list[ProviderModel]]:361 """362 Get all provider model records of the workspace.363 364 :param tenant_id: workspace id365 :return:366 """367 # Get all provider model records of the workspace368 provider_models = (369 db.session.query(ProviderModel)370 .filter(ProviderModel.tenant_id == tenant_id, ProviderModel.is_valid == True)371 .all()372 )373 374 provider_name_to_provider_model_records_dict = defaultdict(list)375 for provider_model in provider_models:376 provider_name_to_provider_model_records_dict[provider_model.provider_name].append(provider_model)377 378 return provider_name_to_provider_model_records_dict379 380 @staticmethod381 def _get_all_preferred_model_providers(tenant_id: str) -> dict[str, TenantPreferredModelProvider]:382 """383 Get All preferred provider types of the workspace.384 385 :param tenant_id: workspace id386 :return:387 """388 preferred_provider_types = (389 db.session.query(TenantPreferredModelProvider)390 .filter(TenantPreferredModelProvider.tenant_id == tenant_id)391 .all()392 )393 394 provider_name_to_preferred_provider_type_records_dict = {395 preferred_provider_type.provider_name: preferred_provider_type396 for preferred_provider_type in preferred_provider_types397 }398 399 return provider_name_to_preferred_provider_type_records_dict400 401 @staticmethod402 def _get_all_provider_model_settings(tenant_id: str) -> dict[str, list[ProviderModelSetting]]:403 """404 Get All provider model settings of the workspace.405 406 :param tenant_id: workspace id407 :return:408 """409 provider_model_settings = (410 db.session.query(ProviderModelSetting).filter(ProviderModelSetting.tenant_id == tenant_id).all()411 )412 413 provider_name_to_provider_model_settings_dict = defaultdict(list)414 for provider_model_setting in provider_model_settings:415 (416 provider_name_to_provider_model_settings_dict[provider_model_setting.provider_name].append(417 provider_model_setting418 )419 )420 421 return provider_name_to_provider_model_settings_dict422 423 @staticmethod424 def _get_all_provider_load_balancing_configs(tenant_id: str) -> dict[str, list[LoadBalancingModelConfig]]:425 """426 Get All provider load balancing configs of the workspace.427 428 :param tenant_id: workspace id429 :return:430 """431 cache_key = f"tenant:{tenant_id}:model_load_balancing_enabled"432 cache_result = redis_client.get(cache_key)433 if cache_result is None:434 model_load_balancing_enabled = FeatureService.get_features(tenant_id).model_load_balancing_enabled435 redis_client.setex(cache_key, 120, str(model_load_balancing_enabled))436 else:437 cache_result = cache_result.decode("utf-8")438 model_load_balancing_enabled = cache_result == "True"439 440 if not model_load_balancing_enabled:441 return {}442 443 provider_load_balancing_configs = (444 db.session.query(LoadBalancingModelConfig).filter(LoadBalancingModelConfig.tenant_id == tenant_id).all()445 )446 447 provider_name_to_provider_load_balancing_model_configs_dict = defaultdict(list)448 for provider_load_balancing_config in provider_load_balancing_configs:449 (450 provider_name_to_provider_load_balancing_model_configs_dict[451 provider_load_balancing_config.provider_name452 ].append(provider_load_balancing_config)453 )454 455 return provider_name_to_provider_load_balancing_model_configs_dict456 457 @staticmethod458 def _init_trial_provider_records(459 tenant_id: str, provider_name_to_provider_records_dict: dict[str, list]460 ) -> dict[str, list]:461 """462 Initialize trial provider records if not exists.463 464 :param tenant_id: workspace id465 :param provider_name_to_provider_records_dict: provider name to provider records dict466 :return:467 """468 # Get hosting configuration469 hosting_configuration = ext_hosting_provider.hosting_configuration470 471 for provider_name, configuration in hosting_configuration.provider_map.items():472 if not configuration.enabled:473 continue474 475 provider_records = provider_name_to_provider_records_dict.get(provider_name)476 if not provider_records:477 provider_records = []478 479 provider_quota_to_provider_record_dict = {}480 for provider_record in provider_records:481 if provider_record.provider_type != ProviderType.SYSTEM.value:482 continue483 484 provider_quota_to_provider_record_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = (485 provider_record486 )487 488 for quota in configuration.quotas:489 if quota.quota_type == ProviderQuotaType.TRIAL:490 # Init trial provider records if not exists491 if ProviderQuotaType.TRIAL not in provider_quota_to_provider_record_dict:492 try:493 provider_record = Provider(494 tenant_id=tenant_id,495 provider_name=provider_name,496 provider_type=ProviderType.SYSTEM.value,497 quota_type=ProviderQuotaType.TRIAL.value,498 quota_limit=quota.quota_limit,499 quota_used=0,500 is_valid=True,501 )502 db.session.add(provider_record)503 db.session.commit()504 except IntegrityError:505 db.session.rollback()506 provider_record = (507 db.session.query(Provider)508 .filter(509 Provider.tenant_id == tenant_id,510 Provider.provider_name == provider_name,511 Provider.provider_type == ProviderType.SYSTEM.value,512 Provider.quota_type == ProviderQuotaType.TRIAL.value,513 )514 .first()515 )516 517 if provider_record and not provider_record.is_valid:518 provider_record.is_valid = True519 db.session.commit()520 521 provider_name_to_provider_records_dict[provider_name].append(provider_record)522 523 return provider_name_to_provider_records_dict524 525 def _to_custom_configuration(526 self,527 tenant_id: str,528 provider_entity: ProviderEntity,529 provider_records: list[Provider],530 provider_model_records: list[ProviderModel],531 ) -> CustomConfiguration:532 """533 Convert to custom configuration.534 535 :param tenant_id: workspace id536 :param provider_entity: provider entity537 :param provider_records: provider records538 :param provider_model_records: provider model records539 :return:540 """541 # Get provider credential secret variables542 provider_credential_secret_variables = self._extract_secret_variables(543 provider_entity.provider_credential_schema.credential_form_schemas544 if provider_entity.provider_credential_schema545 else []546 )547 548 # Get custom provider record549 custom_provider_record = None550 for provider_record in provider_records:551 if provider_record.provider_type == ProviderType.SYSTEM.value:552 continue553 554 if not provider_record.encrypted_config:555 continue556 557 custom_provider_record = provider_record558 559 # Get custom provider credentials560 custom_provider_configuration = None561 if custom_provider_record:562 provider_credentials_cache = ProviderCredentialsCache(563 tenant_id=tenant_id,564 identity_id=custom_provider_record.id,565 cache_type=ProviderCredentialsCacheType.PROVIDER,566 )567 568 # Get cached provider credentials569 cached_provider_credentials = provider_credentials_cache.get()570 571 if not cached_provider_credentials:572 try:573 # fix origin data574 if (575 custom_provider_record.encrypted_config576 and not custom_provider_record.encrypted_config.startswith("{")577 ):578 provider_credentials = {"openai_api_key": custom_provider_record.encrypted_config}579 else:580 provider_credentials = json.loads(custom_provider_record.encrypted_config)581 except JSONDecodeError:582 provider_credentials = {}583 584 # Get decoding rsa key and cipher for decrypting credentials585 if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:586 self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)587 588 for variable in provider_credential_secret_variables:589 if variable in provider_credentials:590 try:591 provider_credentials[variable] = encrypter.decrypt_token_with_decoding(592 provider_credentials.get(variable), self.decoding_rsa_key, self.decoding_cipher_rsa593 )594 except ValueError:595 pass596 597 # cache provider credentials598 provider_credentials_cache.set(credentials=provider_credentials)599 else:600 provider_credentials = cached_provider_credentials601 602 custom_provider_configuration = CustomProviderConfiguration(credentials=provider_credentials)603 604 # Get provider model credential secret variables605 model_credential_secret_variables = self._extract_secret_variables(606 provider_entity.model_credential_schema.credential_form_schemas607 if provider_entity.model_credential_schema608 else []609 )610 611 # Get custom provider model credentials612 custom_model_configurations = []613 for provider_model_record in provider_model_records:614 if not provider_model_record.encrypted_config:615 continue616 617 provider_model_credentials_cache = ProviderCredentialsCache(618 tenant_id=tenant_id, identity_id=provider_model_record.id, cache_type=ProviderCredentialsCacheType.MODEL619 )620 621 # Get cached provider model credentials622 cached_provider_model_credentials = provider_model_credentials_cache.get()623 624 if not cached_provider_model_credentials:625 try:626 provider_model_credentials = json.loads(provider_model_record.encrypted_config)627 except JSONDecodeError:628 continue629 630 # Get decoding rsa key and cipher for decrypting credentials631 if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:632 self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)633 634 for variable in model_credential_secret_variables:635 if variable in provider_model_credentials:636 try:637 provider_model_credentials[variable] = encrypter.decrypt_token_with_decoding(638 provider_model_credentials.get(variable),639 self.decoding_rsa_key,640 self.decoding_cipher_rsa,641 )642 except ValueError:643 pass644 645 # cache provider model credentials646 provider_model_credentials_cache.set(credentials=provider_model_credentials)647 else:648 provider_model_credentials = cached_provider_model_credentials649 650 custom_model_configurations.append(651 CustomModelConfiguration(652 model=provider_model_record.model_name,653 model_type=ModelType.value_of(provider_model_record.model_type),654 credentials=provider_model_credentials,655 )656 )657 658 return CustomConfiguration(provider=custom_provider_configuration, models=custom_model_configurations)659 660 def _to_system_configuration(661 self, tenant_id: str, provider_entity: ProviderEntity, provider_records: list[Provider]662 ) -> SystemConfiguration:663 """664 Convert to system configuration.665 666 :param tenant_id: workspace id667 :param provider_entity: provider entity668 :param provider_records: provider records669 :return:670 """671 # Get hosting configuration672 hosting_configuration = ext_hosting_provider.hosting_configuration673 674 if (675 provider_entity.provider not in hosting_configuration.provider_map676 or not hosting_configuration.provider_map.get(provider_entity.provider).enabled677 ):678 return SystemConfiguration(enabled=False)679 680 provider_hosting_configuration = hosting_configuration.provider_map.get(provider_entity.provider)681 682 # Convert provider_records to dict683 quota_type_to_provider_records_dict = {}684 for provider_record in provider_records:685 if provider_record.provider_type != ProviderType.SYSTEM.value:686 continue687 688 quota_type_to_provider_records_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = (689 provider_record690 )691 692 quota_configurations = []693 for provider_quota in provider_hosting_configuration.quotas:694 if provider_quota.quota_type not in quota_type_to_provider_records_dict:695 if provider_quota.quota_type == ProviderQuotaType.FREE:696 quota_configuration = QuotaConfiguration(697 quota_type=provider_quota.quota_type,698 quota_unit=provider_hosting_configuration.quota_unit,699 quota_used=0,700 quota_limit=0,701 is_valid=False,702 restrict_models=provider_quota.restrict_models,703 )704 else:705 continue706 else:707 provider_record = quota_type_to_provider_records_dict[provider_quota.quota_type]708 709 quota_configuration = QuotaConfiguration(710 quota_type=provider_quota.quota_type,711 quota_unit=provider_hosting_configuration.quota_unit,712 quota_used=provider_record.quota_used,713 quota_limit=provider_record.quota_limit,714 is_valid=provider_record.quota_limit > provider_record.quota_used715 or provider_record.quota_limit == -1,716 restrict_models=provider_quota.restrict_models,717 )718 719 quota_configurations.append(quota_configuration)720 721 if len(quota_configurations) == 0:722 return SystemConfiguration(enabled=False)723 724 current_quota_type = self._choice_current_using_quota_type(quota_configurations)725 726 current_using_credentials = provider_hosting_configuration.credentials727 if current_quota_type == ProviderQuotaType.FREE:728 provider_record = quota_type_to_provider_records_dict.get(current_quota_type)729 730 if provider_record:731 provider_credentials_cache = ProviderCredentialsCache(732 tenant_id=tenant_id,733 identity_id=provider_record.id,734 cache_type=ProviderCredentialsCacheType.PROVIDER,735 )736 737 # Get cached provider credentials738 cached_provider_credentials = provider_credentials_cache.get()739 740 if not cached_provider_credentials:741 try:742 provider_credentials = json.loads(provider_record.encrypted_config)743 except JSONDecodeError:744 provider_credentials = {}745 746 # Get provider credential secret variables747 provider_credential_secret_variables = self._extract_secret_variables(748 provider_entity.provider_credential_schema.credential_form_schemas749 if provider_entity.provider_credential_schema750 else []751 )752 753 # Get decoding rsa key and cipher for decrypting credentials754 if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:755 self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)756 757 for variable in provider_credential_secret_variables:758 if variable in provider_credentials:759 try:760 provider_credentials[variable] = encrypter.decrypt_token_with_decoding(761 provider_credentials.get(variable), self.decoding_rsa_key, self.decoding_cipher_rsa762 )763 except ValueError:764 pass765 766 current_using_credentials = provider_credentials767 768 # cache provider credentials769 provider_credentials_cache.set(credentials=current_using_credentials)770 else:771 current_using_credentials = cached_provider_credentials772 else:773 current_using_credentials = {}774 quota_configurations = []775 776 return SystemConfiguration(777 enabled=True,778 current_quota_type=current_quota_type,779 quota_configurations=quota_configurations,780 credentials=current_using_credentials,781 )782 783 @staticmethod784 def _choice_current_using_quota_type(quota_configurations: list[QuotaConfiguration]) -> ProviderQuotaType:785 """786 Choice current using quota type.787 paid quotas > provider free quotas > hosting trial quotas788 If there is still quota for the corresponding quota type according to the sorting,789 790 :param quota_configurations:791 :return:792 """793 # convert to dict794 quota_type_to_quota_configuration_dict = {795 quota_configuration.quota_type: quota_configuration for quota_configuration in quota_configurations796 }797 798 last_quota_configuration = None799 for quota_type in [ProviderQuotaType.PAID, ProviderQuotaType.FREE, ProviderQuotaType.TRIAL]:800 if quota_type in quota_type_to_quota_configuration_dict:801 last_quota_configuration = quota_type_to_quota_configuration_dict[quota_type]802 if last_quota_configuration.is_valid:803 return quota_type804 805 if last_quota_configuration:806 return last_quota_configuration.quota_type807 808 raise ValueError("No quota type available")809 810 @staticmethod811 def _extract_secret_variables(credential_form_schemas: list[CredentialFormSchema]) -> list[str]:812 """813 Extract secret input form variables.814 815 :param credential_form_schemas:816 :return:817 """818 secret_input_form_variables = []819 for credential_form_schema in credential_form_schemas:820 if credential_form_schema.type == FormType.SECRET_INPUT:821 secret_input_form_variables.append(credential_form_schema.variable)822 823 return secret_input_form_variables824 825 def _to_model_settings(826 self,827 provider_entity: ProviderEntity,828 provider_model_settings: Optional[list[ProviderModelSetting]] = None,829 load_balancing_model_configs: Optional[list[LoadBalancingModelConfig]] = None,830 ) -> list[ModelSettings]:831 """832 Convert to model settings.833 :param provider_entity: provider entity834 :param provider_model_settings: provider model settings include enabled, load balancing enabled835 :param load_balancing_model_configs: load balancing model configs836 :return:837 """838 # Get provider model credential secret variables839 model_credential_secret_variables = self._extract_secret_variables(840 provider_entity.model_credential_schema.credential_form_schemas841 if provider_entity.model_credential_schema842 else []843 )844 845 model_settings = []846 if not provider_model_settings:847 return model_settings848 849 for provider_model_setting in provider_model_settings:850 load_balancing_configs = []851 if provider_model_setting.load_balancing_enabled and load_balancing_model_configs:852 for load_balancing_model_config in load_balancing_model_configs:853 if (854 load_balancing_model_config.model_name == provider_model_setting.model_name855 and load_balancing_model_config.model_type == provider_model_setting.model_type856 ):857 if not load_balancing_model_config.enabled:858 continue859 860 if not load_balancing_model_config.encrypted_config:861 if load_balancing_model_config.name == "__inherit__":862 load_balancing_configs.append(863 ModelLoadBalancingConfiguration(864 id=load_balancing_model_config.id,865 name=load_balancing_model_config.name,866 credentials={},867 )868 )869 continue870 871 provider_model_credentials_cache = ProviderCredentialsCache(872 tenant_id=load_balancing_model_config.tenant_id,873 identity_id=load_balancing_model_config.id,874 cache_type=ProviderCredentialsCacheType.LOAD_BALANCING_MODEL,875 )876 877 # Get cached provider model credentials878 cached_provider_model_credentials = provider_model_credentials_cache.get()879 880 if not cached_provider_model_credentials:881 try:882 provider_model_credentials = json.loads(load_balancing_model_config.encrypted_config)883 except JSONDecodeError:884 continue885 886 # Get decoding rsa key and cipher for decrypting credentials887 if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:888 self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(889 load_balancing_model_config.tenant_id890 )891 892 for variable in model_credential_secret_variables:893 if variable in provider_model_credentials:894 try:895 provider_model_credentials[variable] = encrypter.decrypt_token_with_decoding(896 provider_model_credentials.get(variable),897 self.decoding_rsa_key,898 self.decoding_cipher_rsa,899 )900 except ValueError:901 pass902 903 # cache provider model credentials904 provider_model_credentials_cache.set(credentials=provider_model_credentials)905 else:906 provider_model_credentials = cached_provider_model_credentials907 908 load_balancing_configs.append(909 ModelLoadBalancingConfiguration(910 id=load_balancing_model_config.id,911 name=load_balancing_model_config.name,912 credentials=provider_model_credentials,913 )914 )915 916 model_settings.append(917 ModelSettings(918 model=provider_model_setting.model_name,919 model_type=ModelType.value_of(provider_model_setting.model_type),920 enabled=provider_model_setting.enabled,921 load_balancing_configs=load_balancing_configs if len(load_balancing_configs) > 1 else [],922 )923 )924 925 return model_settings926 