provider_manager.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. import json
  2. from collections import defaultdict
  3. from json import JSONDecodeError
  4. from typing import Any, Optional, cast
  5. from sqlalchemy.exc import IntegrityError
  6. from configs import dify_config
  7. from core.entities import DEFAULT_PLUGIN_ID
  8. from core.entities.model_entities import DefaultModelEntity, DefaultModelProviderEntity
  9. from core.entities.provider_configuration import ProviderConfiguration, ProviderConfigurations, ProviderModelBundle
  10. from core.entities.provider_entities import (
  11. CustomConfiguration,
  12. CustomModelConfiguration,
  13. CustomProviderConfiguration,
  14. ModelLoadBalancingConfiguration,
  15. ModelSettings,
  16. ProviderQuotaType,
  17. QuotaConfiguration,
  18. QuotaUnit,
  19. SystemConfiguration,
  20. )
  21. from core.helper import encrypter
  22. from core.helper.model_provider_cache import ProviderCredentialsCache, ProviderCredentialsCacheType
  23. from core.helper.position_helper import is_filtered
  24. from core.model_runtime.entities.model_entities import ModelType
  25. from core.model_runtime.entities.provider_entities import (
  26. ConfigurateMethod,
  27. CredentialFormSchema,
  28. FormType,
  29. ProviderEntity,
  30. )
  31. from core.model_runtime.model_providers.model_provider_factory import ModelProviderFactory
  32. from core.plugin.entities.plugin import ModelProviderID
  33. from extensions import ext_hosting_provider
  34. from extensions.ext_database import db
  35. from extensions.ext_redis import redis_client
  36. from models.provider import (
  37. LoadBalancingModelConfig,
  38. Provider,
  39. ProviderModel,
  40. ProviderModelSetting,
  41. ProviderType,
  42. TenantDefaultModel,
  43. TenantPreferredModelProvider,
  44. )
  45. from services.feature_service import FeatureService
  46. class ProviderManager:
  47. """
  48. ProviderManager is a class that manages the model providers includes Hosting and Customize Model Providers.
  49. """
  50. def __init__(self) -> None:
  51. self.decoding_rsa_key = None
  52. self.decoding_cipher_rsa = None
  53. def get_configurations(self, tenant_id: str) -> ProviderConfigurations:
  54. """
  55. Get model provider configurations.
  56. Construct ProviderConfiguration objects for each provider
  57. Including:
  58. 1. Basic information of the provider
  59. 2. Hosting configuration information, including:
  60. (1. Whether to enable (support) hosting type, if enabled, the following information exists
  61. (2. List of hosting type provider configurations
  62. (including quota type, quota limit, current remaining quota, etc.)
  63. (3. The current hosting type in use (whether there is a quota or not)
  64. paid quotas > provider free quotas > hosting trial quotas
  65. (4. Unified credentials for hosting providers
  66. 3. Custom configuration information, including:
  67. (1. Whether to enable (support) custom type, if enabled, the following information exists
  68. (2. Custom provider configuration (including credentials)
  69. (3. List of custom provider model configurations (including credentials)
  70. 4. Hosting/custom preferred provider type.
  71. Provide methods:
  72. - Get the current configuration (including credentials)
  73. - Get the availability and status of the hosting configuration: active available,
  74. quota_exceeded insufficient quota, unsupported hosting
  75. - Get the availability of custom configuration
  76. Custom provider available conditions:
  77. (1. custom provider credentials available
  78. (2. at least one custom model credentials available
  79. - Verify, update, and delete custom provider configuration
  80. - Verify, update, and delete custom provider model configuration
  81. - Get the list of available models (optional provider filtering, model type filtering)
  82. Append custom provider models to the list
  83. - Get provider instance
  84. - Switch selection priority
  85. :param tenant_id:
  86. :return:
  87. """
  88. # Get all provider records of the workspace
  89. provider_name_to_provider_records_dict = self._get_all_providers(tenant_id)
  90. # Initialize trial provider records if not exist
  91. provider_name_to_provider_records_dict = self._init_trial_provider_records(
  92. tenant_id, provider_name_to_provider_records_dict
  93. )
  94. # append providers with langgenius/openai/openai
  95. provider_name_list = list(provider_name_to_provider_records_dict.keys())
  96. for provider_name in provider_name_list:
  97. provider_id = ModelProviderID(provider_name)
  98. if str(provider_id) not in provider_name_list:
  99. provider_name_to_provider_records_dict[str(provider_id)] = provider_name_to_provider_records_dict[
  100. provider_name
  101. ]
  102. # Get all provider model records of the workspace
  103. provider_name_to_provider_model_records_dict = self._get_all_provider_models(tenant_id)
  104. # Get all provider entities
  105. model_provider_factory = ModelProviderFactory(tenant_id)
  106. provider_entities = model_provider_factory.get_providers()
  107. # Get All preferred provider types of the workspace
  108. provider_name_to_preferred_model_provider_records_dict = self._get_all_preferred_model_providers(tenant_id)
  109. # Get All provider model settings
  110. provider_name_to_provider_model_settings_dict = self._get_all_provider_model_settings(tenant_id)
  111. # Get All load balancing configs
  112. provider_name_to_provider_load_balancing_model_configs_dict = self._get_all_provider_load_balancing_configs(
  113. tenant_id
  114. )
  115. provider_configurations = ProviderConfigurations(tenant_id=tenant_id)
  116. # Construct ProviderConfiguration objects for each provider
  117. for provider_entity in provider_entities:
  118. # handle include, exclude
  119. if is_filtered(
  120. include_set=cast(set[str], dify_config.POSITION_PROVIDER_INCLUDES_SET),
  121. exclude_set=cast(set[str], dify_config.POSITION_PROVIDER_EXCLUDES_SET),
  122. data=provider_entity,
  123. name_func=lambda x: x.provider,
  124. ):
  125. continue
  126. provider_name = provider_entity.provider
  127. 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. # Convert to custom configuration
  130. custom_configuration = self._to_custom_configuration(
  131. tenant_id, provider_entity, provider_records, provider_model_records
  132. )
  133. # Convert to system configuration
  134. system_configuration = self._to_system_configuration(tenant_id, provider_entity, provider_records)
  135. # Get preferred provider type
  136. preferred_provider_type_record = provider_name_to_preferred_model_provider_records_dict.get(provider_name)
  137. if preferred_provider_type_record:
  138. preferred_provider_type = ProviderType.value_of(preferred_provider_type_record.preferred_provider_type)
  139. elif custom_configuration.provider or custom_configuration.models:
  140. preferred_provider_type = ProviderType.CUSTOM
  141. elif system_configuration.enabled:
  142. preferred_provider_type = ProviderType.SYSTEM
  143. else:
  144. preferred_provider_type = ProviderType.CUSTOM
  145. using_provider_type = preferred_provider_type
  146. has_valid_quota = any(quota_conf.is_valid for quota_conf in system_configuration.quota_configurations)
  147. if preferred_provider_type == ProviderType.SYSTEM:
  148. if not system_configuration.enabled or not has_valid_quota:
  149. using_provider_type = ProviderType.CUSTOM
  150. else:
  151. if not custom_configuration.provider and not custom_configuration.models:
  152. if system_configuration.enabled and has_valid_quota:
  153. using_provider_type = ProviderType.SYSTEM
  154. # Get provider load balancing configs
  155. provider_model_settings = provider_name_to_provider_model_settings_dict.get(provider_name)
  156. # Get provider load balancing configs
  157. provider_load_balancing_configs = provider_name_to_provider_load_balancing_model_configs_dict.get(
  158. provider_name
  159. )
  160. # Convert to model settings
  161. model_settings = self._to_model_settings(
  162. provider_entity=provider_entity,
  163. provider_model_settings=provider_model_settings,
  164. load_balancing_model_configs=provider_load_balancing_configs,
  165. )
  166. provider_configuration = ProviderConfiguration(
  167. tenant_id=tenant_id,
  168. provider=provider_entity,
  169. preferred_provider_type=preferred_provider_type,
  170. using_provider_type=using_provider_type,
  171. system_configuration=system_configuration,
  172. custom_configuration=custom_configuration,
  173. model_settings=model_settings,
  174. )
  175. provider_configurations[str(ModelProviderID(provider_name))] = provider_configuration
  176. # Return the encapsulated object
  177. return provider_configurations
  178. def get_provider_model_bundle(self, tenant_id: str, provider: str, model_type: ModelType) -> ProviderModelBundle:
  179. """
  180. Get provider model bundle.
  181. :param tenant_id: workspace id
  182. :param provider: provider name
  183. :param model_type: model type
  184. :return:
  185. """
  186. provider_configurations = self.get_configurations(tenant_id)
  187. # get provider instance
  188. provider_configuration = provider_configurations.get(provider)
  189. if not provider_configuration:
  190. raise ValueError(f"Provider {provider} does not exist.")
  191. model_type_instance = provider_configuration.get_model_type_instance(model_type)
  192. return ProviderModelBundle(
  193. configuration=provider_configuration,
  194. model_type_instance=model_type_instance,
  195. )
  196. def get_default_model(self, tenant_id: str, model_type: ModelType) -> Optional[DefaultModelEntity]:
  197. """
  198. Get default model.
  199. :param tenant_id: workspace id
  200. :param model_type: model type
  201. :return:
  202. """
  203. # Get the corresponding TenantDefaultModel record
  204. default_model = (
  205. db.session.query(TenantDefaultModel)
  206. .filter(
  207. TenantDefaultModel.tenant_id == tenant_id,
  208. TenantDefaultModel.model_type == model_type.to_origin_model_type(),
  209. )
  210. .first()
  211. )
  212. # If it does not exist, get the first available provider model from get_configurations
  213. # and update the TenantDefaultModel record
  214. if not default_model:
  215. # Get provider configurations
  216. provider_configurations = self.get_configurations(tenant_id)
  217. # get available models from provider_configurations
  218. available_models = provider_configurations.get_models(model_type=model_type, only_active=True)
  219. if available_models:
  220. available_model = next(
  221. (model for model in available_models if model.model == "gpt-4"), available_models[0]
  222. )
  223. default_model = TenantDefaultModel()
  224. default_model.tenant_id = tenant_id
  225. default_model.model_type = model_type.to_origin_model_type()
  226. default_model.provider_name = available_model.provider.provider
  227. default_model.model_name = available_model.model
  228. db.session.add(default_model)
  229. db.session.commit()
  230. if not default_model:
  231. return None
  232. model_provider_factory = ModelProviderFactory(tenant_id)
  233. provider_schema = model_provider_factory.get_provider_schema(provider=default_model.provider_name)
  234. return DefaultModelEntity(
  235. model=default_model.model_name,
  236. model_type=model_type,
  237. provider=DefaultModelProviderEntity(
  238. provider=provider_schema.provider,
  239. label=provider_schema.label,
  240. icon_small=provider_schema.icon_small,
  241. icon_large=provider_schema.icon_large,
  242. supported_model_types=provider_schema.supported_model_types,
  243. ),
  244. )
  245. def get_first_provider_first_model(self, tenant_id: str, model_type: ModelType) -> tuple[str | None, str | None]:
  246. """
  247. Get names of first model and its provider
  248. :param tenant_id: workspace id
  249. :param model_type: model type
  250. :return: provider name, model name
  251. """
  252. provider_configurations = self.get_configurations(tenant_id)
  253. # get available models from provider_configurations
  254. all_models = provider_configurations.get_models(model_type=model_type, only_active=False)
  255. if not all_models:
  256. return None, None
  257. return all_models[0].provider.provider, all_models[0].model
  258. def update_default_model_record(
  259. self, tenant_id: str, model_type: ModelType, provider: str, model: str
  260. ) -> TenantDefaultModel:
  261. """
  262. Update default model record.
  263. :param tenant_id: workspace id
  264. :param model_type: model type
  265. :param provider: provider name
  266. :param model: model name
  267. :return:
  268. """
  269. provider_configurations = self.get_configurations(tenant_id)
  270. if provider not in provider_configurations:
  271. raise ValueError(f"Provider {provider} does not exist.")
  272. # get available models from provider_configurations
  273. available_models = provider_configurations.get_models(model_type=model_type, only_active=True)
  274. # check if the model is exist in available models
  275. model_names = [model.model for model in available_models]
  276. if model not in model_names:
  277. raise ValueError(f"Model {model} does not exist.")
  278. # Get the list of available models from get_configurations and check if it is LLM
  279. default_model = (
  280. db.session.query(TenantDefaultModel)
  281. .filter(
  282. TenantDefaultModel.tenant_id == tenant_id,
  283. TenantDefaultModel.model_type == model_type.to_origin_model_type(),
  284. )
  285. .first()
  286. )
  287. # create or update TenantDefaultModel record
  288. if default_model:
  289. # update default model
  290. default_model.provider_name = provider
  291. default_model.model_name = model
  292. db.session.commit()
  293. else:
  294. # create default model
  295. default_model = TenantDefaultModel(
  296. tenant_id=tenant_id,
  297. model_type=model_type.value,
  298. provider_name=provider,
  299. model_name=model,
  300. )
  301. db.session.add(default_model)
  302. db.session.commit()
  303. return default_model
  304. @staticmethod
  305. def _get_all_providers(tenant_id: str) -> dict[str, list[Provider]]:
  306. """
  307. Get all provider records of the workspace.
  308. :param tenant_id: workspace id
  309. :return:
  310. """
  311. providers = db.session.query(Provider).filter(Provider.tenant_id == tenant_id, Provider.is_valid == True).all()
  312. provider_name_to_provider_records_dict = defaultdict(list)
  313. for provider in providers:
  314. provider_name_to_provider_records_dict[provider.provider_name].append(provider)
  315. return provider_name_to_provider_records_dict
  316. @staticmethod
  317. def _get_all_provider_models(tenant_id: str) -> dict[str, list[ProviderModel]]:
  318. """
  319. Get all provider model records of the workspace.
  320. :param tenant_id: workspace id
  321. :return:
  322. """
  323. # Get all provider model records of the workspace
  324. provider_models = (
  325. db.session.query(ProviderModel)
  326. .filter(ProviderModel.tenant_id == tenant_id, ProviderModel.is_valid == True)
  327. .all()
  328. )
  329. provider_name_to_provider_model_records_dict = defaultdict(list)
  330. for provider_model in provider_models:
  331. provider_name_to_provider_model_records_dict[provider_model.provider_name].append(provider_model)
  332. return provider_name_to_provider_model_records_dict
  333. @staticmethod
  334. def _get_all_preferred_model_providers(tenant_id: str) -> dict[str, TenantPreferredModelProvider]:
  335. """
  336. Get All preferred provider types of the workspace.
  337. :param tenant_id: workspace id
  338. :return:
  339. """
  340. preferred_provider_types = (
  341. db.session.query(TenantPreferredModelProvider)
  342. .filter(TenantPreferredModelProvider.tenant_id == tenant_id)
  343. .all()
  344. )
  345. provider_name_to_preferred_provider_type_records_dict = {
  346. preferred_provider_type.provider_name: preferred_provider_type
  347. for preferred_provider_type in preferred_provider_types
  348. }
  349. return provider_name_to_preferred_provider_type_records_dict
  350. @staticmethod
  351. def _get_all_provider_model_settings(tenant_id: str) -> dict[str, list[ProviderModelSetting]]:
  352. """
  353. Get All provider model settings of the workspace.
  354. :param tenant_id: workspace id
  355. :return:
  356. """
  357. provider_model_settings = (
  358. db.session.query(ProviderModelSetting).filter(ProviderModelSetting.tenant_id == tenant_id).all()
  359. )
  360. provider_name_to_provider_model_settings_dict = defaultdict(list)
  361. for provider_model_setting in provider_model_settings:
  362. (
  363. provider_name_to_provider_model_settings_dict[provider_model_setting.provider_name].append(
  364. provider_model_setting
  365. )
  366. )
  367. return provider_name_to_provider_model_settings_dict
  368. @staticmethod
  369. def _get_all_provider_load_balancing_configs(tenant_id: str) -> dict[str, list[LoadBalancingModelConfig]]:
  370. """
  371. Get All provider load balancing configs of the workspace.
  372. :param tenant_id: workspace id
  373. :return:
  374. """
  375. cache_key = f"tenant:{tenant_id}:model_load_balancing_enabled"
  376. cache_result = redis_client.get(cache_key)
  377. if cache_result is None:
  378. model_load_balancing_enabled = FeatureService.get_features(tenant_id).model_load_balancing_enabled
  379. redis_client.setex(cache_key, 120, str(model_load_balancing_enabled))
  380. else:
  381. cache_result = cache_result.decode("utf-8")
  382. model_load_balancing_enabled = cache_result == "True"
  383. if not model_load_balancing_enabled:
  384. return {}
  385. provider_load_balancing_configs = (
  386. db.session.query(LoadBalancingModelConfig).filter(LoadBalancingModelConfig.tenant_id == tenant_id).all()
  387. )
  388. provider_name_to_provider_load_balancing_model_configs_dict = defaultdict(list)
  389. for provider_load_balancing_config in provider_load_balancing_configs:
  390. provider_name_to_provider_load_balancing_model_configs_dict[
  391. provider_load_balancing_config.provider_name
  392. ].append(provider_load_balancing_config)
  393. return provider_name_to_provider_load_balancing_model_configs_dict
  394. @staticmethod
  395. def _init_trial_provider_records(
  396. tenant_id: str, provider_name_to_provider_records_dict: dict[str, list]
  397. ) -> dict[str, list]:
  398. """
  399. Initialize trial provider records if not exists.
  400. :param tenant_id: workspace id
  401. :param provider_name_to_provider_records_dict: provider name to provider records dict
  402. :return:
  403. """
  404. # Get hosting configuration
  405. hosting_configuration = ext_hosting_provider.hosting_configuration
  406. for provider_name, configuration in hosting_configuration.provider_map.items():
  407. if not configuration.enabled:
  408. continue
  409. provider_records = provider_name_to_provider_records_dict.get(provider_name)
  410. if not provider_records:
  411. provider_records = []
  412. provider_quota_to_provider_record_dict = {}
  413. for provider_record in provider_records:
  414. if provider_record.provider_type != ProviderType.SYSTEM.value:
  415. continue
  416. provider_quota_to_provider_record_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = (
  417. provider_record
  418. )
  419. for quota in configuration.quotas:
  420. if quota.quota_type == ProviderQuotaType.TRIAL:
  421. # Init trial provider records if not exists
  422. if ProviderQuotaType.TRIAL not in provider_quota_to_provider_record_dict:
  423. if not provider_name.startswith(DEFAULT_PLUGIN_ID):
  424. continue
  425. hosting_provider_name = provider_name.split("/")[-1]
  426. try:
  427. # FIXME ignore the type errork, onyl TrialHostingQuota has limit need to change the logic
  428. provider_record = Provider(
  429. tenant_id=tenant_id,
  430. provider_name=hosting_provider_name,
  431. provider_type=ProviderType.SYSTEM.value,
  432. quota_type=ProviderQuotaType.TRIAL.value,
  433. quota_limit=quota.quota_limit, # type: ignore
  434. quota_used=0,
  435. is_valid=True,
  436. )
  437. db.session.add(provider_record)
  438. db.session.commit()
  439. except IntegrityError:
  440. db.session.rollback()
  441. provider_record = (
  442. db.session.query(Provider)
  443. .filter(
  444. Provider.tenant_id == tenant_id,
  445. Provider.provider_name == hosting_provider_name,
  446. Provider.provider_type == ProviderType.SYSTEM.value,
  447. Provider.quota_type == ProviderQuotaType.TRIAL.value,
  448. )
  449. .first()
  450. )
  451. if provider_record and not provider_record.is_valid:
  452. provider_record.is_valid = True
  453. db.session.commit()
  454. provider_name_to_provider_records_dict[provider_name].append(provider_record)
  455. return provider_name_to_provider_records_dict
  456. def _to_custom_configuration(
  457. self,
  458. tenant_id: str,
  459. provider_entity: ProviderEntity,
  460. provider_records: list[Provider],
  461. provider_model_records: list[ProviderModel],
  462. ) -> CustomConfiguration:
  463. """
  464. Convert to custom configuration.
  465. :param tenant_id: workspace id
  466. :param provider_entity: provider entity
  467. :param provider_records: provider records
  468. :param provider_model_records: provider model records
  469. :return:
  470. """
  471. # Get provider credential secret variables
  472. provider_credential_secret_variables = self._extract_secret_variables(
  473. provider_entity.provider_credential_schema.credential_form_schemas
  474. if provider_entity.provider_credential_schema
  475. else []
  476. )
  477. # Get custom provider record
  478. custom_provider_record = None
  479. for provider_record in provider_records:
  480. if provider_record.provider_type == ProviderType.SYSTEM.value:
  481. continue
  482. if not provider_record.encrypted_config:
  483. continue
  484. custom_provider_record = provider_record
  485. # Get custom provider credentials
  486. custom_provider_configuration = None
  487. if custom_provider_record:
  488. provider_credentials_cache = ProviderCredentialsCache(
  489. tenant_id=tenant_id,
  490. identity_id=custom_provider_record.id,
  491. cache_type=ProviderCredentialsCacheType.PROVIDER,
  492. )
  493. # Get cached provider credentials
  494. cached_provider_credentials = provider_credentials_cache.get()
  495. if not cached_provider_credentials:
  496. try:
  497. # fix origin data
  498. if (
  499. custom_provider_record.encrypted_config
  500. and not custom_provider_record.encrypted_config.startswith("{")
  501. ):
  502. provider_credentials = {"openai_api_key": custom_provider_record.encrypted_config}
  503. else:
  504. provider_credentials = json.loads(custom_provider_record.encrypted_config)
  505. except JSONDecodeError:
  506. provider_credentials = {}
  507. # Get decoding rsa key and cipher for decrypting credentials
  508. if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:
  509. self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)
  510. for variable in provider_credential_secret_variables:
  511. if variable in provider_credentials:
  512. try:
  513. provider_credentials[variable] = encrypter.decrypt_token_with_decoding(
  514. provider_credentials.get(variable) or "", # type: ignore
  515. self.decoding_rsa_key,
  516. self.decoding_cipher_rsa,
  517. )
  518. except ValueError:
  519. pass
  520. # cache provider credentials
  521. provider_credentials_cache.set(credentials=provider_credentials)
  522. else:
  523. provider_credentials = cached_provider_credentials
  524. custom_provider_configuration = CustomProviderConfiguration(credentials=provider_credentials)
  525. # Get provider model credential secret variables
  526. model_credential_secret_variables = self._extract_secret_variables(
  527. provider_entity.model_credential_schema.credential_form_schemas
  528. if provider_entity.model_credential_schema
  529. else []
  530. )
  531. # Get custom provider model credentials
  532. custom_model_configurations = []
  533. for provider_model_record in provider_model_records:
  534. if not provider_model_record.encrypted_config:
  535. continue
  536. provider_model_credentials_cache = ProviderCredentialsCache(
  537. tenant_id=tenant_id, identity_id=provider_model_record.id, cache_type=ProviderCredentialsCacheType.MODEL
  538. )
  539. # Get cached provider model credentials
  540. cached_provider_model_credentials = provider_model_credentials_cache.get()
  541. if not cached_provider_model_credentials:
  542. try:
  543. provider_model_credentials = json.loads(provider_model_record.encrypted_config)
  544. except JSONDecodeError:
  545. continue
  546. # Get decoding rsa key and cipher for decrypting credentials
  547. if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:
  548. self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)
  549. for variable in model_credential_secret_variables:
  550. if variable in provider_model_credentials:
  551. try:
  552. provider_model_credentials[variable] = encrypter.decrypt_token_with_decoding(
  553. provider_model_credentials.get(variable),
  554. self.decoding_rsa_key,
  555. self.decoding_cipher_rsa,
  556. )
  557. except ValueError:
  558. pass
  559. # cache provider model credentials
  560. provider_model_credentials_cache.set(credentials=provider_model_credentials)
  561. else:
  562. provider_model_credentials = cached_provider_model_credentials
  563. custom_model_configurations.append(
  564. CustomModelConfiguration(
  565. model=provider_model_record.model_name,
  566. model_type=ModelType.value_of(provider_model_record.model_type),
  567. credentials=provider_model_credentials,
  568. )
  569. )
  570. return CustomConfiguration(provider=custom_provider_configuration, models=custom_model_configurations)
  571. def _to_system_configuration(
  572. self, tenant_id: str, provider_entity: ProviderEntity, provider_records: list[Provider]
  573. ) -> SystemConfiguration:
  574. """
  575. Convert to system configuration.
  576. :param tenant_id: workspace id
  577. :param provider_entity: provider entity
  578. :param provider_records: provider records
  579. :return:
  580. """
  581. # Get hosting configuration
  582. hosting_configuration = ext_hosting_provider.hosting_configuration
  583. provider_hosting_configuration = hosting_configuration.provider_map.get(provider_entity.provider)
  584. if provider_hosting_configuration is None or not provider_hosting_configuration.enabled:
  585. return SystemConfiguration(enabled=False)
  586. # Convert provider_records to dict
  587. quota_type_to_provider_records_dict = {}
  588. for provider_record in provider_records:
  589. if provider_record.provider_type != ProviderType.SYSTEM.value:
  590. continue
  591. quota_type_to_provider_records_dict[ProviderQuotaType.value_of(provider_record.quota_type)] = (
  592. provider_record
  593. )
  594. quota_configurations = []
  595. for provider_quota in provider_hosting_configuration.quotas:
  596. if provider_quota.quota_type not in quota_type_to_provider_records_dict:
  597. if provider_quota.quota_type == ProviderQuotaType.FREE:
  598. quota_configuration = QuotaConfiguration(
  599. quota_type=provider_quota.quota_type,
  600. quota_unit=provider_hosting_configuration.quota_unit or QuotaUnit.TOKENS,
  601. quota_used=0,
  602. quota_limit=0,
  603. is_valid=False,
  604. restrict_models=provider_quota.restrict_models,
  605. )
  606. else:
  607. continue
  608. else:
  609. provider_record = quota_type_to_provider_records_dict[provider_quota.quota_type]
  610. quota_configuration = QuotaConfiguration(
  611. quota_type=provider_quota.quota_type,
  612. quota_unit=provider_hosting_configuration.quota_unit or QuotaUnit.TOKENS,
  613. quota_used=provider_record.quota_used,
  614. quota_limit=provider_record.quota_limit,
  615. is_valid=provider_record.quota_limit > provider_record.quota_used
  616. or provider_record.quota_limit == -1,
  617. restrict_models=provider_quota.restrict_models,
  618. )
  619. quota_configurations.append(quota_configuration)
  620. if len(quota_configurations) == 0:
  621. return SystemConfiguration(enabled=False)
  622. current_quota_type = self._choice_current_using_quota_type(quota_configurations)
  623. current_using_credentials = provider_hosting_configuration.credentials
  624. if current_quota_type == ProviderQuotaType.FREE:
  625. provider_record_quota_free = quota_type_to_provider_records_dict.get(current_quota_type)
  626. if provider_record_quota_free:
  627. provider_credentials_cache = ProviderCredentialsCache(
  628. tenant_id=tenant_id,
  629. identity_id=provider_record_quota_free.id,
  630. cache_type=ProviderCredentialsCacheType.PROVIDER,
  631. )
  632. # Get cached provider credentials
  633. # error occurs
  634. cached_provider_credentials = provider_credentials_cache.get()
  635. if not cached_provider_credentials:
  636. try:
  637. provider_credentials: dict[str, Any] = json.loads(provider_record.encrypted_config)
  638. except JSONDecodeError:
  639. provider_credentials = {}
  640. # Get provider credential secret variables
  641. provider_credential_secret_variables = self._extract_secret_variables(
  642. provider_entity.provider_credential_schema.credential_form_schemas
  643. if provider_entity.provider_credential_schema
  644. else []
  645. )
  646. # Get decoding rsa key and cipher for decrypting credentials
  647. if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:
  648. self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(tenant_id)
  649. for variable in provider_credential_secret_variables:
  650. if variable in provider_credentials:
  651. try:
  652. provider_credentials[variable] = encrypter.decrypt_token_with_decoding(
  653. provider_credentials.get(variable, ""),
  654. self.decoding_rsa_key,
  655. self.decoding_cipher_rsa,
  656. )
  657. except ValueError:
  658. pass
  659. current_using_credentials = provider_credentials or {}
  660. # cache provider credentials
  661. provider_credentials_cache.set(credentials=current_using_credentials)
  662. else:
  663. current_using_credentials = cached_provider_credentials
  664. else:
  665. current_using_credentials = {}
  666. quota_configurations = []
  667. return SystemConfiguration(
  668. enabled=True,
  669. current_quota_type=current_quota_type,
  670. quota_configurations=quota_configurations,
  671. credentials=current_using_credentials,
  672. )
  673. @staticmethod
  674. def _choice_current_using_quota_type(quota_configurations: list[QuotaConfiguration]) -> ProviderQuotaType:
  675. """
  676. Choice current using quota type.
  677. paid quotas > provider free quotas > hosting trial quotas
  678. If there is still quota for the corresponding quota type according to the sorting,
  679. :param quota_configurations:
  680. :return:
  681. """
  682. # convert to dict
  683. quota_type_to_quota_configuration_dict = {
  684. quota_configuration.quota_type: quota_configuration for quota_configuration in quota_configurations
  685. }
  686. last_quota_configuration = None
  687. for quota_type in [ProviderQuotaType.PAID, ProviderQuotaType.FREE, ProviderQuotaType.TRIAL]:
  688. if quota_type in quota_type_to_quota_configuration_dict:
  689. last_quota_configuration = quota_type_to_quota_configuration_dict[quota_type]
  690. if last_quota_configuration.is_valid:
  691. return quota_type
  692. if last_quota_configuration:
  693. return last_quota_configuration.quota_type
  694. raise ValueError("No quota type available")
  695. @staticmethod
  696. def _extract_secret_variables(credential_form_schemas: list[CredentialFormSchema]) -> list[str]:
  697. """
  698. Extract secret input form variables.
  699. :param credential_form_schemas:
  700. :return:
  701. """
  702. secret_input_form_variables = []
  703. for credential_form_schema in credential_form_schemas:
  704. if credential_form_schema.type == FormType.SECRET_INPUT:
  705. secret_input_form_variables.append(credential_form_schema.variable)
  706. return secret_input_form_variables
  707. def _to_model_settings(
  708. self,
  709. provider_entity: ProviderEntity,
  710. provider_model_settings: Optional[list[ProviderModelSetting]] = None,
  711. load_balancing_model_configs: Optional[list[LoadBalancingModelConfig]] = None,
  712. ) -> list[ModelSettings]:
  713. """
  714. Convert to model settings.
  715. :param provider_entity: provider entity
  716. :param provider_model_settings: provider model settings include enabled, load balancing enabled
  717. :param load_balancing_model_configs: load balancing model configs
  718. :return:
  719. """
  720. # Get provider model credential secret variables
  721. if ConfigurateMethod.PREDEFINED_MODEL in provider_entity.configurate_methods:
  722. model_credential_secret_variables = self._extract_secret_variables(
  723. provider_entity.provider_credential_schema.credential_form_schemas
  724. if provider_entity.provider_credential_schema
  725. else []
  726. )
  727. else:
  728. model_credential_secret_variables = self._extract_secret_variables(
  729. provider_entity.model_credential_schema.credential_form_schemas
  730. if provider_entity.model_credential_schema
  731. else []
  732. )
  733. model_settings: list[ModelSettings] = []
  734. if not provider_model_settings:
  735. return model_settings
  736. for provider_model_setting in provider_model_settings:
  737. load_balancing_configs = []
  738. if provider_model_setting.load_balancing_enabled and load_balancing_model_configs:
  739. for load_balancing_model_config in load_balancing_model_configs:
  740. if (
  741. load_balancing_model_config.model_name == provider_model_setting.model_name
  742. and load_balancing_model_config.model_type == provider_model_setting.model_type
  743. ):
  744. if not load_balancing_model_config.enabled:
  745. continue
  746. if not load_balancing_model_config.encrypted_config:
  747. if load_balancing_model_config.name == "__inherit__":
  748. load_balancing_configs.append(
  749. ModelLoadBalancingConfiguration(
  750. id=load_balancing_model_config.id,
  751. name=load_balancing_model_config.name,
  752. credentials={},
  753. )
  754. )
  755. continue
  756. provider_model_credentials_cache = ProviderCredentialsCache(
  757. tenant_id=load_balancing_model_config.tenant_id,
  758. identity_id=load_balancing_model_config.id,
  759. cache_type=ProviderCredentialsCacheType.LOAD_BALANCING_MODEL,
  760. )
  761. # Get cached provider model credentials
  762. cached_provider_model_credentials = provider_model_credentials_cache.get()
  763. if not cached_provider_model_credentials:
  764. try:
  765. provider_model_credentials = json.loads(load_balancing_model_config.encrypted_config)
  766. except JSONDecodeError:
  767. continue
  768. # Get decoding rsa key and cipher for decrypting credentials
  769. if self.decoding_rsa_key is None or self.decoding_cipher_rsa is None:
  770. self.decoding_rsa_key, self.decoding_cipher_rsa = encrypter.get_decrypt_decoding(
  771. load_balancing_model_config.tenant_id
  772. )
  773. for variable in model_credential_secret_variables:
  774. if variable in provider_model_credentials:
  775. try:
  776. provider_model_credentials[variable] = encrypter.decrypt_token_with_decoding(
  777. provider_model_credentials.get(variable),
  778. self.decoding_rsa_key,
  779. self.decoding_cipher_rsa,
  780. )
  781. except ValueError:
  782. pass
  783. # cache provider model credentials
  784. provider_model_credentials_cache.set(credentials=provider_model_credentials)
  785. else:
  786. provider_model_credentials = cached_provider_model_credentials
  787. load_balancing_configs.append(
  788. ModelLoadBalancingConfiguration(
  789. id=load_balancing_model_config.id,
  790. name=load_balancing_model_config.name,
  791. credentials=provider_model_credentials,
  792. )
  793. )
  794. model_settings.append(
  795. ModelSettings(
  796. model=provider_model_setting.model_name,
  797. model_type=ModelType.value_of(provider_model_setting.model_type),
  798. enabled=provider_model_setting.enabled,
  799. load_balancing_configs=load_balancing_configs if len(load_balancing_configs) > 1 else [],
  800. )
  801. )
  802. return model_settings