Skip to content

Commit 1aea6d0

Browse files
committed
fix: recognize topic sentences across indented paragraphs and PDF layouts
1 parent 4011ba9 commit 1aea6d0

9 files changed

Lines changed: 228 additions & 62 deletions

‎doc/core-tests.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ The repository retains 29 automated Node tests, reduced from 77 during the Octob
44

55
Selection ranks original PDF and annotation integrity first, credential protection and authenticated document access next, then translation routing, cancellation, cache persistence and document isolation. Extraction, session recovery, settings preservation, production packaging and bounded rendering complete the suite. Existing retained assertions remain intact.
66

7-
Removed lower-priority checks cover annotation browser filters, topic/keyword emphasis, translation spacing, outline tracking, quick links, pins, navigation helpers and row layout. Helper-level page-edit variants are replaced in the retained coverage by the existing save integration test, which checks disk contents, annotation geometry, rotation and rejection without modifying the PDF. Redundant cache variants were removed. These areas have less automatic regression coverage; additions should replace a lower-priority case to keep the suite below 30.
7+
Removed lower-priority checks cover annotation browser filters, topic/keyword emphasis, translation spacing, outline tracking, quick links, pins, navigation helpers and row layout. Helper-level page-edit variants are replaced in the retained coverage by the existing save integration test, which checks disk contents, annotation geometry, rotation and rejection without modifying the PDF. Redundant cache variants were removed; the generic custom-model cache unit case was replaced by the topic-sentence regression below, while kernel upgrade/restart and paragraph API cache coverage remain. These areas have less automatic regression coverage; additions should replace a lower-priority case to keep the suite below 30.
88

99
Run `npm run build` before `npm test`: the production-stage check consumes the built frontend. Provider requests use mocks; passing tests do not establish live translation quality or visual rendering correctness. Electron smoke scripts remain available for targeted desktop checks outside this Node suite. Historical performance reports retain their original counts.
1010

11+
The topic-sentence regression checks the reported indented Chinese paragraph, math-kernel source/translation geometry, column isolation, page continuations, small numbered footnotes and unchanged length rules.
12+
1113
| # | Test file | Retained behavior |
1214
|---|---|---|
1315
| 1 | server/annotations.test.mjs | annotation store round-trips metadata, embeds standard annotations, rewrites only managed entries, and preserves external entries |
@@ -32,7 +34,7 @@ Run `npm run build` before `npm test`: the production-stage check consumes the b
3234
| 20 | server/preferences.test.mjs | partial saves keep every current setting and unknown key |
3335
| 21 | server/production-stage.test.mjs | production bundle serves and extracts PDFs without an external Express installation |
3436
| 22 | server/render-resolution.test.mjs | large pages remain bounded by backing store memory and canvas dimensions |
35-
| 23 | server/translation-cache.test.mjs | compatible cache survives restart for custom models and strict mode stays isolated |
37+
| 23 | server/topic-sentences.test.mjs | topic sentences start on indented first lines and use original or translated paragraph boundaries |
3638
| 24 | server/translation-cache.test.mjs | paragraph API reuses legacy translations by default, strict mode invokes current provider |
3739
| 25 | server/translation-provider.test.mjs | configured key routes only to OpenAI and aborted fallback sends no translation |
3840
| 26 | server/translation-provider.test.mjs | backend fallback headers survive cache and failure, with independent launch sessions and provider caches |

‎electron/backend-process.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function makeProviderFetch(mode){
2020
await new Promise(resolve=>setTimeout(resolve,600));
2121
if(String(options?.body).includes('fixture 13'))return new Response(JSON.stringify({error:{message:'Synthetic rate limit'}}),{status:429,headers:{'Content-Type':'application/json'}});
2222
}
23-
return new Response(JSON.stringify({choices:[{message:{content:mode==='animation'?'示例译文:新的文字逐个跳跃上来,段落保持自然换行。'.repeat(3)+' 👩🏽‍💻 é':mode==='information-emphasis'?'首先,结果表明支持研究假设。然而,发现高于原先预期。普通内容保持不变。':mode==='topic-sentences'?'译文第一句。第二句保持普通字重。':'Mock translated paragraph'}}]}),{headers:{'Content-Type':'application/json'}});
23+
return new Response(JSON.stringify({choices:[{message:{content:mode==='animation'?'示例译文:新的文字逐个跳跃上来,段落保持自然换行。'.repeat(3)+' 👩🏽‍💻 é':mode==='information-emphasis'?'首先,结果表明支持研究假设。然而,发现高于原先预期。普通内容保持不变。':mode==='topic-sentences'?'译文第一句。第二句保持普通字重。'+'后续段落提供具体证据并说明研究背景。'.repeat(10):'Mock translated paragraph'}}]}),{headers:{'Content-Type':'application/json'}});
2424
};
2525
}
2626

