mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-11 02:22:48 +00:00
Merge pull request #2905 from BerriAI/litellm_ui_add_slack_alerting
UI add slack alerting
This commit is contained in:
@@ -8001,10 +8001,12 @@ async def update_config(config_info: ConfigYAML):
|
||||
_updated_environment_variables[k] = base64.b64encode(
|
||||
encrypted_value
|
||||
).decode("utf-8")
|
||||
config["environment_variables"] = {
|
||||
**_updated_environment_variables,
|
||||
**config["environment_variables"],
|
||||
}
|
||||
|
||||
_existing_env_variables = config["environment_variables"]
|
||||
|
||||
for k, v in _updated_environment_variables.items():
|
||||
# overwrite existing env variables with updated values
|
||||
_existing_env_variables[k] = _updated_environment_variables[k]
|
||||
|
||||
# update the litellm settings
|
||||
if config_info.litellm_settings is not None:
|
||||
|
||||
@@ -46,8 +46,8 @@ const Sidebar: React.FC<SidebarProps> = ({
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh", maxWidth: "100px" }}>
|
||||
<Sider width={100}>
|
||||
<Layout style={{ minHeight: "100vh", maxWidth: "120px" }}>
|
||||
<Sider width={120}>
|
||||
<Menu
|
||||
mode="inline"
|
||||
defaultSelectedKeys={defaultSelectedKey ? defaultSelectedKey : ["1"]}
|
||||
@@ -89,7 +89,7 @@ const Sidebar: React.FC<SidebarProps> = ({
|
||||
) : null}
|
||||
<Menu.Item key="8" onClick={() => setPage("settings")}>
|
||||
<Text>
|
||||
Settings
|
||||
Integrations
|
||||
</Text>
|
||||
</Menu.Item>
|
||||
{userRole == "Admin" ? (
|
||||
|
||||
@@ -176,58 +176,67 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
|
||||
}
|
||||
|
||||
const handleSubmit = async (formValues: Record<string, any>) => {
|
||||
const litellmParamsObj: Record<string, any> = {};
|
||||
const modelInfoObj: Record<string, any> = {};
|
||||
let modelName: string = "";
|
||||
// Iterate through the key-value pairs in formValues
|
||||
for (const [key, value] of Object.entries(formValues)) {
|
||||
if (key == "model_name") {
|
||||
modelName = value
|
||||
}
|
||||
|
||||
// Check if key is any of the specified API related keys
|
||||
if (key === "api_key" || key === "model" || key === "api_base" || key === "api_version" || key.startsWith("aws_")) {
|
||||
// Add key-value pair to litellm_params dictionary
|
||||
litellmParamsObj[key] = value;
|
||||
}
|
||||
|
||||
// Check if key is "base_model"
|
||||
if (key === "base_model") {
|
||||
// Add key-value pair to model_info dictionary
|
||||
modelInfoObj[key] = value;
|
||||
}
|
||||
try {
|
||||
|
||||
|
||||
if (key == "litellm_extra_params") {
|
||||
console.log("litellm_extra_params:", value);
|
||||
let litellmExtraParams = {};
|
||||
try {
|
||||
litellmExtraParams = JSON.parse(value);
|
||||
const litellmParamsObj: Record<string, any> = {};
|
||||
const modelInfoObj: Record<string, any> = {};
|
||||
let modelName: string = "";
|
||||
// Iterate through the key-value pairs in formValues
|
||||
for (const [key, value] of Object.entries(formValues)) {
|
||||
if (key == "model_name") {
|
||||
modelName = value
|
||||
}
|
||||
catch (error) {
|
||||
message.error("Failed to parse LiteLLM Extra Paras: " + error);
|
||||
throw new Error("Failed to parse litellm_extra_params: " + error);
|
||||
}
|
||||
for (const [key, value] of Object.entries(litellmExtraParams)) {
|
||||
|
||||
// Check if key is any of the specified API related keys
|
||||
if (key === "api_key" || key === "model" || key === "api_base" || key === "api_version" || key.startsWith("aws_")) {
|
||||
// Add key-value pair to litellm_params dictionary
|
||||
litellmParamsObj[key] = value;
|
||||
}
|
||||
|
||||
// Check if key is "base_model"
|
||||
if (key === "base_model") {
|
||||
// Add key-value pair to model_info dictionary
|
||||
modelInfoObj[key] = value;
|
||||
}
|
||||
|
||||
|
||||
if (key == "litellm_extra_params") {
|
||||
console.log("litellm_extra_params:", value);
|
||||
let litellmExtraParams = {};
|
||||
if (value && value != undefined) {
|
||||
try {
|
||||
litellmExtraParams = JSON.parse(value);
|
||||
}
|
||||
catch (error) {
|
||||
message.error("Failed to parse LiteLLM Extra Params: " + error);
|
||||
throw new Error("Failed to parse litellm_extra_params: " + error);
|
||||
}
|
||||
for (const [key, value] of Object.entries(litellmExtraParams)) {
|
||||
litellmParamsObj[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const new_model: Model = {
|
||||
"model_name": modelName,
|
||||
"litellm_params": litellmParamsObj,
|
||||
"model_info": modelInfoObj
|
||||
}
|
||||
const new_model: Model = {
|
||||
"model_name": modelName,
|
||||
"litellm_params": litellmParamsObj,
|
||||
"model_info": modelInfoObj
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const response: any = await modelCreateCall(
|
||||
accessToken,
|
||||
new_model
|
||||
);
|
||||
const response: any = await modelCreateCall(
|
||||
accessToken,
|
||||
new_model
|
||||
);
|
||||
form.resetFields();
|
||||
|
||||
console.log(`response for model create call: ${response["data"]}`);
|
||||
console.log(`response for model create call: ${response["data"]}`);
|
||||
} catch (error) {
|
||||
message.error("Failed to create model: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
const handleOk = () => {
|
||||
@@ -235,7 +244,7 @@ const ModelDashboard: React.FC<ModelDashboardProps> = ({
|
||||
.validateFields()
|
||||
.then((values) => {
|
||||
handleSubmit(values);
|
||||
form.resetFields();
|
||||
// form.resetFields();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Validation failed:", error);
|
||||
|
||||
@@ -38,7 +38,7 @@ export const modelCreateCall = async (
|
||||
|
||||
const data = await response.json();
|
||||
console.log("API Response:", data);
|
||||
message.success("Model created successfully. Wait 60s and refresh.")
|
||||
message.success("Model created successfully. Wait 60s and refresh on 'All Models' page");
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Failed to create key:", error);
|
||||
|
||||
@@ -34,6 +34,7 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
const [callbacks, setCallbacks] = useState<string[]>([]);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [selectedCallback, setSelectedCallback] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!accessToken || !userRole || !userID) {
|
||||
@@ -55,6 +56,7 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
const handleCancel = () => {
|
||||
setIsModalVisible(false);
|
||||
form.resetFields();
|
||||
setSelectedCallback(null);
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
@@ -64,8 +66,8 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
// Handle form submission
|
||||
form.validateFields().then((values) => {
|
||||
// Call API to add the callback
|
||||
console.log("Form values:", values);
|
||||
let payload;
|
||||
console.log("Callback values:", values);
|
||||
if (values.callback === 'langfuse') {
|
||||
payload = {
|
||||
environment_variables: {
|
||||
@@ -80,8 +82,19 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
|
||||
// add langfuse to callbacks
|
||||
setCallbacks(callbacks ? [...callbacks, values.callback] : [values.callback]);
|
||||
} else if (values.callback === 'slack') {
|
||||
payload = {
|
||||
litellm_settings: {
|
||||
success_callback: [values.callback]
|
||||
},
|
||||
environment_variables: {
|
||||
SLACK_WEBHOOK_URL: values.slackWebhookUrl
|
||||
}
|
||||
};
|
||||
setCallbacksCall(accessToken, payload);
|
||||
|
||||
|
||||
// add slack to callbacks
|
||||
setCallbacks(callbacks ? [...callbacks, values.callback] : [values.callback]);
|
||||
} else {
|
||||
payload = {
|
||||
error: 'Invalid callback value'
|
||||
@@ -89,9 +102,14 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
}
|
||||
setIsModalVisible(false);
|
||||
form.resetFields();
|
||||
setSelectedCallback(null);
|
||||
});
|
||||
};
|
||||
|
||||
const handleCallbackChange = (value: string) => {
|
||||
setSelectedCallback(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full mx-4">
|
||||
<Grid numItems={1} className="gap-2 p-8 h-[75vh] w-full mt-2">
|
||||
@@ -138,33 +156,48 @@ const Settings: React.FC<SettingsPageProps> = ({
|
||||
name="callback"
|
||||
rules={[{ required: true, message: "Please select a callback" }]}
|
||||
>
|
||||
<Select>
|
||||
<Select onChange={handleCallbackChange}>
|
||||
<Select.Option value="langfuse">langfuse</Select.Option>
|
||||
<Select.Option value="slack">slack</Select.Option>
|
||||
<Select.Option value="slack">slack alerting</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="LANGFUSE_PUBLIC_KEY"
|
||||
name="langfusePublicKey"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the public key" },
|
||||
]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
{selectedCallback === 'langfuse' && (
|
||||
<>
|
||||
<Form.Item
|
||||
label="LANGFUSE_PUBLIC_KEY"
|
||||
name="langfusePublicKey"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the public key" },
|
||||
]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="LANGFUSE_PRIVATE_KEY"
|
||||
name="langfusePrivateKey"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the private key" },
|
||||
]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="LANGFUSE_PRIVATE_KEY"
|
||||
name="langfusePrivateKey"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the private key" },
|
||||
]}
|
||||
>
|
||||
<Input.Password />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
|
||||
{selectedCallback === 'slack' && (
|
||||
<Form.Item
|
||||
label="SLACK_WEBHOOK_URL"
|
||||
name="slackWebhookUrl"
|
||||
rules={[
|
||||
{ required: true, message: "Please enter the Slack webhook URL" },
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
|
||||
<div style={{ textAlign: "right", marginTop: "10px" }}>
|
||||
<Button2 htmlType="submit">Save</Button2>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user