Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(UI) Allow adding custom pricing when adding new model #8165

Merged
merged 7 commits into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 155 additions & 75 deletions ui/litellm-dashboard/src/components/add_model/advanced_settings.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { Form, Switch } from "antd";
import { Text, Button, Accordion, AccordionHeader, AccordionBody } from "@tremor/react";
import { Form, Switch, Select, Input } from "antd";
import { Text, Button, Accordion, AccordionHeader, AccordionBody, TextInput } from "@tremor/react";
import { Row, Col, Typography, Card } from "antd";
import TextArea from "antd/es/input/TextArea";
const { Link } = Typography;
Expand All @@ -15,8 +15,20 @@ const AdvancedSettings: React.FC<AdvancedSettingsProps> = ({
setShowAdvancedSettings,
}) => {
const [form] = Form.useForm();
const [customPricing, setCustomPricing] = React.useState(false);
const [pricingModel, setPricingModel] = React.useState<'per_token' | 'per_second'>('per_token');

// Add validation function for numbers
const validateNumber = (_: any, value: string) => {
if (!value) {
return Promise.resolve();
}
if (isNaN(Number(value)) || Number(value) < 0) {
return Promise.reject('Please enter a valid positive number');
}
return Promise.resolve();
};

// Add validation function
const validateJSON = (_: any, value: string) => {
if (!value) {
return Promise.resolve();
Expand All @@ -29,6 +41,19 @@ const AdvancedSettings: React.FC<AdvancedSettingsProps> = ({
}
};

// Handle custom pricing changes
const handleCustomPricingChange = (checked: boolean) => {
setCustomPricing(checked);
if (!checked) {
// Clear pricing fields when disabled
form.setFieldsValue({
input_cost_per_token: undefined,
output_cost_per_token: undefined,
input_cost_per_second: undefined,
});
}
};

const handlePassThroughChange = (checked: boolean) => {
const currentParams = form.getFieldValue('litellm_extra_params');
try {
Expand Down Expand Up @@ -56,81 +81,136 @@ const AdvancedSettings: React.FC<AdvancedSettingsProps> = ({

return (
<>
<Accordion className="mt-2 mb-4">
<AccordionHeader>
<b>Advanced Settings</b>
</AccordionHeader>
<AccordionBody>
<div className="bg-white rounded-lg">
<Form.Item
label="Custom Pricing"
name="custom_pricing"
valuePropName="checked"
className="mb-4"
>
<Switch onChange={handleCustomPricingChange} className="bg-gray-600" />
</Form.Item>

<Accordion className="mt-2 mb-4">

<AccordionHeader>
<b>Advanced Settings</b>
</AccordionHeader>
<AccordionBody>
<div className="bg-white rounded-lg">
<Form.Item
label="Use in pass through routes"
name="use_in_pass_through"
valuePropName="checked"
className="mb-4 mt-4"
tooltip={
<span>
Allow using these credentials in pass through routes.{" "}
<Link href="https://docs.litellm.ai/docs/pass_through/vertex_ai" target="_blank">
Learn more
</Link>
</span>
}
>
<Switch
onChange={handlePassThroughChange}
className="bg-gray-600"
/>
</Form.Item>
<Form.Item
label="LiteLLM Params"
name="litellm_extra_params"
tooltip="Optional litellm params used for making a litellm.completion() call."
className="mb-4 mt-4"
rules={[{ validator: validateJSON }]}
>
<TextArea
rows={4}
placeholder='{
"rpm": 100,
"timeout": 0,
"stream_timeout": 0
}'
/>
</Form.Item>
<Row className="mb-4">
<Col span={10}></Col>
<Col span={10}>
<Text className="text-gray-600 text-sm">
Pass JSON of litellm supported params{" "}
<Link
href="https://docs.litellm.ai/docs/completion/input"
target="_blank"
{customPricing && (
<div className="ml-6 pl-4 border-l-2 border-gray-200">
<Form.Item
label="Pricing Model"
name="pricing_model"
className="mb-4"
>
<Select
defaultValue="per_token"
onChange={(value) => setPricingModel(value)}
options={[
{ value: 'per_token', label: 'Per Million Tokens' },
{ value: 'per_second', label: 'Per Second' },
]}
/>
</Form.Item>

{pricingModel === 'per_token' ? (
<>
<Form.Item
label="Input Cost (per 1M tokens)"
name="input_cost_per_token"
rules={[{ validator: validateNumber }]}
className="mb-4"
>
litellm.completion() call
</Link>
</Text>
</Col>
</Row>
<Form.Item
label="Model Info"
name="model_info_params"
tooltip="Optional model info params. Returned when calling `/model/info` endpoint."
className="mb-0"
rules={[{ validator: validateJSON }]}
>
<TextArea
rows={4}
placeholder='{
"mode": "chat"
}'
/>
</Form.Item>
</div>
</AccordionBody>
</Accordion>
<TextInput />
</Form.Item>
<Form.Item
label="Output Cost (per 1M tokens)"
name="output_cost_per_token"
rules={[{ validator: validateNumber }]}
className="mb-4"
>
<TextInput />
</Form.Item>
</>
) : (
<Form.Item
label="Cost Per Second"
name="input_cost_per_second"
rules={[{ validator: validateNumber }]}
className="mb-4"
>
<TextInput />
</Form.Item>
)}
</div>
)}

<Form.Item
label="Use in pass through routes"
name="use_in_pass_through"
valuePropName="checked"
className="mb-4 mt-4"
tooltip={
<span>
Allow using these credentials in pass through routes.{" "}
<Link href="https://docs.litellm.ai/docs/pass_through/vertex_ai" target="_blank">
Learn more
</Link>
</span>
}
>
<Switch
onChange={handlePassThroughChange}
className="bg-gray-600"
/>
</Form.Item>
<Form.Item
label="LiteLLM Params"
name="litellm_extra_params"
tooltip="Optional litellm params used for making a litellm.completion() call."
className="mb-4 mt-4"
rules={[{ validator: validateJSON }]}
>
<TextArea
rows={4}
placeholder='{
"rpm": 100,
"timeout": 0,
"stream_timeout": 0
}'
/>
</Form.Item>
<Row className="mb-4">
<Col span={10}></Col>
<Col span={10}>
<Text className="text-gray-600 text-sm">
Pass JSON of litellm supported params{" "}
<Link
href="https://docs.litellm.ai/docs/completion/input"
target="_blank"
>
litellm.completion() call
</Link>
</Text>
</Col>
</Row>
<Form.Item
label="Model Info"
name="model_info_params"
tooltip="Optional model info params. Returned when calling `/model/info` endpoint."
className="mb-0"
rules={[{ validator: validateJSON }]}
>
<TextArea
rows={4}
placeholder='{
"mode": "chat"
}'
/>
</Form.Item>
</div>
</AccordionBody>
</Accordion>
</>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export const handleAddModelSubmit = async (
console.log(`litellm_model: ${litellm_model}`);
const litellmParamsObj: Record<string, any> = {};
const modelInfoObj: Record<string, any> = {};

// Handle pricing conversion before processing other fields
if (formValues.input_cost_per_token) {
formValues.input_cost_per_token = Number(formValues.input_cost_per_token) / 1000000;
}
if (formValues.output_cost_per_token) {
formValues.output_cost_per_token = Number(formValues.output_cost_per_token) / 1000000;
}
// Keep input_cost_per_second as is, no conversion needed

// Iterate through the key-value pairs in formValues
litellmParamsObj["model"] = litellm_model;
let modelName: string = "";
Expand All @@ -43,6 +53,10 @@ export const handleAddModelSubmit = async (
if (value === "") {
continue;
}
// Skip the custom_pricing and pricing_model fields as they're only used for UI control
if (key === 'custom_pricing' || key === 'pricing_model') {
continue;
}
if (key == "model_name") {
modelName = modelName + value;
} else if (key == "custom_llm_provider") {
Expand Down Expand Up @@ -97,6 +111,16 @@ export const handleAddModelSubmit = async (
}
}

// Handle the pricing fields
else if (key === "input_cost_per_token" ||
key === "output_cost_per_token" ||
key === "input_cost_per_second") {
if (value) {
litellmParamsObj[key] = Number(value);
}
continue;
}

// Check if key is any of the specified API related keys
else {
// Add key-value pair to litellm_params dictionary
Expand Down
Loading