[Javascript] Papago API로 번역기능 구현하기

이승준·2025년 1월 11일

JS

목록 보기
3/5
post-thumbnail

이전 html,css 시간에 파파고 페이지를 클론코딩 했었는데 이번 시간엔 파파고 깡통 페이지에 PAPAGO API를 호출하여 번역과 언어감지 기능을 추가해보겠습니다. 코드는 제공되지 않으며, 일부 절차는 스킵될수있습니다.

환경설정

1. Node.js의 npm 패키지 설치하기

준비물 : node 설치하기!
노드를 설치하는게 아니라 이미 설치된 노드의 npm 패키지를 설치하는것이다.

우리는 이제 JS를 활용해 동적으로 웹페이지의 기능을 구현할것이다. 더 이상 vscode의 liveserver가 아닌 node를 이용해 localhost:3000으로 내 파파고 페이지를 접속해보자!

빈 프로젝트를 생성하고 npm i node를 입력하면된다.

설치가 완료되면 npm init을 입력해 프로젝트를 생성하자!


이런 저런 입력할 칸이 뜨는데 할 사람은 해도되는데 그냥 프로젝트에 대한 정보를 적는것이다. 필자는 엔터 광클함.아무튼 package.json이 생기면 성공



Fin. 나머지 의존성 설치

npm i superagent 
npm i express

Express: Node.js 기반 웹 애플리케이션 서버 프레임워크로, 라우팅, 미들웨어, HTTP 요청/응답 처리를 효율적으로 지원합니다. 어렵죠? 그냥 저희 패키지내에서 '/detect' 라는 경로로 호출하면 받아주는 문을 열어주는느낌이라고 생각하세요!
SuperAgent: HTTP 요청을 간단히 작성할 수 있는 라이브러리로, GET, POST 등 클라이언트 요청을 Promise 또는 콜백 방식으로 처리합니다. -> 이것은 파파고 api한테 요청을 보내기위한거라고 생각하세요!






유저가 입력이 종료되고 2초후에 작동하게 해보자

강사님이 요구하신 사항인데, 파파고를 사용해보면 거의 실시간으로 번역 및 언어감지가 되는데, 우리는 api를 돈내고 사용을 하는 입장에서, 한 글자 입력할 때 마다 api가 호출되면 한정된 리소스가 금방 바닥이 나겠죠?! 그래서 저희는 입력이 더이상 들어오지않고 2초가 지난후에 동작하게 구현해보았습니다. 같이 코드를 보시죠!



입력, 출력, select 박스 가져오기

const [sourceSelect, targetSelect] = document.getElementsByTagName('select');
const [sourceTextArea, targetTextArea] = document.getElementsByTagName('textarea');
  • 웹 API를 활용해서 엘리먼트들을 배열로 저장해둡니다! 참고로 위에 부분은 디스트럭터링을 사용한겁니다. 필요하시면 학습하시기를..


let targetLang = 'en';
targetSelect.addEventListener('change', (event) => targetLang = event.target.value);
  • 이 코드는 위에 저 빨간 부분 셀렉트 박스에 이벤트 리스너로 해당 셀렉트박스 값을 가져오게 만들었습니다.


    setTimeout를 이용해 2초후에 콜백으로 요청보내기

    detectLanguage,translate는 이후 api.js 에서 만들건데 언어감지, 번역 api를 요청하는 함수입니다.

//app.js
let timer;
sourceTextArea.addEventListener('input', (event) => {
    if (timer) clearTimeout(timer);

    timer = setTimeout(async () => {
        const text = event.target.value;
        console.log(text);
        const detectedResult = await detectLanguage('/detect', text);

        targetLang = changeLanguage(detectedResult, targetLang);

        const { detectedLanguage, targetLanguage, translatedText } = await translateLanguage('/translate', detectedResult, targetLang, text);

        // 결과값 바인딩
        sourceSelect.value = detectedLanguage;
        targetSelect.value = targetLanguage;
        targetTextArea.value = translatedText;
    }, 1500);

});
  • soucreTextArea(유저가 입력하는 공간)에 input 이벤트리스너 등록
  • input이 발생하고 2초 타이머를 동작시킴.
    • if (timer) clearTimeout(timer); 디바운싱이라고도 부르는데, 이 코드가 없으면 한 글자 입력할때마다 각각 2초에 타이머가 가동됨. 기존에 타이머가 존재하면 타이머를 모두 삭제해주는 기능.
  • 입력한 값을 가져와 요청을 보낸후 값을 출력창에 바인딩.





HTTP 통신 해보자!

//index.js
import express, { json } from 'express';
import HTTP from 'superagent';

const app = express();

