feat: AI categorisation fallback, unsubscribe confidence scoring, one-line summaries
Heuristic classifier falls back to AI only when it can't determine a category; unsubscribe confidence blends method reliability with an AI safety opinion and surfaces it in the Unsubscribe Manager; emails get an on-demand AI one-line summary in the detail pane. All AI calls degrade gracefully when AI is disabled or the provider errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -71,10 +71,13 @@ function SenderList({ senders, selectedId, onSelect, search, onSearch }) {
|
||||
function EmailDetail({ email: summary, onBack }) {
|
||||
const [detail, setDetail] = useState(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [aiSummary, setAiSummary] = useState(null);
|
||||
const [aiLoading, setAiLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDetail(null);
|
||||
setLoading(true);
|
||||
setAiSummary(null);
|
||||
EmailApi.get(summary.id)
|
||||
.then(setDetail)
|
||||
.catch(() => setDetail(null))
|
||||
@@ -83,6 +86,14 @@ function EmailDetail({ email: summary, onBack }) {
|
||||
|
||||
const email = detail ?? summary;
|
||||
|
||||
const fetchAiSummary = () => {
|
||||
setAiLoading(true);
|
||||
EmailApi.summary(summary.id)
|
||||
.then((r) => setAiSummary(r.summary))
|
||||
.catch(() => setAiSummary(null))
|
||||
.finally(() => setAiLoading(false));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="sd-detail">
|
||||
<button className="sd-back" onClick={onBack}>← Back to list</button>
|
||||
@@ -101,6 +112,18 @@ function EmailDetail({ email: summary, onBack }) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!loading && (
|
||||
<div className="sd-ai-summary">
|
||||
{aiSummary != null ? (
|
||||
<div className="sd-ai-summary-text">✨ {aiSummary}</div>
|
||||
) : (
|
||||
<button className="btn-sm" onClick={fetchAiSummary} disabled={aiLoading}>
|
||||
{aiLoading ? 'Summarising…' : '✨ AI summary'}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading && <div className="sd-body-loading muted">Loading message…</div>}
|
||||
|
||||
{!loading && detail?.bodyText && (
|
||||
|
||||
Reference in New Issue
Block a user