Merge pull request #2905 from BerriAI/litellm_ui_add_slack_alerting

UI add slack alerting
This commit is contained in:
Ishaan Jaff
2024-04-08 20:39:33 -07:00
committed by GitHub
5 changed files with 118 additions and 74 deletions
+6 -4
View File
@@ -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>