Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

provider_manager.py 43KB

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