base.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. from abc import ABC, abstractmethod
  2. from datetime import datetime
  3. from typing import Type, Optional
  4. from flask import current_app
  5. from pydantic import BaseModel
  6. from core.model_providers.error import QuotaExceededError, LLMBadRequestError
  7. from extensions.ext_database import db
  8. from core.model_providers.models.entity.model_params import ModelType, ModelKwargsRules
  9. from core.model_providers.models.entity.provider import ProviderQuotaUnit
  10. from core.model_providers.rules import provider_rules
  11. from models.provider import Provider, ProviderType, ProviderModel
  12. class BaseModelProvider(BaseModel, ABC):
  13. provider: Provider
  14. class Config:
  15. """Configuration for this pydantic object."""
  16. arbitrary_types_allowed = True
  17. @property
  18. @abstractmethod
  19. def provider_name(self):
  20. """
  21. Returns the name of a provider.
  22. """
  23. raise NotImplementedError
  24. def get_rules(self):
  25. """
  26. Returns the rules of a provider.
  27. """
  28. return provider_rules[self.provider_name]
  29. def get_supported_model_list(self, model_type: ModelType) -> list[dict]:
  30. """
  31. get supported model object list for use.
  32. :param model_type:
  33. :return:
  34. """
  35. rules = self.get_rules()
  36. if 'custom' not in rules['support_provider_types']:
  37. return self._get_fixed_model_list(model_type)
  38. if 'model_flexibility' not in rules:
  39. return self._get_fixed_model_list(model_type)
  40. if rules['model_flexibility'] == 'fixed':
  41. return self._get_fixed_model_list(model_type)
  42. # get configurable provider models
  43. provider_models = db.session.query(ProviderModel).filter(
  44. ProviderModel.tenant_id == self.provider.tenant_id,
  45. ProviderModel.provider_name == self.provider.provider_name,
  46. ProviderModel.model_type == model_type.value,
  47. ProviderModel.is_valid == True
  48. ).order_by(ProviderModel.created_at.asc()).all()
  49. provider_model_list = []
  50. for provider_model in provider_models:
  51. provider_model_dict = {
  52. 'id': provider_model.model_name,
  53. 'name': provider_model.model_name
  54. }
  55. if model_type == ModelType.TEXT_GENERATION:
  56. provider_model_dict['mode'] = self._get_text_generation_model_mode(provider_model.model_name)
  57. provider_model_list.append(provider_model_dict)
  58. return provider_model_list
  59. @abstractmethod
  60. def _get_fixed_model_list(self, model_type: ModelType) -> list[dict]:
  61. """
  62. get supported model object list for use.
  63. :param model_type:
  64. :return:
  65. """
  66. raise NotImplementedError
  67. @abstractmethod
  68. def _get_text_generation_model_mode(self, model_name) -> str:
  69. """
  70. get text generation model mode.
  71. :param model_name:
  72. :return:
  73. """
  74. raise NotImplementedError
  75. @abstractmethod
  76. def get_model_class(self, model_type: ModelType) -> Type:
  77. """
  78. get specific model class.
  79. :param model_type:
  80. :return:
  81. """
  82. raise NotImplementedError
  83. @classmethod
  84. @abstractmethod
  85. def is_provider_credentials_valid_or_raise(cls, credentials: dict):
  86. """
  87. check provider credentials valid.
  88. :param credentials:
  89. """
  90. raise NotImplementedError
  91. @classmethod
  92. @abstractmethod
  93. def encrypt_provider_credentials(cls, tenant_id: str, credentials: dict) -> dict:
  94. """
  95. encrypt provider credentials for save.
  96. :param tenant_id:
  97. :param credentials:
  98. :return:
  99. """
  100. raise NotImplementedError
  101. @abstractmethod
  102. def get_provider_credentials(self, obfuscated: bool = False) -> dict:
  103. """
  104. get credentials for llm use.
  105. :param obfuscated:
  106. :return:
  107. """
  108. raise NotImplementedError
  109. @classmethod
  110. @abstractmethod
  111. def is_model_credentials_valid_or_raise(cls, model_name: str, model_type: ModelType, credentials: dict):
  112. """
  113. check model credentials valid.
  114. :param model_name:
  115. :param model_type:
  116. :param credentials:
  117. """
  118. raise NotImplementedError
  119. @classmethod
  120. @abstractmethod
  121. def encrypt_model_credentials(cls, tenant_id: str, model_name: str, model_type: ModelType,
  122. credentials: dict) -> dict:
  123. """
  124. encrypt model credentials for save.
  125. :param tenant_id:
  126. :param model_name:
  127. :param model_type:
  128. :param credentials:
  129. :return:
  130. """
  131. raise NotImplementedError
  132. @abstractmethod
  133. def get_model_parameter_rules(self, model_name: str, model_type: ModelType) -> ModelKwargsRules:
  134. """
  135. get model parameter rules.
  136. :param model_name:
  137. :param model_type:
  138. :return:
  139. """
  140. raise NotImplementedError
  141. @abstractmethod
  142. def get_model_credentials(self, model_name: str, model_type: ModelType, obfuscated: bool = False) -> dict:
  143. """
  144. get credentials for llm use.
  145. :param model_name:
  146. :param model_type:
  147. :param obfuscated:
  148. :return:
  149. """
  150. raise NotImplementedError
  151. @classmethod
  152. def is_provider_type_system_supported(cls) -> bool:
  153. return current_app.config['EDITION'] == 'CLOUD'
  154. def check_quota_over_limit(self):
  155. """
  156. check provider quota over limit.
  157. :return:
  158. """
  159. if self.provider.provider_type != ProviderType.SYSTEM.value:
  160. return
  161. rules = self.get_rules()
  162. if 'system' not in rules['support_provider_types']:
  163. return
  164. provider = db.session.query(Provider).filter(
  165. db.and_(
  166. Provider.id == self.provider.id,
  167. Provider.is_valid == True,
  168. Provider.quota_limit > Provider.quota_used
  169. )
  170. ).first()
  171. if not provider:
  172. raise QuotaExceededError()
  173. def deduct_quota(self, used_tokens: int = 0) -> None:
  174. """
  175. deduct available quota when provider type is system or paid.
  176. :return:
  177. """
  178. if self.provider.provider_type != ProviderType.SYSTEM.value:
  179. return
  180. rules = self.get_rules()
  181. if 'system' not in rules['support_provider_types']:
  182. return
  183. if not self.should_deduct_quota():
  184. return
  185. if 'system_config' not in rules:
  186. quota_unit = ProviderQuotaUnit.TIMES.value
  187. elif 'quota_unit' not in rules['system_config']:
  188. quota_unit = ProviderQuotaUnit.TIMES.value
  189. else:
  190. quota_unit = rules['system_config']['quota_unit']
  191. if quota_unit == ProviderQuotaUnit.TOKENS.value:
  192. used_quota = used_tokens
  193. else:
  194. used_quota = 1
  195. db.session.query(Provider).filter(
  196. Provider.tenant_id == self.provider.tenant_id,
  197. Provider.provider_name == self.provider.provider_name,
  198. Provider.provider_type == self.provider.provider_type,
  199. Provider.quota_type == self.provider.quota_type,
  200. Provider.quota_limit > Provider.quota_used
  201. ).update({'quota_used': Provider.quota_used + used_quota})
  202. db.session.commit()
  203. def should_deduct_quota(self):
  204. return False
  205. def update_last_used(self) -> None:
  206. """
  207. update last used time.
  208. :return:
  209. """
  210. db.session.query(Provider).filter(
  211. Provider.tenant_id == self.provider.tenant_id,
  212. Provider.provider_name == self.provider.provider_name
  213. ).update({'last_used': datetime.utcnow()})
  214. db.session.commit()
  215. def _get_provider_model(self, model_name: str, model_type: ModelType) -> ProviderModel:
  216. """
  217. get provider model.
  218. :param model_name:
  219. :param model_type:
  220. :return:
  221. """
  222. provider_model = db.session.query(ProviderModel).filter(
  223. ProviderModel.tenant_id == self.provider.tenant_id,
  224. ProviderModel.provider_name == self.provider.provider_name,
  225. ProviderModel.model_name == model_name,
  226. ProviderModel.model_type == model_type.value,
  227. ProviderModel.is_valid == True
  228. ).first()
  229. if not provider_model:
  230. raise LLMBadRequestError(f"The model {model_name} does not exist. "
  231. f"Please check the configuration.")
  232. return provider_model
  233. class CredentialsValidateFailedError(Exception):
  234. pass