DesertWolf's picture
Upload folder using huggingface_hub
447ebeb verified
import React, { useState, useEffect } from "react";
import {
Card,
Title,
Text,
Grid,
Badge,
Button as TremorButton,
Tab,
TabGroup,
TabList,
TabPanel,
TabPanels,
TextInput,
} from "@tremor/react";
import { Button, Form, Input, Select, message, Tooltip, Divider } from "antd";
import { InfoCircleOutlined } from '@ant-design/icons';
import { getGuardrailInfo, updateGuardrailCall, getGuardrailUISettings } from "@/components/networking";
import { getGuardrailLogoAndName } from "./guardrail_info_helpers";
import PiiConfiguration from "./pii_configuration";
export interface GuardrailInfoProps {
guardrailId: string;
onClose: () => void;
accessToken: string | null;
isAdmin: boolean;
}
const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({
guardrailId,
onClose,
accessToken,
isAdmin
}) => {
const [guardrailData, setGuardrailData] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [isEditing, setIsEditing] = useState(false);
const [form] = Form.useForm();
const [selectedPiiEntities, setSelectedPiiEntities] = useState<string[]>([]);
const [selectedPiiActions, setSelectedPiiActions] = useState<{[key: string]: string}>({});
const [guardrailSettings, setGuardrailSettings] = useState<{
supported_entities: string[];
supported_actions: string[];
pii_entity_categories: Array<{
category: string;
entities: string[];
}>;
supported_modes: string[];
} | null>(null);
const fetchGuardrailInfo = async () => {
try {
setLoading(true);
if (!accessToken) return;
const response = await getGuardrailInfo(accessToken, guardrailId);
setGuardrailData(response);
// Initialize PII configuration from guardrail data
if (response.litellm_params?.pii_entities_config) {
const piiConfig = response.litellm_params.pii_entities_config;
// Clear previous selections
setSelectedPiiEntities([]);
setSelectedPiiActions({});
// Only if there are entities configured
if (Object.keys(piiConfig).length > 0) {
const entities: string[] = [];
const actions: {[key: string]: string} = {};
Object.entries(piiConfig).forEach(([entity, action]: [string, any]) => {
entities.push(entity);
actions[entity] = typeof action === 'string' ? action : "MASK";
});
setSelectedPiiEntities(entities);
setSelectedPiiActions(actions);
}
} else {
// Clear selections if no PII config exists
setSelectedPiiEntities([]);
setSelectedPiiActions({});
}
} catch (error) {
message.error("Failed to load guardrail information");
console.error("Error fetching guardrail info:", error);
} finally {
setLoading(false);
}
};
const fetchGuardrailUISettings = async () => {
try {
if (!accessToken) return;
const uiSettings = await getGuardrailUISettings(accessToken);
setGuardrailSettings(uiSettings);
} catch (error) {
console.error("Error fetching guardrail UI settings:", error);
}
};
useEffect(() => {
fetchGuardrailInfo();
fetchGuardrailUISettings();
}, [guardrailId, accessToken]);
const handlePiiEntitySelect = (entity: string) => {
setSelectedPiiEntities(prev => {
if (prev.includes(entity)) {
return prev.filter(e => e !== entity);
} else {
return [...prev, entity];
}
});
};
const handlePiiActionSelect = (entity: string, action: string) => {
setSelectedPiiActions(prev => ({
...prev,
[entity]: action
}));
};
const handleGuardrailUpdate = async (values: any) => {
try {
if (!accessToken) return;
// Prepare update data object
const updateData: any = {
guardrail_name: values.guardrail_name,
litellm_params: {
default_on: values.default_on,
},
guardrail_info: values.guardrail_info ? JSON.parse(values.guardrail_info) : undefined
};
// Only add PII entities config if we have selected entities
if (selectedPiiEntities.length > 0) {
// Create PII config object only with selected entities
const piiEntitiesConfig: {[key: string]: string} = {};
selectedPiiEntities.forEach(entity => {
piiEntitiesConfig[entity] = selectedPiiActions[entity] || "MASK";
});
// Add to litellm_params only if we have entities
updateData.litellm_params.pii_entities_config = piiEntitiesConfig;
} else {
// If no entities selected, explicitly set to empty object
// This will clear any existing PII config
updateData.litellm_params.pii_entities_config = {};
}
await updateGuardrailCall(accessToken, guardrailId, updateData);
message.success("Guardrail updated successfully");
fetchGuardrailInfo();
setIsEditing(false);
} catch (error) {
console.error("Error updating guardrail:", error);
message.error("Failed to update guardrail");
}
};
if (loading) {
return <div className="p-4">Loading...</div>;
}
if (!guardrailData) {
return <div className="p-4">Guardrail not found</div>;
}
// Format date helper function
const formatDate = (dateString?: string) => {
if (!dateString) return "-";
const date = new Date(dateString);
return date.toLocaleString();
};
// Format the provider display name and logo
const { logo, displayName } = getGuardrailLogoAndName(guardrailData.litellm_params?.guardrail || "");
return (
<div className="p-4">
<div className="flex justify-between items-center mb-6">
<div>
<Button onClick={onClose} className="mb-4">← Back</Button>
<Title>{guardrailData.guardrail_name || "Unnamed Guardrail"}</Title>
<Text className="text-gray-500 font-mono">{guardrailData.guardrail_id}</Text>
</div>
</div>
<TabGroup>
<TabList className="mb-4">
<Tab key="overview">Overview</Tab>
{isAdmin ? <Tab key="settings">Settings</Tab> : <></>}
</TabList>
<TabPanels>
{/* Overview Panel */}
<TabPanel>
<Grid numItems={1} numItemsSm={2} numItemsLg={3} className="gap-6">
<Card>
<Text>Provider</Text>
<div className="mt-2 flex items-center space-x-2">
{logo && (
<img
src={logo}
alt={`${displayName} logo`}
className="w-6 h-6"
onError={(e) => {
// Hide broken image
(e.target as HTMLImageElement).style.display = 'none';
}}
/>
)}
<Title>{displayName}</Title>
</div>
</Card>
<Card>
<Text>Mode</Text>
<div className="mt-2">
<Title>{guardrailData.litellm_params?.mode || "-"}</Title>
<Badge color={guardrailData.litellm_params?.default_on ? "green" : "gray"}>
{guardrailData.litellm_params?.default_on ? "Default On" : "Default Off"}
</Badge>
</div>
</Card>
<Card>
<Text>Created At</Text>
<div className="mt-2">
<Title>{formatDate(guardrailData.created_at)}</Title>
<Text>Last Updated: {formatDate(guardrailData.updated_at)}</Text>
</div>
</Card>
</Grid>
{guardrailData.litellm_params?.pii_entities_config && Object.keys(guardrailData.litellm_params.pii_entities_config).length > 0 && (
<Card className="mt-6">
<div className="flex justify-between items-center">
<Text className="font-medium">PII Protection</Text>
<Badge color="blue">
{Object.keys(guardrailData.litellm_params.pii_entities_config).length} PII entities configured
</Badge>
</div>
</Card>
)}
{guardrailData.guardrail_info && Object.keys(guardrailData.guardrail_info).length > 0 && (
<Card className="mt-6">
<Text>Guardrail Info</Text>
<div className="mt-2 space-y-2">
{Object.entries(guardrailData.guardrail_info).map(([key, value]) => (
<div key={key} className="flex">
<Text className="font-medium w-1/3">{key}</Text>
<Text className="w-2/3">
{typeof value === 'object'
? JSON.stringify(value, null, 2)
: String(value)}
</Text>
</div>
))}
</div>
</Card>
)}
</TabPanel>
{/* Settings Panel (only for admins) */}
{isAdmin && (
<TabPanel>
<Card>
<div className="flex justify-between items-center mb-4">
<Title>Guardrail Settings</Title>
{!isEditing && (
<TremorButton
onClick={() => setIsEditing(true)}
>
Edit Settings
</TremorButton>
)}
</div>
{isEditing ? (
<Form
form={form}
onFinish={handleGuardrailUpdate}
initialValues={{
guardrail_name: guardrailData.guardrail_name,
...guardrailData.litellm_params,
guardrail_info: guardrailData.guardrail_info
? JSON.stringify(guardrailData.guardrail_info, null, 2)
: "",
}}
layout="vertical"
>
<Form.Item
label="Guardrail Name"
name="guardrail_name"
rules={[{ required: true, message: "Please input a guardrail name" }]}
>
<TextInput />
</Form.Item>
<Form.Item
label="Default On"
name="default_on"
>
<Select>
<Select.Option value={true}>Yes</Select.Option>
<Select.Option value={false}>No</Select.Option>
</Select>
</Form.Item>
<Divider orientation="left">PII Protection</Divider>
<div className="mb-6">
{guardrailSettings && (
<PiiConfiguration
entities={guardrailSettings.supported_entities}
actions={guardrailSettings.supported_actions}
selectedEntities={selectedPiiEntities}
selectedActions={selectedPiiActions}
onEntitySelect={handlePiiEntitySelect}
onActionSelect={handlePiiActionSelect}
entityCategories={guardrailSettings.pii_entity_categories}
/>
)}
</div>
<Divider orientation="left">Advanced Settings</Divider>
<Form.Item
label="Guardrail Information"
name="guardrail_info"
>
<Input.TextArea rows={5} />
</Form.Item>
<div className="flex justify-end gap-2 mt-6">
<Button onClick={() => setIsEditing(false)}>
Cancel
</Button>
<TremorButton>
Save Changes
</TremorButton>
</div>
</Form>
) : (
<div className="space-y-4">
<div>
<Text className="font-medium">Guardrail ID</Text>
<div className="font-mono">{guardrailData.guardrail_id}</div>
</div>
<div>
<Text className="font-medium">Guardrail Name</Text>
<div>{guardrailData.guardrail_name || "Unnamed Guardrail"}</div>
</div>
<div>
<Text className="font-medium">Provider</Text>
<div>{displayName}</div>
</div>
<div>
<Text className="font-medium">Mode</Text>
<div>{guardrailData.litellm_params?.mode || "-"}</div>
</div>
<div>
<Text className="font-medium">Default On</Text>
<Badge color={guardrailData.litellm_params?.default_on ? "green" : "gray"}>
{guardrailData.litellm_params?.default_on ? "Yes" : "No"}
</Badge>
</div>
{guardrailData.litellm_params?.pii_entities_config && Object.keys(guardrailData.litellm_params.pii_entities_config).length > 0 && (
<div>
<Text className="font-medium">PII Protection</Text>
<div className="mt-2">
<Badge color="blue">
{Object.keys(guardrailData.litellm_params.pii_entities_config).length} PII entities configured
</Badge>
</div>
</div>
)}
<div>
<Text className="font-medium">Created At</Text>
<div>{formatDate(guardrailData.created_at)}</div>
</div>
<div>
<Text className="font-medium">Last Updated</Text>
<div>{formatDate(guardrailData.updated_at)}</div>
</div>
</div>
)}
</Card>
</TabPanel>
)}
</TabPanels>
</TabGroup>
</div>
);
};
export default GuardrailInfoView;