‎electron/main.mjs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ else {
438438
ipcMain.handle('window:new',async event=>{trustedWindow(event);await createWindow();});
439439
if(!smoke&&preferences.load().restoreDocuments){for(const document of documentSession.restore()){try{await validateSystemPDF(document.path);}catch{continue;}if(!pendingFiles.includes(document.path))await createWindow(document.path,document.view);}}
440440
window=[...windows.keys()][0]||await createWindow(pendingFiles.shift());backend=windows.get(window).backend;documentsReady=true;await deliverPendingFiles();
441-
if(smoke){const checks=await import('./smoke.mjs');if(smoke==='information-emphasis')await (await import('./information-emphasis-smoke.mjs')).verifyInformationEmphasis(window,recents);else if(smoke==='topic-sentences')await (await import('./topic-sentences-smoke.mjs')).verifyTopicSentences(window);else if(smoke==='page-edits')await (await import('./page-edits-smoke.mjs')).verifyPageEdits(window,recents);else if(smoke==='cache-progress')await (await import('./cache-progress-smoke.mjs')).verifyCacheProgress(window);else if(smoke==='quick-links')await (await import('./quick-links-smoke.mjs')).verifyQuickLinks(window);else if(smoke==='translation-prefetch')await (await import('./translation-prefetch-smoke.mjs')).verifyTranslationPrefetch(window,recents);else if(smoke==='pdf-navigation')await (await import('./pdf-navigation-smoke.mjs')).verifyPDFNavigation(window,recents);else if(['sidebar','sidebar-keys'].includes(smoke))await (await import('./sidebar-smoke.mjs')).verifySidebar(window,recents);else if(smoke==='advanced-cache')await (await import('./advanced-cache-smoke.mjs')).verifyAdvancedCache(window);else if(smoke==='large-open')await (await import('./large-open-smoke.mjs')).verifyLargeOpen(window,recents);else if(smoke==='file-menu')await (await import('./file-menu-smoke.mjs')).verifyFileMenu(window,recents);else if(smoke==='recent-menu')await (await import('./recent-menu-smoke.mjs')).verifyRecentMenu(window,recents);else if(smoke==='startup')await (await import('./startup-smoke.mjs')).verifyStartup(window);else if(smoke==='session')await (await import('./session-smoke.mjs')).verifySession(window,windows,createWindow);else if(smoke==='layout-settings')await (await import('./layout-settings-smoke.mjs')).verifyLayoutSettings(window);else if(smoke==='windows-settings')await (await import('./windows-settings-smoke.mjs')).verifyWindowsSettings(window);else if(smoke==='locales')await (await import('./locales-smoke.mjs')).verifyLocales(window);else if(smoke==='advanced')await (await import('./advanced-smoke.mjs')).verifyAdvanced(window);else if(smoke==='fluent')await (await import('./fluent-smoke.mjs')).verifyFluent(window);else if(smoke==='search')await (await import('./search-smoke.mjs')).verifySearch(window);else if(smoke==='multi-window')await (await import('./multi-window-smoke.mjs')).verifyMultiWindow(window,windows,createWindow);else if(smoke==='crop')await (await import('./crop-smoke.mjs')).verifyCrop(window,recents);else if(smoke==='fit-width')await (await import('./fit-width-smoke.mjs')).verifyFitWidth(window,recents);else if(smoke==='reading-view')await (await import('./reading-view-smoke.mjs')).verifyReadingView(window,recents);else if(smoke==='performance')await (await import('./performance-smoke.mjs')).verifyPerformance(window);else if(smoke==='benchmark')await (await import('./benchmark-smoke.mjs')).verifyBenchmark(window);else if(smoke==='coverage')await (await import('./coverage-smoke.mjs')).verifyCoverage(window,backend,token);else if(smoke==='resize'){await (await import('./recents-smoke.mjs')).verifyRecents(window,recents);await (await import('./resize-smoke.mjs')).verifyResize(window);}else if(smoke==='animation')await (await import('./animation-smoke.mjs')).verifyAnimation(window);else if(smoke==='ux')await (await import('./ux-smoke.mjs')).verifyUX(window,recents);else if(smoke==='layout-region')await (await import('./layout-region-smoke.mjs')).verifyLayoutRegion(window);else if(smoke==='kernel-choice')await (await import('./kernel-choice-smoke.mjs')).verifyKernelChoice(window);else if(smoke==='kernels')await (await import('./kernel-smoke.mjs')).verifyKernelUI(window);else if(['annotations','annotation-shortcuts'].includes(smoke))await (await import('./annotations-smoke.mjs')).verifyAnnotations(window,recents);else if(smoke==='file-open')await checks.verifySystemOpen(window);else await checks.verify(window,backend,token,smoke,credentials);}
441+
if(smoke){const checks=await import('./smoke.mjs');if(smoke==='information-emphasis')await (await import('./information-emphasis-smoke.mjs')).verifyInformationEmphasis(window,recents);else if(smoke==='topic-sentences')await (await import('./topic-sentences-smoke.mjs')).verifyTopicSentences(window,recents);else if(smoke==='page-edits')await (await import('./page-edits-smoke.mjs')).verifyPageEdits(window,recents);else if(smoke==='cache-progress')await (await import('./cache-progress-smoke.mjs')).verifyCacheProgress(window);else if(smoke==='quick-links')await (await import('./quick-links-smoke.mjs')).verifyQuickLinks(window);else if(smoke==='translation-prefetch')await (await import('./translation-prefetch-smoke.mjs')).verifyTranslationPrefetch(window,recents);else if(smoke==='pdf-navigation')await (await import('./pdf-navigation-smoke.mjs')).verifyPDFNavigation(window,recents);else if(['sidebar','sidebar-keys'].includes(smoke))await (await import('./sidebar-smoke.mjs')).verifySidebar(window,recents);else if(smoke==='advanced-cache')await (await import('./advanced-cache-smoke.mjs')).verifyAdvancedCache(window);else if(smoke==='large-open')await (await import('./large-open-smoke.mjs')).verifyLargeOpen(window,recents);else if(smoke==='file-menu')await (await import('./file-menu-smoke.mjs')).verifyFileMenu(window,recents);else if(smoke==='recent-menu')await (await import('./recent-menu-smoke.mjs')).verifyRecentMenu(window,recents);else if(smoke==='startup')await (await import('./startup-smoke.mjs')).verifyStartup(window);else if(smoke==='session')await (await import('./session-smoke.mjs')).verifySession(window,windows,createWindow);else if(smoke==='layout-settings')await (await import('./layout-settings-smoke.mjs')).verifyLayoutSettings(window);else if(smoke==='windows-settings')await (await import('./windows-settings-smoke.mjs')).verifyWindowsSettings(window);else if(smoke==='locales')await (await import('./locales-smoke.mjs')).verifyLocales(window);else if(smoke==='advanced')await (await import('./advanced-smoke.mjs')).verifyAdvanced(window);else if(smoke==='fluent')await (await import('./fluent-smoke.mjs')).verifyFluent(window);else if(smoke==='search')await (await import('./search-smoke.mjs')).verifySearch(window);else if(smoke==='multi-window')await (await import('./multi-window-smoke.mjs')).verifyMultiWindow(window,windows,createWindow);else if(smoke==='crop')await (await import('./crop-smoke.mjs')).verifyCrop(window,recents);else if(smoke==='fit-width')await (await import('./fit-width-smoke.mjs')).verifyFitWidth(window,recents);else if(smoke==='reading-view')await (await import('./reading-view-smoke.mjs')).verifyReadingView(window,recents);else if(smoke==='performance')await (await import('./performance-smoke.mjs')).verifyPerformance(window);else if(smoke==='benchmark')await (await import('./benchmark-smoke.mjs')).verifyBenchmark(window);else if(smoke==='coverage')await (await import('./coverage-smoke.mjs')).verifyCoverage(window,backend,token);else if(smoke==='resize'){await (await import('./recents-smoke.mjs')).verifyRecents(window,recents);await (await import('./resize-smoke.mjs')).verifyResize(window);}else if(smoke==='animation')await (await import('./animation-smoke.mjs')).verifyAnimation(window);else if(smoke==='ux')await (await import('./ux-smoke.mjs')).verifyUX(window,recents);else if(smoke==='layout-region')await (await import('./layout-region-smoke.mjs')).verifyLayoutRegion(window);else if(smoke==='kernel-choice')await (await import('./kernel-choice-smoke.mjs')).verifyKernelChoice(window);else if(smoke==='kernels')await (await import('./kernel-smoke.mjs')).verifyKernelUI(window);else if(['annotations','annotation-shortcuts'].includes(smoke))await (await import('./annotations-smoke.mjs')).verifyAnnotations(window,recents);else if(smoke==='file-open')await checks.verifySystemOpen(window);else await checks.verify(window,backend,token,smoke,credentials);}
442442
}).catch(async error=>{if(smoke){await backend?.close();console.error('Desktop smoke failed:',error.stack||error.message);if(smoke==='file-open')await writeFile('/tmp/preview-system-open-result.json',JSON.stringify({passed:false,error:error.message}));app.exit(1);return;}dialog.showErrorBox('PDFMathReader',`The local reader could not start.\n\n${error?.message||'The backend utility process did not become ready.'}\n\nQuit and reopen PDFMathReader.`);app.quit();});
443443
app.on('before-quit',event=>{
444444
if(!backend || quitting)return;

0 commit comments

Comments
 (0)