feat: streamline Kiku duplicate grouping and popup flow (#38)

This commit is contained in:
2026-04-01 00:04:03 -07:00
parent ec64eebb80
commit 006ff22d42
29 changed files with 1218 additions and 34 deletions

View File

@@ -112,6 +112,11 @@ interface CardCreationDeps {
isUpdateInProgress: () => boolean;
setUpdateInProgress: (value: boolean) => void;
trackLastAddedNoteId?: (noteId: number) => void;
trackLastAddedDuplicateNoteIds?: (noteId: number, duplicateNoteIds: number[]) => void;
findDuplicateNoteIds?: (
expression: string,
noteInfo: CardCreationNoteInfo,
) => Promise<number[]>;
recordCardsMinedCallback?: (count: number, noteIds?: number[]) => void;
}
@@ -548,6 +553,33 @@ export class CardCreationService {
fields[getConfiguredWordFieldName(this.deps.getConfig())] = sentence;
}
const pendingNoteInfo = this.createPendingNoteInfo(fields);
const pendingNoteFields = Object.fromEntries(
Object.entries(fields).map(([name, value]) => [name.toLowerCase(), value]),
);
const pendingExpressionText = getPreferredWordValueFromExtractedFields(
pendingNoteFields,
this.deps.getConfig(),
).trim();
let duplicateNoteIds: number[] = [];
if (
sentenceCardConfig.kikuEnabled &&
sentenceCardConfig.kikuFieldGrouping !== 'disabled' &&
pendingExpressionText &&
this.deps.findDuplicateNoteIds
) {
try {
duplicateNoteIds = sortUniqueNoteIds(
await this.deps.findDuplicateNoteIds(pendingExpressionText, pendingNoteInfo),
);
} catch (error) {
log.warn(
'Failed to capture pre-add duplicate note ids:',
(error as Error).message,
);
}
}
const deck = this.deps.getConfig().deck || 'Default';
let noteId: number;
try {
@@ -570,6 +602,14 @@ export class CardCreationService {
log.warn('Failed to track last added note:', (error as Error).message);
}
if (duplicateNoteIds.length > 0) {
try {
this.deps.trackLastAddedDuplicateNoteIds?.(noteId, duplicateNoteIds);
} catch (error) {
log.warn('Failed to track duplicate note ids:', (error as Error).message);
}
}
try {
this.deps.recordCardsMinedCallback?.(1, [noteId]);
} catch (error) {
@@ -685,6 +725,15 @@ export class CardCreationService {
);
}
private createPendingNoteInfo(fields: Record<string, string>): CardCreationNoteInfo {
return {
noteId: -1,
fields: Object.fromEntries(
Object.entries(fields).map(([name, value]) => [name, { value }]),
),
};
}
private async mediaGenerateAudio(
videoPath: string,
startTime: number,
@@ -764,3 +813,7 @@ export class CardCreationService {
return `image_${timestamp}.${ext}`;
}
}
function sortUniqueNoteIds(noteIds: number[]): number[] {
return [...new Set(noteIds)].sort((left, right) => left - right);
}