DataPlay - 데이터 갖고 놀기 2탄 : 이미지 번역기 코드 정리
이번 글에는 해당 프로젝트의 코드를 정리해보겠습니다
1. 파파고 API
- 파파고 API 는 네이버의 파파고 라는 번역기를 사용할 수 있도록 하는 API 이다.
- 당연히 파파고 api 를 사용하기 위한 시크릿키와 아이디값이 있는데 해당 값들은 APIdata 라는 인터페이스 안에 따로 선언해두었다.
- 파파고 API 를 사용해서 view 에서 들어오는 데이터를 번역 할 수 있도록 한다.
- 네이버 개발자 API 센터에 어떻게 사용하는지 아주 자세하게!! 정말 자세하게 적혀있다. 아래 있는 코드는 해당 코드를 내가 필요한것에 맞게 변형시켜서 만든 코드이다.
- 내가 추가한 코드는 주로 번역될 언어를 선택하는 getSource 메소드, api 로 데이터를 보내는 post 메소드, 번역 결과를 parsing 하는 메소드 등이 있다.
- 코드의 자세한 내용은 주석 참고!
package HJproject.Hellospring.WordTrans;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class PapagoAPI {
public String translator(String word, String source, String target) {
String clientId = APIdata.naverPaPagoSearchID; // "애플리케이션 클라이언트 아이디값";
String clientSecret = APIdata.naverPaPagoSecret; // "애플리케이션 클라이언트 시크릿값";
String apiURL = "https://openapi.naver.com/v1/papago/n2mt"; // 검색 url
String text;
try {
text = URLEncoder.encode(word, "UTF-8"); // 번역할 내용
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("인코딩 실패", e);
}
Map<String, String> requestHeaders = new HashMap<>();
requestHeaders.put("X-Naver-Client-Id", clientId);
requestHeaders.put("X-Naver-Client-Secret", clientSecret);
// getSourceAndTarget 메소드를 이용해 API에서 사용가능한 source 언어를 가져온다
// 정확히는
String sourceLang = setSource(source);
// 번역에 사용되는 post 메소드에 apiURL, requestHeader, 프론트 view 에서 넘어온 text 와 해당 text 의 언어
// 번역할 target 언어를 매개변수로 담아준다
String responseBody = post(apiURL, requestHeaders, text, sourceLang, target);
return parsingTrans(responseBody);
}
// parsingTrans 메소드는 JSON 으로 return 되는 번역 내용을 파싱하기 위한 메소드이다.
private String parsingTrans(String responseBody){
// JSON 파싱하는 객체
JSONParser parser = new JSONParser();
String transText = null;
try {
// response 파싱
JSONObject parsing = (JSONObject)parser.parse(responseBody);
// response 파싱한 결과에서 message 에 대한 값을 가져와서 obj 에 저장
JSONObject obj = (JSONObject) parsing.get("message");
//System.out.println("obj : "+obj.toString());
// obj 에서 다시 result 에 대한 값을 가져와서 저장
JSONObject result = (JSONObject)obj.get("result");
//System.out.println("result : "+result.toString());
// result 에서 translatedText 를 가져와서 text 로 저장한 후 return
transText = result.get("translatedText").toString();
//System.out.println(text);
} catch (ParseException e) {
e.printStackTrace();
}
return transText;
}
private String post(String apiUrl, Map<String, String> requestHeaders, String text, String source, String target){
HttpURLConnection con = connect(apiUrl);
String postParams = "source="+source+"&target="+target+"&text=" + text; // source=원본언어&target=번역언어
try {
con.setRequestMethod("POST");
for(Map.Entry<String, String> header :requestHeaders.entrySet()) {
con.setRequestProperty(header.getKey(), header.getValue());
}
con.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
wr.write(postParams.getBytes());
wr.flush();
}
int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 응답
return readBody(con.getInputStream());
} else { // 에러 응답
return readBody(con.getErrorStream());
}
} catch (IOException e) {
throw new RuntimeException("API 요청과 응답 실패", e);
} finally {
con.disconnect();
}
}
private HttpURLConnection connect(String apiUrl){
try {
URL url = new URL(apiUrl);
return (HttpURLConnection)url.openConnection();
} catch (MalformedURLException e) {
throw new RuntimeException("API URL이 잘못되었습니다. : " + apiUrl, e);
} catch (IOException e) {
throw new RuntimeException("연결이 실패했습니다. : " + apiUrl, e);
}
}
private String readBody(InputStream body){
InputStreamReader streamReader = new InputStreamReader(body);
try (BufferedReader lineReader = new BufferedReader(streamReader)) {
StringBuilder responseBody = new StringBuilder();
String line;
while ((line = lineReader.readLine()) != null) {
responseBody.append(line);
}
return responseBody.toString();
} catch (IOException e) {
throw new RuntimeException("API 응답을 읽는데 실패했습니다.", e);
}
}
private String setSource(String lang){
switch (lang) {
case "kor":
return "ko";
case "eng":
return "en";
case "jpn":
return "ja";
}
return null;
}
}
2. TransController
- 요청 request에 맞춰 내가 원하는 view 로 보내기 위한 controller.
- 이 부분은 간단한데 하나는 루트 / 로 요청되었을 때와 /transword 로 요청받았을 때 처리하기 위한 내용을 담는다.
package HJproject.Hellospring.Controller;
import HJproject.Hellospring.WordTrans.PapagoAPI;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Controller
@RequiredArgsConstructor
public class TransController {
@GetMapping("/")
public String home(){
return "thymeleaf/dataplay/wordtrans";
}
@RequestMapping(value = "/transword", method = RequestMethod.GET)
public void sendData(HttpServletResponse res, HttpServletRequest req) throws IOException {
// ajax 에서 넘어온 값을 확인 후 변수에 저장
String text = req.getParameter("text");
String source = req.getParameter("source");
String target = req.getParameter("target");
//System.out.println("text : "+text);
// 저장된 변수를 PapagoAPI 의 translator 메소드에 넣기 -> 번역된 내용을 trans 변수 안에 저장
String trans = new PapagoAPI().translator(text, source, target);
//System.out.println(trans);
// resp 객체의 문자 타입을 utf-8 로 선언 후 요청 request 가 있었던 web 으로 전달
res.setContentType("text/plain;charset=utf-8");
PrintWriter out = res.getWriter();
out.println(trans);
//System.out.println(trans);
}
}
3. wordtrans.html
- wordtrans.html 은 프론트에 해당하는 페이지이다.
- 이곳에서 번역이 필요한 사진을 올리고, 해당 사진 안의 내용이 어떤 언어인지 선택한다.
- 사진의 내용의 길이에 따라서 약간의 시간이 필요한데 이때 loading.gif 를 사용해서 내용 추출이 진행되는 듯한 느낌을 받도록 하였다.
- 마지막으로 추출된 내용을 번역하고 싶은 언어를 select 에서 선택한 후 번역하기 버튼을 누르면 바로 번역이 될 수 있도록 만들었다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>wordtranslator</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<!-- tesseract.js CDN -->
<script src='https://unpkg.com/tesseract.js@2.1.4/dist/tesseract.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tesseract.js/2.1.5/tesseract.min.js" integrity="sha512-QMGuBW4cKAKmxjxukfPlQqFL8Tc2yYWTBhg9o8fKx06BGZrNXMmafjtnmXthGasytcaIILHRrg5N5Hw0yOuSjw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="module">
</script>
<script>
// 전역변수 txt 선언
var txt;
// translatorArea 를 변수로 선언
var $translatorArea = $("#translatorArea");
// 로딩 이미지, 텍스트 영역
// const $extractOn = $("#extractOn");
//const $Loading = $("#Loading");
// 여기는 너무 어려움ㅠ
const recognize = async ({ target: { files } }) =>
{
// 추출할 언어 선택
const $langsel = $("#langsel").val();
await $("#extractOn").hide();
await $("#Loading").show();
const
{ data:
{ text }
} = await Tesseract.recognize(
files[0],
$langsel,
{
corePath: 'https://unpkg.com/tesseract.js-core@v2.0.0/tesseract-core.wasm.js',
//logger: m => console.log(m),
});
//console.log(text);
// 텍스트 추출이 끝나면 로딩 이미지 감추기
$("#Loading").hide();
// 텍스트 추출이 끝나면 텍스트 영역 보이도록 만들기
$("#extractOn").show();
// 추출된 내용을 extractTxt 에 넣어둠
$("#extractTxt").val(text);
txt = text;
}
// 페이지 로딩 시 실행되는 함수
$(function (){
// 처음에는 텍스트 창 안보이게 && 로딩창도 안보이게
$("#extractOn").hide();
$("#Loading").hide();
const $img = $("#upload")
// 이미지가 바뀔 때마다 recognize 함수가 실행됨 -> 사진에서 텍스트 가져오기
$img.on("change", recognize);
// 번역하기 버튼을 누르면 ajax 로 pagago 번역 실행
$("#translator").on("click", function(){
var source = $("#langsel").val();
var target = $("#toTrans").val();
var data = {
"text": txt,
"source": source,
"target": target
}
//console.log(data);
$.ajax({
url : "/transword",
type : "GET",
data : data,
dataType : "text",
//contentType : "application/json;charset=utf-8",
success : function(result){
// console.log(result)
$("#transText").val(result);
}
})
})
})
</script>
<style>
#txt {
border: 1px solid black;
resize: none;
}
#transText {
border: 1px solid black;
resize: none;
margin-left: 100px;
}
</style>
</head>
<body>
<h1>번역 시작</h1>
<div>
1. 추출할 언어 선택<br>
<select id="langsel">
<option value="eng" selected> English </option>
<option value="kor" selected> Korean </option>
<option value="jpn" selected> Japanese </option>
</select>
</div>
<br>
<div>
<div id="imgSelArea">
<span>2. 글자를 인식할 파일선택</span><br>
<input type="file" id="upload" name="upload">
</div>
</div>
<br>
<div id = translatorArea>
<img src="/transLoading/loading.gif" id="Loading" alt="Loading">
<div id="extractOn">
<span>3. 번역할 언어 선택</span>
<select id="toTrans">
<option value='en' selected> English </option>
<option value="ko" selected> Korean </option>
<option value="ja" selected> Japanese </option>
</select>
<br>
<textarea name="text" id="extractTxt" cols="100" rows="30" ></textarea>
<textarea name="text" id="transText" cols="100" rows="30" ></textarea>
<br>
<input type="button" id="translator" name="translator" value="번역하기">
</div>
</div>
</body>
</html>
'토이 프로젝트 > Spring&Java 갖고놀기' 카테고리의 다른 글
Spring Boot Web Chatting : 스프링 부트로 실시간 채팅 만들기(1) stomp, socketjs, websocket (8) | 2022.08.29 |
---|---|
Spring Web Chatting : 스프링 채팅 만들기 웹소켓 맛보기 (8) | 2022.08.24 |
DataPlay Project - 2 : 이미지 텍스트 번역기 (1) 파파고 API & Tesseract OCR (0) | 2022.06.01 |
DataPlay project - 1 : word cloud 생성기 코드 정리 (0) | 2022.05.10 |
DataPlay project - 1 : java로 Word Cloud 생성기- 크롤링, API, JSON (0) | 2022.05.04 |
댓글