mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): view_logs/VectorStoreViewer to shadcn
- antd Collapse \u2192 shadcn Accordion. Inline SVG chevron \u2192 lucide ChevronRight. - Gray palette replaced with semantic bg-background/border-border/ bg-muted and text-muted-foreground tokens. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
f286c5a592
commit
c69d0c6aa6
1 changed files with 149 additions and 102 deletions
|
|
@ -1,5 +1,12 @@
|
|||
import React, { useState } from "react";
|
||||
import { Collapse } from "antd";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
AccordionItem,
|
||||
AccordionTrigger,
|
||||
} from "@/components/ui/accordion";
|
||||
import { ChevronRight } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { getProviderLogoAndName } from "../provider_info_helpers";
|
||||
|
||||
interface VectorStoreContent {
|
||||
|
|
@ -31,7 +38,9 @@ interface VectorStoreViewerProps {
|
|||
}
|
||||
|
||||
export function VectorStoreViewer({ data }: VectorStoreViewerProps) {
|
||||
const [expandedResults, setExpandedResults] = useState<Record<string, boolean>>({});
|
||||
const [expandedResults, setExpandedResults] = useState<
|
||||
Record<string, boolean>
|
||||
>({});
|
||||
|
||||
if (!data || data.length === 0) {
|
||||
return null;
|
||||
|
|
@ -43,7 +52,7 @@ export function VectorStoreViewer({ data }: VectorStoreViewerProps) {
|
|||
};
|
||||
|
||||
const calculateDuration = (start: number, end: number): string => {
|
||||
const duration = (end - start) * 1000; // convert to milliseconds
|
||||
const duration = (end - start) * 1000;
|
||||
return `${duration.toFixed(2)}ms`;
|
||||
};
|
||||
|
||||
|
|
@ -56,111 +65,149 @@ export function VectorStoreViewer({ data }: VectorStoreViewerProps) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="bg-white rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||
<Collapse
|
||||
defaultActiveKey={["1"]}
|
||||
expandIconPosition="start"
|
||||
items={[
|
||||
{
|
||||
key: "1",
|
||||
label: <h3 className="text-lg font-medium text-gray-900">Vector Store Requests</h3>,
|
||||
children: (
|
||||
<div className="p-4">
|
||||
{data.map((request, index) => (
|
||||
<div key={index} className="mb-6 last:mb-0">
|
||||
<div className="bg-white rounded-lg border p-4 mb-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Query:</span>
|
||||
<span className="font-mono">{request.query}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Vector Store ID:</span>
|
||||
<span className="font-mono">{request.vector_store_id}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Provider:</span>
|
||||
<span className="flex items-center">
|
||||
{(() => {
|
||||
const { logo, displayName } = getProviderLogoAndName(request.custom_llm_provider);
|
||||
return (
|
||||
<>
|
||||
{logo && <img src={logo} alt={`${displayName} logo`} className="h-5 w-5 mr-2" />}
|
||||
{displayName}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Start Time:</span>
|
||||
<span>{formatTime(request.start_time)}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">End Time:</span>
|
||||
<span>{formatTime(request.end_time)}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Duration:</span>
|
||||
<span>{calculateDuration(request.start_time, request.end_time)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 className="font-medium mb-2">Search Results</h4>
|
||||
<div className="space-y-2">
|
||||
{request.vector_store_search_response.data.map((result, resultIndex) => {
|
||||
const isExpanded = expandedResults[`${index}-${resultIndex}`] || false;
|
||||
|
||||
return (
|
||||
<div key={resultIndex} className="border rounded-lg overflow-hidden">
|
||||
<div
|
||||
className="flex items-center p-3 bg-gray-50 cursor-pointer"
|
||||
onClick={() => toggleResult(index, resultIndex)}
|
||||
>
|
||||
<svg
|
||||
className={`w-5 h-5 mr-2 transition-transform ${isExpanded ? "transform rotate-90" : ""}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<div className="flex items-center">
|
||||
<span className="font-medium mr-2">Result {resultIndex + 1}</span>
|
||||
<span className="text-gray-500 text-sm">
|
||||
Score: <span className="font-mono">{result.score.toFixed(4)}</span>
|
||||
<div className="bg-background rounded-lg shadow w-full max-w-full overflow-hidden mb-6">
|
||||
<Accordion type="single" collapsible defaultValue="vector-store">
|
||||
<AccordionItem value="vector-store">
|
||||
<AccordionTrigger>
|
||||
<h3 className="text-lg font-medium text-foreground m-0">
|
||||
Vector Store Requests
|
||||
</h3>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="p-4">
|
||||
{data.map((request, index) => (
|
||||
<div key={index} className="mb-6 last:mb-0">
|
||||
<div className="bg-background rounded-lg border border-border p-4 mb-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Query:</span>
|
||||
<span className="font-mono">{request.query}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">
|
||||
Vector Store ID:
|
||||
</span>
|
||||
<span className="font-mono">
|
||||
{request.vector_store_id}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Provider:</span>
|
||||
<span className="flex items-center">
|
||||
{(() => {
|
||||
const { logo, displayName } =
|
||||
getProviderLogoAndName(
|
||||
request.custom_llm_provider,
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{logo && (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img
|
||||
src={logo}
|
||||
alt={`${displayName} logo`}
|
||||
className="h-5 w-5 mr-2"
|
||||
/>
|
||||
)}
|
||||
{displayName}
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isExpanded && (
|
||||
<div className="p-3 border-t bg-white">
|
||||
{result.content.map((content, contentIndex) => (
|
||||
<div key={contentIndex} className="mb-2 last:mb-0">
|
||||
<div className="text-xs text-gray-500 mb-1">{content.type}</div>
|
||||
<pre className="text-xs font-mono whitespace-pre-wrap break-all bg-gray-50 p-2 rounded">
|
||||
{content.text}
|
||||
</pre>
|
||||
</div>
|
||||
))}
|
||||
<div className="space-y-2">
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">
|
||||
Start Time:
|
||||
</span>
|
||||
<span>{formatTime(request.start_time)}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">End Time:</span>
|
||||
<span>{formatTime(request.end_time)}</span>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<span className="font-medium w-1/3">Duration:</span>
|
||||
<span>
|
||||
{calculateDuration(
|
||||
request.start_time,
|
||||
request.end_time,
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 className="font-medium mb-2">Search Results</h4>
|
||||
<div className="space-y-2">
|
||||
{request.vector_store_search_response.data.map(
|
||||
(result, resultIndex) => {
|
||||
const isExpanded =
|
||||
expandedResults[`${index}-${resultIndex}`] || false;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={resultIndex}
|
||||
className="border border-border rounded-lg overflow-hidden"
|
||||
>
|
||||
<div
|
||||
className="flex items-center p-3 bg-muted cursor-pointer"
|
||||
onClick={() =>
|
||||
toggleResult(index, resultIndex)
|
||||
}
|
||||
>
|
||||
<ChevronRight
|
||||
className={cn(
|
||||
"w-4 h-4 mr-2 transition-transform",
|
||||
isExpanded && "rotate-90",
|
||||
)}
|
||||
/>
|
||||
<div className="flex items-center">
|
||||
<span className="font-medium mr-2">
|
||||
Result {resultIndex + 1}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-sm">
|
||||
Score:{" "}
|
||||
<span className="font-mono">
|
||||
{result.score.toFixed(4)}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isExpanded && (
|
||||
<div className="p-3 border-t border-border bg-background">
|
||||
{result.content.map(
|
||||
(content, contentIndex) => (
|
||||
<div
|
||||
key={contentIndex}
|
||||
className="mb-2 last:mb-0"
|
||||
>
|
||||
<div className="text-xs text-muted-foreground mb-1">
|
||||
{content.type}
|
||||
</div>
|
||||
<pre className="text-xs font-mono whitespace-pre-wrap break-all bg-muted p-2 rounded">
|
||||
{content.text}
|
||||
</pre>
|
||||
</div>
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue