Skip to content

Commit

Permalink
feat: Add write API to java CL
Browse files Browse the repository at this point in the history
  • Loading branch information
JanEbbing committed Jan 16, 2025
1 parent 40997d8 commit d826569
Show file tree
Hide file tree
Showing 15 changed files with 475 additions and 52 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).


## [Unreleased]
### Added
* Added support for the Write API in the client library, the implementation
can be found in the `DeepLClient` class. Please refer to the README for usage
instructions.
### Changed
* The main functionality of the library is now also exposed via the `DeepLClient`
class. Please change your code to use this over the `Translator` class whenever
convenient.

## [1.7.0] - 2024-11-15
### Added
* Added `modelType` option to `translateText()` to use models with higher
Expand Down Expand Up @@ -125,6 +135,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
Initial version.


[Unreleased]: https://github.com/DeepLcom/deepl-java/compare/v1.7.0...HEAD
[1.7.0]: https://github.com/DeepLcom/deepl-java/compare/v1.6.0...v1.7.0
[1.6.0]: https://github.com/DeepLcom/deepl-java/compare/v1.5.1...v1.6.0
[1.5.1]: https://github.com/DeepLcom/deepl-java/compare/v1.5.0...v1.5.1
Expand Down
146 changes: 100 additions & 46 deletions README.md

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/DeepLClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.

package com.deepl.api;

import com.deepl.api.http.HttpResponse;
import com.deepl.api.utils.KeyValuePair;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable;

