mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-03 02:22:24 +00:00
feat(ui): i18n for guardrails monitor batch 1
This commit is contained in:
parent
7298777feb
commit
3795d7f468
8 changed files with 474 additions and 194 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { CloseOutlined, PlayCircleOutlined } from "@ant-design/icons";
|
||||
import { Button, Modal, Select, Input } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { fetchAvailableModels, type ModelGroup } from "@/components/playground/llm_calls/fetch_models";
|
||||
|
||||
const DEFAULT_PROMPT = `Evaluate whether this guardrail's decision was correct.
|
||||
|
|
@ -37,6 +38,7 @@ export function EvaluationSettingsModal({
|
|||
accessToken,
|
||||
onRunEvaluation,
|
||||
}: EvaluationSettingsModalProps) {
|
||||
const { t } = useTranslation();
|
||||
const [prompt, setPrompt] = useState(DEFAULT_PROMPT);
|
||||
const [schema, setSchema] = useState(DEFAULT_SCHEMA);
|
||||
const [model, setModel] = useState<string | null>(null);
|
||||
|
|
@ -80,7 +82,7 @@ export function EvaluationSettingsModal({
|
|||
|
||||
return (
|
||||
<Modal
|
||||
title="Evaluation Settings"
|
||||
title={t("guardrailsMonitor.evaluationSettingsModal.title")}
|
||||
open={open}
|
||||
onCancel={onClose}
|
||||
width={640}
|
||||
|
|
@ -90,16 +92,18 @@ export function EvaluationSettingsModal({
|
|||
>
|
||||
<p className="text-sm text-gray-500 mb-4">
|
||||
{guardrailName
|
||||
? `Configure AI evaluation for ${guardrailName}`
|
||||
: "Configure AI evaluation for re-running on logs"}
|
||||
? t("guardrailsMonitor.evaluationSettingsModal.describeForGuardrail", { name: guardrailName })
|
||||
: t("guardrailsMonitor.evaluationSettingsModal.describeForLogs")}
|
||||
</p>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-1.5">
|
||||
<label className="text-sm font-medium text-gray-700">Evaluation Prompt</label>
|
||||
<label className="text-sm font-medium text-gray-700">
|
||||
{t("guardrailsMonitor.evaluationSettingsModal.promptLabel")}
|
||||
</label>
|
||||
<button type="button" onClick={handleResetPrompt} className="text-xs text-indigo-600 hover:text-indigo-700">
|
||||
Reset to default
|
||||
{t("guardrailsMonitor.evaluationSettingsModal.resetToDefault")}
|
||||
</button>
|
||||
</div>
|
||||
<Input.TextArea
|
||||
|
|
@ -108,13 +112,13 @@ export function EvaluationSettingsModal({
|
|||
rows={6}
|
||||
className="font-mono text-sm"
|
||||
/>
|
||||
<p className="text-xs text-gray-400 mt-1">
|
||||
System prompt sent to the evaluation model. Output is structured via response_format.
|
||||
</p>
|
||||
<p className="text-xs text-gray-400 mt-1">{t("guardrailsMonitor.evaluationSettingsModal.promptHint")}</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Response Schema</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.evaluationSettingsModal.schemaLabel")}
|
||||
</label>
|
||||
<p className="text-xs text-gray-400 mb-1">response_format: json_schema</p>
|
||||
<Input.TextArea
|
||||
value={schema}
|
||||
|
|
@ -125,9 +129,13 @@ export function EvaluationSettingsModal({
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Model</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.evaluationSettingsModal.modelLabel")}
|
||||
</label>
|
||||
<Select
|
||||
placeholder={loadingModels ? "Loading models…" : "Select a model"}
|
||||
placeholder={
|
||||
loadingModels ? t("common.loading") : t("guardrailsMonitor.evaluationSettingsModal.selectModel")
|
||||
}
|
||||
value={model ?? undefined}
|
||||
onChange={setModel}
|
||||
options={modelSelectOptions}
|
||||
|
|
@ -135,15 +143,19 @@ export function EvaluationSettingsModal({
|
|||
showSearch
|
||||
optionFilterProp="label"
|
||||
loading={loadingModels}
|
||||
notFoundContent={!accessToken ? "Sign in to see models" : "No models available"}
|
||||
notFoundContent={
|
||||
!accessToken
|
||||
? t("guardrailsMonitor.evaluationSettingsModal.signInToSeeModels")
|
||||
: t("guardrailsMonitor.evaluationSettingsModal.noModelsAvailable")
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-end gap-2 mt-6 pt-4 border-t border-gray-100">
|
||||
<Button onClick={onClose}>Cancel</Button>
|
||||
<Button onClick={onClose}>{t("common.cancel")}</Button>
|
||||
<Button type="primary" icon={<PlayCircleOutlined />} onClick={handleRun} disabled={!model}>
|
||||
Run Evaluation
|
||||
{t("guardrailsMonitor.evaluationSettingsModal.runEvaluation")}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ import {
|
|||
SaveOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Button, Input, Select, Switch } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { TFunction } from "i18next";
|
||||
|
||||
interface GuardrailConfigProps {
|
||||
guardrailName: string;
|
||||
|
|
@ -14,19 +16,47 @@ interface GuardrailConfigProps {
|
|||
provider: string;
|
||||
}
|
||||
|
||||
const versions = [
|
||||
const versionsBase = [
|
||||
{
|
||||
id: "v3",
|
||||
label: "v3 (current)",
|
||||
date: "2026-02-18",
|
||||
author: "admin@company.com",
|
||||
changes: "Adjusted sensitivity for medical terms",
|
||||
},
|
||||
{ id: "v2", label: "v2", date: "2026-02-10", author: "admin@company.com", changes: "Added custom categories list" },
|
||||
{ id: "v1", label: "v1", date: "2026-01-28", author: "admin@company.com", changes: "Initial configuration" },
|
||||
{ id: "v2", date: "2026-02-10", author: "admin@company.com", changes: "Added custom categories list" },
|
||||
{ id: "v1", date: "2026-01-28", author: "admin@company.com", changes: "Initial configuration" },
|
||||
];
|
||||
|
||||
const getVersions = (t: TFunction, currentId: string) =>
|
||||
versionsBase.map((v) => ({
|
||||
...v,
|
||||
label: v.id === currentId ? `${v.id} (${t("guardrailsMonitor.guardrailConfig.current")})` : v.id,
|
||||
}));
|
||||
|
||||
const getActionOptions = (t: TFunction) => [
|
||||
{ value: "block", label: t("guardrailsMonitor.guardrailConfig.actionBlock") },
|
||||
{ value: "flag", label: t("guardrailsMonitor.guardrailConfig.actionFlag") },
|
||||
{ value: "log", label: t("guardrailsMonitor.guardrailConfig.actionLog") },
|
||||
{ value: "fallback", label: t("guardrailsMonitor.guardrailConfig.actionFallback") },
|
||||
];
|
||||
|
||||
const getProviderOptions = (t: TFunction) => [
|
||||
{ value: "bedrock", label: t("guardrailsMonitor.guardrailConfig.providerBedrock") },
|
||||
{ value: "google", label: t("guardrailsMonitor.guardrailConfig.providerGoogle") },
|
||||
{ value: "litellm", label: t("guardrailsMonitor.guardrailConfig.providerLiteLLM") },
|
||||
{ value: "custom", label: t("guardrailsMonitor.guardrailConfig.providerCustom") },
|
||||
];
|
||||
|
||||
const getGuardrailTypeOptions = (t: TFunction) => [
|
||||
{ value: "Content Safety", label: t("guardrailsMonitor.guardrailConfig.typeContentSafety") },
|
||||
{ value: "PII", label: t("guardrailsMonitor.guardrailConfig.typePII") },
|
||||
{ value: "Topic", label: t("guardrailsMonitor.guardrailConfig.typeTopic") },
|
||||
{ value: "prompt_injection", label: t("guardrailsMonitor.guardrailConfig.typePromptInjection") },
|
||||
{ value: "custom", label: t("guardrailsMonitor.guardrailConfig.typeCustom") },
|
||||
];
|
||||
|
||||
export function GuardrailConfig({ guardrailName, guardrailType, provider }: GuardrailConfigProps) {
|
||||
const { t } = useTranslation();
|
||||
const [action, setAction] = useState("block");
|
||||
const [enabled, setEnabled] = useState(true);
|
||||
const [customCode, setCustomCode] = useState("");
|
||||
|
|
@ -35,6 +65,11 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
const [version, setVersion] = useState("v3");
|
||||
const [showVersionHistory, setShowVersionHistory] = useState(false);
|
||||
|
||||
const versions = useMemo(() => getVersions(t, version), [t, version]);
|
||||
const actionOptions = useMemo(() => getActionOptions(t), [t]);
|
||||
const providerOptions = useMemo(() => getProviderOptions(t), [t]);
|
||||
const guardrailTypeOptions = useMemo(() => getGuardrailTypeOptions(t), [t]);
|
||||
|
||||
const handleRerun = () => {
|
||||
setRerunStatus("running");
|
||||
setTimeout(() => {
|
||||
|
|
@ -49,7 +84,9 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
<div className="bg-white border border-gray-200 rounded-lg p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-sm font-medium text-gray-700">Version:</span>
|
||||
<span className="text-sm font-medium text-gray-700">
|
||||
{t("guardrailsMonitor.guardrailConfig.versionLabel")}
|
||||
</span>
|
||||
<Select
|
||||
value={version}
|
||||
onChange={setVersion}
|
||||
|
|
@ -57,13 +94,17 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
style={{ width: 140 }}
|
||||
/>
|
||||
<Button type="link" size="small" onClick={() => setShowVersionHistory(!showVersionHistory)}>
|
||||
{showVersionHistory ? "Hide history" : "View history"}
|
||||
{showVersionHistory
|
||||
? t("guardrailsMonitor.guardrailConfig.hideHistory")
|
||||
: t("guardrailsMonitor.guardrailConfig.viewHistory")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button icon={<RollbackOutlined />}>Revert</Button>
|
||||
<Button icon={<RollbackOutlined />}>{t("guardrailsMonitor.guardrailConfig.revert")}</Button>
|
||||
<Button type="primary" icon={<SaveOutlined />}>
|
||||
Save as v{parseInt(version.replace("v", ""), 10) + 1}
|
||||
{t("guardrailsMonitor.guardrailConfig.saveAsVersion", {
|
||||
version: parseInt(version.replace("v", ""), 10) + 1,
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -97,62 +138,45 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
|
||||
{/* Parameters */}
|
||||
<div className="bg-white border border-gray-200 rounded-lg p-6">
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-1">Parameters</h3>
|
||||
<p className="text-xs text-gray-500 mb-5">Configure {guardrailName} behavior</p>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-1">
|
||||
{t("guardrailsMonitor.guardrailConfig.parametersTitle")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mb-5">
|
||||
{t("guardrailsMonitor.guardrailConfig.parametersDesc", { name: guardrailName })}
|
||||
</p>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Action on Failure</label>
|
||||
<Select
|
||||
value={action}
|
||||
onChange={setAction}
|
||||
style={{ width: "100%" }}
|
||||
options={[
|
||||
{ value: "block", label: "Block Request" },
|
||||
{ value: "flag", label: "Flag for Review" },
|
||||
{ value: "log", label: "Log Only" },
|
||||
{ value: "fallback", label: "Use Fallback Response" },
|
||||
]}
|
||||
/>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.guardrailConfig.actionOnFailure")}
|
||||
</label>
|
||||
<Select value={action} onChange={setAction} style={{ width: "100%" }} options={actionOptions} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Provider</label>
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
defaultValue={provider}
|
||||
options={[
|
||||
{ value: "bedrock", label: "AWS Bedrock Guardrails" },
|
||||
{ value: "google", label: "Google Cloud AI Safety" },
|
||||
{ value: "litellm", label: "LiteLLM Built-in" },
|
||||
{ value: "custom", label: "Custom Code" },
|
||||
]}
|
||||
/>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.guardrailConfig.providerLabel")}
|
||||
</label>
|
||||
<Select style={{ width: "100%" }} defaultValue={provider} options={providerOptions} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Guardrail Type</label>
|
||||
<Select
|
||||
style={{ width: "100%" }}
|
||||
defaultValue={guardrailType}
|
||||
options={[
|
||||
{ value: "Content Safety", label: "Content Safety" },
|
||||
{ value: "PII", label: "PII Detection" },
|
||||
{ value: "Topic", label: "Topic Restriction" },
|
||||
{ value: "prompt_injection", label: "Prompt Injection" },
|
||||
{ value: "custom", label: "Custom" },
|
||||
]}
|
||||
/>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.guardrailConfig.guardrailTypeLabel")}
|
||||
</label>
|
||||
<Select style={{ width: "100%" }} defaultValue={guardrailType} options={guardrailTypeOptions} />
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">Categories (comma-separated)</label>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1.5">
|
||||
{t("guardrailsMonitor.guardrailConfig.categoriesLabel")}
|
||||
</label>
|
||||
<Input defaultValue="violence, hate_speech, sexual_content, self_harm, illegal_activity" />
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2 flex items-center gap-3">
|
||||
<Switch checked={enabled} onChange={setEnabled} />
|
||||
<span className="text-sm text-gray-700">Guardrail enabled in production</span>
|
||||
<span className="text-sm text-gray-700">{t("guardrailsMonitor.guardrailConfig.enabledInProduction")}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -163,9 +187,9 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
<div>
|
||||
<h3 className="text-base font-semibold text-gray-900 flex items-center gap-2">
|
||||
<CodeOutlined className="text-gray-500" />
|
||||
Custom Code Override
|
||||
{t("guardrailsMonitor.guardrailConfig.customCodeTitle")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mt-0.5">Replace the built-in guardrail with custom evaluation code</p>
|
||||
<p className="text-xs text-gray-500 mt-0.5">{t("guardrailsMonitor.guardrailConfig.customCodeDesc")}</p>
|
||||
</div>
|
||||
<Switch checked={useCustomCode} onChange={setUseCustomCode} />
|
||||
</div>
|
||||
|
|
@ -188,10 +212,10 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
|
||||
{/* Re-run on Failing Logs */}
|
||||
<div className="bg-white border border-gray-200 rounded-lg p-6">
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-1">Test Configuration</h3>
|
||||
<p className="text-xs text-gray-500 mb-4">
|
||||
Re-run this guardrail on recent failing logs to validate your changes
|
||||
</p>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-1">
|
||||
{t("guardrailsMonitor.guardrailConfig.testConfigTitle")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mb-4">{t("guardrailsMonitor.guardrailConfig.testConfigDesc")}</p>
|
||||
|
||||
<div className="flex items-center gap-3">
|
||||
<Button
|
||||
|
|
@ -200,16 +224,20 @@ export function GuardrailConfig({ guardrailName, guardrailType, provider }: Guar
|
|||
loading={rerunStatus === "running"}
|
||||
onClick={handleRerun}
|
||||
>
|
||||
{rerunStatus === "running" ? "Running on 10 samples..." : "Re-run on failing logs"}
|
||||
{rerunStatus === "running"
|
||||
? t("guardrailsMonitor.guardrailConfig.runningOnSamples")
|
||||
: t("guardrailsMonitor.guardrailConfig.rerunOnFailingLogs")}
|
||||
</Button>
|
||||
|
||||
{rerunStatus === "success" && (
|
||||
<span className="text-sm text-green-600 flex items-center gap-2">
|
||||
<CheckCircleOutlined /> 7/10 would now pass with new config
|
||||
<CheckCircleOutlined /> {t("guardrailsMonitor.guardrailConfig.rerunSuccess")}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{rerunStatus === "error" && <span className="text-sm text-red-600">Error running tests</span>}
|
||||
{rerunStatus === "error" && (
|
||||
<span className="text-sm text-red-600">{t("guardrailsMonitor.guardrailConfig.rerunError")}</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { ArrowLeftOutlined, SafetyOutlined, SettingOutlined, WarningOutlined } f
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { Button, Col, Row, Spin, Tabs } from "antd";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getGuardrailsUsageDetail, getGuardrailsUsageLogs } from "@/components/networking";
|
||||
import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
|
||||
import { LogViewer } from "./LogViewer";
|
||||
|
|
@ -23,6 +24,7 @@ const statusColors: Record<string, { bg: string; text: string; dot: string }> =
|
|||
};
|
||||
|
||||
export function GuardrailDetail({ guardrailId, onBack, accessToken = null, startDate, endDate }: GuardrailDetailProps) {
|
||||
const { t } = useTranslation();
|
||||
const [activeTab, setActiveTab] = useState("overview");
|
||||
const [evaluationModalOpen, setEvaluationModalOpen] = useState(false);
|
||||
const [logsPage, setLogsPage] = useState(1);
|
||||
|
|
@ -100,9 +102,9 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
return (
|
||||
<div>
|
||||
<Button type="link" icon={<ArrowLeftOutlined />} onClick={onBack} className="pl-0 mb-4">
|
||||
Back to Overview
|
||||
{t("guardrailsMonitor.guardrailDetail.backToOverview")}
|
||||
</Button>
|
||||
<p className="text-red-600">Failed to load guardrail details.</p>
|
||||
<p className="text-red-600">{t("guardrailsMonitor.guardrailDetail.loadError")}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -111,7 +113,7 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
<div>
|
||||
<div className="mb-6">
|
||||
<Button type="link" icon={<ArrowLeftOutlined />} onClick={onBack} className="pl-0 mb-4">
|
||||
Back to Overview
|
||||
{t("guardrailsMonitor.guardrailDetail.backToOverview")}
|
||||
</Button>
|
||||
|
||||
<div className="flex items-start justify-between">
|
||||
|
|
@ -136,7 +138,7 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
type="default"
|
||||
icon={<SettingOutlined />}
|
||||
onClick={() => setEvaluationModalOpen(true)}
|
||||
title="Evaluation settings"
|
||||
title={t("guardrailsMonitor.guardrailDetail.evaluationSettings")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -146,8 +148,8 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
activeKey={activeTab}
|
||||
onChange={setActiveTab}
|
||||
items={[
|
||||
{ key: "overview", label: "Overview" },
|
||||
{ key: "logs", label: "Logs" },
|
||||
{ key: "overview", label: t("guardrailsMonitor.guardrailDetail.tabOverview") },
|
||||
{ key: "logs", label: t("guardrailsMonitor.guardrailDetail.tabLogs") },
|
||||
]}
|
||||
/>
|
||||
|
||||
|
|
@ -155,22 +157,27 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
<div className="space-y-6 mt-4">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col xs={12} md={8}>
|
||||
<MetricCard label="Requests Evaluated" value={data.requestsEvaluated.toLocaleString()} />
|
||||
<MetricCard
|
||||
label={t("guardrailsMonitor.guardrailDetail.requestsEvaluated")}
|
||||
value={data.requestsEvaluated.toLocaleString()}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={12} md={8}>
|
||||
<MetricCard
|
||||
label="Fail Rate"
|
||||
label={t("guardrailsMonitor.guardrailDetail.failRate")}
|
||||
value={`${data.failRate}%`}
|
||||
valueColor={
|
||||
data.failRate > 15 ? "text-red-600" : data.failRate > 5 ? "text-amber-600" : "text-green-600"
|
||||
}
|
||||
subtitle={`${Math.round((data.requestsEvaluated * data.failRate) / 100).toLocaleString()} blocked`}
|
||||
subtitle={t("guardrailsMonitor.guardrailDetail.blockedCount", {
|
||||
count: Math.round((data.requestsEvaluated * data.failRate) / 100).toLocaleString(),
|
||||
})}
|
||||
icon={data.failRate > 15 ? <WarningOutlined className="text-red-400" /> : undefined}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={12} md={8}>
|
||||
<MetricCard
|
||||
label="Avg. latency added"
|
||||
label={t("guardrailsMonitor.guardrailDetail.avgLatency")}
|
||||
value={data.avgLatency != null ? `${Math.round(data.avgLatency)}ms` : "—"}
|
||||
valueColor={
|
||||
data.avgLatency != null
|
||||
|
|
@ -181,7 +188,9 @@ export function GuardrailDetail({ guardrailId, onBack, accessToken = null, start
|
|||
: "text-green-600"
|
||||
: "text-gray-500"
|
||||
}
|
||||
subtitle={data.avgLatency != null ? "Per request (avg)" : "No data"}
|
||||
subtitle={
|
||||
data.avgLatency != null ? t("guardrailsMonitor.guardrailDetail.perRequestAvg") : t("common.noData")
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { useQuery } from "@tanstack/react-query";
|
|||
import { Button, Card, Col, Row, Spin, Table, Typography } from "antd";
|
||||
import type { ColumnsType } from "antd/es/table";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { getGuardrailsUsageOverview } from "@/components/networking";
|
||||
import { type PerformanceRow } from "./mockData";
|
||||
import { EvaluationSettingsModal } from "./EvaluationSettingsModal";
|
||||
|
|
@ -41,6 +42,7 @@ export function GuardrailsOverview({
|
|||
endDate,
|
||||
onSelectGuardrail,
|
||||
}: GuardrailsOverviewProps) {
|
||||
const { t } = useTranslation();
|
||||
const [sortBy, setSortBy] = useState<SortKey>("failRate");
|
||||
const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");
|
||||
const [evaluationModalOpen, setEvaluationModalOpen] = useState(false);
|
||||
|
|
@ -82,92 +84,95 @@ export function GuardrailsOverview({
|
|||
const isLoading = guardrailsLoading;
|
||||
const error = guardrailsError;
|
||||
|
||||
const columns: ColumnsType<PerformanceRow> = [
|
||||
{
|
||||
title: "Guardrail",
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
render: (name: string, row) => (
|
||||
<button
|
||||
type="button"
|
||||
className="text-sm font-medium text-gray-900 hover:text-indigo-600 text-left"
|
||||
onClick={() => onSelectGuardrail(row.id)}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Provider",
|
||||
dataIndex: "provider",
|
||||
key: "provider",
|
||||
render: (provider: string) => (
|
||||
<span
|
||||
className={`inline-flex items-center px-2 py-0.5 text-xs font-medium rounded border ${
|
||||
providerColors[provider] ?? providerColors.Custom
|
||||
}`}
|
||||
>
|
||||
{provider}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Requests",
|
||||
dataIndex: "requestsEvaluated",
|
||||
key: "requestsEvaluated",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "requestsEvaluated" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v: number) => v.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: "Fail Rate",
|
||||
dataIndex: "failRate",
|
||||
key: "failRate",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "failRate" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v: number, row) => (
|
||||
<span className={v > 15 ? "text-red-600" : v > 5 ? "text-amber-600" : "text-green-600"}>
|
||||
{v}%{row.trend === "up" && <span className="ml-1 text-xs text-red-400">↑</span>}
|
||||
{row.trend === "down" && <span className="ml-1 text-xs text-green-400">↓</span>}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Avg. latency added",
|
||||
dataIndex: "avgLatency",
|
||||
key: "avgLatency",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "avgLatency" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v?: number) => (
|
||||
<span
|
||||
className={
|
||||
v == null ? "text-gray-400" : v > 150 ? "text-red-600" : v > 50 ? "text-amber-600" : "text-green-600"
|
||||
}
|
||||
>
|
||||
{v != null ? `${v}ms` : "—"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
align: "center",
|
||||
render: (status: string) => (
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
const columns: ColumnsType<PerformanceRow> = useMemo(
|
||||
() => [
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colGuardrail"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
render: (name: string, row) => (
|
||||
<button
|
||||
type="button"
|
||||
className="text-sm font-medium text-gray-900 hover:text-indigo-600 text-left"
|
||||
onClick={() => onSelectGuardrail(row.id)}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colProvider"),
|
||||
dataIndex: "provider",
|
||||
key: "provider",
|
||||
render: (provider: string) => (
|
||||
<span
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
status === "healthy" ? "bg-green-500" : status === "warning" ? "bg-amber-500" : "bg-red-500"
|
||||
className={`inline-flex items-center px-2 py-0.5 text-xs font-medium rounded border ${
|
||||
providerColors[provider] ?? providerColors.Custom
|
||||
}`}
|
||||
/>
|
||||
<span className="text-xs text-gray-600 capitalize">{status}</span>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
>
|
||||
{provider}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colRequests"),
|
||||
dataIndex: "requestsEvaluated",
|
||||
key: "requestsEvaluated",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "requestsEvaluated" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v: number) => v.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colFailRate"),
|
||||
dataIndex: "failRate",
|
||||
key: "failRate",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "failRate" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v: number, row) => (
|
||||
<span className={v > 15 ? "text-red-600" : v > 5 ? "text-amber-600" : "text-green-600"}>
|
||||
{v}%{row.trend === "up" && <span className="ml-1 text-xs text-red-400">↑</span>}
|
||||
{row.trend === "down" && <span className="ml-1 text-xs text-green-400">↓</span>}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colAvgLatency"),
|
||||
dataIndex: "avgLatency",
|
||||
key: "avgLatency",
|
||||
align: "right",
|
||||
sorter: true,
|
||||
sortOrder: sortBy === "avgLatency" ? (sortDir === "desc" ? "descend" : "ascend") : null,
|
||||
render: (v?: number) => (
|
||||
<span
|
||||
className={
|
||||
v == null ? "text-gray-400" : v > 150 ? "text-red-600" : v > 50 ? "text-amber-600" : "text-green-600"
|
||||
}
|
||||
>
|
||||
{v != null ? `${v}ms` : "—"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("guardrailsMonitor.guardrailsOverview.colStatus"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
align: "center",
|
||||
render: (status: string) => (
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<span
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
status === "healthy" ? "bg-green-500" : status === "warning" ? "bg-amber-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-xs text-gray-600 capitalize">{status}</span>
|
||||
</span>
|
||||
),
|
||||
},
|
||||
],
|
||||
[t, sortBy, sortDir, onSelectGuardrail],
|
||||
);
|
||||
|
||||
const sortableKeys: SortKey[] = ["failRate", "requestsEvaluated", "avgLatency"];
|
||||
const handleTableChange = (_pagination: unknown, _filters: unknown, sorter: unknown) => {
|
||||
|
|
@ -184,24 +189,27 @@ export function GuardrailsOverview({
|
|||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<SafetyOutlined className="text-lg text-indigo-500" />
|
||||
<h1 className="text-xl font-semibold text-gray-900">Guardrails Monitor</h1>
|
||||
<h1 className="text-xl font-semibold text-gray-900">{t("guardrailsMonitor.guardrailsOverview.title")}</h1>
|
||||
</div>
|
||||
<p className="text-sm text-gray-500">Monitor guardrail performance across all requests</p>
|
||||
<p className="text-sm text-gray-500">{t("guardrailsMonitor.guardrailsOverview.subtitle")}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<Button type="default" icon={<DownloadOutlined />} title="Coming soon">
|
||||
Export Data
|
||||
<Button type="default" icon={<DownloadOutlined />} title={t("common.comingSoon")}>
|
||||
{t("common.export")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Row gutter={[16, 16]} className="mb-6">
|
||||
<Col xs={12} sm={12} md={8} flex="1 0 20%">
|
||||
<MetricCard label="Total Evaluations" value={metrics.totalRequests.toLocaleString()} />
|
||||
<MetricCard
|
||||
label={t("guardrailsMonitor.guardrailsOverview.totalEvaluations")}
|
||||
value={metrics.totalRequests.toLocaleString()}
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={12} sm={12} md={8} flex="1 0 20%">
|
||||
<MetricCard
|
||||
label="Blocked Requests"
|
||||
label={t("guardrailsMonitor.guardrailsOverview.blockedRequests")}
|
||||
value={metrics.totalBlocked.toLocaleString()}
|
||||
valueColor="text-red-600"
|
||||
icon={<WarningOutlined className="text-red-400" />}
|
||||
|
|
@ -209,7 +217,7 @@ export function GuardrailsOverview({
|
|||
</Col>
|
||||
<Col xs={12} sm={12} md={8} flex="1 0 20%">
|
||||
<MetricCard
|
||||
label="Pass Rate"
|
||||
label={t("guardrailsMonitor.guardrailsOverview.passRate")}
|
||||
value={`${metrics.passRate}%`}
|
||||
valueColor="text-green-600"
|
||||
icon={<RiseOutlined className="text-green-400" />}
|
||||
|
|
@ -217,7 +225,7 @@ export function GuardrailsOverview({
|
|||
</Col>
|
||||
<Col xs={12} sm={12} md={8} flex="1 0 20%">
|
||||
<MetricCard
|
||||
label="Avg. latency added"
|
||||
label={t("guardrailsMonitor.guardrailsOverview.avgLatency")}
|
||||
value={`${metrics.avgLatency}ms`}
|
||||
valueColor={
|
||||
metrics.avgLatency > 150 ? "text-red-600" : metrics.avgLatency > 50 ? "text-amber-600" : "text-green-600"
|
||||
|
|
@ -225,7 +233,7 @@ export function GuardrailsOverview({
|
|||
/>
|
||||
</Col>
|
||||
<Col xs={12} sm={12} md={8} flex="1 0 20%">
|
||||
<MetricCard label="Active Guardrails" value={metrics.count} />
|
||||
<MetricCard label={t("guardrailsMonitor.guardrailsOverview.activeGuardrails")} value={metrics.count} />
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
|
|
@ -237,22 +245,26 @@ export function GuardrailsOverview({
|
|||
{(isLoading || error) && (
|
||||
<div className="px-6 py-4 border-b border-gray-200 flex items-center gap-2">
|
||||
{isLoading && <Spin size="small" />}
|
||||
{error && <span className="text-sm text-red-600">Failed to load data. Try again.</span>}
|
||||
{error && (
|
||||
<span className="text-sm text-red-600">{t("guardrailsMonitor.guardrailsOverview.loadError")}</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="px-6 py-4 border-b border-gray-200 flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<Typography.Title level={5} className="!mb-0 text-gray-900">
|
||||
Guardrail Performance
|
||||
{t("guardrailsMonitor.guardrailsOverview.performanceTitle")}
|
||||
</Typography.Title>
|
||||
<p className="text-xs text-gray-500 mt-0.5">Click a guardrail to view details, logs, and configuration</p>
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
{t("guardrailsMonitor.guardrailsOverview.performanceSubtitle")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
type="default"
|
||||
icon={<SettingOutlined />}
|
||||
onClick={() => setEvaluationModalOpen(true)}
|
||||
title="Evaluation settings"
|
||||
title={t("guardrailsMonitor.guardrailsOverview.evaluationSettings")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -263,7 +275,11 @@ export function GuardrailsOverview({
|
|||
pagination={false}
|
||||
loading={isLoading}
|
||||
onChange={handleTableChange}
|
||||
locale={activeData.length === 0 && !isLoading ? { emptyText: "No data for this period" } : undefined}
|
||||
locale={
|
||||
activeData.length === 0 && !isLoading
|
||||
? { emptyText: t("guardrailsMonitor.guardrailsOverview.noDataForPeriod") }
|
||||
: undefined
|
||||
}
|
||||
onRow={(row) => ({
|
||||
onClick: () => onSelectGuardrail(row.id),
|
||||
style: { cursor: "pointer" },
|
||||
|
|
|
|||
|
|
@ -2,36 +2,34 @@ import { CheckCircleOutlined, CloseOutlined, DownOutlined, WarningOutlined } fro
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import moment from "moment";
|
||||
import { Button, Spin } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { uiSpendLogsCall } from "@/components/networking";
|
||||
import { LogDetailsDrawer } from "@/components/view_logs/LogDetailsDrawer";
|
||||
import type { LogEntry as ViewLogsLogEntry } from "@/components/view_logs/columns";
|
||||
import type { LogEntry } from "./mockData";
|
||||
|
||||
const actionConfig: Record<
|
||||
const actionStyles: Record<
|
||||
"blocked" | "passed" | "flagged",
|
||||
{ icon: React.ElementType; color: string; bg: string; border: string; label: string }
|
||||
{ icon: React.ElementType; color: string; bg: string; border: string }
|
||||
> = {
|
||||
blocked: {
|
||||
icon: CloseOutlined,
|
||||
color: "text-red-600",
|
||||
bg: "bg-red-50",
|
||||
border: "border-red-200",
|
||||
label: "Blocked",
|
||||
},
|
||||
passed: {
|
||||
icon: CheckCircleOutlined,
|
||||
color: "text-green-600",
|
||||
bg: "bg-green-50",
|
||||
border: "border-green-200",
|
||||
label: "Passed",
|
||||
},
|
||||
flagged: {
|
||||
icon: WarningOutlined,
|
||||
color: "text-amber-600",
|
||||
bg: "bg-amber-50",
|
||||
border: "border-amber-200",
|
||||
label: "Flagged",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -56,11 +54,21 @@ export function LogViewer({
|
|||
startDate = "",
|
||||
endDate = "",
|
||||
}: LogViewerProps) {
|
||||
const { t } = useTranslation();
|
||||
const [sampleSize, setSampleSize] = useState(10);
|
||||
const [activeFilter, setActiveFilter] = useState<string>(filterAction);
|
||||
const [selectedRequestId, setSelectedRequestId] = useState<string | null>(null);
|
||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||
|
||||
const actionConfig = useMemo(
|
||||
() => ({
|
||||
blocked: { ...actionStyles.blocked, label: t("guardrailsMonitor.logViewer.actionBlocked") },
|
||||
passed: { ...actionStyles.passed, label: t("guardrailsMonitor.logViewer.actionPassed") },
|
||||
flagged: { ...actionStyles.flagged, label: t("guardrailsMonitor.logViewer.actionFlagged") },
|
||||
}),
|
||||
[t],
|
||||
);
|
||||
|
||||
const filteredLogs = logs.filter((log) => activeFilter === "all" || log.action === activeFilter);
|
||||
const displayLogs = filteredLogs.slice(0, sampleSize);
|
||||
const total = totalLogs ?? logs.length;
|
||||
|
|
@ -109,14 +117,19 @@ export function LogViewer({
|
|||
<div className="flex items-center justify-between flex-wrap gap-3">
|
||||
<div>
|
||||
<h3 className="text-base font-semibold text-gray-900">
|
||||
{guardrailName ? `Logs — ${guardrailName}` : "Request Logs"}
|
||||
{guardrailName
|
||||
? t("guardrailsMonitor.logViewer.titleWithName", { name: guardrailName })
|
||||
: t("guardrailsMonitor.logViewer.titleDefault")}
|
||||
</h3>
|
||||
<p className="text-xs text-gray-500 mt-0.5">
|
||||
{logsLoading
|
||||
? "Loading…"
|
||||
? t("common.loading")
|
||||
: logs.length > 0
|
||||
? `Showing ${displayLogs.length} of ${total} entries`
|
||||
: "No logs for this period. Select a guardrail and date range."}
|
||||
? t("guardrailsMonitor.logViewer.showingEntries", {
|
||||
shown: displayLogs.length,
|
||||
total,
|
||||
})
|
||||
: t("guardrailsMonitor.logViewer.noLogsForPeriod")}
|
||||
</p>
|
||||
</div>
|
||||
{logs.length > 0 && (
|
||||
|
|
@ -135,7 +148,7 @@ export function LogViewer({
|
|||
</div>
|
||||
<div className="h-4 w-px bg-gray-200" />
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="text-xs text-gray-500 mr-1">Sample:</span>
|
||||
<span className="text-xs text-gray-500 mr-1">{t("guardrailsMonitor.logViewer.sampleLabel")}</span>
|
||||
{sampleSizes.map((size) => (
|
||||
<Button
|
||||
key={size}
|
||||
|
|
@ -158,7 +171,9 @@ export function LogViewer({
|
|||
</div>
|
||||
)}
|
||||
{!logsLoading && displayLogs.length === 0 && (
|
||||
<div className="py-12 text-center text-sm text-gray-500">No logs to display. Adjust filters or date range.</div>
|
||||
<div className="py-12 text-center text-sm text-gray-500">
|
||||
{t("guardrailsMonitor.logViewer.noLogsToDisplay")}
|
||||
</div>
|
||||
)}
|
||||
{!logsLoading && displayLogs.length > 0 && (
|
||||
<div className="divide-y divide-gray-100">
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { BarChart, Card, Title } from "@tremor/react";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
/**
|
||||
* Overview chart: Request Outcomes Over Time (passed vs blocked).
|
||||
|
|
@ -10,11 +11,12 @@ interface ScoreChartProps {
|
|||
}
|
||||
|
||||
export function ScoreChart({ data }: ScoreChartProps) {
|
||||
const { t } = useTranslation();
|
||||
const chartData = data && data.length > 0 ? data : [];
|
||||
|
||||
return (
|
||||
<Card className="bg-white border border-gray-200">
|
||||
<Title className="text-base font-semibold text-gray-900 mb-4">Request Outcomes Over Time</Title>
|
||||
<Title className="text-base font-semibold text-gray-900 mb-4">{t("guardrailsMonitor.scoreChart.title")}</Title>
|
||||
<div className="h-80 min-h-[280px]">
|
||||
{chartData.length > 0 ? (
|
||||
<BarChart
|
||||
|
|
@ -29,7 +31,7 @@ export function ScoreChart({ data }: ScoreChartProps) {
|
|||
/>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full text-sm text-gray-500">
|
||||
No chart data for this period
|
||||
{t("guardrailsMonitor.scoreChart.noData")}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6784,5 +6784,104 @@
|
|||
"noModels": "No models",
|
||||
"statusBlocked": "Blocked"
|
||||
}
|
||||
},
|
||||
"guardrailsMonitor": {
|
||||
"evaluationSettingsModal": {
|
||||
"title": "Evaluation Settings",
|
||||
"describeForGuardrail": "Configure AI evaluation for {{name}}",
|
||||
"describeForLogs": "Configure AI evaluation for re-running on logs",
|
||||
"promptLabel": "Evaluation Prompt",
|
||||
"resetToDefault": "Reset to default",
|
||||
"promptHint": "System prompt sent to the evaluation model. Output is structured via response_format.",
|
||||
"schemaLabel": "Response Schema",
|
||||
"modelLabel": "Model",
|
||||
"selectModel": "Select a model",
|
||||
"signInToSeeModels": "Sign in to see models",
|
||||
"noModelsAvailable": "No models available",
|
||||
"runEvaluation": "Run Evaluation"
|
||||
},
|
||||
"guardrailConfig": {
|
||||
"current": "current",
|
||||
"versionLabel": "Version:",
|
||||
"hideHistory": "Hide history",
|
||||
"viewHistory": "View history",
|
||||
"revert": "Revert",
|
||||
"saveAsVersion": "Save as v{{version}}",
|
||||
"parametersTitle": "Parameters",
|
||||
"parametersDesc": "Configure {{name}} behavior",
|
||||
"actionOnFailure": "Action on Failure",
|
||||
"actionBlock": "Block Request",
|
||||
"actionFlag": "Flag for Review",
|
||||
"actionLog": "Log Only",
|
||||
"actionFallback": "Use Fallback Response",
|
||||
"providerLabel": "Provider",
|
||||
"providerBedrock": "AWS Bedrock Guardrails",
|
||||
"providerGoogle": "Google Cloud AI Safety",
|
||||
"providerLiteLLM": "LiteLLM Built-in",
|
||||
"providerCustom": "Custom Code",
|
||||
"guardrailTypeLabel": "Guardrail Type",
|
||||
"typeContentSafety": "Content Safety",
|
||||
"typePII": "PII Detection",
|
||||
"typeTopic": "Topic Restriction",
|
||||
"typePromptInjection": "Prompt Injection",
|
||||
"typeCustom": "Custom",
|
||||
"categoriesLabel": "Categories (comma-separated)",
|
||||
"enabledInProduction": "Guardrail enabled in production",
|
||||
"customCodeTitle": "Custom Code Override",
|
||||
"customCodeDesc": "Replace the built-in guardrail with custom evaluation code",
|
||||
"testConfigTitle": "Test Configuration",
|
||||
"testConfigDesc": "Re-run this guardrail on recent failing logs to validate your changes",
|
||||
"runningOnSamples": "Running on 10 samples...",
|
||||
"rerunOnFailingLogs": "Re-run on failing logs",
|
||||
"rerunSuccess": "7/10 would now pass with new config",
|
||||
"rerunError": "Error running tests"
|
||||
},
|
||||
"guardrailDetail": {
|
||||
"backToOverview": "Back to Overview",
|
||||
"loadError": "Failed to load guardrail details.",
|
||||
"evaluationSettings": "Evaluation settings",
|
||||
"tabOverview": "Overview",
|
||||
"tabLogs": "Logs",
|
||||
"requestsEvaluated": "Requests Evaluated",
|
||||
"failRate": "Fail Rate",
|
||||
"blockedCount": "{{count}} blocked",
|
||||
"avgLatency": "Avg. latency added",
|
||||
"perRequestAvg": "Per request (avg)"
|
||||
},
|
||||
"guardrailsOverview": {
|
||||
"title": "Guardrails Monitor",
|
||||
"subtitle": "Monitor guardrail performance across all requests",
|
||||
"totalEvaluations": "Total Evaluations",
|
||||
"blockedRequests": "Blocked Requests",
|
||||
"passRate": "Pass Rate",
|
||||
"avgLatency": "Avg. latency added",
|
||||
"activeGuardrails": "Active Guardrails",
|
||||
"colGuardrail": "Guardrail",
|
||||
"colProvider": "Provider",
|
||||
"colRequests": "Requests",
|
||||
"colFailRate": "Fail Rate",
|
||||
"colAvgLatency": "Avg. latency added",
|
||||
"colStatus": "Status",
|
||||
"performanceTitle": "Guardrail Performance",
|
||||
"performanceSubtitle": "Click a guardrail to view details, logs, and configuration",
|
||||
"evaluationSettings": "Evaluation settings",
|
||||
"noDataForPeriod": "No data for this period",
|
||||
"loadError": "Failed to load data. Try again."
|
||||
},
|
||||
"logViewer": {
|
||||
"titleWithName": "Logs — {{name}}",
|
||||
"titleDefault": "Request Logs",
|
||||
"showingEntries": "Showing {{shown}} of {{total}} entries",
|
||||
"noLogsForPeriod": "No logs for this period. Select a guardrail and date range.",
|
||||
"sampleLabel": "Sample:",
|
||||
"noLogsToDisplay": "No logs to display. Adjust filters or date range.",
|
||||
"actionBlocked": "Blocked",
|
||||
"actionPassed": "Passed",
|
||||
"actionFlagged": "Flagged"
|
||||
},
|
||||
"scoreChart": {
|
||||
"title": "Request Outcomes Over Time",
|
||||
"noData": "No chart data for this period"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6784,5 +6784,104 @@
|
|||
"noModels": "无模型",
|
||||
"statusBlocked": "已封锁"
|
||||
}
|
||||
},
|
||||
"guardrailsMonitor": {
|
||||
"evaluationSettingsModal": {
|
||||
"title": "评估设置",
|
||||
"describeForGuardrail": "为 {{name}} 配置 AI 评估",
|
||||
"describeForLogs": "配置 AI 评估以在日志上重新运行",
|
||||
"promptLabel": "评估提示词",
|
||||
"resetToDefault": "恢复默认",
|
||||
"promptHint": "发送给评估模型的系统提示词,输出通过 response_format 结构化。",
|
||||
"schemaLabel": "响应 Schema",
|
||||
"modelLabel": "模型",
|
||||
"selectModel": "选择模型",
|
||||
"signInToSeeModels": "请登录以查看可用模型",
|
||||
"noModelsAvailable": "暂无可用模型",
|
||||
"runEvaluation": "运行评估"
|
||||
},
|
||||
"guardrailConfig": {
|
||||
"current": "当前",
|
||||
"versionLabel": "版本:",
|
||||
"hideHistory": "隐藏历史",
|
||||
"viewHistory": "查看历史",
|
||||
"revert": "回退",
|
||||
"saveAsVersion": "保存为 v{{version}}",
|
||||
"parametersTitle": "参数",
|
||||
"parametersDesc": "配置 {{name}} 行为",
|
||||
"actionOnFailure": "失败时的动作",
|
||||
"actionBlock": "拦截请求",
|
||||
"actionFlag": "标记审查",
|
||||
"actionLog": "仅记录日志",
|
||||
"actionFallback": "使用回退响应",
|
||||
"providerLabel": "提供商",
|
||||
"providerBedrock": "AWS Bedrock 护栏",
|
||||
"providerGoogle": "Google Cloud AI 安全",
|
||||
"providerLiteLLM": "LiteLLM 内置",
|
||||
"providerCustom": "自定义代码",
|
||||
"guardrailTypeLabel": "护栏类型",
|
||||
"typeContentSafety": "内容安全",
|
||||
"typePII": "PII 检测",
|
||||
"typeTopic": "话题限制",
|
||||
"typePromptInjection": "提示词注入",
|
||||
"typeCustom": "自定义",
|
||||
"categoriesLabel": "类别(逗号分隔)",
|
||||
"enabledInProduction": "在生产环境中启用护栏",
|
||||
"customCodeTitle": "自定义代码覆盖",
|
||||
"customCodeDesc": "用自定义评估代码替换内置护栏",
|
||||
"testConfigTitle": "测试配置",
|
||||
"testConfigDesc": "在近期失败日志上重新运行此护栏以验证更改",
|
||||
"runningOnSamples": "正在运行 10 个样本...",
|
||||
"rerunOnFailingLogs": "在失败日志上重新运行",
|
||||
"rerunSuccess": "使用新配置后 7/10 将通过",
|
||||
"rerunError": "运行测试时出错"
|
||||
},
|
||||
"guardrailDetail": {
|
||||
"backToOverview": "返回概览",
|
||||
"loadError": "加载护栏详情失败。",
|
||||
"evaluationSettings": "评估设置",
|
||||
"tabOverview": "概览",
|
||||
"tabLogs": "日志",
|
||||
"requestsEvaluated": "已评估请求数",
|
||||
"failRate": "失败率",
|
||||
"blockedCount": "已拦截 {{count}} 个",
|
||||
"avgLatency": "新增平均延迟",
|
||||
"perRequestAvg": "每次请求(平均)"
|
||||
},
|
||||
"guardrailsOverview": {
|
||||
"title": "护栏监控",
|
||||
"subtitle": "监控所有请求的护栏性能",
|
||||
"totalEvaluations": "总评估次数",
|
||||
"blockedRequests": "已拦截请求",
|
||||
"passRate": "通过率",
|
||||
"avgLatency": "新增平均延迟",
|
||||
"activeGuardrails": "活跃护栏数",
|
||||
"colGuardrail": "护栏",
|
||||
"colProvider": "提供商",
|
||||
"colRequests": "请求数",
|
||||
"colFailRate": "失败率",
|
||||
"colAvgLatency": "新增平均延迟",
|
||||
"colStatus": "状态",
|
||||
"performanceTitle": "护栏性能",
|
||||
"performanceSubtitle": "点击护栏查看详情、日志和配置",
|
||||
"evaluationSettings": "评估设置",
|
||||
"noDataForPeriod": "该时段暂无数据",
|
||||
"loadError": "加载数据失败,请重试。"
|
||||
},
|
||||
"logViewer": {
|
||||
"titleWithName": "日志 — {{name}}",
|
||||
"titleDefault": "请求日志",
|
||||
"showingEntries": "显示 {{shown}} / {{total}} 条",
|
||||
"noLogsForPeriod": "该时段暂无日志,请选择护栏和日期范围。",
|
||||
"sampleLabel": "样本:",
|
||||
"noLogsToDisplay": "暂无日志,请调整过滤条件或日期范围。",
|
||||
"actionBlocked": "已拦截",
|
||||
"actionPassed": "已通过",
|
||||
"actionFlagged": "已标记"
|
||||
},
|
||||
"scoreChart": {
|
||||
"title": "请求结果随时间变化",
|
||||
"noData": "该时段暂无图表数据"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue