Spaces:
Running
Running
| import { Trace } from "@/types"; | |
| export interface TrendDataPoint { | |
| time: string; | |
| value: number; | |
| value2?: number; // Optional second value for dual-line charts | |
| date: Date; | |
| } | |
| export interface TrendData { | |
| tracesAndGraphs: TrendDataPoint[]; // Combined traces + graphs | |
| entitiesAndRelations: TrendDataPoint[]; // Combined entities + relations | |
| failures: TrendDataPoint[]; // New failures trend | |
| // Legacy single values for backwards compatibility | |
| traces: TrendDataPoint[]; | |
| agentGraphs: TrendDataPoint[]; | |
| entities: TrendDataPoint[]; | |
| relations: TrendDataPoint[]; | |
| } | |
| function createRealTrendData( | |
| traces: Trace[], | |
| valueExtractor: (traces: Trace[], date: Date) => number, | |
| valueExtractor2?: (traces: Trace[], date: Date) => number | |
| ): TrendDataPoint[] { | |
| const data: TrendDataPoint[] = []; | |
| const now = new Date(); | |
| // Get all upload dates from traces | |
| const traceDates = traces | |
| .map((trace) => | |
| trace.upload_timestamp ? new Date(trace.upload_timestamp) : null | |
| ) | |
| .filter((date): date is Date => date !== null) | |
| .sort((a, b) => a.getTime() - b.getTime()); | |
| if (traceDates.length === 0) { | |
| // If no traces, return empty data | |
| return []; | |
| } | |
| // Create data points for the last 7 days | |
| for (let i = 6; i >= 0; i--) { | |
| const date = new Date(now); | |
| date.setDate(date.getDate() - i); | |
| date.setHours(23, 59, 59, 999); // End of day for cumulative counting | |
| const value = valueExtractor(traces, date); | |
| const value2 = valueExtractor2 ? valueExtractor2(traces, date) : undefined; | |
| data.push({ | |
| time: date.toLocaleDateString("en-US", { | |
| month: "short", | |
| day: "numeric", | |
| }), | |
| value: value, | |
| value2: value2, | |
| date: date, | |
| }); | |
| } | |
| return data; | |
| } | |
| function createCombinedRealTrendData( | |
| traces: Trace[], | |
| valueExtractor1: (traces: Trace[], date: Date) => number, | |
| valueExtractor2: (traces: Trace[], date: Date) => number | |
| ): TrendDataPoint[] { | |
| return createRealTrendData(traces, valueExtractor1, valueExtractor2); | |
| } | |
| // Helper function to extract failure count from traces | |
| export function calculateFailureCount(traces: Trace[]): number { | |
| let totalFailures = 0; | |
| traces.forEach((trace) => { | |
| trace.knowledge_graphs?.forEach((kg: any) => { | |
| if (kg.graph_data) { | |
| try { | |
| const graphData = | |
| typeof kg.graph_data === "string" | |
| ? JSON.parse(kg.graph_data) | |
| : kg.graph_data; | |
| // Count failures | |
| if (graphData.failures && Array.isArray(graphData.failures)) { | |
| totalFailures += graphData.failures.length; | |
| } | |
| } catch (error) { | |
| console.warn("Error parsing graph_data for failure count:", error); | |
| } | |
| } | |
| }); | |
| }); | |
| return totalFailures; | |
| } | |
| // Value extractors for different metrics - CUMULATIVE COUNTS | |
| const getTracesUpToDate = (traces: Trace[], date: Date): number => { | |
| return traces.filter((trace) => { | |
| if (!trace.upload_timestamp) return false; | |
| const uploadDate = new Date(trace.upload_timestamp); | |
| return uploadDate <= date; // Cumulative: count all traces up to this date | |
| }).length; | |
| }; | |
| const getKnowledgeGraphsUpToDate = (traces: Trace[], date: Date): number => { | |
| return traces.reduce((count, trace) => { | |
| const finalKGs = | |
| trace.knowledge_graphs?.filter((kg) => { | |
| if (!kg.created_at) return false; | |
| const creationDate = new Date(kg.created_at); | |
| const isBeforeOrOnDate = creationDate <= date; // Cumulative | |
| const isFinal = | |
| kg.is_final === true || | |
| (kg.window_index === null && kg.window_total !== null); | |
| return isBeforeOrOnDate && isFinal; | |
| }) || []; | |
| return count + finalKGs.length; | |
| }, 0); | |
| }; | |
| const getEntitiesUpToDate = (traces: Trace[], date: Date): number => { | |
| return traces.reduce((count, trace) => { | |
| const entityCount = | |
| trace.knowledge_graphs?.reduce((kgTotal, kg) => { | |
| if (!kg.created_at) return kgTotal; | |
| const creationDate = new Date(kg.created_at); | |
| const isBeforeOrOnDate = creationDate <= date; // Cumulative | |
| return isBeforeOrOnDate ? kgTotal + (kg.entity_count || 0) : kgTotal; | |
| }, 0) || 0; | |
| return count + entityCount; | |
| }, 0); | |
| }; | |
| const getRelationsUpToDate = (traces: Trace[], date: Date): number => { | |
| return traces.reduce((count, trace) => { | |
| const relationCount = | |
| trace.knowledge_graphs?.reduce((kgTotal, kg) => { | |
| if (!kg.created_at) return kgTotal; | |
| const creationDate = new Date(kg.created_at); | |
| const isBeforeOrOnDate = creationDate <= date; // Cumulative | |
| return isBeforeOrOnDate ? kgTotal + (kg.relation_count || 0) : kgTotal; | |
| }, 0) || 0; | |
| return count + relationCount; | |
| }, 0); | |
| }; | |
| const getFailuresUpToDate = (traces: Trace[], date: Date): number => { | |
| return traces.reduce((count, trace) => { | |
| let traceFailures = 0; | |
| trace.knowledge_graphs?.forEach((kg) => { | |
| if (!kg.created_at) return; | |
| const creationDate = new Date(kg.created_at); | |
| const isBeforeOrOnDate = creationDate <= date; // Cumulative | |
| if (isBeforeOrOnDate && kg.graph_data) { | |
| try { | |
| const graphData = | |
| typeof kg.graph_data === "string" | |
| ? JSON.parse(kg.graph_data) | |
| : kg.graph_data; | |
| if (graphData.failures && Array.isArray(graphData.failures)) { | |
| traceFailures += graphData.failures.length; | |
| } | |
| } catch (error) { | |
| console.warn("Error parsing graph_data for failure count:", error); | |
| } | |
| } | |
| }); | |
| return count + traceFailures; | |
| }, 0); | |
| }; | |
| export function generateTrendData(traces: Trace[]): TrendData { | |
| return { | |
| // New combined data for merged cards | |
| tracesAndGraphs: createCombinedRealTrendData( | |
| traces, | |
| getTracesUpToDate, | |
| getKnowledgeGraphsUpToDate | |
| ), | |
| entitiesAndRelations: createCombinedRealTrendData( | |
| traces, | |
| getEntitiesUpToDate, | |
| getRelationsUpToDate | |
| ), | |
| failures: createRealTrendData(traces, getFailuresUpToDate), | |
| // Legacy single values for backwards compatibility | |
| traces: createRealTrendData(traces, getTracesUpToDate), | |
| agentGraphs: createRealTrendData(traces, getKnowledgeGraphsUpToDate), | |
| entities: createRealTrendData(traces, getEntitiesUpToDate), | |
| relations: createRealTrendData(traces, getRelationsUpToDate), | |
| }; | |
| } | |