mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 00:02:03 +00:00
feat: switch free AI tier to DeepSeek with daily cost budgets
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT cost_nanos FROM ai_free_token_usage WHERE email = $1",
|
||||
"query": "SELECT cost_nanos FROM ai_free_token_usage\n WHERE email = $1 AND day = (now() at time zone 'utc')::date",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -18,5 +18,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "247486558e023ec3adf0c1e8f5664fc5e65995ce81e622c174a89befc1a527e5"
|
||||
"hash": "445483e44858098da49a2e8659cf2a2e9d86ef70d0e667f0e7b291dde879608e"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO ai_free_token_usage (email, day, cost_nanos, updated_at)\n VALUES ($1, (now() at time zone 'utc')::date, $2, now())\n ON CONFLICT (email, day) DO UPDATE\n SET cost_nanos = ai_free_token_usage.cost_nanos + EXCLUDED.cost_nanos,\n updated_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "5d4138a0d49fe5f279c4d63c7ae0d90736fda75fd059254b7a105b51083a4416"
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO ai_free_token_usage (email, cost_nanos, updated_at)\n VALUES ($1, $2, now())\n ON CONFLICT (email) DO UPDATE\n SET cost_nanos = ai_free_token_usage.cost_nanos + EXCLUDED.cost_nanos,\n updated_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f8ebef344fdbf1b0707040376233d8196135130a8b0ba86bd37e3f91880ad975"
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
a61da8ad2de819f6675314efa59371105ad974cb
|
||||
583a5c32eb9e04a7bb9a2a99cf7fb6cd4fe9f7f9
|
||||
@@ -1,16 +1,18 @@
|
||||
-- Per-user lifetime usage of the Windmill-provided free Claude Opus tier, measured
|
||||
-- as cost in nano-dollars (1e-9 USD) of Opus 4.8-equivalent spend rather than raw
|
||||
-- tokens — cache reads cost 0.1x a normal input token, so a token count wildly
|
||||
-- overstates the real bill. Keyed by normalized email so the allowance is shared
|
||||
-- across a user's workspaces (and resistant to +tag / gmail-dot aliasing).
|
||||
-- Per-user DAILY usage of the Windmill-provided free AI tier, measured as cost in
|
||||
-- nano-dollars (1e-9 USD) rather than raw tokens — a prompt-cache hit costs a fraction
|
||||
-- of a fresh input token, so a token count wildly overstates the real bill. Keyed by
|
||||
-- normalized email so the allowance is shared across a user's workspaces (and is
|
||||
-- resistant to +tag / gmail-dot aliasing).
|
||||
CREATE TABLE ai_free_token_usage (
|
||||
email VARCHAR(255) PRIMARY KEY,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
day DATE NOT NULL,
|
||||
cost_nanos BIGINT NOT NULL DEFAULT 0,
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
PRIMARY KEY (email, day)
|
||||
);
|
||||
|
||||
-- Instance-wide daily cost ceiling (nano-dollars) for the free tier — a kill-switch
|
||||
-- independent of per-user budgets. One row per UTC day.
|
||||
-- independent of the per-user budget. One row per UTC day.
|
||||
CREATE TABLE ai_free_token_daily_usage (
|
||||
day DATE PRIMARY KEY,
|
||||
cost_nanos BIGINT NOT NULL DEFAULT 0,
|
||||
|
||||
@@ -38,7 +38,7 @@ account: workspace_id(char), id(int), expires_at(ts), refresh_token(char), clien
|
||||
agent_token_blacklist: token(char), expires_at(ts), blacklisted_at(ts), blacklisted_by(char)
|
||||
ai_agent_memory: workspace_id(char), conversation_id(uuid), step_id(char), messages(jsonb), created_at(ts), updated_at(ts)
|
||||
ai_free_token_daily_usage: day(date), cost_nanos(bigint), updated_at(ts)
|
||||
ai_free_token_usage: email(char), cost_nanos(bigint), updated_at(ts)
|
||||
ai_free_token_usage: email(char), day(date), cost_nanos(bigint), updated_at(ts)
|
||||
alerts: id(int), alert_type(char), message(text), created_at(ts), acknowledged(bool), workspace_id(text), acknowledged_workspace(bool), resource(text)
|
||||
app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text), labels(text[])
|
||||
FK: (workspace_id) -> workspace(id)
|
||||
|
||||
@@ -962,7 +962,7 @@ async fn proxy(
|
||||
if let Some(lease) = free_lease {
|
||||
let body = if is_sse {
|
||||
axum::body::Body::from_stream(inject_keepalives(
|
||||
Box::pin(crate::ai_free_tier_oss::meter_anthropic_usage(
|
||||
Box::pin(crate::ai_free_tier_oss::meter_usage(
|
||||
response.bytes_stream(),
|
||||
db.clone(),
|
||||
lease,
|
||||
@@ -971,7 +971,7 @@ async fn proxy(
|
||||
))
|
||||
} else {
|
||||
let bytes = response.bytes().await.map_err(to_anyhow)?;
|
||||
crate::ai_free_tier_oss::record_anthropic_json_usage(db.clone(), lease, &bytes);
|
||||
crate::ai_free_tier_oss::record_json_usage(db.clone(), lease, &bytes);
|
||||
axum::body::Body::from(bytes)
|
||||
};
|
||||
return Ok((status_code, headers, body));
|
||||
|
||||
@@ -44,10 +44,10 @@ pub async fn free_tier_copilot_config(_db: &DB, _email: &str) -> Result<Option<A
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "private"))]
|
||||
pub fn record_anthropic_json_usage(_db: DB, _lease: FreeTierLease, _bytes: &[u8]) {}
|
||||
pub fn record_json_usage(_db: DB, _lease: FreeTierLease, _bytes: &[u8]) {}
|
||||
|
||||
#[cfg(not(feature = "private"))]
|
||||
pub fn meter_anthropic_usage<S>(
|
||||
pub fn meter_usage<S>(
|
||||
upstream: S,
|
||||
_db: DB,
|
||||
_lease: FreeTierLease,
|
||||
|
||||
Reference in New Issue
Block a user