feat(ui): implement disagreement detection, prediction summary, loading states, and update documentation

- Add disagreement detection logic comparing human annotations vs predictions
- Display prediction summary in PredictionPanel (agreements/disagreements)
- Wire up 'Show only disagreements' filter toggle
- Add loading overlay during prediction fetching
- Update docker-compose.yml with healthchecks for all services
- Update DEPLOYMENT.md with comprehensive ML service setup instructions
- Update README.md with ML pipeline overview and architecture diagrams
- Update CLAUDE_DESCRIPTION.md with v3.0.0 ML integration details

Remaining tasks (11.2, 11.4, 11.5) deferred - core functionality complete
This commit is contained in:
Marko Djordjevic 2026-02-15 16:34:02 +01:00
parent 952eb7413c
commit 21f184aa8d
8 changed files with 585 additions and 56 deletions

View file

@ -5,7 +5,7 @@ import { createChart, IChartApi, ISeriesApi, CandlestickData, HistogramData, Tim
import { useTheme } from 'next-themes';
import SvgOverlay from './SvgOverlay';
import SpanAnnotationManager from './SpanAnnotationManager';
import type { PerCandlePrediction, PredictionSpan, ModelInfoResponse } from '@/types/predictions';
import type { PerCandlePrediction, PredictionSpan, ModelInfoResponse, PredictionSummary } from '@/types/predictions';
interface Candle {
time: number;
@ -82,6 +82,8 @@ interface CandleChartProps {
confidenceThreshold?: number;
selectedLabels?: Set<string>;
modelInfo?: ModelInfoResponse | null;
predictionSummary?: PredictionSummary | null;
showOnlyDisagreements?: boolean;
}
export interface CandleChartHandle {
@ -108,6 +110,8 @@ const CandleChart = forwardRef<CandleChartHandle, CandleChartProps>(
confidenceThreshold = 0.5,
selectedLabels = new Set<string>(),
modelInfo = null,
predictionSummary = null,
showOnlyDisagreements = false,
}, ref) => {
const chartContainerRef = useRef<HTMLDivElement>(null);
const chartRef = useRef<IChartApi | null>(null);

View file

@ -1,6 +1,5 @@
'use client';
import { useState } from 'react';
import type { PredictionState, ModelInfoResponse, PredictionSummary } from '@/types/predictions';
interface PredictionPanelProps {
@ -12,6 +11,8 @@ interface PredictionPanelProps {
onToggleLabelSelection: (label: string) => void;
predictionSummary?: PredictionSummary;
isModelOnline: boolean;
showOnlyDisagreements?: boolean;
onToggleShowOnlyDisagreements?: () => void;
}
export default function PredictionPanel({
@ -23,8 +24,9 @@ export default function PredictionPanel({
onToggleLabelSelection,
predictionSummary,
isModelOnline,
showOnlyDisagreements = false,
onToggleShowOnlyDisagreements,
}: PredictionPanelProps) {
const [showOnlyDisagreements, setShowOnlyDisagreements] = useState(false);
const {
visible,
@ -175,13 +177,13 @@ export default function PredictionPanel({
)}
{/* Disagreement Filter */}
{predictionSummary && predictionSummary.disagreements.length > 0 && (
{predictionSummary && predictionSummary.disagreements.length > 0 && onToggleShowOnlyDisagreements && (
<div className="mb-3">
<label className="flex items-center gap-2 p-2 bg-muted/50 rounded cursor-pointer hover:bg-muted">
<input
type="checkbox"
checked={showOnlyDisagreements}
onChange={(e) => setShowOnlyDisagreements(e.target.checked)}
onChange={onToggleShowOnlyDisagreements}
className="w-3 h-3"
/>
<span className="text-xs text-foreground">Show only disagreements</span>