크롬 음성 인식 확장 프로그램 개발해보기




manifest.json

 

{

  "manifest_version": 3,

  "name": "Voice Typer Everywhere",

  "version": "1.0",

  "description": "어디서나 단축키로 구글 음성인식을 실행합니다.",

  "permissions": [

    "activeTab",

    "scripting"

  ],

  "background": {

    "service_worker": "background.js"

  },

  "commands": {

    "toggle-voice-typing": {

      "suggested_key": {

        "default": "Ctrl+Shift+Y",

        "mac": "MacCtrl+Shift+Y"

      },

      "description": "음성 인식 시작/종료"

    }

  },

  "content_scripts": [

    {

      "matches": ["<all_urls>"],

      "js": ["content.js"]

    }

  ]

}





background.js



// 사용자가 설정한 단축키 명령을 감지합니다.

chrome.commands.onCommand.addListener((command) => {

  if (command === "toggle-voice-typing") {

    // 현재 사용자가 보고 있는 활성화된 탭을 찾습니다.

    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {

      if (tabs[0]) {

        // 활성화된 탭(content.js)으로 "음성인식을 토글하라"는 메시지를 보냅니다.

        chrome.tabs.sendMessage(tabs[0].id, { action: "TOGGLE_VOICE" });

      }

    });

  }

});





content.js



let recognition = null;

let isListening = false;



// 구글 음성 인식(Web Speech API) 초기화 함수

function initSpeechRecognition() {

  // 브라우저 내장 구글 음성 인식 엔진 호출

  const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;

  

  if (!SpeechRecognition) {

    console.error("이 브라우저는 구글 음성 인식 API를 지원하지 않습니다.");

    return null;

  }



  const rec = new SpeechRecognition();

  rec.continuous = true;          // 말이 끊겨도 계속 인식하도록 설정

  rec.interimResults = true;     // 중간 인식 결과를 실시간으로 보여줌

  rec.lang = 'ko-KR';             // 인식 언어를 한국어로 설정



  // 음성이 인식되어 텍스트로 변환되었을 때 실행되는 이벤트

  rec.onresult = (event) => {

    let resultText = '';

    for (let i = event.resultIndex; i < event.results.length; ++i) {

      if (event.results[i].isFinal) {

        resultText += event.results[i][0].transcript;

      }

    }



    // 현재 사용자가 클릭해서 커서가 위치해 있는 텍스트 박스(입력창)를 찾습니다.

    const activeElement = document.activeElement;

    

    if (activeElement && resultText) {

      // 일반적인 input창이나 textarea 창일 때 글자 주입

      if (activeElement.tagName === 'INPUT' || activeElement.tagName === 'TEXTAREA') {

        activeElement.value += resultText + ' ';

      } 

      // 구글 문서, 노션 등 contenteditable 속성을 쓰는 에디터일 때 글자 주입

      else if (activeElement.isContentEditable) {

        document.execCommand('insertText', false, resultText + ' ');

      }

    }

  };



  rec.onerror = (event) => {

    console.error("음성 인식 오류 발생:", event.error);

    isListening = false;

  };



  rec.onend = () => {

    console.log("음성 인식 종료");

    isListening = false;

  };



  return rec;

}



// background.js로부터 단축키 신호를 받았을 때의 처리

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {

  if (request.action === "TOGGLE_VOICE") {

    if (!recognition) {

      recognition = initSpeechRecognition();

    }



    if (!recognition) return;



    if (!isListening) {

      recognition.start();

      isListening = true;

      console.log("🎤 음성 인식을 시작합니다... 말을 하세요.");

    } else {

      recognition.stop();

      isListening = false;

      console.log("🛑 음성 인식을 종료합니다.");

    }

  }

});







Post a Comment

Previous Post Next Post
본 블로그에서는 제휴마케팅 활동의 일환으로 이에 따른 일정액의 수수료를 제공받습니다.