40858e0025
Deterministic, on-device, no model: - src/lib/learn pure modules (tokenize, summary [TextRank-ish], glossary [definition-pattern + frequency], flashcards [cloze/Q-A], srs [SM-2], quiz [MCQ with distractors]) — 37 unit tests. - Flashcard persistence: Dexie v4 + native v4 `flashcards` table; create/list/ listDue/updateSrs/delete/counts; cascades (transcript delete, course->Unsorted). - UI: transcript "Study aids" (generate summary+glossary, click-to-seek; create flashcards), Study screen (SM-2 review + Anki CSV export), per-lecture Quiz, library Study link with due-count badge. 215 tests green, 0 tsc errors, web export builds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { summarize } from './summary';
|
|
import type { Segment } from '../types';
|
|
|
|
const seg = (start: number, text: string, id?: string): Segment => ({
|
|
id,
|
|
start,
|
|
end: start + 1,
|
|
text,
|
|
});
|
|
|
|
describe('summarize', () => {
|
|
it('returns [] for no segments', () => {
|
|
expect(summarize([])).toEqual([]);
|
|
});
|
|
|
|
it('returns [] when maxSentences <= 0', () => {
|
|
expect(summarize([seg(0, 'Neural networks learn.')], { maxSentences: 0 })).toEqual(
|
|
[],
|
|
);
|
|
});
|
|
|
|
it('picks the top-N highest-frequency sentences', () => {
|
|
// "neural" + "networks" dominate; the off-topic sentence should be dropped.
|
|
const segs = [
|
|
seg(0, 'Neural networks process data.'),
|
|
seg(1, 'Neural networks learn from neural networks.'),
|
|
seg(2, 'The weather today is sunny.'),
|
|
];
|
|
const out = summarize(segs, { maxSentences: 2 });
|
|
expect(out.length).toBe(2);
|
|
const texts = out.map((s) => s.text);
|
|
expect(texts).not.toContain('The weather today is sunny.');
|
|
});
|
|
|
|
it('returns sentences in chronological order with the right start + id', () => {
|
|
const segs = [
|
|
seg(10, 'Gradient descent optimizes the gradient.', 'segB'),
|
|
seg(2, 'Gradient descent uses the gradient slope.', 'segA'),
|
|
];
|
|
const out = summarize(segs, { maxSentences: 2 });
|
|
// Both kept; chronological order means start 2 comes before start 10.
|
|
expect(out.map((s) => s.start)).toEqual([2, 10]);
|
|
expect(out[0]!.segmentId).toBe('segA');
|
|
expect(out[1]!.segmentId).toBe('segB');
|
|
});
|
|
|
|
it('flattens multi-sentence segments and tags them with the segment start', () => {
|
|
const segs = [seg(5, 'Alpha beta gamma. Alpha beta delta.', 'multi')];
|
|
const out = summarize(segs, { maxSentences: 5 });
|
|
expect(out.length).toBe(2);
|
|
for (const s of out) {
|
|
expect(s.start).toBe(5);
|
|
expect(s.segmentId).toBe('multi');
|
|
}
|
|
});
|
|
});
|