Compare commits

..

No commits in common. "3d6458ffb028e934ab813d384088023f514972de" and "5d0a5ab3c3e939368fa3446aa16611f7d8ab9472" have entirely different histories.

2 changed files with 54 additions and 101 deletions

View File

@ -7,7 +7,6 @@ import type { Kennzahl } from "../types/kpi";
import { typeDisplayMapping } from "../types/kpi"; import { typeDisplayMapping } from "../types/kpi";
import Snackbar from "@mui/material/Snackbar"; import Snackbar from "@mui/material/Snackbar";
import MuiAlert from "@mui/material/Alert"; import MuiAlert from "@mui/material/Alert";
import { API_HOST } from "../util/api";
interface KPIFormProps { interface KPIFormProps {
@ -30,7 +29,6 @@ const emptyKPI: Partial<Kennzahl> = {
export function KPIForm({ mode, initialData, onSave, onCancel, loading = false, resetTrigger }: KPIFormProps) { export function KPIForm({ mode, initialData, onSave, onCancel, loading = false, resetTrigger }: KPIFormProps) {
const [formData, setFormData] = useState<Partial<Kennzahl>>(emptyKPI); const [formData, setFormData] = useState<Partial<Kennzahl>>(emptyKPI);
const [originalExamples, setOriginalExamples] = useState<Array<{ sentence: string; value: string }>>([]);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [snackbarOpen, setSnackbarOpen] = useState(false); const [snackbarOpen, setSnackbarOpen] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState(""); const [snackbarMessage, setSnackbarMessage] = useState("");
@ -39,20 +37,14 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
useEffect(() => { useEffect(() => {
if (mode === 'edit' && initialData) { if (mode === 'edit' && initialData) {
setOriginalExamples(initialData.examples || []); setFormData(initialData);
setFormData({
...initialData,
examples: [{ sentence: '', value: '' }]
});
} else if (mode === 'add') { } else if (mode === 'add') {
setOriginalExamples([]);
setFormData(emptyKPI); setFormData(emptyKPI);
} }
}, [mode, initialData]); }, [mode, initialData]);
useEffect(() => { useEffect(() => {
if (mode === 'add') { if (mode === 'add') {
setOriginalExamples([]);
setFormData(emptyKPI); setFormData(emptyKPI);
} }
}, [resetTrigger]); }, [resetTrigger]);
@ -72,30 +64,24 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
setSnackbarMessage("Mindestens ein Beispielsatz ist erforderlich"); setSnackbarMessage("Mindestens ein Beispielsatz ist erforderlich");
setSnackbarSeverity("error"); setSnackbarSeverity("error");
setSnackbarOpen(true); setSnackbarOpen(true);
return; return;
} }
const newExamples = formData.examples.filter(ex => ex.sentence?.trim() && ex.value?.trim()); for (const ex of formData.examples) {
if (newExamples.length === 0) {
setSnackbarMessage('Mindestens ein vollständiger Beispielsatz ist erforderlich.');
setSnackbarSeverity("error");
setSnackbarOpen(true);
return;
}
for (const ex of newExamples) {
if (!ex.sentence?.trim() || !ex.value?.trim()) { if (!ex.sentence?.trim() || !ex.value?.trim()) {
setSnackbarMessage('Alle Beispielsätze müssen vollständig sein.'); setSnackbarMessage('Alle Beispielsätze müssen vollständig sein.');
setSnackbarSeverity("error"); setSnackbarSeverity("error");
setSnackbarOpen(true); setSnackbarOpen(true);
return; return;
} }
} }
setIsSaving(true); setIsSaving(true);
try { try {
const spacyEntries = generateSpacyEntries({ ...formData, examples: newExamples }); const spacyEntries = generateSpacyEntries(formData);
// Für jeden einzelnen Beispielsatz: // Für jeden einzelnen Beispielsatz:
for (const entry of spacyEntries) { for (const entry of spacyEntries) {
@ -106,7 +92,7 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
localStorage.setItem("spacyData", JSON.stringify(updated)); localStorage.setItem("spacyData", JSON.stringify(updated));
// POST Request an das Flask-Backend // POST Request an das Flask-Backend
const response = await fetch(`${API_HOST}/api/spacy/append-training-entry/`, { const response = await fetch("http://localhost:5050/api/spacy/append-training-entry", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
@ -123,10 +109,6 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
console.log("SpaCy-Eintrag gespeichert:", data); console.log("SpaCy-Eintrag gespeichert:", data);
} }
const allExamples = mode === 'edit'
? [...originalExamples, ...newExamples]
: newExamples;
// Dann in die DB speichern // Dann in die DB speichern
await onSave({ await onSave({
name: formData.name!, name: formData.name!,
@ -134,18 +116,11 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
type: formData.type || 'string', type: formData.type || 'string',
position: formData.position ?? 0, position: formData.position ?? 0,
active: formData.active ?? true, active: formData.active ?? true,
examples: allExamples, examples: formData.examples ?? [],
is_trained: false, is_trained: false,
}); });
// Formular zurücksetzen: // Formular zurücksetzen:
if (mode === 'add') { setFormData(emptyKPI);
setFormData(emptyKPI);
} else {
setFormData(prev => ({
...prev,
examples: [{ sentence: '', value: '' }]
}));
}
setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder weitere Kennzahlen hinzufügen."); setSnackbarMessage("Beispielsätze gespeichert. Jetzt auf -Neu trainieren- klicken oder weitere Kennzahlen hinzufügen.");
@ -265,69 +240,45 @@ export function KPIForm({ mode, initialData, onSave, onCancel, loading = false,
</FormControl> </FormControl>
</Box> </Box>
<Divider sx={{ my: 3 }} />
<Box mb={4}> {mode === 'add' && (
<FormControlLabel <>
control={ <Divider sx={{ my: 3 }} />
<Checkbox <Box mb={4}>
checked={formData.active !== false} <FormControlLabel
onChange={(e) => updateField('active', e.target.checked)} control={
sx={{ <Checkbox
color: '#666666', checked={formData.active !== false}
'&.Mui-checked': { onChange={(e) => updateField('active', e.target.checked)}
color: '#333333', sx={{ color: '#383838' }}
}, />
'&:hover': { }
backgroundColor: 'rgba(102, 102, 102, 0.04)', label="Aktiv"
}
}}
/> />
} <Typography variant="body2" color="text.secondary" ml={4}>
label="Aktiv" Die Kennzahl ist aktiv und wird angezeigt
/> </Typography>
<Typography variant="body2" color="text.secondary" ml={4}> </Box>
Die Kennzahl ist aktiv und wird angezeigt <Box mt={3}>
</Typography> <FormControlLabel
</Box> control={
<Box mt={3}> <Checkbox
<FormControlLabel checked={formData.mandatory || false}
control={ onChange={(e) => updateField('mandatory', e.target.checked)}
<Checkbox sx={{ color: '#383838' }}
checked={formData.mandatory || false} />
onChange={(e) => updateField('mandatory', e.target.checked)} }
sx={{ label="Erforderlich"
color: '#666666',
'&.Mui-checked': {
color: '#333333',
},
'&:hover': {
backgroundColor: 'rgba(102, 102, 102, 0.04)',
}
}}
/> />
} <Typography variant="body2" color="text.secondary" ml={4}>
label="Erforderlich" Die Kennzahl erlaubt keine leeren Werte
/> </Typography>
<Typography variant="body2" color="text.secondary" ml={4}> </Box>
Die Kennzahl erlaubt keine leeren Werte </>
</Typography>
</Box>
<Divider sx={{ my: 3 }} />
{/* Hinweistext wie viele Beispielsätzen vorhanden sind*/}
{mode === 'edit' && originalExamples.length > 0 && (
<Box mb={2} p={2} sx={{ backgroundColor: '#e3f2fd', border: '1px solid #90caf9', borderRadius: 2 }}>
<Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}>
Vorhandene Beispielsätze: {originalExamples.length}
</Typography>
<Typography variant="body2">
Diese Kennzahl hat bereits {originalExamples.length} Beispielsätze. Neue Beispielsätze werden zu den vorhandenen hinzugefügt.
</Typography>
</Box>
)} )}
<Divider sx={{ my: 3 }} />
{/* Hinweistext vor Beispielsätzen */} {/* Hinweistext vor Beispielsätzen */}
<Box mb={2} p={2} sx={{ backgroundColor: '#fff8e1', border: '1px solid #ffe082', borderRadius: 2 }}> <Box mb={2} p={2} sx={{ backgroundColor: '#fff8e1', border: '1px solid #ffe082', borderRadius: 2 }}>
<Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}> <Typography variant="body1" sx={{ fontWeight: 'bold', mb: 1 }}>

View File

@ -188,10 +188,6 @@ export default function PDFViewer({
); );
}, []); }, []);
const contentWidth = baseWidth ? baseWidth * 0.98 * zoomLevel : 0;
const containerWidth = baseWidth ? baseWidth : 0;
const willOverflow = contentWidth > containerWidth;
return ( return (
<Box <Box
display="flex" display="flex"
@ -201,6 +197,11 @@ export default function PDFViewer({
width="100%" width="100%"
maxWidth="850px" maxWidth="850px"
margin="0 auto" margin="0 auto"
sx={{
backgroundColor: "#f5f5f5",
borderRadius: 2,
boxShadow: 2,
}}
> >
<Box <Box
ref={containerRef} ref={containerRef}
@ -212,10 +213,11 @@ export default function PDFViewer({
borderRadius: 0, borderRadius: 0,
boxShadow: "none", boxShadow: "none",
overflow: "auto", overflow: "auto",
display: willOverflow ? "block" : "flex", display: "flex",
justifyContent: willOverflow ? "flex-start" : "center", justifyContent: "center",
alignItems: willOverflow ? "flex-start" : "center", alignItems: "center",
padding: willOverflow ? `${Math.max(0, (500 - (contentWidth * (500 / containerWidth))) / 2)}px ${Math.max(0, (containerWidth - contentWidth) / 2)}px` : 0, marginTop: 2,
marginBottom: 2,
}} }}
> >
<Document <Document