프로젝트에서 DeepL API를 사용해 PDF를 번역하는 기능이 추가되었다.
https://developers.deepl.com/docs
Introduction | DeepL API Documentation
Learn more about the DeepL API's capabilities and common use cases.
developers.deepl.com
우선 DeepL의 공식문서이다.
처음에는 늘 그렇듯 curl을 사용해 파일을 보내고, 응답을 받을 것이라고 생각했지만 자바쪽으로 지원해주는 라이브러리가 있었다.
자바 라이브러리의 주소는 다음과 같다.
https://github.com/DeepLcom/deepl-java
GitHub - DeepLcom/deepl-java: Official Java library for the DeepL language translation API.
Official Java library for the DeepL language translation API. - DeepLcom/deepl-java
github.com
요즘에는 자료가 많이 없는 기능들을 사용하다보니, 이렇게 깃허브에 직접 찾아들어가 사용방법을 찾아보는 일이 많아졌다.
implementation("com.deepl.api:deepl-java:1.9.0")
현재 기준으로 가장 최신 버전인 해당 라이브러리를 추가해준다.
처음에는 해당 문서처럼 Translator를 생성하려고 했지만, 해당 기능은 Deprecated 되었다고 한다.
(그러면 문서 좀 수정해주지...)
지금은 DeepLClient 클래스를 생성하고, 해당 생성자에 DeepL의 API 키를 넘겨주면 된다.
DeepLClient(deepLKey)
해당 클래스에서도 translateDocument라는 함수를 사용할 것이다.
해당 함수를 오버로딩하고 있는 함수들은 다음과 같다.
public DocumentStatus translateDocument(File inputFile, File outputFile, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DocumentTranslationException, IOException {
try {
if (outputFile.exists()) {
throw new IOException("File already exists at output path");
} else {
InputStream inputStream = new FileInputStream(inputFile);
DocumentStatus var8;
try {
OutputStream outputStream = new FileOutputStream(outputFile);
try {
var8 = this.translateDocument(inputStream, inputFile.getName(), outputStream, sourceLang, targetLang, options);
} catch (Throwable var12) {
try {
outputStream.close();
} catch (Throwable var11) {
var12.addSuppressed(var11);
}
throw var12;
}
outputStream.close();
} catch (Throwable var13) {
try {
inputStream.close();
} catch (Throwable var10) {
var13.addSuppressed(var10);
}
throw var13;
}
inputStream.close();
return var8;
}
} catch (Exception exception) {
outputFile.delete();
throw exception;
}
}
public DocumentStatus translateDocument(File inputFile, File outputFile, @Nullable String sourceLang, String targetLang) throws DocumentTranslationException, IOException {
return this.translateDocument((File)inputFile, (File)outputFile, (String)sourceLang, targetLang, (DocumentTranslationOptions)null);
}
public DocumentStatus translateDocument(InputStream inputStream, String fileName, OutputStream outputStream, @Nullable String sourceLang, String targetLang, @Nullable DocumentTranslationOptions options) throws DocumentTranslationException {
DocumentHandle handle = null;
try {
handle = this.translateDocumentUpload(inputStream, fileName, sourceLang, targetLang, options);
DocumentStatus status = this.translateDocumentWaitUntilDone(handle);
this.translateDocumentDownload(handle, outputStream);
return status;
} catch (Exception exception) {
throw new DocumentTranslationException("Error occurred during document translation: " + exception.getMessage(), exception, handle);
}
}
public DocumentStatus translateDocument(InputStream inputFile, String fileName, OutputStream outputFile, @Nullable String sourceLang, String targetLang) throws DocumentTranslationException {
return this.translateDocument(inputFile, fileName, outputFile, sourceLang, targetLang, (DocumentTranslationOptions)null);
}
File을 넘기는 함수가 아닌 inpuStream을 넘기는 함수를 사용할 것이며, 사용 가능한 언어의 종류는 DeepL의 공식문서에 나와있다.
여기서 sourceLang은 Null이 가능하다.
현재 문서에 대한 정보를 주지 않아도, 번역을 해보니 sourceLang을 지정해 줄 때와 똑같은 결과가 나왔었다.
해당 함수를 사용하면 byteOutputStream이 나오게 된다.
해당 byteOutputStream을 byteArray로 바꾸어서 controller에서 응답해주면 된다.
@Service
class DeepLManager(
@Value("\${deepL.key}")
private val deepLKey: String
) {
fun translateDocument(inputStream: InputStream, fileName: String, targetLang: LanguageEnum): ByteArray {
ByteArrayOutputStream().use{
byteArrayOutputStream ->
DeepLClient(deepLKey).translateDocument(
inputStream,
fileName,
byteArrayOutputStream,
null,
targetLang.targetLang,
)
return byteArrayOutputStream.toByteArray()
}
}
}
해당 서비스는 DeepL로 부터 번역된 ByteArray를 가져오는 서비스이고
그냥 응답받은 byteArrayOutputStream에서 toByteArray만 호출하면 ByteArray로 변환된다.
이렇게 응답받은 ByteArray을
return translateConnector.createTranslate(
docsId, createTranslateReq
).map{
ByteArrayOutputStream().use{
}
ResponseEntity.ok()
.contentType(
MediaType.APPLICATION_OCTET_STREAM
)
.headers{
header ->
header.contentDisposition = ContentDisposition.builder("pdf")
.filename("${docsId}-${createTranslateReq.targetLang.name}.pdf")
.build()
}
.body(it)
}
이런 식으로 controller에서 응답해주면 된다.
이렇게 하면 지정해준 파일의 이름으로 번역된 파일을 다운받을 수 있다.
+ 근데 이게 생각보다 돈이 많이 나오는 거 같다.
이렇게 만들고 몇번 요청을 한 후, PM한테 금액을 확인해달라고 부탁하니 벌써 5만원이 나왔다고 한다...
다들 조심해서 사용하는 게 좋을 것 같다.......
'틔움랩' 카테고리의 다른 글
MockBean deprecated와 대체 (0) | 2025.01.28 |
---|---|
Github action을 통한 Spring CI/CD 설정 (0) | 2025.01.25 |