livrare lot 2
This commit is contained in:
commit
8ecc78e729
763 changed files with 164593 additions and 0 deletions
|
|
@ -0,0 +1,152 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Card, CardContent, Typography, Box, Switch, TextField, Slider, Button, FormControlLabel, Alert } from '@mui/material';
|
||||
import { Save as SaveIcon } from '@mui/icons-material';
|
||||
import type { ModerationConfig } from './api';
|
||||
import { updateModerationConfig } from './api';
|
||||
|
||||
interface Props {
|
||||
config: ModerationConfig;
|
||||
onSaved: (next: ModerationConfig) => void;
|
||||
onError: (msg: string) => void;
|
||||
}
|
||||
|
||||
export const TriageCard: React.FC<Props> = ({ config, onSaved, onError }) => {
|
||||
const [draft, setDraft] = useState<ModerationConfig>(config);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
React.useEffect(() => { setDraft(config); }, [config]);
|
||||
|
||||
const dirty = JSON.stringify(draft) !== JSON.stringify(config);
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
try {
|
||||
const res = await updateModerationConfig({
|
||||
triage_enabled: draft.triage_enabled,
|
||||
confidence_low: Number(draft.confidence_low),
|
||||
risk_grey_min: Number(draft.risk_grey_min),
|
||||
risk_grey_max: Number(draft.risk_grey_max),
|
||||
queue_relax_at: draft.queue_relax_at,
|
||||
queue_strict_at: draft.queue_strict_at,
|
||||
auto_tune_enabled: draft.auto_tune_enabled,
|
||||
});
|
||||
if (res.success && res.data) {
|
||||
onSaved(res.data);
|
||||
} else {
|
||||
onError(res.error ?? 'Update failed');
|
||||
}
|
||||
} catch (e) {
|
||||
onError((e as Error).message);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card variant="outlined">
|
||||
<CardContent>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="flex-start" mb={1}>
|
||||
<Box>
|
||||
<Typography variant="h6" fontWeight={700}>Triage</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Decide which sessions enter the moderation queue. Edits sync to Redis on save.
|
||||
</Typography>
|
||||
</Box>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={draft.triage_enabled}
|
||||
onChange={(e) => setDraft({ ...draft, triage_enabled: e.target.checked })}
|
||||
/>
|
||||
}
|
||||
label={draft.triage_enabled ? 'Enabled' : 'Disabled'}
|
||||
labelPlacement="start"
|
||||
/>
|
||||
</Box>
|
||||
|
||||
{!draft.triage_enabled && (
|
||||
<Alert severity="info" sx={{ mb: 2 }}>
|
||||
Triage is OFF. No sessions will enter the moderation queue.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Box display="grid" gridTemplateColumns="1fr 1fr" gap={3} mt={2}>
|
||||
<Box>
|
||||
<Typography variant="body2" gutterBottom>Confidence threshold (low)</Typography>
|
||||
<Slider
|
||||
value={Number(draft.confidence_low)}
|
||||
min={0}
|
||||
max={100}
|
||||
step={1}
|
||||
valueLabelDisplay="auto"
|
||||
onChange={(_, v) => setDraft({ ...draft, confidence_low: Number(v) })}
|
||||
/>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Sessions with confidence < {draft.confidence_low} go to queue
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Typography variant="body2" gutterBottom>Risk grey zone</Typography>
|
||||
<Box display="flex" gap={1} alignItems="center">
|
||||
<TextField
|
||||
size="small" type="number" label="min"
|
||||
value={draft.risk_grey_min}
|
||||
onChange={(e) => setDraft({ ...draft, risk_grey_min: e.target.value })}
|
||||
/>
|
||||
<Typography>—</Typography>
|
||||
<TextField
|
||||
size="small" type="number" label="max"
|
||||
value={draft.risk_grey_max}
|
||||
onChange={(e) => setDraft({ ...draft, risk_grey_max: e.target.value })}
|
||||
/>
|
||||
</Box>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
Sensitive topics with risk in this band go to queue
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<TextField
|
||||
size="small" type="number" fullWidth label="Auto-relax at pending"
|
||||
helperText="If queue ≥ this many pending, drop topic filter"
|
||||
value={draft.queue_relax_at}
|
||||
onChange={(e) => setDraft({ ...draft, queue_relax_at: parseInt(e.target.value, 10) || 0 })}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<TextField
|
||||
size="small" type="number" fullWidth label="Auto-strict at pending"
|
||||
helperText="If queue ≤ this many pending, broaden triage"
|
||||
value={draft.queue_strict_at}
|
||||
onChange={(e) => setDraft({ ...draft, queue_strict_at: parseInt(e.target.value, 10) || 0 })}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<FormControlLabel
|
||||
control={
|
||||
<Switch
|
||||
checked={draft.auto_tune_enabled}
|
||||
onChange={(e) => setDraft({ ...draft, auto_tune_enabled: e.target.checked })}
|
||||
/>
|
||||
}
|
||||
label="Auto-tune thresholds (cron)"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box mt={2} display="flex" justifyContent="flex-end" gap={1}>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<SaveIcon />}
|
||||
onClick={handleSave}
|
||||
disabled={!dirty || saving}
|
||||
>
|
||||
{saving ? 'Saving…' : 'Save Triage'}
|
||||
</Button>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue