增加pdf中划句或段ai伴读功能
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import type {
|
||||
StoredParagraph,
|
||||
StoredSentence,
|
||||
} from "../infrastructure/storage/lectureStore";
|
||||
|
||||
export function normalizeSelectionText(text: string): string {
|
||||
return text
|
||||
.replace(/[\u0000-\u001f\f]/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
}
|
||||
|
||||
export interface PreparedSentenceMatch {
|
||||
paragraph: StoredParagraph;
|
||||
sentence: StoredSentence;
|
||||
}
|
||||
|
||||
function overlapScore(a: string, b: string): number {
|
||||
const na = normalizeSelectionText(a);
|
||||
const nb = normalizeSelectionText(b);
|
||||
if (!na || !nb) return 0;
|
||||
if (na === nb) return 100;
|
||||
if (na.includes(nb) || nb.includes(na)) {
|
||||
const shorter = Math.min(na.length, nb.length);
|
||||
const longer = Math.max(na.length, nb.length);
|
||||
return Math.round((shorter / longer) * 90);
|
||||
}
|
||||
|
||||
const aWords = new Set(na.split(/\s+/).filter((w) => w.length > 2));
|
||||
const bWords = nb.split(/\s+/).filter((w) => w.length > 2);
|
||||
if (!aWords.size || !bWords.length) return 0;
|
||||
let shared = 0;
|
||||
for (const w of bWords) {
|
||||
if (aWords.has(w)) shared += 1;
|
||||
}
|
||||
return Math.round((shared / bWords.length) * 70);
|
||||
}
|
||||
|
||||
export function findMatchingPreparedSentence(
|
||||
paragraphs: StoredParagraph[] | undefined,
|
||||
selectedText: string,
|
||||
options?: { requireTts?: boolean },
|
||||
): PreparedSentenceMatch | undefined {
|
||||
if (!paragraphs?.length || !selectedText.trim()) return undefined;
|
||||
|
||||
const requireTts = options?.requireTts !== false;
|
||||
let best: PreparedSentenceMatch | undefined;
|
||||
let bestScore = 0;
|
||||
|
||||
for (const paragraph of paragraphs) {
|
||||
if (paragraph.genStatus !== "ready") continue;
|
||||
|
||||
for (const sentence of paragraph.sentences ?? []) {
|
||||
if (requireTts && sentence.ttsZhStatus !== "ready") continue;
|
||||
const score = overlapScore(selectedText, sentence.text);
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
best = { paragraph, sentence };
|
||||
}
|
||||
}
|
||||
|
||||
if (!paragraph.sentences?.length) {
|
||||
const score = overlapScore(selectedText, paragraph.originalText);
|
||||
if (score > bestScore && (!requireTts || paragraph.ttsZhStatus === "ready")) {
|
||||
bestScore = score;
|
||||
best = {
|
||||
paragraph,
|
||||
sentence: {
|
||||
id: `${paragraph.id}-whole`,
|
||||
orderIndex: 0,
|
||||
text: paragraph.originalText,
|
||||
translation: paragraph.translation,
|
||||
page: paragraph.page,
|
||||
searchText: paragraph.searchText,
|
||||
audioPathEn: paragraph.audioPathEn,
|
||||
audioPathZh: paragraph.audioPathZh,
|
||||
ttsEnStatus: paragraph.ttsEnStatus,
|
||||
ttsZhStatus: paragraph.ttsZhStatus,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bestScore >= 55 ? best : undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user