이번 포스트에서는 React와 TypeScript, WinkNLP를 사용하여 중요 문장 하이라이팅 및 포커스 모드 기능을 구현하는 방법을 소개하겠습니다.
https://observablehq.com/@winkjs/how-to-visualize-key-sentences-in-a-document
다운로드는 오른쪽 위에 점 3개 > export > download
WinkNLP의 its.sentenceWiseImportance 헬퍼를 활용하여 문장의 중요도를 계산하고 해당 가설은 논문 Examining the Content Load of Part of Speech Blocks for Information Retrieval에서 제시되었습니다.
npm install wink-nlp wink-eng-lite-web-model d3
import React, { useState } from "react";
import winkNLP from "wink-nlp";
import model from "wink-eng-lite-web-model";
import { interpolateRgb } from "d3";
// NLP 초기화
const nlp = winkNLP(model);
const its = nlp.its;
const App: React.FC = () => {
const [text, setText] = useState<string>(""); // 텍스트 상태 관리
const [highlightPercentage, setHighlightPercentage] = useState<number>(20); // 하이라이팅 퍼센티지 상태 관리
const [showControls, setShowControls] = useState<boolean>(false); // 컨트롤 표시 여부 상태 관리
// 문장별 중요도 계산 함수
const sentenceWiseNormalizedWeights = (doc: any, its: any) => {
return doc.out(its.sentenceWiseImportance).map((e: any) => e.importance);
};
// 텍스트 하이라이팅 적용 함수
const highlightText = (importance: number, maxImportance: number) => {
if (!showControls || highlightPercentage === 0) {
// 하이라이팅이 비활성화된 경우 기본 스타일 반환
return { backgroundColor: "transparent", color: "black", opacity: 1 };
}
const normalizedImportance = importance / maxImportance;
const opacity = Math.min(1, highlightPercentage / 100);
const colorScale = interpolateRgb(
`rgba(151, 78, 175, 0)`,
`rgba(151, 78, 175, ${opacity})`
);
const backgroundColor = colorScale(normalizedImportance);
return {
backgroundColor,
color: "black",
opacity: 1,
transition: "opacity 0.3s ease",
display: "inline",
};
};
// 텍스트 처리 및 출력 함수
const processText = () => {
const doc = nlp.readDoc(text); // 텍스트를 NLP로 처리
const sentences = doc.sentences().out(its.value); // 문장 단위로 분리
const sentenceWeights = sentenceWiseNormalizedWeights(doc, its); // 문장별 중요도 계산
const maxImportance = Math.max(...sentenceWeights); // 최대 중요도 값 계산
return sentences.map((sentence, index) => {
const importance = sentenceWeights[index]; // 각 문장의 중요도
const style = highlightText(importance, maxImportance); // 중요도에 따른 스타일 적용
return (
<span
key={index}
style={style} // 계산된 스타일을 적용
>
{sentence}{" "}
</span>
);
});
};
return (
<div className="p-4">
<textarea
value={text}
onChange={(e) => setText(e.target.value)} // 사용자가 입력한 텍스트를 상태로 저장
placeholder="Enter your text here..."
className="w-full p-2 border border-gray-300 dark:border-gray-700 rounded mb-4 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
rows={10}
/>
<div className="mb-4 flex items-center">
<label className="mr-2">Enable Controls</label>
<label className="inline-flex relative items-center cursor-pointer">
<input
type="checkbox"
checked={showControls}
onChange={() => setShowControls(!showControls)}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 rounded-full peer peer-focus:ring-4 peer-focus:ring-[#974EAF] dark:peer-focus:ring-[#974EAF] dark:bg-gray-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all dark:border-gray-600 peer-checked:bg-[#974EAF]"></div>
</label>
</div>
{showControls && (
<div>
<div className="mb-4">
<label className="mr-2">Highlight Percentage:</label>
<input
type="range"
min="0"
max="100"
value={highlightPercentage}
onChange={(e) => setHighlightPercentage(Number(e.target.value))}
className="w-full accent-[#974EAF]"
/>
<span className="ml-2">{highlightPercentage}%</span>
</div>
</div>
)}
<div className="prose prose-basic dark:prose-invert">{processText()}</div>
</div>
);
};
export default App;
Tailwind CSS를 사용해서
prose prose-basic
없이는 스타일이 적용이 되지 않습니다.<div className="prose prose-basic">{processText()}</div>
문장의 중요도를 분석하는 중요한 함수
const sentenceWiseNormalizedWeights = (doc: any, its: any) => { return doc.out(its.sentenceWiseImportance).map((e: any) => e.importance); };
이번 포스트에서는 React와 TypeScript를 활용하여 문서에서 중요한 문장을 하이라이팅하는 기능을 만들어 봤습니다.