app.use(express.static('public'))
app.use(json())

// 코드 일부분 발췌

app.get('/', (_, response) => {
    response.sendFile('index.html');
});

app.post('/detect', (request, response) => {
    const url = 'https://naveropenapi.apigw.ntruss.com/langs/v1/dect';

    HTTP.post(url)
        .send(request.body)
        .set('Content-Type', 'application/json')
        .set('X-NCP-APIGW-API-KEY-ID', clientId)
        .set('X-NCP-APIGW-API-KEY', clientSecret)
        .end((error, result) => {
            if (result.statusCode === 200) {
                response.send(result.body);
            } else {
                console.error(error);
            }
        });
});


// 번역 요청 처리 API
app.post('/translate', (request, response) => {

    const url = 'https://naveropenapi.apigw.ntruss.com/nmt/v1/translation';

    HTTP.post(url)
        .send(request.body)
        .set('Content-Type', 'application/json')
        .set('X-NCP-APIGW-API-KEY-ID', clientId)
        .set('X-NCP-APIGW-API-KEY', clientSecret)
        .end((error, result) => {
            if (result.statusCode === 200) {
                // 파파고 서버로부터 응답받은 결과 데이터
                const responseDataFromPapago = result.body;

                // 화면 출력에 필요한 값만 추출
                const { srcLangType: detectedLanguage, tarLangType: targetLanguage, translatedText } = responseDataFromPapago.message.result;

                const responseData = {
                    detectedLanguage,
                    targetLanguage,
                    translatedText
                }

                response.send(responseData);
            } else {
                console.error(error);
            }
        });
});
  • 파파고의 api 스펙은 파파고 API docs를 참고.
    • request.body: 입력창에 사용자가 입력한 값이다.
    • set 구문들은 헤더에 json으로 보낼라는것과
    • 파파고를 사용하려면 필요한 id와 키값을 넣어야한다.
  • 정리하면 이 server.js에서는 입력한 값을 받아 실제 파파고 서버에 HTTP 서버로 요청을 보내고 결과값을 result.body에 담아 다시 리턴한다.






api.js에 fetch 함수들을 분리해서 구현하자.

사실 app.js에서 바로 fetch를 사용해도 된다. 하지만 너무 코드가 길어지고, 나중에 관리하기도 힘들어서 따로 빼는방식을 추천해주셨다.

//api.js
export const detectLanguage = async (url, text) => {
    let sourceLanguage;

    const body = { query: text };

    await fetch(url, optionsFrom('POST', body))
        .then(response => response.json())
        .then(data => {
            sourceLanguage = data.langCode;
        });

    return sourceLanguage;
}

// 언어 번역 요청 기능을 수행하는 함수
export const translateLanguage = async (url, detectedLanguage, targetLanguage, text) => {

    const body = {
        source: detectedLanguage,
        target: targetLanguage,
        text, // text: text와 같음
    }

    const result = await fetch(url, optionsFrom('POST', body))
        .then(response => response.json())
        .then(data => data)
        .catch(error => console.error(error));

    return result;
}
  • detectLanguage: 주어진 텍스트를 기반으로 언어를 감지하는 API 요청 함수로, 입력한 언어의 코드값을 return 합니다. 이 값을 셀렉트박스 <options>에 value로 넣어뒀다면, 그 값을 셀렉트박스에 넣기만하면 매칭이 된다.

  • translateLanguage: 감지된 언어에서 목표 언어로 텍스트를 번역하는 API 요청 함수로, 번역 결과를 반환합니다.

  • 두 함수 모두 fetch를 사용하며, HTTP 요청 옵션은 optionsFrom 함수로 생성됩니다.

    • optionsFrom 함수는 요청을 보내기전에 필요한 가공과정을 따로 분리해둔 유틸함수이다. 바디에 담을 데이터를 JSON으로 변환하고, 헤더에 Json으로 전송할것을 세팅한다.






정리

간략하게 요약하자면, 사용자가 입력한 값을 2초후에 api.js에 모둘화한 함수를 호출하고, api.js에 정의된 함수는 index.js로 요청을 보낸다.
index.js는 실제 파파고 서버와 HTTP 통신을 한 이후에 결과값을 웹 페이지에 랜더링한다.







학습한 점

  • Json과 자바스크립트에서 사용하는 오브젝트간의 변환과정.
  • 우리가 인터넷을 활용해 통신할때는 Json을 활용한다. 이는 Json이 문자열방식이고, 자바스크립트 객체를 그대로 전송하는것보다 효율적이기 때문이다.
profile
들은것은 잊어버린다 본것은 기억된다 해본것은 내것이 된다

0개의 댓글