
Chrome 브라우저에는 AI가 내장되어 있으며, API를 통해 AI 기반 작업을 실행할 수 있도록 지원합니다.
Language Detector는 입력 텍스트의 언어를 감지하여 확률이 높은 언어부터 낮은 언어 순으로 반환합니다.
이를 이용해 Translator API에 번역할 텍스트의 입력 언어를 전달할 수 있습니다.
브라우저 지원 현황을 확인하세요
MDN 에서 브라우저별 지원 현황을 확인할 수 있습니다.
Typescript를 사용한다면
@types/dom-chromium-ai npm 패키지를 사용하여 TypeScript 타이핑을 가져오세요.
const isBrowserSupported = "LanguageDetector" in self;
API가 준비되었는지 확인하려면 비동기 availability() 함수를 호출합니다.
const availability = await LanguageDetector.availability({
expectedInputLanguages: languages,
});
이 함수는 다음 값 중 하나가 포함된 프로미스를 반환합니다.
available : 모델이 이미 다운로드되어 있고 사용할 수 있습니다.downloading : 모델이 다운로드 중입니다.downloadable : 모델을 다운로드 할 수 있습니다.unavailable : 지원되지 않습니다. 기기의 전원이나 디스크 공간이 부족할 수 있습니다.모델 다운로드 및 인스턴스 생성을 위해 create() 함수를 호출합니다.
이 때 예상 언어를 전달하거나, 작업을 중단하기 위한 시그널을 전달할 수 있습니다.
const abortController = new AbortController();
const detector = await LanguageDetector.create({
expectedInputLanguages: languages,
monitor(m) {
m.addEventListener("downloadprogress", (e) => {
console.log(`Downloaded ${e.loaded * 100}%`);
});
},
signal: abortController.signal,
});
언어 감지를 위해 detect() 함수를 호출합니다.
const detectedLanguages = await detector.detect(text);
이 함수는 다음과 같은 목록을 포함하는 프로미스를 반환합니다.
[
{
"confidence": 0.9427181482315063,
"detectedLanguage": "en"
},
{
"confidence": 0.016950147226452827,
"detectedLanguage": "es"
},
...
]
작업이 완료되면 인스턴스를 삭제합니다.
detector.destroy();
create 함수를 호출할 때 전달하는 signal을 통해서 작업을 중단해도 같은 효과를 얻을 수 있습니다
( create() 가 완료되기 전에 abort할 경우에는 create 작업이 취소됩니다. )
abortController.abort();
사용자의 상호작용 없이 AI 모델을 다운로드하려고 하면 에러가 발생할 수 있습니다.
따라서 컴포넌트가 마운트되었을 때 인스턴스를 생성하는 것보다는
사용자의 상호작용이 있을 때 인스턴스를 생성할 수 있도록 유틸 함수를 작성합니다.
export const getLanguageDetector = async (languages: string[], signal: AbortSignal) => {
const isBrowserSupported = "LanguageDetector" in self;
if (!isBrowserSupported) {
throw new Error("Language Detector is not supported in this browser");
}
const availability = await LanguageDetector.availability({
expectedInputLanguages: languages,
});
if (availability === "unavailable") {
throw new Error("Model is not available for the given languages");
}
return LanguageDetector.create({
expectedInputLanguages: languages,
monitor(m) {
m.addEventListener("downloadprogress", (e) => {
console.log(`Downloaded ${e.loaded * 100}%`);
});
},
signal: signal,
});
컴포넌트가 유지되는 동안은 Language Detector 인스턴스가 유지되도록 작성했습니다.
클린업도 신경써주도록 합니다.
import { useEffect, useState } from "react";
import { getLanguageDetector } from "@/utils/languageDetector";
export const LanguageDetector = () => {
const detectorRef = useRef<LanguageDetector | null>(null);
const abortControllerRef = useRef<AbortController | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [detectedLanguage, setDetectedLanguage] = useState<
LanguageDetectionResult[]
>([]);
useEffect(() => {
return () => {
abortControllerRef.current?.abort();
};
}, []);
const detectLanguage = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
const text = formData.get("text") as string;
try {
setIsLoading(true);
if (!detectorRef.current) {
abortControllerRef.current = new AbortController();
detectorRef.current = await getDetector(
["en"],
abortControllerRef.current.signal
);
}
const results = (await detectorRef.current?.detect(text)) ?? [];
setDetectedLanguage(results);
} catch (error) {
console.error("Error detecting language", error);
} finally {
setIsLoading(false);
}
};
return (
<div>
<form onSubmit={detectLanguage}>
<input type="text" name="text" />
<button type="submit">Detect</button>
</form>
{detectedLanguage.map((language) => (
<div key={language.detectedLanguage}>
{language.detectedLanguage}: {language.confidence}
</div>
))}
</div>
);
};