Let imports opt out of AI classification
Classification preferences gains "Classify newly imported transactions with AI", stored as classify_on_import in config.toml and on by default, so existing configurations keep their behaviour. It covers CSV imports and bank synchronization alike. With it off, no import path contacts the provider: classification falls to the new provider-free rules path, where an opted-in merchant rule still applies its category and tags, an alias match still attaches its merchant, and everything else arrives on the editable fallback without a provenance error that would suggest the provider had failed. Analyse remains available on demand.
This commit is contained in:
@@ -630,6 +630,7 @@ function ImportForm({
|
||||
{prepared && (
|
||||
<ImportReview
|
||||
prepared={prepared}
|
||||
state={state}
|
||||
acceptState={acceptState}
|
||||
onError={onError}
|
||||
close={() => {
|
||||
@@ -647,16 +648,20 @@ function ImportForm({
|
||||
// only obvious against real records.
|
||||
function ImportReview({
|
||||
prepared,
|
||||
state,
|
||||
acceptState,
|
||||
onError,
|
||||
close,
|
||||
}: {
|
||||
prepared: PreparedImport;
|
||||
state: State;
|
||||
acceptState: (state: State, message?: string) => void;
|
||||
onError: (error: string) => void;
|
||||
close: () => void;
|
||||
}) {
|
||||
const [busy, setBusy] = useState(false);
|
||||
const classifying =
|
||||
state.settings.classify_on_import && state.status.ai_configured;
|
||||
const discard = () => {
|
||||
// Free the server's prepared statement; an expiring one is harmless.
|
||||
void request("/api/import/cancel", { id: prepared.id }).catch(() => {});
|
||||
@@ -744,6 +749,11 @@ function ImportReview({
|
||||
{prepared.samples.length} of {prepared.records} records, including the
|
||||
largest amount and both directions of money.
|
||||
</p>
|
||||
<p className="muted small">
|
||||
{classifying
|
||||
? "After importing, these transactions are classified with AI. Turn that off under Settings → Classification preferences."
|
||||
: "AI classification of imports is off, so these transactions arrive unclassified and editable. Enabled merchant rules still apply."}
|
||||
</p>
|
||||
</div>
|
||||
<div className="form-actions">
|
||||
<button
|
||||
|
||||
+22
-1
@@ -16,6 +16,9 @@ export function Settings({ state, mutate }: { state: State; mutate: Mutate }) {
|
||||
const [includeAmount, setIncludeAmount] = useState(
|
||||
state.settings.include_amount,
|
||||
);
|
||||
const [classifyOnImport, setClassifyOnImport] = useState(
|
||||
state.settings.classify_on_import,
|
||||
);
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [rebuild, setRebuild] = useState(false);
|
||||
@@ -334,7 +337,11 @@ export function Settings({ state, mutate }: { state: State; mutate: Mutate }) {
|
||||
try {
|
||||
await mutate(
|
||||
"/api/settings",
|
||||
{ model: model.trim(), include_amount: includeAmount },
|
||||
{
|
||||
model: model.trim(),
|
||||
include_amount: includeAmount,
|
||||
classify_on_import: classifyOnImport,
|
||||
},
|
||||
"Classification preferences saved",
|
||||
);
|
||||
} catch (err) {
|
||||
@@ -366,6 +373,20 @@ export function Settings({ state, mutate }: { state: State; mutate: Mutate }) {
|
||||
Disabled by default for privacy. Enabling this shares the amount
|
||||
with the configured AI provider to help classification.
|
||||
</p>
|
||||
<label className="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={classifyOnImport}
|
||||
onChange={(e) => setClassifyOnImport(e.target.checked)}
|
||||
/>
|
||||
Classify newly imported transactions with AI
|
||||
</label>
|
||||
<p className="muted small">
|
||||
Applies to CSV imports and bank synchronization. When off, no
|
||||
import contacts your AI provider: enabled merchant rules still
|
||||
classify, and everything else arrives unclassified and editable.
|
||||
AI classification → Analyse is unaffected.
|
||||
</p>
|
||||
<button
|
||||
className="button primary"
|
||||
disabled={busy || credentialsBusy}
|
||||
|
||||
+5
-1
@@ -93,7 +93,11 @@ export interface State {
|
||||
banking_configured: boolean;
|
||||
ai_configured: boolean;
|
||||
};
|
||||
settings: { model: string; include_amount: boolean };
|
||||
settings: {
|
||||
model: string;
|
||||
include_amount: boolean;
|
||||
classify_on_import: boolean;
|
||||
};
|
||||
sessions: { session_id: string; valid_until: string; accounts: Account[] }[];
|
||||
}
|
||||
export interface Total {
|
||||
|
||||
+1
-1
@@ -382,7 +382,7 @@ function App() {
|
||||
)}
|
||||
{page === "settings" && (
|
||||
<Settings
|
||||
key={`${state.settings.model}-${state.settings.include_amount}`}
|
||||
key={`${state.settings.model}-${state.settings.include_amount}-${state.settings.classify_on_import}`}
|
||||
state={state}
|
||||
mutate={mutate}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user