(ui) create user

This commit is contained in:
ishaan-jaff 2024-02-20 16:41:51 -08:00
parent c656eaf7a4
commit 02f7b902db
4 changed files with 221 additions and 11 deletions

View file

@ -79,14 +79,12 @@ const CreateKey: React.FC<CreateKeyProps> = ({
name="key_alias" name="key_alias"
> >
<Input /> <Input />
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Team ID" label="Team ID"
name="team_id" name="team_id"
> >
<Input placeholder="ai_team" /> <Input placeholder="ai_team" />
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Models" label="Models"
@ -103,44 +101,36 @@ const CreateKey: React.FC<CreateKeyProps> = ({
</Option> </Option>
))} ))}
</Select> </Select>
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults to all models</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Max Budget (USD)" label="Max Budget (USD)"
name="max_budget" name="max_budget"
> >
<InputNumber step={0.01} precision={2} width={200}/> <InputNumber step={0.01} precision={2} width={200}/>
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults Unlimited Budget </p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Tokens per minute Limit (TPM)" label="Tokens per minute Limit (TPM)"
name="tpm_limit" name="tpm_limit"
> >
<InputNumber step={1} width={400}/> <InputNumber step={1} width={400}/>
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults to Unlimited TPM</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Requests per minute Limit (RPM)" label="Requests per minute Limit (RPM)"
name="rpm_limit" name="rpm_limit"
> >
<InputNumber step={1} width={400}/> <InputNumber step={1} width={400}/>
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults to Unlimited RPM</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Duration (eg: 30s, 30h, 30d)" label="Duration (eg: 30s, 30h, 30d)"
name="duration" name="duration"
> >
<Input /> <Input />
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults to never expiring key</p>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="Metadata" label="Metadata"
name="metadata" name="metadata"
> >
<Input.TextArea rows={4} placeholder="Enter metadata as JSON" /> <Input.TextArea rows={4} placeholder="Enter metadata as JSON" />
<p style={{ fontStyle: 'italic', color: 'gray' }}>Optional, defaults to null</p>
</Form.Item> </Form.Item>
</> </>
) : ( ) : (

View file

@ -0,0 +1,148 @@
import React, { useState } from "react";
import { Button, Modal, Form, Input, message, Select, InputNumber } from "antd";
import { Button as Button2 } from "@tremor/react";
import { userCreateCall } from "./networking";
interface CreateuserProps {
userID: string;
accessToken: string;
}
const Createuser: React.FC<CreateuserProps> = ({ userID, accessToken }) => {
const [form] = Form.useForm();
const [isModalVisible, setIsModalVisible] = useState(false);
const [apiuser, setApiuser] = useState<string | null>(null);
const handleOk = () => {
setIsModalVisible(false);
form.resetFields();
};
const handleCancel = () => {
setIsModalVisible(false);
setApiuser(null);
form.resetFields();
};
const handleCreate = async (formValues: { user_id: string }) => {
try {
message.info("Making API Call");
setIsModalVisible(true);
console.log("formValues in create user:", formValues);
const response = await userCreateCall(accessToken, userID, formValues);
console.log("user create Response:", response);
setApiuser(response["key"]);
message.success("API user Created");
form.resetFields();
localStorage.removeItem("userData" + userID);
} catch (error) {
console.error("Error creating the user:", error);
}
};
return (
<div>
<Button2 className="mx-auto" onClick={() => setIsModalVisible(true)}>
+ Create New User
</Button2>
<Modal
title="Create User"
visible={isModalVisible}
width={800}
footer={null}
onOk={handleOk}
onCancel={handleCancel}
>
<Form form={form} onFinish={handleCreate} labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} labelAlign="left">
<Form.Item
label="User ID"
name="user_id"
>
<Input placeholder="Enter User ID" />
</Form.Item>
<Form.Item
label="Team ID"
name="team_id"
>
<Input placeholder="ai_team" />
</Form.Item>
<Form.Item
label="Models"
name="models"
>
{/* <Select
mode="multiple"
placeholder="Select models"
style={{ width: '100%' }}
>
{userModels.map((model) => (
<Option key={model} value={model}>
{model}
</Option>
))}
</Select> */}
</Form.Item>
<Form.Item
label="Max Budget (USD)"
name="max_budget"
>
<InputNumber step={0.01} precision={2} width={200}/>
</Form.Item>
<Form.Item
label="Tokens per minute Limit (TPM)"
name="tpm_limit"
>
<InputNumber step={1} width={400}/>
</Form.Item>
<Form.Item
label="Requests per minute Limit (RPM)"
name="rpm_limit"
>
<InputNumber step={1} width={400}/>
</Form.Item>
<Form.Item
label="Duration (eg: 30s, 30h, 30d)"
name="duration"
>
<Input />
</Form.Item>
<Form.Item
label="Metadata"
name="metadata"
>
<Input.TextArea rows={4} placeholder="Enter metadata as JSON" />
</Form.Item>
<Button htmlType="submit">
Create User
</Button>
</Form>
</Modal>
{apiuser && (
<Modal
title="Save Your User"
visible={isModalVisible}
onOk={handleOk}
onCancel={handleCancel}
footer={null}
>
<p>
Please save this secret user somewhere safe and accessible. For
security reasons, <b>you will not be able to view it again</b> through
your LiteLLM account. If you lose this secret user, you will need to
generate a new one.
</p>
<p>{apiuser != null ? `API user: ${apiuser}` : "User being created, this might take 30s"}</p>
</Modal>
)}
</div>
);
};
export default Createuser;

