feat(ui/model_dashboard.tsx): show if model is config or db model

This commit is contained in:
Krrish Dholakia 2024-05-07 18:29:14 -07:00
parent a325bf2fb8
commit fbcda918de
4 changed files with 42 additions and 8 deletions

View file

@ -2516,20 +2516,21 @@ class ProxyConfig:
router = litellm.Router(**router_params) # type:ignore router = litellm.Router(**router_params) # type:ignore
return router, model_list, general_settings 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 Common logic across add + delete router models
Parameters: Parameters:
- deployment - deployment
- db_model -> flag for differentiating model stored in db vs. config -> used on UI
Return model info w/ id Return model info w/ id
""" """
if model.model_info is not None and isinstance(model.model_info, dict): if model.model_info is not None and isinstance(model.model_info, dict):
if "id" not in model.model_info: if "id" not in model.model_info:
model.model_info["id"] = model.model_id model.model_info["id"] = model.model_id
_model_info = RouterModelInfo(**model.model_info) _model_info = RouterModelInfo(**model.model_info, db_model=db_model)
else: else:
_model_info = RouterModelInfo(id=model.model_id) _model_info = RouterModelInfo(id=model.model_id, db_model=db_model)
return _model_info return _model_info
async def _delete_deployment(self, db_models: list) -> int: 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}" f"Invalid model added to proxy db. Invalid litellm params. litellm_params={_litellm_params}"
) )
continue # skip to next model 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( added = llm_router.add_deployment(
deployment=Deployment( deployment=Deployment(
@ -7449,6 +7452,16 @@ async def update_model(
) )
) )
if _existing_litellm_params is None: 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") raise Exception("model not found")
_existing_litellm_params_dict = dict( _existing_litellm_params_dict = dict(
_existing_litellm_params.litellm_params _existing_litellm_params.litellm_params

View file

@ -2595,11 +2595,21 @@ class Router:
except: except:
return None 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: for model in self.model_list:
if "model_info" in model and "id" in model["model_info"]: if "model_info" in model and "id" in model["model_info"]:
if model_id == model["model_info"]["id"]: if model_id == model["model_info"]["id"]:
if isinstance(model, dict):
return Deployment(**model)
elif isinstance(model, Deployment):
return model return model
else:
raise Exception("Model invalid format - {}".format(type(model)))
return None return None
def get_model_info(self, id: str) -> Optional[dict]: def get_model_info(self, id: str) -> Optional[dict]:

View file

@ -1,6 +1,6 @@
from typing import List, Optional, Union, Dict, Tuple, Literal from typing import List, Optional, Union, Dict, Tuple, Literal
import httpx import httpx
from pydantic import BaseModel, validator from pydantic import BaseModel, validator, Field
from .completion import CompletionRequest from .completion import CompletionRequest
from .embedding import EmbeddingRequest from .embedding import EmbeddingRequest
import uuid, enum import uuid, enum
@ -70,6 +70,9 @@ class ModelInfo(BaseModel):
id: Optional[ id: Optional[
str str
] # Allow id to be optional on input, but it will always be present as a str in the model instance ] # 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): def __init__(self, id: Optional[Union[str, int]] = None, **params):
if id is None: if id is None:

View file

@ -37,7 +37,7 @@ import { Badge, BadgeDelta, Button } from "@tremor/react";
import RequestAccess from "./request_model_access"; import RequestAccess from "./request_model_access";
import { Typography } from "antd"; import { Typography } from "antd";
import TextArea from "antd/es/input/TextArea"; 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"; import DeleteModelButton from "./delete_model_button";
const { Title: Title2, Link } = Typography; const { Title: Title2, Link } = Typography;
import { UploadOutlined } from '@ant-design/icons'; import { UploadOutlined } from '@ant-design/icons';
@ -921,6 +921,7 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
<TableHeaderCell>Input Price per token ($)</TableHeaderCell> <TableHeaderCell>Input Price per token ($)</TableHeaderCell>
<TableHeaderCell>Output Price per token ($)</TableHeaderCell> <TableHeaderCell>Output Price per token ($)</TableHeaderCell>
<TableHeaderCell>Max Tokens</TableHeaderCell> <TableHeaderCell>Max Tokens</TableHeaderCell>
<TableHeaderCell>Status</TableHeaderCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@ -929,6 +930,7 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
selectedModelGroup === "all" || model.model_name === selectedModelGroup || selectedModelGroup === null || selectedModelGroup === undefined || selectedModelGroup === "" selectedModelGroup === "all" || model.model_name === selectedModelGroup || selectedModelGroup === null || selectedModelGroup === undefined || selectedModelGroup === ""
) )
.map((model: any, index: number) => ( .map((model: any, index: number) => (
<TableRow key={index}> <TableRow key={index}>
<TableCell> <TableCell>
<Text>{model.model_name}</Text> <Text>{model.model_name}</Text>
@ -958,6 +960,12 @@ const handleEditSubmit = async (formValues: Record<string, any>) => {
<TableCell>{model.input_cost}</TableCell> <TableCell>{model.input_cost}</TableCell>
<TableCell>{model.output_cost}</TableCell> <TableCell>{model.output_cost}</TableCell>
<TableCell>{model.max_tokens}</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> <TableCell>
<Icon <Icon
icon={PencilAltIcon} icon={PencilAltIcon}