import { useEffect, useRef, useState } from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Chip from '@mui/material/Chip'; import CircularProgress from '@mui/material/CircularProgress'; import Collapse from '@mui/material/Collapse'; import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import IconButton from '@mui/material/IconButton'; import Typography from '@mui/material/Typography'; import Alert from '@mui/material/Alert'; import CloseIcon from '@mui/icons-material/Close'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; import ErrorOutlinedIcon from '@mui/icons-material/ErrorOutlined'; import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf'; import TextSnippetOutlinedIcon from '@mui/icons-material/TextSnippetOutlined'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; /** Chip colour by SSE event type */ const EVENT_CHIP_COLOR = { status: 'default', llm_call: 'primary', tool_call: 'secondary', usage: 'info', }; function EventLog({ messages, streaming }) { const bottomRef = useRef(null); const [expanded, setExpanded] = useState(true); useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [messages]); if (!messages?.length && !streaming) return null; return ( setExpanded((v) => !v)} > LLM-Protokoll {streaming ? ( ) : ( )} {expanded ? : } (t.palette.mode === 'dark' ? 'grey.900' : 'grey.50'), p: 1, }} > {messages.map((msg, i) => ( {msg.text} ))} {streaming && !messages.length && ( Verbinde… )}
); } export default function ManifestPdfDialog({ open, filename, data, unmatchedSupplierName, onCreateSupplier, onClose, onAbort, }) { if (!open) return null; const { streaming = false, messages = [], result = null, error = null, aborted = false } = data ?? {}; const hasResult = Boolean(result); const isTextDoc = filename?.toLowerCase().endsWith('.txt') || filename?.toLowerCase().endsWith('.csv'); const handleAbortOrClose = streaming ? (onAbort || onClose) : onClose; return ( {aborted ? ( ) : error ? ( ) : streaming ? ( ) : isTextDoc ? ( ) : ( )} {streaming ? (isTextDoc ? 'Dokument wird analysiert…' : 'PDF wird analysiert…') : aborted ? 'Analyse abgebrochen' : error ? 'Analyse fehlgeschlagen' : (isTextDoc ? 'Dokument-Analyse abgeschlossen' : 'PDF-Analyse abgeschlossen')} {filename ? ( {filename} ) : null} theme.palette.grey[500] }} > {/* Error or Aborted Alert */} {error && ( } sx={{ mb: 2 }}> {error} )} {/* Live log */} {/* Success notification */} {hasResult && !streaming && !error && !aborted && ( Daten erfolgreich in das Formular übernommen. )} {/* Unmatched supplier alert */} {hasResult && !streaming && !error && !aborted && unmatchedSupplierName && ( onCreateSupplier(unmatchedSupplierName)} > Lieferant anlegen ) : null } > Lieferant „{unmatchedSupplierName}“ wurde im Dokument erkannt, existiert aber noch nicht in den Stammdaten. )} {streaming ? ( ) : ( <> {unmatchedSupplierName && onCreateSupplier ? ( ) : null} )} ); }