Skip to content

Language Detector ​

Chrome 브라우저에는 AI가 내장되어 있으며, API를 통해 AI 기반 작업을 실행할 수 있도록 지원합니다.

Language Detector는 입력 텍스트의 언어를 감지하여 확률이 높은 언어부터 낮은 언어 순으로 반환합니다.

Language Detector is not supported in this browser

이를 이용해 Translator API에 번역할 텍스트의 입력 언어를 전달할 수 있습니다.

0. 준비 ​

브라우저 지원 현황을 확인하세요

MDN 에서 브라우저별 지원 현황을 확인할 수 있습니다.

Typescript를 사용한다면

@types/dom-chromium-ai npm 패키지를 사용하여 TypeScript 타이핑을 가져오세요.

1. 브라우저가 Language Detector API를 지원하는지 확인 ​

js
const isBrowserSupported = "LanguageDetector" in self;

2. AI 모델이 준비되었는지 확인 ​

API가 준비되었는지 확인하려면 비동기 availability() 함수를 호출합니다.

js
const availability = await LanguageDetector.availability({
  expectedInputLanguages: languages,
});

이 함수는 다음 값 중 하나가 포함된 프로미스를 반환합니다.

  • available : 모델이 이미 다운로드되어 있고 사용할 수 있습니다.
  • downloading : 모델이 다운로드 중입니다.
  • downloadable : 모델을 다운로드 할 수 있습니다.
  • unavailable : 지원되지 않습니다. 기기의 전원이나 디스크 공간이 부족할 수 있습니다.

3. 모델 다운로드 및 인스턴스 생성 ​

모델 다운로드 및 인스턴스 생성을 위해 create() 함수를 호출합니다.

이 때 예상 언어를 전달하거나, 작업을 중단하기 위한 시그널을 전달할 수 있습니다.

ts
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,
});

4. 언어 감지 ​

언어 감지를 위해 detect() 함수를 호출합니다.

js
const detectedLanguages = await detector.detect(text);

이 함수는 다음과 같은 목록을 포함하는 프로미스를 반환합니다.

ts
[
  {
      "confidence": 0.9427181482315063,
      "detectedLanguage": "en"
  },
  {
      "confidence": 0.016950147226452827,
      "detectedLanguage": "es"
  },
  ...
]

5. 인스턴스 해제 ​

작업이 완료되면 인스턴스를 해제합니다.

ts
detector.destroy();

create() 를 호출할 때 전달하는 signal을 통해서 작업을 중단해도 같은 효과를 얻을 수 있습니다

( create() 가 완료되기 전에 abort할 경우에는 create 작업이 취소됩니다. )

ts
abortController.abort();

React 예제 ​

사용자의 상호작용 없이 AI 모델을 다운로드하려고 하면 에러가 발생할 수 있습니다.

따라서 컴포넌트가 마운트되었을 때 인스턴스를 생성하는 것보다는

사용자의 상호작용이 있을 때 인스턴스를 생성할 수 있도록 유틸 함수를 작성합니다.

languageDetector.ts
ts
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 인스턴스가 유지되도록 작성했습니다.

클린업도 신경써주도록 합니다.

LanguageDetector.tsx
tsx
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>
  );
};