public class DeepLClient extends Translator {

/** {@inheritDoc} */
public DeepLClient(String authKey, TranslatorOptions options) throws IllegalArgumentException {
super(authKey, options);
}

public WriteResult rephraseText(
String text, @Nullable String targetLang, @Nullable TextRephraseOptions options)
throws InterruptedException, DeepLException {
ArrayList<String> texts = new ArrayList<>();
texts.add(text);
return this.rephraseText(texts, targetLang, options).get(0);
}

public List<WriteResult> rephraseText(
List<String> texts, @Nullable String targetLang, @Nullable TextRephraseOptions options)
throws InterruptedException, DeepLException {
Iterable<KeyValuePair<String, String>> params =
createWriteHttpParams(texts, targetLang, options);
HttpResponse response = httpClientWrapper.sendRequestWithBackoff("/v2/write/rephrase", params);
checkResponse(response, false, false);
return jsonParser.parseWriteResult(response.getBody());
}

protected static ArrayList<KeyValuePair<String, String>> createWriteHttpParams(
List<String> texts, @Nullable String targetLang, @Nullable TextRephraseOptions options) {
targetLang = LanguageCode.standardize(targetLang);
checkValidLanguages(null, targetLang);

ArrayList<KeyValuePair<String, String>> params = new ArrayList<>();
if (targetLang != null) {
params.add(new KeyValuePair<>("target_lang", targetLang));
}
if (options != null && options.getWritingStyle() != null) {
params.add(new KeyValuePair<>("writing_style", options.getWritingStyle()));
}
if (options != null && options.getTone() != null) {
params.add(new KeyValuePair<>("tone", options.getTone()));
}

texts.forEach(
(text) -> {
if (text.isEmpty()) throw new IllegalArgumentException("text must not be empty");
params.add(new KeyValuePair<>("text", text));
});

return params;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

/** {@inheritDoc} */
public class DeepLClientOptions extends TranslatorOptions {}
49 changes: 49 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/TextRephraseOptions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

/**
* Options to control text rephrasing behaviour. These options may be provided to {@link
* DeepLClient#rephraseText} overloads.
*
* <p>All properties have corresponding setters in fluent-style, so the following is possible:
* <code>
* TextRephraseOptions options = new TextRephraseOptions()
* .WritingStyle(WritingStyle.Business.getValue());
* </code>
*/
public class TextRephraseOptions {
private String writingStyle;
private String tone;

/**
* Sets a style the improved text should be in. Note that only style OR tone can be set.
*
* @see WritingStyle
*/
public TextRephraseOptions setWritingStyle(String style) {
this.writingStyle = style;
return this;
}

/**
* Sets a tone the improved text should be in. Note that only style OR tone can be set.
*
* @see WritingTone
*/
public TextRephraseOptions setTone(String tone) {
this.tone = tone;
return this;
}

/** Gets the current style setting. */
public String getWritingStyle() {
return writingStyle;
}

/** Gets the current tone setting. */
public String getTone() {
return tone;
}
}
15 changes: 9 additions & 6 deletions deepl-java/src/main/java/com/deepl/api/Translator.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@
* Client for the DeepL API. To use the DeepL API, initialize an instance of this class using your
* DeepL Authentication Key as found in your <a href="https://www.deepl.com/pro-account/">DeepL
* account</a>.
*
* @deprecated Use {@link DeepLClient} instead.
*/
@Deprecated
public class Translator {
/** Base URL for DeepL API Free accounts. */
private static final String DEEPL_SERVER_URL_FREE = "https://api-free.deepl.com";
/** Base URL for DeepL API Pro accounts */
private static final String DEEPL_SERVER_URL_PRO = "https://api.deepl.com";

private final Parser jsonParser = new Parser();
private final HttpClientWrapper httpClientWrapper;
protected final Parser jsonParser = new Parser();
protected final HttpClientWrapper httpClientWrapper;

/**
* Initializes a new Translator object using your Authentication Key.
Expand Down Expand Up @@ -841,7 +844,7 @@ private static ArrayList<KeyValuePair<String, String>> createHttpParams(
* @param options Options influencing translation.
* @return Iterable of parameters for HTTP request.
*/
private static ArrayList<KeyValuePair<String, String>> createHttpParams(
protected static ArrayList<KeyValuePair<String, String>> createHttpParams(
String sourceLang, String targetLang, DocumentTranslationOptions options) {
return createHttpParamsCommon(
sourceLang,
Expand All @@ -861,7 +864,7 @@ private static ArrayList<KeyValuePair<String, String>> createHttpParams(
* @param glossaryId ID of glossary to use for translation.
* @return Iterable of parameters for HTTP request.
*/
private static ArrayList<KeyValuePair<String, String>> createHttpParamsCommon(
protected static ArrayList<KeyValuePair<String, String>> createHttpParamsCommon(
@Nullable String sourceLang,
String targetLang,
@Nullable Formality formality,
Expand Down Expand Up @@ -920,7 +923,7 @@ private static String joinTags(Iterable<String> tags) {
* @param targetLang Language code of the desired output language.
* @throws IllegalArgumentException If either language code is invalid.
*/
private static void checkValidLanguages(@Nullable String sourceLang, String targetLang)
protected static void checkValidLanguages(@Nullable String sourceLang, String targetLang)
throws IllegalArgumentException {
if (sourceLang != null && sourceLang.isEmpty()) {
throw new IllegalArgumentException("sourceLang must be null or non-empty");
Expand Down Expand Up @@ -982,7 +985,7 @@ private void checkResponse(HttpResponseStream response) throws DeepLException {
* @throws DeepLException Throws {@link DeepLException} or a derived exception depending on the
* type of error.
*/
private void checkResponse(
protected void checkResponse(
HttpResponse response, boolean inDocumentDownload, boolean usingGlossary)
throws DeepLException {
if (response.getCode() >= 200 && response.getCode() < 300) {
Expand Down
3 changes: 3 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/TranslatorOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@
* TranslatorOptions options = new TranslatorOptions()
* .setTimeout(Duration.ofSeconds(1)).setMaxRetries(2);
* </code>
*
* @deprecated Use {@link DeepLClientOptions} instead.
*/
@Deprecated
public class TranslatorOptions {
private int maxRetries = 5;
private Duration timeout = Duration.ofSeconds(10);
Expand Down
33 changes: 33 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/WriteResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

/** The result of a text translation. */
public class WriteResult {
private final String text;
private final String detectedSourceLanguage;
private final String targetLanguage;

/** Constructs a new instance. */
public WriteResult(String text, String detectedSourceLanguage, String targetLanguage) {
this.text = text;
this.detectedSourceLanguage = LanguageCode.standardize(detectedSourceLanguage);
this.targetLanguage = targetLanguage;
}

/** The translated text. */
public String getText() {
return text;
}

/** The language code of the source text detected by DeepL. */
public String getDetectedSourceLanguage() {
return detectedSourceLanguage;
}

/** The language code of the target language set by the request. */
public String getTargetLanguage() {
return targetLanguage;
}
}
27 changes: 27 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/WritingStyle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

/** Represents the style the improved text should be in in a rephrase request. */
public enum WritingStyle {
Academic("academic"),
Business("business"),
Casual("casual"),
Default("default"),
PreferAcademic("prefer_academic"),
PreferBusiness("prefer_business"),
PreferCasual("prefer_casual"),
PreferSimple("prefer_simple"),
Simple("simple");

private final String value;

WritingStyle(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}
27 changes: 27 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/WritingTone.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api;

/** Represents the tone the improved text should be in in a rephrase request. */
public enum WritingTone {
Confident("confident"),
Default("default"),
Diplomatic("diplomatic"),
Enthusiastic("enthusiastic"),
Friendly("friendly"),
PreferConfident("prefer_confident"),
PreferDiplomatic("prefer_diplomatic"),
PreferEnthusiastic("prefer_enthusiastic"),
PreferFriendly("prefer_friendly");

private final String value;

WritingTone(String value) {
this.value = value;
}

public String getValue() {
return value;
}
}
6 changes: 6 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/parsing/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class Parser {
public Parser() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(TextResult.class, new TextResultDeserializer());
gsonBuilder.registerTypeAdapter(WriteResult.class, new WriteResultDeserializer());
gsonBuilder.registerTypeAdapter(Language.class, new LanguageDeserializer());
gsonBuilder.registerTypeAdapter(Usage.class, new UsageDeserializer());
gson = gsonBuilder.create();
Expand All @@ -31,6 +32,11 @@ public List<TextResult> parseTextResult(String json) {
return result.translations;
}

public List<WriteResult> parseWriteResult(String json) {
WriteResponse result = gson.fromJson(json, WriteResponse.class);
return result.improvements;
}

public Usage parseUsage(String json) {
return gson.fromJson(json, Usage.class);
}
Expand Down
16 changes: 16 additions & 0 deletions deepl-java/src/main/java/com/deepl/api/parsing/WriteResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api.parsing;

import com.deepl.api.WriteResult;
import java.util.List;

/**
* Class representing text rephrase responses from the DeepL API.
*
* <p>This class is internal; you should not use this class directly.
*/
class WriteResponse {
public List<WriteResult> improvements;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2025 DeepL SE (https://www.deepl.com)
// Use of this source code is governed by an MIT
// license that can be found in the LICENSE file.
package com.deepl.api.parsing;

import com.deepl.api.WriteResult;
import com.google.gson.*;
import java.lang.reflect.Type;

/**
* Utility class for deserializing text rephrase results returned by the DeepL API.
*
* <p>This class is internal; you should not use this class directly.
*/
class WriteResultDeserializer implements JsonDeserializer<WriteResult> {
public WriteResult deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
return new WriteResult(
jsonObject.get("text").getAsString(),
jsonObject.get("detected_source_language").getAsString(),
jsonObject.get("target_language").getAsString());
}
}
Loading

0 comments on commit d826569

Please sign in to comment.