Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
D
dify
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ai-tech
dify
Commits
9adbeade
Unverified
Commit
9adbeade
authored
Aug 17, 2023
by
takatost
Committed by
GitHub
Aug 17, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: claude paid optimize (#890)
parent
2f7b234c
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
69 additions
and
25 deletions
+69
-25
.env.example
api/.env.example
+4
-2
commands.py
api/commands.py
+5
-2
config.py
api/config.py
+10
-6
stripe.py
api/controllers/console/webhook/stripe.py
+9
-1
base.py
api/core/model_providers/models/llm/base.py
+2
-0
anthropic_provider.py
api/core/model_providers/providers/anthropic_provider.py
+2
-0
hosted.py
api/core/model_providers/providers/hosted.py
+5
-1
anthropic.json
api/core/model_providers/rules/anthropic.json
+3
-2
provider_checkout_service.py
api/services/provider_checkout_service.py
+25
-9
provider_service.py
api/services/provider_service.py
+4
-2
No files found.
api/.env.example
View file @
9adbeade
...
...
@@ -117,10 +117,12 @@ HOSTED_AZURE_OPENAI_QUOTA_LIMIT=200
HOSTED_ANTHROPIC_ENABLED=false
HOSTED_ANTHROPIC_API_BASE=
HOSTED_ANTHROPIC_API_KEY=
HOSTED_ANTHROPIC_QUOTA_LIMIT=
10
00000
HOSTED_ANTHROPIC_QUOTA_LIMIT=
6
00000
HOSTED_ANTHROPIC_PAID_ENABLED=false
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_WEBHOOK_SECRET=
\ No newline at end of file
api/commands.py
View file @
9adbeade
...
...
@@ -258,6 +258,8 @@ def sync_anthropic_hosted_providers():
click
.
echo
(
click
.
style
(
'Start sync anthropic hosted providers.'
,
fg
=
'green'
))
count
=
0
new_quota_limit
=
hosted_model_providers
.
anthropic
.
quota_limit
page
=
1
while
True
:
try
:
...
...
@@ -265,6 +267,7 @@ def sync_anthropic_hosted_providers():
Provider
.
provider_name
==
'anthropic'
,
Provider
.
provider_type
==
ProviderType
.
SYSTEM
.
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
)
except
NotFound
:
break
...
...
@@ -272,9 +275,9 @@ def sync_anthropic_hosted_providers():
page
+=
1
for
provider
in
providers
:
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
new_quota_limit
=
hosted_model_providers
.
anthropic
.
quota_limit
division
=
math
.
ceil
(
new_quota_limit
/
1000
)
provider
.
quota_limit
=
new_quota_limit
if
original_quota_limit
==
1000
\
...
...
api/config.py
View file @
9adbeade
...
...
@@ -57,10 +57,12 @@ DEFAULTS = {
'HOSTED_OPENAI_PAID_INCREASE_QUOTA'
:
1
,
'HOSTED_AZURE_OPENAI_ENABLED'
:
'False'
,
'HOSTED_AZURE_OPENAI_QUOTA_LIMIT'
:
200
,
'HOSTED_ANTHROPIC_QUOTA_LIMIT'
:
10
00000
,
'HOSTED_ANTHROPIC_QUOTA_LIMIT'
:
6
00000
,
'HOSTED_ANTHROPIC_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
,
'CLEAN_DAY_SETTING'
:
30
,
'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_BASE
=
get_env
(
'HOSTED_OPENAI_API_BASE'
)
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_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'
))
...
...
@@ -219,15 +221,17 @@ class Config:
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_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_API_BASE
=
get_env
(
'HOSTED_ANTHROPIC_API_BASE'
)
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_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_WEBHOOK_SECRET
=
get_env
(
'STRIPE_WEBHOOK_SECRET'
)
...
...
api/controllers/console/webhook/stripe.py
View file @
9adbeade
...
...
@@ -38,12 +38,20 @@ class StripeWebhookApi(Resource):
logging
.
debug
(
event
[
'data'
][
'object'
][
'payment_status'
])
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...
provider_checkout_service
=
ProviderCheckoutService
()
try
:
provider_checkout_service
.
fulfill_provider_order
(
event
)
provider_checkout_service
.
fulfill_provider_order
(
event
,
session
.
line_items
)
except
Exception
as
e
:
logging
.
debug
(
str
(
e
))
return
'success'
,
200
...
...
api/core/model_providers/models/llm/base.py
View file @
9adbeade
...
...
@@ -125,6 +125,8 @@ class BaseLLM(BaseProviderModel):
completion_tokens
=
self
.
get_num_tokens
([
PromptMessage
(
content
=
completion_content
,
type
=
MessageType
.
ASSISTANT
)])
total_tokens
=
prompt_tokens
+
completion_tokens
self
.
model_provider
.
update_last_used
()
if
self
.
deduct_quota
:
self
.
model_provider
.
deduct_quota
(
total_tokens
)
...
...
api/core/model_providers/providers/anthropic_provider.py
View file @
9adbeade
...
...
@@ -183,6 +183,8 @@ class AnthropicProvider(BaseModelProvider):
return
{
'product_id'
:
hosted_model_providers
.
anthropic
.
paid_stripe_price_id
,
'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
...
...
api/core/model_providers/providers/hosted.py
View file @
9adbeade
...
...
@@ -31,7 +31,9 @@ class HostedAnthropic(BaseModel):
"""Quota limit for the anthropic hosted model. 0 means unlimited."""
paid_enabled
:
bool
=
False
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
):
...
...
@@ -73,4 +75,6 @@ def init_app(app: Flask):
paid_enabled
=
app
.
config
.
get
(
"HOSTED_ANTHROPIC_PAID_ENABLED"
),
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_min_quantity
=
app
.
config
.
get
(
"HOSTED_ANTHROPIC_PAID_MIN_QUANTITY"
),
paid_max_quantity
=
app
.
config
.
get
(
"HOSTED_ANTHROPIC_PAID_MAX_QUANTITY"
),
)
api/core/model_providers/rules/anthropic.json
View file @
9adbeade
...
...
@@ -5,10 +5,11 @@
],
"system_config"
:
{
"supported_quota_types"
:
[
"paid"
,
"trial"
],
"quota_unit"
:
"t
ime
s"
,
"quota_limit"
:
1
000
"quota_unit"
:
"t
oken
s"
,
"quota_limit"
:
600
000
},
"model_flexibility"
:
"fixed"
}
\ No newline at end of file
api/services/provider_checkout_service.py
View file @
9adbeade
...
...
@@ -39,6 +39,8 @@ class ProviderCheckoutService:
raise
ValueError
(
f
'provider name {provider_name} not support payment'
)
payment_product_id
=
payment_info
[
'product_id'
]
payment_min_quantity
=
payment_info
[
'min_quantity'
]
payment_max_quantity
=
payment_info
[
'max_quantity'
]
# create provider order
provider_order
=
ProviderOrder
(
...
...
@@ -53,18 +55,29 @@ class ProviderCheckoutService:
db
.
session
.
add
(
provider_order
)
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
:
# create stripe checkout session
checkout_session
=
stripe
.
checkout
.
Session
.
create
(
line_items
=
[
{
'price'
:
f
'{payment_product_id}'
,
'quantity'
:
1
,
},
line_item
],
mode
=
'payment'
,
success_url
=
current_app
.
config
.
get
(
"CONSOLE_WEB_URL"
)
+
'?provider_payment=succeeded'
,
cancel_url
=
current_app
.
config
.
get
(
"CONSOLE_WEB_URL"
)
+
'?provider_payment=cancelled'
,
success_url
=
current_app
.
config
.
get
(
"CONSOLE_WEB_URL"
)
+
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
},
)
except
Exception
as
e
:
...
...
@@ -76,7 +89,7 @@ class ProviderCheckoutService:
return
ProviderCheckout
(
checkout_session
)
def
fulfill_provider_order
(
self
,
event
):
def
fulfill_provider_order
(
self
,
event
,
line_items
):
provider_order
=
db
.
session
.
query
(
ProviderOrder
)
\
.
filter
(
ProviderOrder
.
payment_id
==
event
[
'data'
][
'object'
][
'id'
])
\
.
first
()
...
...
@@ -85,7 +98,8 @@ class ProviderCheckoutService:
raise
ValueError
(
f
'provider order not found, payment id: {event["data"]["object"]["id"]}'
)
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
.
currency
=
event
[
'data'
][
'object'
][
'currency'
]
...
...
@@ -110,10 +124,12 @@ class ProviderCheckoutService:
model_provider
=
model_provider_class
(
provider
=
provider
)
payment_info
=
model_provider
.
get_payment_info
()
quantity
=
line_items
[
'data'
][
0
][
'quantity'
]
if
not
payment_info
:
increase_quota
=
0
else
:
increase_quota
=
int
(
payment_info
[
'increase_quota'
])
increase_quota
=
int
(
payment_info
[
'increase_quota'
])
*
quantity
if
increase_quota
>
0
:
provider
.
quota_limit
+=
increase_quota
...
...
api/services/provider_service.py
View file @
9adbeade
...
...
@@ -133,12 +133,14 @@ class ProviderService:
provider_parameter_dict
[
key
][
'is_valid'
]
=
provider
.
is_valid
provider_parameter_dict
[
key
][
'quota_used'
]
=
provider
.
quota_used
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
\
and
ProviderType
.
CUSTOM
.
value
in
provider_parameter_dict
:
# if custom
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
if
model_provider_rule
[
'model_flexibility'
]
==
'fixed'
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment