forked from phoenix/litellm-mirror
feat(ui/model_dashboard.tsx): show if model is config or db model
This commit is contained in:
parent
a325bf2fb8
commit
fbcda918de
4 changed files with 42 additions and 8 deletions
|
@ -2516,20 +2516,21 @@ class ProxyConfig:
|
|||
router = litellm.Router(**router_params) # type:ignore
|
||||
return router, model_list, general_settings
|
||||
|
||||
def get_model_info_with_id(self, model) -> RouterModelInfo:
|
||||
def get_model_info_with_id(self, model, db_model=False) -> RouterModelInfo:
|
||||
"""
|
||||
Common logic across add + delete router models
|
||||
Parameters:
|
||||
- deployment
|
||||
- db_model -> flag for differentiating model stored in db vs. config -> used on UI
|
||||
|
||||
Return model info w/ id
|
||||
"""
|
||||
if model.model_info is not None and isinstance(model.model_info, dict):
|
||||
if "id" not in model.model_info:
|
||||
model.model_info["id"] = model.model_id
|
||||
_model_info = RouterModelInfo(**model.model_info)
|
||||
_model_info = RouterModelInfo(**model.model_info, db_model=db_model)
|
||||
else:
|
||||
_model_info = RouterModelInfo(id=model.model_id)
|
||||
_model_info = RouterModelInfo(id=model.model_id, db_model=db_model)
|
||||
return _model_info
|
||||
|
||||
async def _delete_deployment(self, db_models: list) -> int:
|
||||
|
@ -2624,7 +2625,9 @@ class ProxyConfig:
|
|||
f"Invalid model added to proxy db. Invalid litellm params. litellm_params={_litellm_params}"
|
||||
)
|
||||
continue # skip to next model
|
||||
_model_info = self.get_model_info_with_id(model=m)
|
||||
_model_info = self.get_model_info_with_id(
|
||||
model=m, db_model=True
|
||||
) ## 👈 FLAG = True for db_models
|
||||
|
||||
added = llm_router.add_deployment(
|
||||
deployment=Deployment(
|
||||
|
@ -7449,6 +7452,16 @@ async def update_model(
|
|||
)
|
||||
)
|
||||
if _existing_litellm_params is None:
|
||||
if (
|
||||
llm_router is not None
|
||||
and llm_router.get_deployment(model_id=_model_id) is not None
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail={
|
||||
"error": "Can't edit model. Model in config. Store model in db via `/model/new`. to edit."
|
||||
},
|
||||
)
|
||||
raise Exception("model not found")
|
||||
_existing_litellm_params_dict = dict(
|
||||
_existing_litellm_params.litellm_params
|
||||
|
|
|
@ -2595,11 +2595,21 @@ class Router:
|
|||
except:
|
||||
return None
|
||||
|
||||
def get_deployment(self, model_id: str):
|
||||
def get_deployment(self, model_id: str) -> Optional[Deployment]:
|
||||
"""
|
||||
Returns -> Deployment or None
|
||||
|
||||
Raise Exception -> if model found in invalid format
|
||||
"""
|
||||
for model in self.model_list:
|
||||
if "model_info" in model and "id" in model["model_info"]:
|
||||
if model_id == model["model_info"]["id"]:
|
||||
return model
|
||||
if isinstance(model, dict):
|
||||
return Deployment(**model)
|
||||
elif isinstance(model, Deployment):
|
||||
return model
|
||||
else:
|
||||
raise Exception("Model invalid format - {}".format(type(model)))
|
||||
return None
|
||||
|
||||
def get_model_info(self, id: str) -> Optional[dict]:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import List, Optional, Union, Dict, Tuple, Literal
|
||||
import httpx
|
||||
from pydantic import BaseModel, validator
|
||||
from pydantic import BaseModel, validator, Field
|
||||
from .completion import CompletionRequest
|
||||
from .embedding import EmbeddingRequest
|
||||
import uuid, enum
|
||||
|
@ -70,6 +70,9 @@ class ModelInfo(BaseModel):
|
|||
id: Optional[
|
||||
str
|
||||
] # Allow id to be optional on input, but it will always be present as a str in the model instance
|
||||
db_model: bool = (
|
||||
False # used for proxy - to separate models which are stored in the db vs. config.
|
||||
)
|
||||
|
||||
def __init__(self, id: Optional[Union[str, int]] = None, **params):
|
||||
if id is None:
|
||||
|
|
|
@ -37,7 +37,7 @@ import { Badge, BadgeDelta, Button } from "@tremor/react";
|
|||
import RequestAccess from "./request_model_access";
|
||||
import { Typography } from "antd";
|
||||
import TextArea from "antd/es/input/TextArea";
|
||||
import { InformationCircleIcon, PencilAltIcon, PencilIcon, StatusOnlineIcon, TrashIcon, RefreshIcon } from "@heroicons/react/outline";
|
||||
import { InformationCircleIcon, PencilAltIcon, PencilIcon, StatusOnlineIcon, TrashIcon, RefreshIcon, CheckCircleIcon, XCircleIcon } from "@heroicons/react/outline";
|
||||
import DeleteModelButton from "./delete_model_button";
|
||||
const { Title: Title2, Link } = Typography;
|
||||
import { UploadOutlined } from '@ant-design/icons';
|
||||
|
@ -921,6 +921,7 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
|
|||
<TableHeaderCell>Input Price per token ($)</TableHeaderCell>
|
||||
<TableHeaderCell>Output Price per token ($)</TableHeaderCell>
|
||||
<TableHeaderCell>Max Tokens</TableHeaderCell>
|
||||
<TableHeaderCell>Status</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
|
@ -929,6 +930,7 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
|
|||
selectedModelGroup === "all" || model.model_name === selectedModelGroup || selectedModelGroup === null || selectedModelGroup === undefined || selectedModelGroup === ""
|
||||
)
|
||||
.map((model: any, index: number) => (
|
||||
|
||||
<TableRow key={index}>
|
||||
<TableCell>
|
||||
<Text>{model.model_name}</Text>
|
||||
|
@ -958,6 +960,12 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
|
|||
<TableCell>{model.input_cost}</TableCell>
|
||||
<TableCell>{model.output_cost}</TableCell>
|
||||
<TableCell>{model.max_tokens}</TableCell>
|
||||
<TableCell>
|
||||
{
|
||||
model.model_info.db_model ? <Badge icon={CheckCircleIcon} className="text-white">DB Model</Badge> : <Badge icon={XCircleIcon} className="text-black">Config Model</Badge>
|
||||
}
|
||||
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Icon
|
||||
icon={PencilAltIcon}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue