forked from phoenix/litellm-mirror
Merge pull request #1669 from BerriAI/litellm_feat_admin_ui_imp
[UI] Improve LiteLLM admin UI
This commit is contained in:
commit
a9e215b2cc
7 changed files with 86 additions and 4 deletions
|
@ -278,6 +278,18 @@ Request Params:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Default /key/generate params
|
||||||
|
Use this, if you need to control the default `max_budget` or any `key/generate` param per key
|
||||||
|
|
||||||
|
Set `litellm_settings:default_key_generate_params`:
|
||||||
|
litellm_settings:
|
||||||
|
default_key_generate_params:
|
||||||
|
max_budget: 1.5000
|
||||||
|
models: ["azure-gpt-3.5"]
|
||||||
|
duration: # blank means `null`
|
||||||
|
metadata: {"setting":"default"}
|
||||||
|
team_id: "core-infra"
|
||||||
|
|
||||||
## Set Budgets - Per Key
|
## Set Budgets - Per Key
|
||||||
|
|
||||||
Set `max_budget` in (USD $) param in the `key/generate` request. By default the `max_budget` is set to `null` and is not checked for keys
|
Set `max_budget` in (USD $) param in the `key/generate` request. By default the `max_budget` is set to `null` and is not checked for keys
|
||||||
|
|
|
@ -143,6 +143,7 @@ model_cost_map_url: str = "https://raw.githubusercontent.com/BerriAI/litellm/mai
|
||||||
suppress_debug_info = False
|
suppress_debug_info = False
|
||||||
dynamodb_table_name: Optional[str] = None
|
dynamodb_table_name: Optional[str] = None
|
||||||
s3_callback_params: Optional[Dict] = None
|
s3_callback_params: Optional[Dict] = None
|
||||||
|
default_key_generate_params: Optional[Dict] = None
|
||||||
#### RELIABILITY ####
|
#### RELIABILITY ####
|
||||||
request_timeout: Optional[float] = 6000
|
request_timeout: Optional[float] = 6000
|
||||||
num_retries: Optional[int] = None # per model endpoint
|
num_retries: Optional[int] = None # per model endpoint
|
||||||
|
|
|
@ -69,11 +69,16 @@ litellm_settings:
|
||||||
success_callback: ['langfuse']
|
success_callback: ['langfuse']
|
||||||
max_budget: 10 # global budget for proxy
|
max_budget: 10 # global budget for proxy
|
||||||
budget_duration: 30d # global budget duration, will reset after 30d
|
budget_duration: 30d # global budget duration, will reset after 30d
|
||||||
|
default_key_generate_params:
|
||||||
|
max_budget: 1.5000
|
||||||
|
models: ["azure-gpt-3.5"]
|
||||||
|
duration: None
|
||||||
# cache: True
|
# cache: True
|
||||||
# setting callback class
|
# setting callback class
|
||||||
# callbacks: custom_callbacks.proxy_handler_instance # sets litellm.callbacks = [proxy_handler_instance]
|
# callbacks: custom_callbacks.proxy_handler_instance # sets litellm.callbacks = [proxy_handler_instance]
|
||||||
|
|
||||||
general_settings:
|
general_settings:
|
||||||
|
allow_user_auth: True
|
||||||
master_key: sk-1234
|
master_key: sk-1234
|
||||||
alerting: ["slack"]
|
alerting: ["slack"]
|
||||||
alerting_threshold: 10 # sends alerts if requests hang for 2 seconds
|
alerting_threshold: 10 # sends alerts if requests hang for 2 seconds
|
||||||
|
|
|
@ -1117,6 +1117,9 @@ class ProxyConfig:
|
||||||
# see usage here: https://docs.litellm.ai/docs/proxy/caching
|
# see usage here: https://docs.litellm.ai/docs/proxy/caching
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
verbose_proxy_logger.debug(
|
||||||
|
f"{blue_color_code} setting litellm.{key}={value}{reset_color_code}"
|
||||||
|
)
|
||||||
setattr(litellm, key, value)
|
setattr(litellm, key, value)
|
||||||
|
|
||||||
## GENERAL SERVER SETTINGS (e.g. master key,..) # do this after initializing litellm, to ensure sentry logging works for proxylogging
|
## GENERAL SERVER SETTINGS (e.g. master key,..) # do this after initializing litellm, to ensure sentry logging works for proxylogging
|
||||||
|
@ -2385,6 +2388,26 @@ async def generate_key_fn(
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_403_FORBIDDEN, detail=message
|
status_code=status.HTTP_403_FORBIDDEN, detail=message
|
||||||
)
|
)
|
||||||
|
# check if user set default key/generate params on config.yaml
|
||||||
|
if litellm.default_key_generate_params is not None:
|
||||||
|
for elem in data:
|
||||||
|
key, value = elem
|
||||||
|
if value is None and key in [
|
||||||
|
"max_budget",
|
||||||
|
"user_id",
|
||||||
|
"team_id",
|
||||||
|
"max_parallel_requests",
|
||||||
|
"tpm_limit",
|
||||||
|
"rpm_limit",
|
||||||
|
"budget_duration",
|
||||||
|
]:
|
||||||
|
setattr(
|
||||||
|
data, key, litellm.default_key_generate_params.get(key, None)
|
||||||
|
)
|
||||||
|
elif key == "models" and value == []:
|
||||||
|
setattr(data, key, litellm.default_key_generate_params.get(key, []))
|
||||||
|
elif key == "metadata" and value == {}:
|
||||||
|
setattr(data, key, litellm.default_key_generate_params.get(key, {}))
|
||||||
|
|
||||||
data_json = data.json() # type: ignore
|
data_json = data.json() # type: ignore
|
||||||
|
|
||||||
|
@ -2959,6 +2982,11 @@ async def google_callback(code: str, request: Request):
|
||||||
user_id = response["user_id"] # type: ignore
|
user_id = response["user_id"] # type: ignore
|
||||||
litellm_dashboard_ui = "https://litellm-dashboard.vercel.app/"
|
litellm_dashboard_ui = "https://litellm-dashboard.vercel.app/"
|
||||||
|
|
||||||
|
# if user set LITELLM_UI_LINK in .env, use that
|
||||||
|
litellm_ui_link_in_env = os.getenv("LITELLM_UI_LINK", None)
|
||||||
|
if litellm_ui_link_in_env is not None:
|
||||||
|
litellm_dashboard_ui = litellm_ui_link_in_env
|
||||||
|
|
||||||
litellm_dashboard_ui += (
|
litellm_dashboard_ui += (
|
||||||
"?userID="
|
"?userID="
|
||||||
+ user_id
|
+ user_id
|
||||||
|
|
|
@ -1188,3 +1188,27 @@ async def test_key_name_set(prisma_client):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("Got Exception", e)
|
print("Got Exception", e)
|
||||||
pytest.fail(f"Got exception {e}")
|
pytest.fail(f"Got exception {e}")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio()
|
||||||
|
async def test_default_key_params(prisma_client):
|
||||||
|
"""
|
||||||
|
- create key
|
||||||
|
- get key info
|
||||||
|
- assert key_name is not null
|
||||||
|
"""
|
||||||
|
setattr(litellm.proxy.proxy_server, "prisma_client", prisma_client)
|
||||||
|
setattr(litellm.proxy.proxy_server, "master_key", "sk-1234")
|
||||||
|
setattr(litellm.proxy.proxy_server, "general_settings", {"allow_user_auth": True})
|
||||||
|
litellm.default_key_generate_params = {"max_budget": 0.000122}
|
||||||
|
await litellm.proxy.proxy_server.prisma_client.connect()
|
||||||
|
try:
|
||||||
|
request = GenerateKeyRequest()
|
||||||
|
key = await generate_key_fn(request)
|
||||||
|
generated_key = key.key
|
||||||
|
result = await info_key_fn(key=generated_key)
|
||||||
|
print("result from info_key_fn", result)
|
||||||
|
assert result["info"]["max_budget"] == 0.000122
|
||||||
|
except Exception as e:
|
||||||
|
print("Got Exception", e)
|
||||||
|
pytest.fail(f"Got exception {e}")
|
||||||
|
|
|
@ -15,8 +15,6 @@ export const keyCreateCall = async (
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
team_id: "core-infra-4",
|
|
||||||
max_budget: 10,
|
|
||||||
user_id: userID,
|
user_id: userID,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -58,7 +58,8 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
<TableHead>
|
<TableHead>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHeaderCell>Secret Key</TableHeaderCell>
|
<TableHeaderCell>Secret Key</TableHeaderCell>
|
||||||
<TableHeaderCell>Spend</TableHeaderCell>
|
<TableHeaderCell>Spend (USD)</TableHeaderCell>
|
||||||
|
<TableHeaderCell>Key Budget (USD)</TableHeaderCell>
|
||||||
<TableHeaderCell>Expires</TableHeaderCell>
|
<TableHeaderCell>Expires</TableHeaderCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
|
@ -68,11 +69,24 @@ const ViewKeyTable: React.FC<ViewKeyTableProps> = ({
|
||||||
return (
|
return (
|
||||||
<TableRow key={item.token}>
|
<TableRow key={item.token}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Text>{item.key_name}</Text>
|
{item.key_name != null ? (
|
||||||
|
<Text>{item.key_name}</Text>
|
||||||
|
) : (
|
||||||
|
<Text>{item.token}</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Text>{item.spend}</Text>
|
<Text>{item.spend}</Text>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
{item.max_budget != null ? (
|
||||||
|
<Text>{item.max_budget}</Text>
|
||||||
|
) : (
|
||||||
|
<Text>Unlimited Budget</Text>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{item.expires != null ? (
|
{item.expires != null ? (
|
||||||
<Text>{item.expires}</Text>
|
<Text>{item.expires}</Text>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue