Co-authored-by: takatost <takatost@gmail.com>tags/0.5.3
| 'HOSTED_OPENAI_QUOTA_LIMIT': 200, | 'HOSTED_OPENAI_QUOTA_LIMIT': 200, | ||||
| 'HOSTED_OPENAI_TRIAL_ENABLED': 'False', | 'HOSTED_OPENAI_TRIAL_ENABLED': 'False', | ||||
| 'HOSTED_OPENAI_PAID_ENABLED': 'False', | 'HOSTED_OPENAI_PAID_ENABLED': 'False', | ||||
| 'HOSTED_OPENAI_PAID_INCREASE_QUOTA': 1, | |||||
| 'HOSTED_OPENAI_PAID_MIN_QUANTITY': 1, | |||||
| 'HOSTED_OPENAI_PAID_MAX_QUANTITY': 1, | |||||
| 'HOSTED_AZURE_OPENAI_ENABLED': 'False', | 'HOSTED_AZURE_OPENAI_ENABLED': 'False', | ||||
| 'HOSTED_AZURE_OPENAI_QUOTA_LIMIT': 200, | 'HOSTED_AZURE_OPENAI_QUOTA_LIMIT': 200, | ||||
| 'HOSTED_ANTHROPIC_QUOTA_LIMIT': 600000, | 'HOSTED_ANTHROPIC_QUOTA_LIMIT': 600000, | ||||
| 'HOSTED_ANTHROPIC_TRIAL_ENABLED': 'False', | 'HOSTED_ANTHROPIC_TRIAL_ENABLED': 'False', | ||||
| 'HOSTED_ANTHROPIC_PAID_ENABLED': 'False', | 'HOSTED_ANTHROPIC_PAID_ENABLED': 'False', | ||||
| 'HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA': 1, | |||||
| 'HOSTED_ANTHROPIC_PAID_MIN_QUANTITY': 1, | |||||
| 'HOSTED_ANTHROPIC_PAID_MAX_QUANTITY': 1, | |||||
| 'HOSTED_MODERATION_ENABLED': 'False', | 'HOSTED_MODERATION_ENABLED': 'False', | ||||
| 'HOSTED_MODERATION_PROVIDERS': '', | 'HOSTED_MODERATION_PROVIDERS': '', | ||||
| 'CLEAN_DAY_SETTING': 30, | 'CLEAN_DAY_SETTING': 30, | ||||
| self.HOSTED_OPENAI_TRIAL_ENABLED = get_bool_env('HOSTED_OPENAI_TRIAL_ENABLED') | self.HOSTED_OPENAI_TRIAL_ENABLED = get_bool_env('HOSTED_OPENAI_TRIAL_ENABLED') | ||||
| self.HOSTED_OPENAI_QUOTA_LIMIT = int(get_env('HOSTED_OPENAI_QUOTA_LIMIT')) | self.HOSTED_OPENAI_QUOTA_LIMIT = int(get_env('HOSTED_OPENAI_QUOTA_LIMIT')) | ||||
| self.HOSTED_OPENAI_PAID_ENABLED = get_bool_env('HOSTED_OPENAI_PAID_ENABLED') | self.HOSTED_OPENAI_PAID_ENABLED = get_bool_env('HOSTED_OPENAI_PAID_ENABLED') | ||||
| self.HOSTED_OPENAI_PAID_STRIPE_PRICE_ID = get_env('HOSTED_OPENAI_PAID_STRIPE_PRICE_ID') | |||||
| self.HOSTED_OPENAI_PAID_INCREASE_QUOTA = int(get_env('HOSTED_OPENAI_PAID_INCREASE_QUOTA')) | |||||
| self.HOSTED_OPENAI_PAID_MIN_QUANTITY = int(get_env('HOSTED_OPENAI_PAID_MIN_QUANTITY')) | |||||
| self.HOSTED_OPENAI_PAID_MAX_QUANTITY = int(get_env('HOSTED_OPENAI_PAID_MAX_QUANTITY')) | |||||
| self.HOSTED_AZURE_OPENAI_ENABLED = get_bool_env('HOSTED_AZURE_OPENAI_ENABLED') | self.HOSTED_AZURE_OPENAI_ENABLED = get_bool_env('HOSTED_AZURE_OPENAI_ENABLED') | ||||
| self.HOSTED_AZURE_OPENAI_API_KEY = get_env('HOSTED_AZURE_OPENAI_API_KEY') | self.HOSTED_AZURE_OPENAI_API_KEY = get_env('HOSTED_AZURE_OPENAI_API_KEY') | ||||
| self.HOSTED_ANTHROPIC_TRIAL_ENABLED = get_bool_env('HOSTED_ANTHROPIC_TRIAL_ENABLED') | self.HOSTED_ANTHROPIC_TRIAL_ENABLED = get_bool_env('HOSTED_ANTHROPIC_TRIAL_ENABLED') | ||||
| self.HOSTED_ANTHROPIC_QUOTA_LIMIT = int(get_env('HOSTED_ANTHROPIC_QUOTA_LIMIT')) | self.HOSTED_ANTHROPIC_QUOTA_LIMIT = int(get_env('HOSTED_ANTHROPIC_QUOTA_LIMIT')) | ||||
| self.HOSTED_ANTHROPIC_PAID_ENABLED = get_bool_env('HOSTED_ANTHROPIC_PAID_ENABLED') | self.HOSTED_ANTHROPIC_PAID_ENABLED = get_bool_env('HOSTED_ANTHROPIC_PAID_ENABLED') | ||||
| self.HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID = get_env('HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID') | |||||
| self.HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA = int(get_env('HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA')) | |||||
| self.HOSTED_ANTHROPIC_PAID_MIN_QUANTITY = int(get_env('HOSTED_ANTHROPIC_PAID_MIN_QUANTITY')) | |||||
| self.HOSTED_ANTHROPIC_PAID_MAX_QUANTITY = int(get_env('HOSTED_ANTHROPIC_PAID_MAX_QUANTITY')) | |||||
| self.HOSTED_MINIMAX_ENABLED = get_bool_env('HOSTED_MINIMAX_ENABLED') | self.HOSTED_MINIMAX_ENABLED = get_bool_env('HOSTED_MINIMAX_ENABLED') | ||||
| self.HOSTED_SPARK_ENABLED = get_bool_env('HOSTED_SPARK_ENABLED') | self.HOSTED_SPARK_ENABLED = get_bool_env('HOSTED_SPARK_ENABLED') |
| parser.add_argument('interval', type=str, required=True, location='args', choices=['month', 'year']) | parser.add_argument('interval', type=str, required=True, location='args', choices=['month', 'year']) | ||||
| args = parser.parse_args() | args = parser.parse_args() | ||||
| BillingService.is_tenant_owner(current_user) | |||||
| BillingService.is_tenant_owner_or_admin(current_user) | |||||
| return BillingService.get_subscription(args['plan'], | return BillingService.get_subscription(args['plan'], | ||||
| args['interval'], | args['interval'], | ||||
| @account_initialization_required | @account_initialization_required | ||||
| @only_edition_cloud | @only_edition_cloud | ||||
| def get(self): | def get(self): | ||||
| BillingService.is_tenant_owner(current_user) | |||||
| return BillingService.get_invoices(current_user.email) | |||||
| BillingService.is_tenant_owner_or_admin(current_user) | |||||
| return BillingService.get_invoices(current_user.email, current_user.current_tenant_id) | |||||
| api.add_resource(Subscription, '/billing/subscription') | api.add_resource(Subscription, '/billing/subscription') |
| def get(self, provider: str): | def get(self, provider: str): | ||||
| if provider != 'anthropic': | if provider != 'anthropic': | ||||
| raise ValueError(f'provider name {provider} is invalid') | raise ValueError(f'provider name {provider} is invalid') | ||||
| BillingService.is_tenant_owner_or_admin(current_user) | |||||
| data = BillingService.get_model_provider_payment_link(provider_name=provider, | data = BillingService.get_model_provider_payment_link(provider_name=provider, | ||||
| tenant_id=current_user.current_tenant_id, | tenant_id=current_user.current_tenant_id, | ||||
| account_id=current_user.id) | |||||
| account_id=current_user.id, | |||||
| prefilled_email=current_user.email) | |||||
| return data | return data | ||||
| class QuotaUnit(Enum): | class QuotaUnit(Enum): | ||||
| TIMES = 'times' | TIMES = 'times' | ||||
| TOKENS = 'tokens' | TOKENS = 'tokens' | ||||
| CREDITS = 'credits' | |||||
| class SystemConfigurationStatus(Enum): | class SystemConfigurationStatus(Enum): |
| class PaidHostingQuota(HostingQuota): | class PaidHostingQuota(HostingQuota): | ||||
| quota_type: ProviderQuotaType = ProviderQuotaType.PAID | quota_type: ProviderQuotaType = ProviderQuotaType.PAID | ||||
| stripe_price_id: str = None | |||||
| increase_quota: int = 1 | |||||
| min_quantity: int = 20 | |||||
| max_quantity: int = 100 | |||||
| class FreeHostingQuota(HostingQuota): | class FreeHostingQuota(HostingQuota): | ||||
| ) | ) | ||||
| def init_openai(self, app_config: Config) -> HostingProvider: | def init_openai(self, app_config: Config) -> HostingProvider: | ||||
| quota_unit = QuotaUnit.TIMES | |||||
| quota_unit = QuotaUnit.CREDITS | |||||
| quotas = [] | quotas = [] | ||||
| if app_config.get("HOSTED_OPENAI_TRIAL_ENABLED"): | if app_config.get("HOSTED_OPENAI_TRIAL_ENABLED"): | ||||
| RestrictModel(model="gpt-3.5-turbo-1106", model_type=ModelType.LLM), | RestrictModel(model="gpt-3.5-turbo-1106", model_type=ModelType.LLM), | ||||
| RestrictModel(model="gpt-3.5-turbo-instruct", model_type=ModelType.LLM), | RestrictModel(model="gpt-3.5-turbo-instruct", model_type=ModelType.LLM), | ||||
| RestrictModel(model="gpt-3.5-turbo-16k", model_type=ModelType.LLM), | RestrictModel(model="gpt-3.5-turbo-16k", model_type=ModelType.LLM), | ||||
| RestrictModel(model="gpt-3.5-turbo-16k-0613", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-0613", model_type=ModelType.LLM), | |||||
| RestrictModel(model="text-davinci-003", model_type=ModelType.LLM), | RestrictModel(model="text-davinci-003", model_type=ModelType.LLM), | ||||
| RestrictModel(model="whisper-1", model_type=ModelType.SPEECH2TEXT), | RestrictModel(model="whisper-1", model_type=ModelType.SPEECH2TEXT), | ||||
| ] | ] | ||||
| if app_config.get("HOSTED_OPENAI_PAID_ENABLED"): | if app_config.get("HOSTED_OPENAI_PAID_ENABLED"): | ||||
| paid_quota = PaidHostingQuota( | paid_quota = PaidHostingQuota( | ||||
| stripe_price_id=app_config.get("HOSTED_OPENAI_PAID_STRIPE_PRICE_ID"), | |||||
| increase_quota=int(app_config.get("HOSTED_OPENAI_PAID_INCREASE_QUOTA", "1")), | |||||
| min_quantity=int(app_config.get("HOSTED_OPENAI_PAID_MIN_QUANTITY", "1")), | |||||
| max_quantity=int(app_config.get("HOSTED_OPENAI_PAID_MAX_QUANTITY", "1")) | |||||
| restrict_models=[ | |||||
| RestrictModel(model="gpt-4", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-4-turbo-preview", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-4-32k", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-4-1106-preview", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-16k", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-16k-0613", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-1106", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-4-0125-preview", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-0613", model_type=ModelType.LLM), | |||||
| RestrictModel(model="gpt-3.5-turbo-instruct", model_type=ModelType.LLM), | |||||
| RestrictModel(model="text-davinci-003", model_type=ModelType.LLM), | |||||
| ] | |||||
| ) | ) | ||||
| quotas.append(paid_quota) | quotas.append(paid_quota) | ||||
| quotas.append(trial_quota) | quotas.append(trial_quota) | ||||
| if app_config.get("HOSTED_ANTHROPIC_PAID_ENABLED"): | if app_config.get("HOSTED_ANTHROPIC_PAID_ENABLED"): | ||||
| paid_quota = PaidHostingQuota( | |||||
| stripe_price_id=app_config.get("HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID"), | |||||
| increase_quota=int(app_config.get("HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA", "1000000")), | |||||
| min_quantity=int(app_config.get("HOSTED_ANTHROPIC_PAID_MIN_QUANTITY", "20")), | |||||
| max_quantity=int(app_config.get("HOSTED_ANTHROPIC_PAID_MAX_QUANTITY", "100")) | |||||
| ) | |||||
| paid_quota = PaidHostingQuota() | |||||
| quotas.append(paid_quota) | quotas.append(paid_quota) | ||||
| if len(quotas) > 0: | if len(quotas) > 0: |
| output: '0.002' | output: '0.002' | ||||
| unit: '0.001' | unit: '0.001' | ||||
| currency: USD | currency: USD | ||||
| deprecated: true |
| if quota_unit: | if quota_unit: | ||||
| if quota_unit == QuotaUnit.TOKENS: | if quota_unit == QuotaUnit.TOKENS: | ||||
| used_quota = message.message_tokens + message.answer_tokens | used_quota = message.message_tokens + message.answer_tokens | ||||
| elif quota_unit == QuotaUnit.CREDITS: | |||||
| used_quota = 1 | |||||
| if 'gpt-4' in model_config.model: | |||||
| used_quota = 20 | |||||
| else: | else: | ||||
| used_quota = 1 | used_quota = 1 | ||||
| def get_model_provider_payment_link(cls, | def get_model_provider_payment_link(cls, | ||||
| provider_name: str, | provider_name: str, | ||||
| tenant_id: str, | tenant_id: str, | ||||
| account_id: str): | |||||
| account_id: str, | |||||
| prefilled_email: str): | |||||
| params = { | params = { | ||||
| 'provider_name': provider_name, | 'provider_name': provider_name, | ||||
| 'tenant_id': tenant_id, | 'tenant_id': tenant_id, | ||||
| 'account_id': account_id | |||||
| 'account_id': account_id, | |||||
| 'prefilled_email': prefilled_email | |||||
| } | } | ||||
| return cls._send_request('GET', '/model-provider/payment-link', params=params) | return cls._send_request('GET', '/model-provider/payment-link', params=params) | ||||
| @classmethod | @classmethod | ||||
| def get_invoices(cls, prefilled_email: str = ''): | |||||
| params = {'prefilled_email': prefilled_email} | |||||
| def get_invoices(cls, prefilled_email: str = '', tenant_id: str = ''): | |||||
| params = { | |||||
| 'prefilled_email': prefilled_email, | |||||
| 'tenant_id': tenant_id | |||||
| } | |||||
| return cls._send_request('GET', '/invoices', params=params) | return cls._send_request('GET', '/invoices', params=params) | ||||
| @classmethod | @classmethod | ||||
| return response.json() | return response.json() | ||||
| @staticmethod | @staticmethod | ||||
| def is_tenant_owner(current_user): | |||||
| def is_tenant_owner_or_admin(current_user): | |||||
| tenant_id = current_user.current_tenant_id | tenant_id = current_user.current_tenant_id | ||||
| join = db.session.query(TenantAccountJoin).filter( | join = db.session.query(TenantAccountJoin).filter( | ||||
| TenantAccountJoin.account_id == current_user.id | TenantAccountJoin.account_id == current_user.id | ||||
| ).first() | ).first() | ||||
| if join.role != 'owner': | |||||
| raise ValueError('Only tenant owner can perform this action') | |||||
| if join.role not in ['owner', 'admin']: | |||||
| raise ValueError('Only team owner or team admin can perform this action') |