diff --git a/ell-studio/src/App.css b/ell-studio/src/App.css deleted file mode 100644 index 74b5e053..00000000 --- a/ell-studio/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/ell-studio/src/components/LMPDetailsSidePanel.js b/ell-studio/src/components/LMPDetailsSidePanel.js index 8d06f64c..474e6454 100644 --- a/ell-studio/src/components/LMPDetailsSidePanel.js +++ b/ell-studio/src/components/LMPDetailsSidePanel.js @@ -1,14 +1,15 @@ import React, { useMemo } from 'react'; import { Link } from 'react-router-dom'; -import { FiClock, FiTag, FiGitCommit, FiZap, FiHash, FiCalendar } from 'react-icons/fi'; +import { FiClock, FiTag, FiZap, FiHash, FiChevronRight, FiCode } from 'react-icons/fi'; import { getTimeAgo } from '../utils/lmpUtils'; import VersionBadge from './VersionBadge'; import { useInvocationsFromLMP } from '../hooks/useBackend'; import { LMPCardTitle } from './depgraph/LMPCardTitle'; import { format } from 'date-fns'; import SidePanel from './common/SidePanel'; -import StatItem from './common/StatItem'; -import MetricCard from './common/MetricCard'; +import MetricChart from './MetricChart'; +import { motion } from 'framer-motion'; +import {Card} from './common/Card'; function LMPDetailsSidePanel({ lmp, uses, versionHistory }) { const { data: invocations } = useInvocationsFromLMP(lmp.name, lmp.lmp_id, 0, 100); @@ -33,94 +34,126 @@ function LMPDetailsSidePanel({ lmp, uses, versionHistory }) { return ( -
-
-

Version

- + +
+
+

Version Info

+ +
+
+
+ + Created: +
+
{getTimeAgo(new Date(lmp.created_at))}
+
+ + Is LMP: +
+
{lmp.is_lm ? 'Yes' : 'No'}
+
+ + Invocations: +
+
{totalInvocations}
+
+ + Avg. Latency: +
+
{avgLatency.toFixed(2)}ms
+
- - - - -
- {lmp.lm_kwargs && ( -
-

LM Keywords

-
-            {JSON.stringify(lmp.lm_kwargs, null, 2)}
-          
-
- )} - -
-

Uses

- {uses && uses.length > 0 ? ( -
    - {uses.filter(use => !!use).map((use) => ( -
  • - - - -
  • - ))} -
- ) : ( -

No dependencies

+ {lmp.lm_kwargs && ( +
+

+ LM Keywords +

+
+              {JSON.stringify(lmp.lm_kwargs, null, 2)}
+            
+
)} -
- +
+

Uses

+ {uses && uses.length > 0 ? ( +
    + {uses.filter(use => !!use).map((use) => ( + + + + + + + + ))} +
+ ) : ( +

No dependencies

+ )} +
- + -
-

Version History

-
- {versionHistory.map((version, index) => ( - -
- - v{versionHistory.length - index} - - - - {format(new Date(version.created_at), 'MMM d, yyyy')} - -
- {version.commit_message && ( -

- - {version.commit_message} -

- )} - - ))} -
-
+ +{/* +
+

Version History

+
+ {versionHistory.map((version, index) => ( + + +
+
+ v{versionHistory.length - index} + + {format(new Date(version.created_at), 'MMM d, yyyy HH:mm')} + +
+ +
+ {version.commit_message && ( +

+ {version.commit_message} +

+ )} + +
+ ))} +
+
*/} + ); } diff --git a/ell-studio/src/components/MetricChart.js b/ell-studio/src/components/MetricChart.js index f7daadc1..3d735b75 100644 --- a/ell-studio/src/components/MetricChart.js +++ b/ell-studio/src/components/MetricChart.js @@ -8,22 +8,17 @@ import { ResponsiveContainer, CartesianGrid, Brush, - Legend } from "recharts"; import { format, differenceInDays, differenceInHours, - differenceInMinutes, startOfMinute, - endOfMinute, eachMinuteOfInterval, eachHourOfInterval, eachDayOfInterval, startOfHour, - endOfHour, startOfDay, - endOfDay, addMinutes, getMinutes, subMonths, @@ -43,23 +38,16 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t { value: "12h", label: "Last 12 Hours" }, { value: "1h", label: "Last Hour" }, ].filter((range) => { - if(!rawData) - return true; - else { - // if the range extends beyond the available data, don't show it - const earliestDate = new Date(rawData[0]?.date); - if(range.value === "all") - return true; - else { - const start = range.value === "1m" ? subMonths(new Date(), 1) : - range.value === "7d" ? subDays(new Date(), 7) : - range.value === "24h" ? subHours(new Date(), 24) : - range.value === "12h" ? subHours(new Date(), 12) : - range.value === "1h" ? subHours(new Date(), 1) : - new Date(); // Default case, shouldn't occur - return start >= earliestDate; - } - } + if(!rawData) return true; + const earliestDate = new Date(rawData[0]?.date); + if(range.value === "all") return true; + const start = range.value === "1m" ? subMonths(new Date(), 1) : + range.value === "7d" ? subDays(new Date(), 7) : + range.value === "24h" ? subHours(new Date(), 24) : + range.value === "12h" ? subHours(new Date(), 12) : + range.value === "1h" ? subHours(new Date(), 1) : + new Date(); + return start >= earliestDate; }), [rawData]); useEffect(() => { @@ -68,24 +56,12 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t let start = rawData[0]?.date; switch (selectedTimeRange) { - case "1m": - start = subMonths(latestNow, 1); - break; - case "7d": - start = subDays(latestNow, 7); - break; - case "24h": - start = subHours(latestNow, 24); - break; - case "12h": - start = subHours(latestNow, 12); - break; - case "1h": - start = subHours(latestNow, 1); - break; - default: - // "all" - use the earliest date in rawData - break; + case "1m": start = subMonths(latestNow, 1); break; + case "7d": start = subDays(latestNow, 7); break; + case "24h": start = subHours(latestNow, 24); break; + case "12h": start = subHours(latestNow, 12); break; + case "1h": start = subHours(latestNow, 1); break; + default: break; } setDateRange({ @@ -95,19 +71,16 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t } }, [rawData, selectedTimeRange]); - // Determine aggregation based on zoom const aggregatedData = useMemo(() => { if (!rawData?.length || !dateRange) return []; - const zoomStart = dateRange.start; + const zoomStart = dateRange.start; const zoomEnd = dateRange.end; const daysDiff = differenceInDays(zoomEnd, zoomStart); const hoursDiff = differenceInHours(zoomEnd, zoomStart); - const minutesDiff = differenceInMinutes(zoomEnd, zoomStart); - let aggregationInterval; - let aggregationFunction; + let aggregationInterval, aggregationFunction; if (daysDiff > 30) { aggregationInterval = eachDayOfInterval; @@ -157,7 +130,6 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t ); }, [rawData, dateRange, dataKey, aggregation]); - // Memoize formatting functions const formatXAxis = useCallback( (tickItem) => { const date = new Date(tickItem); @@ -171,19 +143,17 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t const formatTooltip = useCallback( (value) => { - return [`${value} ${yAxisLabel || ''}`, title]; + return [`${value} ${yAxisLabel || ''}`, '']; }, - [yAxisLabel, title] + [yAxisLabel] ); - const handleZoom = (domain) => { - }; - return ( -
-
+
+
+

{title}

-
+
@@ -208,49 +178,45 @@ function MetricChart({ rawData, dataKey, color, yAxisLabel, aggregation="sum", t - + format(new Date(label), "PPpp")} formatter={formatTooltip} /> - diff --git a/ell-studio/src/components/Sidebar.js b/ell-studio/src/components/Sidebar.js index d3e1578f..80ad504d 100644 --- a/ell-studio/src/components/Sidebar.js +++ b/ell-studio/src/components/Sidebar.js @@ -12,7 +12,7 @@ const Sidebar = () => { to={to} className={({ isActive }) => ` group flex items-center py-3 px-4 rounded-lg transition-all duration-200 - ${isActive ? 'bg-blue-500/10 text-blue-500' : 'text-gray-400 hover:text-white'} + ${isActive ? 'bg-accent text-accent-foreground' : 'text-muted-foreground hover:text-foreground hover:bg-accent/50'} `} > @@ -20,7 +20,7 @@ const Sidebar = () => { {label} )} {!isExpanded && ( -
+
{label}
)} @@ -31,7 +31,7 @@ const Sidebar = () => {
ell-studio Logo @@ -50,9 +50,9 @@ const Sidebar = () => { diff --git a/ell-studio/src/components/common/MetricCard.js b/ell-studio/src/components/common/MetricCard.js index b4aaa1ba..10d29b92 100644 --- a/ell-studio/src/components/common/MetricCard.js +++ b/ell-studio/src/components/common/MetricCard.js @@ -2,8 +2,7 @@ import React from 'react'; import MetricChart from '../MetricChart'; const MetricCard = ({ title, rawData, dataKey, color, yAxisLabel, aggregation }) => ( -
-

{title}

+
( - -

{title}

+ +

{title}

{children}
diff --git a/ell-studio/src/components/invocations/InvocationsAnalyticsSidePanel.js b/ell-studio/src/components/invocations/InvocationsAnalyticsSidePanel.js index 377871e4..8a98b8e7 100644 --- a/ell-studio/src/components/invocations/InvocationsAnalyticsSidePanel.js +++ b/ell-studio/src/components/invocations/InvocationsAnalyticsSidePanel.js @@ -1,73 +1,117 @@ import React from 'react'; -import SidePanel from '../common/SidePanel'; -import StatItem from '../common/StatItem'; -import MetricCard from '../common/MetricCard'; import { FiZap, FiClock, FiHash, FiUsers, FiPercent, FiBox } from 'react-icons/fi'; +import { Link } from 'react-router-dom'; +import SidePanel from '../common/SidePanel'; +import MetricChart from '../MetricChart'; +import { motion } from 'framer-motion'; +import { LMPCardTitle } from '../depgraph/LMPCardTitle'; +import { Card } from '../common/Card'; const InvocationsAnalyticsSidePanel = ({ aggregateData, sidebarMetrics }) => { - if (!aggregateData) return null; - - const statsData = [ - { icon: FiZap, label: "Total Invocations", value: aggregateData.total_invocations }, - { icon: FiClock, label: "Avg Latency", value: `${aggregateData.avg_latency.toFixed(2)}ms` }, - { icon: FiHash, label: "Total Tokens", value: aggregateData.total_tokens }, - { icon: FiUsers, label: "Unique LMPs", value: aggregateData.unique_lmps }, - ]; + if (!aggregateData || !sidebarMetrics) return null; return ( -
- {statsData.map((stat, index) => ( - - ))} -
- - + +
+

Overview

+
+
+ + Total Invocations: +
+
{sidebarMetrics.totalInvocations}
+
+ + Avg. Latency: +
+
{sidebarMetrics.avgLatency?.toFixed(2)}ms
+
+ + Total Tokens: +
+
{sidebarMetrics.totalTokens}
+
+ + Unique LMPs: +
+
{sidebarMetrics.uniqueLMPs}
+
+ + Success Rate: +
+
{sidebarMetrics.successRate.toFixed(2)}%
+
+ + Avg Tokens/Invocation: +
+
{(sidebarMetrics.totalTokens / sidebarMetrics.totalInvocations)?.toFixed(2)}
+
+
- + - + -
-

Top 5 LMPs

-
    - {sidebarMetrics.topLMPs.map(([lmp, count], index) => ( -
  • - - {index + 1}. - {lmp} - - {count} invocations -
  • - ))} -
-
+ -
-

Additional Metrics

- - -
+ {/*
+

Top 5 LMPs

+
    + {sidebarMetrics.topLMPs.map(([lmpName, count], index) => ( + + + + +
    + {count} invocations +
    +
    +
    +
    +
    + +
    + ))} +
+
*/} +
); }; diff --git a/ell-studio/src/components/layouts/GenericPageLayout.js b/ell-studio/src/components/layouts/GenericPageLayout.js index f5789f1d..06a4aec2 100644 --- a/ell-studio/src/components/layouts/GenericPageLayout.js +++ b/ell-studio/src/components/layouts/GenericPageLayout.js @@ -17,22 +17,22 @@ const GenericPageLayout = ({ }, [selectedTrace, showSidebar]); return ( - + -
- {children} -
+
+ {children} +
- - - + + + {sidebarContent} diff --git a/ell-studio/src/contexts/ThemeContext.js b/ell-studio/src/contexts/ThemeContext.js index 847202f6..a2b2a58b 100644 --- a/ell-studio/src/contexts/ThemeContext.js +++ b/ell-studio/src/contexts/ThemeContext.js @@ -1,4 +1,4 @@ -import React, { createContext, useState, useContext } from 'react'; +import React, { createContext, useState, useContext, useEffect } from 'react'; const ThemeContext = createContext(); @@ -7,6 +7,14 @@ export const useTheme = () => useContext(ThemeContext); export const ThemeProvider = ({ children }) => { const [darkMode, setDarkMode] = useState(true); + useEffect(() => { + if (darkMode) { + document.documentElement.classList.add('dark'); + } else { + document.documentElement.classList.remove('dark'); + } + }, [darkMode]); + const toggleDarkMode = () => { setDarkMode(!darkMode); }; diff --git a/ell-studio/src/pages/Home.js b/ell-studio/src/pages/Home.js index e6a3485f..6436530f 100644 --- a/ell-studio/src/pages/Home.js +++ b/ell-studio/src/pages/Home.js @@ -17,7 +17,6 @@ function Home() { const { darkMode } = useTheme(); const { data: lmps, isLoading: isLoadingLMPs } = useLatestLMPs(); const { data: traces, isLoading: isLoadingTraces } = useTraces(lmps); - const toggleExpand = (lmpName, event) => { if (event.target.tagName.toLowerCase() !== 'a') { @@ -45,58 +44,58 @@ function Home() { const memoizedLMPs = useMemo(() => firstLMPs, [firstLMPs]); if (!memoizedLMPs || !memoizedTraces) { - return
-

Loading...

+ return
+

Loading...

; } return ( -
+
-
- +
+ Language Model Programs
- + Total LMPs: {lmps.length} - + Last Updated: {lmps[0] && lmps[0].versions && lmps[0].versions[0] ? getTimeAgo(lmps[0].versions[0].created_at) : 'N/A'}
- +
-
+
{lmps.map((lmp) => ( toggleExpand(lmp.name, e)} >
e.stopPropagation()} > - {lmp.name} + {lmp.name}
- + ID: {truncateId(lmp.lmp_id)} - + Latest @@ -104,9 +103,9 @@ function Home() {
-
- - {lmp.source.length > 100 ? `${lmp.source.substring(0, 100)}...` : lmp.source} +
+ + {lmp.source.length > 100 ? `${lmp.source.substring(0, 100)}...` : lmp.source}
diff --git a/ell-studio/src/pages/Invocations.js b/ell-studio/src/pages/Invocations.js index ad1e2a61..073d3b81 100644 --- a/ell-studio/src/pages/Invocations.js +++ b/ell-studio/src/pages/Invocations.js @@ -145,24 +145,30 @@ const Invocations = () => { setSelectedTrace={setSelectedTrace} sidebarContent={sidebarContent} > -
-

- Invocations -

-
+
+
+

Invocations

+
+ +
+
- {/* Search bar, advanced filters, and controls */} -
-
-
+
+
setSearchTerm(e.target.value)} /> - +
-
{advancedFilters.isOpen && ( @@ -238,23 +237,22 @@ const Invocations = () => {
)} +
+ +
+
- -
- -
- ); }; diff --git a/ell-studio/src/pages/LMP.js b/ell-studio/src/pages/LMP.js index 4bbbf65c..9cc2f66a 100644 --- a/ell-studio/src/pages/LMP.js +++ b/ell-studio/src/pages/LMP.js @@ -116,7 +116,7 @@ function LMP() { if (isLoadingLMP) return ( -
+
Loading...
); @@ -129,143 +129,144 @@ function LMP() { setSelectedTrace={setSelectedTrace} sidebarContent={sidebar} > -
-

- - - - - -

-
+
+
+

+ + + + + +

+
-
-
-
-
-

Language Model Program

- {(id || requestedInvocationId) && ( - <> - - - - )} +
+
+
+
+

Language Model Program

+ {(id || requestedInvocationId) && ( + <> + + + + )} +
+
+ {previousVersion && ( + <> + {viewMode === "Diff" && ( +
+ + Comparing to + +
+ )} + + + )} + +
-
- {previousVersion && ( - <> - {viewMode === "Diff" && ( -
- - Comparing to - -
- )} - - - )} - +
+
-
- -
-
-
-
- {["Runs", "Version History"].map((tab) => ( - - ))} -
+
+
+ {["Runs", "Version History"].map((tab) => ( + + ))} +
-
- {activeTab === "runs" && ( - <> -
-
- - - - - + + + + +
+
- -
- { - setSelectedTrace(trace); - setSearchParams({ i: trace.id }); - }} - currentlySelectedTrace={selectedTrace} - omitColumns={omitColumns} - /> - - )} - {activeTab === "version_history" && ( - - )} + { + setSelectedTrace(trace); + setSearchParams({ i: trace.id }); + }} + currentlySelectedTrace={selectedTrace} + omitColumns={omitColumns} + /> + + )} + {activeTab === "version_history" && ( + + )} +
-
-
+ +
); } -export default LMP; +export default LMP; \ No newline at end of file diff --git a/ell-studio/src/styles/globals.css b/ell-studio/src/styles/globals.css index 4c6132f7..3a4fdaca 100644 --- a/ell-studio/src/styles/globals.css +++ b/ell-studio/src/styles/globals.css @@ -4,32 +4,49 @@ @layer base { :root { - --background: 222.2 84% 4.9%; - --foreground: 210 40% 98%; - --card: 222.2 84% 4.9%; - --card-foreground: 210 40% 98%; - --popover: 222.2 84% 4.9%; - --popover-foreground: 210 40% 98%; - --primary: 217.2 91.2% 59.8%; - --primary-foreground: 222.2 47.4% 11.2%; - --secondary: 217.2 32.6% 17.5%; + --background: 224 71% 4%; + --foreground: 213 31% 91%; + --card: 224 71% 4%; + --card-foreground: 213 31% 91%; + --popover: 224 71% 4%; + --popover-foreground: 213 31% 91%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 1.2%; + --secondary: 222.2 47.4% 11.2%; --secondary-foreground: 210 40% 98%; - --muted: 217.2 32.6% 17.5%; - --muted-foreground: 215 20.2% 65.1%; - --accent: 217.2 32.6% 17.5%; + --muted: 223 47% 11%; + --muted-foreground: 215.4 16.3% 56.9%; + --accent: 216 34% 17%; --accent-foreground: 210 40% 98%; - --destructive: 0 62.8% 30.6%; + --destructive: 0 63% 31%; --destructive-foreground: 210 40% 98%; - --border: 217.2 32.6% 17.5%; - --input: 217.2 32.6% 17.5%; - --ring: 224.3 76.3% 48%; - --chart-1: 220 70% 50%; - --chart-2: 160 60% 45%; - --chart-3: 30 80% 55%; - --chart-4: 280 65% 60%; - --chart-5: 340 75% 55%; + --border: 216 34% 17%; + --input: 216 34% 17%; + --ring: 216 34% 17%; --radius: 0.5rem; } + + .dark { + --background: 224 71% 4%; + --foreground: 213 31% 91%; + --card: 224 71% 4%; + --card-foreground: 213 31% 91%; + --popover: 224 71% 4%; + --popover-foreground: 213 31% 91%; + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 1.2%; + --secondary: 222.2 47.4% 11.2%; + --secondary-foreground: 210 40% 98%; + --muted: 223 47% 11%; + --muted-foreground: 215.4 16.3% 56.9%; + --accent: 216 34% 17%; + --accent-foreground: 210 40% 98%; + --destructive: 0 63% 31%; + --destructive-foreground: 210 40% 98%; + --border: 216 34% 17%; + --input: 216 34% 17%; + --ring: 216 34% 17%; + } } @layer base { @@ -88,3 +105,4 @@ stroke-dashoffset: -10; } } + diff --git a/tailwind.config.js b/tailwind.config.js index d3ec7ae0..dc8495df 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,11 +1,43 @@ module.exports = { - // ... other config + darkMode: ["class"], + content: [ + "./src/**/*.{js,jsx,ts,tsx}", + ], theme: { extend: { colors: { - gray: { - 750: '#2d333b', - 850: '#22272e', + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", }, }, keyframes: { @@ -29,5 +61,4 @@ module.exports = { addUtilities(newUtilities, ['responsive', 'hover']); }, ], - // ... other config -}; \ No newline at end of file +} \ No newline at end of file