mirror of
https://github.com/langgenius/dify.git
synced 2024-11-16 11:42:29 +08:00
feat: claude paid optimize (#890)
This commit is contained in:
parent
2f7b234cc5
commit
9adbeadeec
|
@ -117,10 +117,12 @@ HOSTED_AZURE_OPENAI_QUOTA_LIMIT=200
|
||||||
HOSTED_ANTHROPIC_ENABLED=false
|
HOSTED_ANTHROPIC_ENABLED=false
|
||||||
HOSTED_ANTHROPIC_API_BASE=
|
HOSTED_ANTHROPIC_API_BASE=
|
||||||
HOSTED_ANTHROPIC_API_KEY=
|
HOSTED_ANTHROPIC_API_KEY=
|
||||||
HOSTED_ANTHROPIC_QUOTA_LIMIT=1000000
|
HOSTED_ANTHROPIC_QUOTA_LIMIT=600000
|
||||||
HOSTED_ANTHROPIC_PAID_ENABLED=false
|
HOSTED_ANTHROPIC_PAID_ENABLED=false
|
||||||
HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID=
|
HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID=
|
||||||
HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA=1
|
HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA=1000000
|
||||||
|
HOSTED_ANTHROPIC_PAID_MIN_QUANTITY=20
|
||||||
|
HOSTED_ANTHROPIC_PAID_MAX_QUANTITY=100
|
||||||
|
|
||||||
STRIPE_API_KEY=
|
STRIPE_API_KEY=
|
||||||
STRIPE_WEBHOOK_SECRET=
|
STRIPE_WEBHOOK_SECRET=
|
|
@ -258,6 +258,8 @@ def sync_anthropic_hosted_providers():
|
||||||
click.echo(click.style('Start sync anthropic hosted providers.', fg='green'))
|
click.echo(click.style('Start sync anthropic hosted providers.', fg='green'))
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
new_quota_limit = hosted_model_providers.anthropic.quota_limit
|
||||||
|
|
||||||
page = 1
|
page = 1
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -265,6 +267,7 @@ def sync_anthropic_hosted_providers():
|
||||||
Provider.provider_name == 'anthropic',
|
Provider.provider_name == 'anthropic',
|
||||||
Provider.provider_type == ProviderType.SYSTEM.value,
|
Provider.provider_type == ProviderType.SYSTEM.value,
|
||||||
Provider.quota_type == ProviderQuotaType.TRIAL.value,
|
Provider.quota_type == ProviderQuotaType.TRIAL.value,
|
||||||
|
Provider.quota_limit != new_quota_limit
|
||||||
).order_by(Provider.created_at.desc()).paginate(page=page, per_page=100)
|
).order_by(Provider.created_at.desc()).paginate(page=page, per_page=100)
|
||||||
except NotFound:
|
except NotFound:
|
||||||
break
|
break
|
||||||
|
@ -272,9 +275,9 @@ def sync_anthropic_hosted_providers():
|
||||||
page += 1
|
page += 1
|
||||||
for provider in providers:
|
for provider in providers:
|
||||||
try:
|
try:
|
||||||
click.echo('Syncing tenant anthropic hosted provider: {}'.format(provider.tenant_id))
|
click.echo('Syncing tenant anthropic hosted provider: {}, origin: limit {}, used {}'
|
||||||
|
.format(provider.tenant_id, provider.quota_limit, provider.quota_used))
|
||||||
original_quota_limit = provider.quota_limit
|
original_quota_limit = provider.quota_limit
|
||||||
new_quota_limit = hosted_model_providers.anthropic.quota_limit
|
|
||||||
division = math.ceil(new_quota_limit / 1000)
|
division = math.ceil(new_quota_limit / 1000)
|
||||||
|
|
||||||
provider.quota_limit = new_quota_limit if original_quota_limit == 1000 \
|
provider.quota_limit = new_quota_limit if original_quota_limit == 1000 \
|
||||||
|
|
|
@ -57,10 +57,12 @@ DEFAULTS = {
|
||||||
'HOSTED_OPENAI_PAID_INCREASE_QUOTA': 1,
|
'HOSTED_OPENAI_PAID_INCREASE_QUOTA': 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': 1000000,
|
'HOSTED_ANTHROPIC_QUOTA_LIMIT': 600000,
|
||||||
'HOSTED_ANTHROPIC_ENABLED': 'False',
|
'HOSTED_ANTHROPIC_ENABLED': 'False',
|
||||||
'HOSTED_ANTHROPIC_PAID_ENABLED': 'False',
|
'HOSTED_ANTHROPIC_PAID_ENABLED': 'False',
|
||||||
'HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA': 1,
|
'HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA': 1000000,
|
||||||
|
'HOSTED_ANTHROPIC_PAID_MIN_QUANTITY': 20,
|
||||||
|
'HOSTED_ANTHROPIC_PAID_MAX_QUANTITY': 100,
|
||||||
'TENANT_DOCUMENT_COUNT': 100,
|
'TENANT_DOCUMENT_COUNT': 100,
|
||||||
'CLEAN_DAY_SETTING': 30,
|
'CLEAN_DAY_SETTING': 30,
|
||||||
'UPLOAD_FILE_SIZE_LIMIT': 15,
|
'UPLOAD_FILE_SIZE_LIMIT': 15,
|
||||||
|
@ -211,7 +213,7 @@ class Config:
|
||||||
self.HOSTED_OPENAI_API_KEY = get_env('HOSTED_OPENAI_API_KEY')
|
self.HOSTED_OPENAI_API_KEY = get_env('HOSTED_OPENAI_API_KEY')
|
||||||
self.HOSTED_OPENAI_API_BASE = get_env('HOSTED_OPENAI_API_BASE')
|
self.HOSTED_OPENAI_API_BASE = get_env('HOSTED_OPENAI_API_BASE')
|
||||||
self.HOSTED_OPENAI_API_ORGANIZATION = get_env('HOSTED_OPENAI_API_ORGANIZATION')
|
self.HOSTED_OPENAI_API_ORGANIZATION = get_env('HOSTED_OPENAI_API_ORGANIZATION')
|
||||||
self.HOSTED_OPENAI_QUOTA_LIMIT = 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_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_INCREASE_QUOTA = int(get_env('HOSTED_OPENAI_PAID_INCREASE_QUOTA'))
|
||||||
|
@ -219,15 +221,17 @@ class Config:
|
||||||
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_AZURE_OPENAI_API_BASE = get_env('HOSTED_AZURE_OPENAI_API_BASE')
|
self.HOSTED_AZURE_OPENAI_API_BASE = get_env('HOSTED_AZURE_OPENAI_API_BASE')
|
||||||
self.HOSTED_AZURE_OPENAI_QUOTA_LIMIT = get_env('HOSTED_AZURE_OPENAI_QUOTA_LIMIT')
|
self.HOSTED_AZURE_OPENAI_QUOTA_LIMIT = int(get_env('HOSTED_AZURE_OPENAI_QUOTA_LIMIT'))
|
||||||
|
|
||||||
self.HOSTED_ANTHROPIC_ENABLED = get_bool_env('HOSTED_ANTHROPIC_ENABLED')
|
self.HOSTED_ANTHROPIC_ENABLED = get_bool_env('HOSTED_ANTHROPIC_ENABLED')
|
||||||
self.HOSTED_ANTHROPIC_API_BASE = get_env('HOSTED_ANTHROPIC_API_BASE')
|
self.HOSTED_ANTHROPIC_API_BASE = get_env('HOSTED_ANTHROPIC_API_BASE')
|
||||||
self.HOSTED_ANTHROPIC_API_KEY = get_env('HOSTED_ANTHROPIC_API_KEY')
|
self.HOSTED_ANTHROPIC_API_KEY = get_env('HOSTED_ANTHROPIC_API_KEY')
|
||||||
self.HOSTED_ANTHROPIC_QUOTA_LIMIT = 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_STRIPE_PRICE_ID = get_env('HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID')
|
||||||
self.HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA = get_env('HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA')
|
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.STRIPE_API_KEY = get_env('STRIPE_API_KEY')
|
self.STRIPE_API_KEY = get_env('STRIPE_API_KEY')
|
||||||
self.STRIPE_WEBHOOK_SECRET = get_env('STRIPE_WEBHOOK_SECRET')
|
self.STRIPE_WEBHOOK_SECRET = get_env('STRIPE_WEBHOOK_SECRET')
|
||||||
|
|
|
@ -38,12 +38,20 @@ class StripeWebhookApi(Resource):
|
||||||
logging.debug(event['data']['object']['payment_status'])
|
logging.debug(event['data']['object']['payment_status'])
|
||||||
logging.debug(event['data']['object']['metadata'])
|
logging.debug(event['data']['object']['metadata'])
|
||||||
|
|
||||||
|
session = stripe.checkout.Session.retrieve(
|
||||||
|
event['data']['object']['id'],
|
||||||
|
expand=['line_items'],
|
||||||
|
)
|
||||||
|
|
||||||
|
logging.debug(session.line_items['data'][0]['quantity'])
|
||||||
|
|
||||||
# Fulfill the purchase...
|
# Fulfill the purchase...
|
||||||
provider_checkout_service = ProviderCheckoutService()
|
provider_checkout_service = ProviderCheckoutService()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
provider_checkout_service.fulfill_provider_order(event)
|
provider_checkout_service.fulfill_provider_order(event, session.line_items)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
||||||
logging.debug(str(e))
|
logging.debug(str(e))
|
||||||
return 'success', 200
|
return 'success', 200
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,8 @@ class BaseLLM(BaseProviderModel):
|
||||||
completion_tokens = self.get_num_tokens([PromptMessage(content=completion_content, type=MessageType.ASSISTANT)])
|
completion_tokens = self.get_num_tokens([PromptMessage(content=completion_content, type=MessageType.ASSISTANT)])
|
||||||
total_tokens = prompt_tokens + completion_tokens
|
total_tokens = prompt_tokens + completion_tokens
|
||||||
|
|
||||||
|
self.model_provider.update_last_used()
|
||||||
|
|
||||||
if self.deduct_quota:
|
if self.deduct_quota:
|
||||||
self.model_provider.deduct_quota(total_tokens)
|
self.model_provider.deduct_quota(total_tokens)
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,8 @@ class AnthropicProvider(BaseModelProvider):
|
||||||
return {
|
return {
|
||||||
'product_id': hosted_model_providers.anthropic.paid_stripe_price_id,
|
'product_id': hosted_model_providers.anthropic.paid_stripe_price_id,
|
||||||
'increase_quota': hosted_model_providers.anthropic.paid_increase_quota,
|
'increase_quota': hosted_model_providers.anthropic.paid_increase_quota,
|
||||||
|
'min_quantity': hosted_model_providers.anthropic.paid_min_quantity,
|
||||||
|
'max_quantity': hosted_model_providers.anthropic.paid_max_quantity,
|
||||||
}
|
}
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -31,7 +31,9 @@ class HostedAnthropic(BaseModel):
|
||||||
"""Quota limit for the anthropic hosted model. 0 means unlimited."""
|
"""Quota limit for the anthropic hosted model. 0 means unlimited."""
|
||||||
paid_enabled: bool = False
|
paid_enabled: bool = False
|
||||||
paid_stripe_price_id: str = None
|
paid_stripe_price_id: str = None
|
||||||
paid_increase_quota: int = 1
|
paid_increase_quota: int = 1000000
|
||||||
|
paid_min_quantity: int = 20
|
||||||
|
paid_max_quantity: int = 100
|
||||||
|
|
||||||
|
|
||||||
class HostedModelProviders(BaseModel):
|
class HostedModelProviders(BaseModel):
|
||||||
|
@ -73,4 +75,6 @@ def init_app(app: Flask):
|
||||||
paid_enabled=app.config.get("HOSTED_ANTHROPIC_PAID_ENABLED"),
|
paid_enabled=app.config.get("HOSTED_ANTHROPIC_PAID_ENABLED"),
|
||||||
paid_stripe_price_id=app.config.get("HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID"),
|
paid_stripe_price_id=app.config.get("HOSTED_ANTHROPIC_PAID_STRIPE_PRICE_ID"),
|
||||||
paid_increase_quota=app.config.get("HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA"),
|
paid_increase_quota=app.config.get("HOSTED_ANTHROPIC_PAID_INCREASE_QUOTA"),
|
||||||
|
paid_min_quantity=app.config.get("HOSTED_ANTHROPIC_PAID_MIN_QUANTITY"),
|
||||||
|
paid_max_quantity=app.config.get("HOSTED_ANTHROPIC_PAID_MAX_QUANTITY"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
],
|
],
|
||||||
"system_config": {
|
"system_config": {
|
||||||
"supported_quota_types": [
|
"supported_quota_types": [
|
||||||
|
"paid",
|
||||||
"trial"
|
"trial"
|
||||||
],
|
],
|
||||||
"quota_unit": "times",
|
"quota_unit": "tokens",
|
||||||
"quota_limit": 1000
|
"quota_limit": 600000
|
||||||
},
|
},
|
||||||
"model_flexibility": "fixed"
|
"model_flexibility": "fixed"
|
||||||
}
|
}
|
|
@ -39,6 +39,8 @@ class ProviderCheckoutService:
|
||||||
raise ValueError(f'provider name {provider_name} not support payment')
|
raise ValueError(f'provider name {provider_name} not support payment')
|
||||||
|
|
||||||
payment_product_id = payment_info['product_id']
|
payment_product_id = payment_info['product_id']
|
||||||
|
payment_min_quantity = payment_info['min_quantity']
|
||||||
|
payment_max_quantity = payment_info['max_quantity']
|
||||||
|
|
||||||
# create provider order
|
# create provider order
|
||||||
provider_order = ProviderOrder(
|
provider_order = ProviderOrder(
|
||||||
|
@ -53,18 +55,29 @@ class ProviderCheckoutService:
|
||||||
db.session.add(provider_order)
|
db.session.add(provider_order)
|
||||||
db.session.flush()
|
db.session.flush()
|
||||||
|
|
||||||
|
line_item = {
|
||||||
|
'price': f'{payment_product_id}',
|
||||||
|
'quantity': payment_min_quantity
|
||||||
|
}
|
||||||
|
|
||||||
|
if payment_min_quantity > 1 and payment_max_quantity != payment_min_quantity:
|
||||||
|
line_item['adjustable_quantity'] = {
|
||||||
|
'enabled': True,
|
||||||
|
'minimum': payment_min_quantity,
|
||||||
|
'maximum': payment_max_quantity
|
||||||
|
}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# create stripe checkout session
|
# create stripe checkout session
|
||||||
checkout_session = stripe.checkout.Session.create(
|
checkout_session = stripe.checkout.Session.create(
|
||||||
line_items=[
|
line_items=[
|
||||||
{
|
line_item
|
||||||
'price': f'{payment_product_id}',
|
|
||||||
'quantity': 1,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
mode='payment',
|
mode='payment',
|
||||||
success_url=current_app.config.get("CONSOLE_WEB_URL") + '?provider_payment=succeeded',
|
success_url=current_app.config.get("CONSOLE_WEB_URL")
|
||||||
cancel_url=current_app.config.get("CONSOLE_WEB_URL") + '?provider_payment=cancelled',
|
+ f'?provider_name={provider_name}&payment_result=succeeded',
|
||||||
|
cancel_url=current_app.config.get("CONSOLE_WEB_URL")
|
||||||
|
+ f'?provider_name={provider_name}&payment_result=cancelled',
|
||||||
automatic_tax={'enabled': True},
|
automatic_tax={'enabled': True},
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -76,7 +89,7 @@ class ProviderCheckoutService:
|
||||||
|
|
||||||
return ProviderCheckout(checkout_session)
|
return ProviderCheckout(checkout_session)
|
||||||
|
|
||||||
def fulfill_provider_order(self, event):
|
def fulfill_provider_order(self, event, line_items):
|
||||||
provider_order = db.session.query(ProviderOrder) \
|
provider_order = db.session.query(ProviderOrder) \
|
||||||
.filter(ProviderOrder.payment_id == event['data']['object']['id']) \
|
.filter(ProviderOrder.payment_id == event['data']['object']['id']) \
|
||||||
.first()
|
.first()
|
||||||
|
@ -85,7 +98,8 @@ class ProviderCheckoutService:
|
||||||
raise ValueError(f'provider order not found, payment id: {event["data"]["object"]["id"]}')
|
raise ValueError(f'provider order not found, payment id: {event["data"]["object"]["id"]}')
|
||||||
|
|
||||||
if provider_order.payment_status != ProviderOrderPaymentStatus.WAIT_PAY.value:
|
if provider_order.payment_status != ProviderOrderPaymentStatus.WAIT_PAY.value:
|
||||||
raise ValueError(f'provider order payment status is not wait pay, payment id: {event["data"]["object"]["id"]}')
|
raise ValueError(
|
||||||
|
f'provider order payment status is not wait pay, payment id: {event["data"]["object"]["id"]}')
|
||||||
|
|
||||||
provider_order.transaction_id = event['data']['object']['payment_intent']
|
provider_order.transaction_id = event['data']['object']['payment_intent']
|
||||||
provider_order.currency = event['data']['object']['currency']
|
provider_order.currency = event['data']['object']['currency']
|
||||||
|
@ -110,10 +124,12 @@ class ProviderCheckoutService:
|
||||||
model_provider = model_provider_class(provider=provider)
|
model_provider = model_provider_class(provider=provider)
|
||||||
payment_info = model_provider.get_payment_info()
|
payment_info = model_provider.get_payment_info()
|
||||||
|
|
||||||
|
quantity = line_items['data'][0]['quantity']
|
||||||
|
|
||||||
if not payment_info:
|
if not payment_info:
|
||||||
increase_quota = 0
|
increase_quota = 0
|
||||||
else:
|
else:
|
||||||
increase_quota = int(payment_info['increase_quota'])
|
increase_quota = int(payment_info['increase_quota']) * quantity
|
||||||
|
|
||||||
if increase_quota > 0:
|
if increase_quota > 0:
|
||||||
provider.quota_limit += increase_quota
|
provider.quota_limit += increase_quota
|
||||||
|
|
|
@ -133,12 +133,14 @@ class ProviderService:
|
||||||
provider_parameter_dict[key]['is_valid'] = provider.is_valid
|
provider_parameter_dict[key]['is_valid'] = provider.is_valid
|
||||||
provider_parameter_dict[key]['quota_used'] = provider.quota_used
|
provider_parameter_dict[key]['quota_used'] = provider.quota_used
|
||||||
provider_parameter_dict[key]['quota_limit'] = provider.quota_limit
|
provider_parameter_dict[key]['quota_limit'] = provider.quota_limit
|
||||||
provider_parameter_dict[key]['last_used'] = provider.last_used
|
provider_parameter_dict[key]['last_used'] = int(provider.last_used.timestamp()) \
|
||||||
|
if provider.last_used else None
|
||||||
elif provider.provider_type == ProviderType.CUSTOM.value \
|
elif provider.provider_type == ProviderType.CUSTOM.value \
|
||||||
and ProviderType.CUSTOM.value in provider_parameter_dict:
|
and ProviderType.CUSTOM.value in provider_parameter_dict:
|
||||||
# if custom
|
# if custom
|
||||||
key = ProviderType.CUSTOM.value
|
key = ProviderType.CUSTOM.value
|
||||||
provider_parameter_dict[key]['last_used'] = provider.last_used
|
provider_parameter_dict[key]['last_used'] = int(provider.last_used.timestamp()) \
|
||||||
|
if provider.last_used else None
|
||||||
provider_parameter_dict[key]['is_valid'] = provider.is_valid
|
provider_parameter_dict[key]['is_valid'] = provider.is_valid
|
||||||
|
|
||||||
if model_provider_rule['model_flexibility'] == 'fixed':
|
if model_provider_rule['model_flexibility'] == 'fixed':
|
||||||
|
|
Loading…
Reference in New Issue
Block a user