View file

@ -69,6 +69,71 @@ export const keyCreateCall = async (
} }
}; };
export const userCreateCall = async (
accessToken: string,
userID: string,
formValues: Record<string, any> // Assuming formValues is an object
) => {
try {
console.log("Form Values in keyCreateCall:", formValues); // Log the form values before making the API call
// check if formValues.description is not undefined, make it a string and add it to formValues.metadata
if (formValues.description) {
// add to formValues.metadata
if (!formValues.metadata) {
formValues.metadata = {};
}
// value needs to be in "", valid JSON
formValues.metadata.description = formValues.description;
// remove descrption from formValues
delete formValues.description;
formValues.metadata = JSON.stringify(formValues.metadata);
}
// if formValues.metadata is not undefined, make it a valid dict
if (formValues.metadata) {
console.log("formValues.metadata:", formValues.metadata);
// if there's an exception JSON.parse, show it in the message
try {
formValues.metadata = JSON.parse(formValues.metadata);
} catch (error) {
message.error("Failed to parse metadata: " + error);
throw new Error("Failed to parse metadata: " + error);
}
}
console.log("Form Values after check:", formValues);
const url = proxyBaseUrl ? `${proxyBaseUrl}/user/new` : `/user/new`;
const response = await fetch(url, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: userID,
...formValues, // Include formValues in the request body
}),
});
if (!response.ok) {
const errorData = await response.text();
message.error("Failed to create key: " + errorData);
console.error("Error response from the server:", errorData);
throw new Error("Network response was not ok");
}
const data = await response.json();
console.log("API Response:", data);
return data;
// Handle success - you might want to update some state or UI based on the created key
} catch (error) {
console.error("Failed to create key:", error);
throw error;
}
};
export const keyDeleteCall = async (accessToken: String, user_key: String) => { export const keyDeleteCall = async (accessToken: String, user_key: String) => {
try { try {
const url = proxyBaseUrl ? `${proxyBaseUrl}/key/delete` : `/key/delete`; const url = proxyBaseUrl ? `${proxyBaseUrl}/key/delete` : `/key/delete`;

View file

@ -3,6 +3,7 @@ import { Card, Title, Subtitle, Table, TableHead, TableRow, TableCell, TableBody
import { userInfoCall } from "./networking"; import { userInfoCall } from "./networking";
import { Badge, BadgeDelta, Button } from '@tremor/react'; import { Badge, BadgeDelta, Button } from '@tremor/react';
import RequestAccess from "./request_model_access"; import RequestAccess from "./request_model_access";
import CreateUser from "./create_user_button";
interface ViewUserDashboardProps { interface ViewUserDashboardProps {
accessToken: string | null; accessToken: string | null;
@ -55,6 +56,12 @@ const ViewUserDashboard: React.FC<ViewUserDashboardProps> = ({
return ( return (
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
<Grid className="gap-2 p-10 h-[75vh] w-full"> <Grid className="gap-2 p-10 h-[75vh] w-full">
<CreateUser
userID={userID}
userRole={userRole}
userModels={["litellm-proxy-budget"]}
accessToken={accessToken}
/>
<Card> <Card>
<Table className="mt-5"> <Table className="mt-5">
<TableHead> <TableHead>