Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ public static void main(String[] args) {
while (!generateVideosOperation.done().filter(Boolean::booleanValue).isPresent()) {
try {
Thread.sleep(10000); // Sleep for 10 seconds.
generateVideosOperation =
client.operations.getVideosOperation(generateVideosOperation, null);
generateVideosOperation = client.operations.get(generateVideosOperation, null);
System.out.println("Waiting for operation to complete...");
} catch (InterruptedException e) {
System.out.println("Thread was interrupted while sleeping.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public static void main(String[] args) {
try {
Thread.sleep(10000); // Sleep for 10 seconds.
try {
operation = client.async.operations.getVideosOperation(operation, null).get();
operation = client.async.operations.get(operation, null).get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/com/google/genai/AsyncOperations.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import com.google.genai.types.GenerateVideosOperation;
import com.google.genai.types.GetOperationConfig;
import com.google.genai.types.Operation;
import java.util.concurrent.CompletableFuture;

/** Async module of {@link Operations} */
Expand All @@ -41,4 +42,16 @@ public CompletableFuture<GenerateVideosOperation> getVideosOperation(
GenerateVideosOperation operation, GetOperationConfig config) {
return CompletableFuture.supplyAsync(() -> operations.getVideosOperation(operation, config));
}

/**
* Gets the status of an Operation.
*
* @param operation An Operation.
* @param config The configuration for getting the operation.
* @return An Operation with the updated status of the operation.
*/
public <T, U extends Operation<T, U>> CompletableFuture<U> get(
U operation, GetOperationConfig config) {
return CompletableFuture.supplyAsync(() -> operations.get(operation, config));
}
}
5 changes: 3 additions & 2 deletions src/main/java/com/google/genai/JsonSerializable.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
/** A class that can be serialized to JSON and deserialized from JSON. */
public abstract class JsonSerializable {

static final ObjectMapper objectMapper = new ObjectMapper();
@InternalApi protected static final ObjectMapper objectMapper = new ObjectMapper();

/** Custom Jackson serializer for {@link java.time.Duration} to output "Xs" format. */
static class CustomDurationSerializer extends JsonSerializer<java.time.Duration> {
Expand Down Expand Up @@ -134,7 +134,8 @@ protected static <T extends JsonSerializable> T fromJsonString(
}

/** Deserializes a JsonNode to an object of the given type. */
static <T extends JsonSerializable> T fromJsonNode(JsonNode jsonNode, Class<T> clazz) {
@InternalApi
protected static <T extends JsonSerializable> T fromJsonNode(JsonNode jsonNode, Class<T> clazz) {
try {
return objectMapper.treeToValue(jsonNode, clazz);
} catch (JsonProcessingException e) {
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/google/genai/LiveConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/** Internal SDK converter functions. */
final class LiveConverters {
private final ApiClient apiClient;

Expand Down
60 changes: 38 additions & 22 deletions src/main/java/com/google/genai/Operations.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.genai.types.GetOperationConfig;
import com.google.genai.types.GetOperationParameters;
import com.google.genai.types.HttpOptions;
import com.google.genai.types.Operation;
import java.io.IOException;
import java.util.Optional;
import okhttp3.ResponseBody;
Expand Down Expand Up @@ -355,8 +356,7 @@ ObjectNode generateVideosOperationFromVertex(JsonNode fromObject, ObjectNode par
return toObject;
}

GenerateVideosOperation privateGetVideosOperation(
String operationName, GetOperationConfig config) {
JsonNode privateGetVideosOperation(String operationName, GetOperationConfig config) {

GetOperationParameters.Builder parameterBuilder = GetOperationParameters.builder();

Expand Down Expand Up @@ -408,17 +408,11 @@ GenerateVideosOperation privateGetVideosOperation(
throw new GenAiIOException("Failed to read HTTP response.", e);
}

JsonNode responseNode = JsonSerializable.stringToJsonNode(responseString);
if (this.apiClient.vertexAI()) {
responseNode = generateVideosOperationFromVertex(responseNode, null);
} else {
responseNode = generateVideosOperationFromMldev(responseNode, null);
}
return JsonSerializable.fromJsonNode(responseNode, GenerateVideosOperation.class);
return JsonSerializable.stringToJsonNode(responseString);
}
}

GenerateVideosOperation privateFetchPredictVideosOperation(
JsonNode privateFetchPredictVideosOperation(
String operationName, String resourceName, FetchPredictOperationConfig config) {

FetchPredictOperationParameters.Builder parameterBuilder =
Expand Down Expand Up @@ -471,14 +465,7 @@ GenerateVideosOperation privateFetchPredictVideosOperation(
throw new GenAiIOException("Failed to read HTTP response.", e);
}

JsonNode responseNode = JsonSerializable.stringToJsonNode(responseString);
if (this.apiClient.vertexAI()) {
responseNode = generateVideosOperationFromVertex(responseNode, null);
} else {
throw new UnsupportedOperationException(
"This method is only supported in the Vertex AI client.");
}
return JsonSerializable.fromJsonNode(responseNode, GenerateVideosOperation.class);
return JsonSerializable.stringToJsonNode(responseString);
}
}

Expand All @@ -491,20 +478,49 @@ GenerateVideosOperation privateFetchPredictVideosOperation(
*/
public GenerateVideosOperation getVideosOperation(
GenerateVideosOperation operation, GetOperationConfig config) {
if (!operation.name().isPresent()) {
throw new IllegalArgumentException("Operation name is required.");
}

if (this.apiClient.vertexAI()) {
String resourceName = operation.name().get().split("/operations/")[0];

FetchPredictOperationConfig fetchConfig = FetchPredictOperationConfig.builder().build();

JsonNode response =
this.privateFetchPredictVideosOperation(
operation.name().get(), resourceName, fetchConfig);
return operation.fromApiResponse(response, true);
} else {
JsonNode response = this.privateGetVideosOperation(operation.name().get(), config);
return operation.fromApiResponse(response, false);
}
}

/**
* Gets the status of an Operation.
*
* @param operation An Operation.
* @param config The configuration for getting the operation.
* @return An Operation with the updated status of the operation.
*/
public <T, U extends Operation<T, U>> U get(U operation, GetOperationConfig config) {
if (!operation.name().isPresent()) {
throw new Error("Operation name is required.");
throw new IllegalArgumentException("Operation name is required.");
}

if (this.apiClient.vertexAI()) {
String resourceName = operation.name().get().split("/operations/")[0];

FetchPredictOperationConfig fetchConfig = FetchPredictOperationConfig.builder().build();

return this.privateFetchPredictVideosOperation(
operation.name().get(), resourceName, fetchConfig);
JsonNode response =
this.privateFetchPredictVideosOperation(
operation.name().get(), resourceName, fetchConfig);
return operation.fromApiResponse(response, true);
} else {
return this.privateGetVideosOperation(operation.name().get(), config);
JsonNode response = this.privateGetVideosOperation(operation.name().get(), config);
return operation.fromApiResponse(response, false);
}
}
}
44 changes: 31 additions & 13 deletions src/main/java/com/google/genai/OperationsConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,21 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.api.core.InternalApi;

final class OperationsConverters {
/** Internal SDK converter functions. */
@InternalApi
public final class OperationsConverters {
private final ApiClient apiClient;

public OperationsConverters(ApiClient apiClient) {
this.apiClient = apiClient;
}

@ExcludeFromGeneratedCoverageReport
ObjectNode fetchPredictOperationParametersToMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode fetchPredictOperationParametersToMldev(
JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (!Common.isZero(Common.getValueByPath(fromObject, new String[] {"operationName"}))) {
throw new IllegalArgumentException("operationName parameter is not supported in Gemini API.");
Expand All @@ -49,7 +54,8 @@ ObjectNode fetchPredictOperationParametersToMldev(JsonNode fromObject, ObjectNod
}

@ExcludeFromGeneratedCoverageReport
ObjectNode getOperationParametersToMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode getOperationParametersToMldev(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"operationName"}) != null) {
Common.setValueByPath(
Expand All @@ -69,7 +75,9 @@ ObjectNode getOperationParametersToMldev(JsonNode fromObject, ObjectNode parentO
}

@ExcludeFromGeneratedCoverageReport
ObjectNode fetchPredictOperationParametersToVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode fetchPredictOperationParametersToVertex(
JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"operationName"}) != null) {
Common.setValueByPath(
Expand All @@ -96,7 +104,8 @@ ObjectNode fetchPredictOperationParametersToVertex(JsonNode fromObject, ObjectNo
}

@ExcludeFromGeneratedCoverageReport
ObjectNode getOperationParametersToVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode getOperationParametersToVertex(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"operationName"}) != null) {
Common.setValueByPath(
Expand All @@ -116,7 +125,8 @@ ObjectNode getOperationParametersToVertex(JsonNode fromObject, ObjectNode parent
}

@ExcludeFromGeneratedCoverageReport
ObjectNode videoFromMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode videoFromMldev(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"video", "uri"}) != null) {
Common.setValueByPath(
Expand Down Expand Up @@ -144,7 +154,8 @@ ObjectNode videoFromMldev(JsonNode fromObject, ObjectNode parentObject) {
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generatedVideoFromMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generatedVideoFromMldev(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"_self"}) != null) {
Common.setValueByPath(
Expand All @@ -160,7 +171,8 @@ ObjectNode generatedVideoFromMldev(JsonNode fromObject, ObjectNode parentObject)
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generateVideosResponseFromMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generateVideosResponseFromMldev(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"generatedSamples"}) != null) {
ArrayNode keyArray =
Expand Down Expand Up @@ -192,7 +204,8 @@ ObjectNode generateVideosResponseFromMldev(JsonNode fromObject, ObjectNode paren
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generateVideosOperationFromMldev(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generateVideosOperationFromMldev(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"name"}) != null) {
Common.setValueByPath(
Expand Down Expand Up @@ -238,7 +251,8 @@ ObjectNode generateVideosOperationFromMldev(JsonNode fromObject, ObjectNode pare
}

@ExcludeFromGeneratedCoverageReport
ObjectNode videoFromVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode videoFromVertex(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"gcsUri"}) != null) {
Common.setValueByPath(
Expand Down Expand Up @@ -266,7 +280,8 @@ ObjectNode videoFromVertex(JsonNode fromObject, ObjectNode parentObject) {
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generatedVideoFromVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generatedVideoFromVertex(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"_self"}) != null) {
Common.setValueByPath(
Expand All @@ -282,7 +297,8 @@ ObjectNode generatedVideoFromVertex(JsonNode fromObject, ObjectNode parentObject
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generateVideosResponseFromVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generateVideosResponseFromVertex(JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"videos"}) != null) {
ArrayNode keyArray = (ArrayNode) Common.getValueByPath(fromObject, new String[] {"videos"});
Expand Down Expand Up @@ -313,7 +329,9 @@ ObjectNode generateVideosResponseFromVertex(JsonNode fromObject, ObjectNode pare
}

@ExcludeFromGeneratedCoverageReport
ObjectNode generateVideosOperationFromVertex(JsonNode fromObject, ObjectNode parentObject) {
@InternalApi
public ObjectNode generateVideosOperationFromVertex(
JsonNode fromObject, ObjectNode parentObject) {
ObjectNode toObject = JsonSerializable.objectMapper.createObjectNode();
if (Common.getValueByPath(fromObject, new String[] {"name"}) != null) {
Common.setValueByPath(
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/google/genai/TokensConverters.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

/** Internal SDK converter functions. */
final class TokensConverters {
private final ApiClient apiClient;

Expand Down
46 changes: 17 additions & 29 deletions src/main/java/com/google/genai/types/GenerateVideosOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,36 @@

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.google.auto.value.AutoValue;
import com.google.genai.JsonSerializable;
import com.google.genai.OperationsConverters;
import java.util.Map;
import java.util.Optional;

/** A video generation operation. */
@AutoValue
@JsonDeserialize(builder = GenerateVideosOperation.Builder.class)
public abstract class GenerateVideosOperation extends JsonSerializable {
/**
* The server-assigned name, which is only unique within the same service that originally returns
* it. If you use the default HTTP mapping, the `name` should be a resource name ending with
* `operations/{unique_id}`.
*/
@JsonProperty("name")
public abstract Optional<String> name();

/**
* Service-specific metadata associated with the operation. It typically contains progress
* information and common metadata such as create time. Some services might not provide such
* metadata. Any method that returns a long-running operation should document the metadata type,
* if any.
*/
@JsonProperty("metadata")
public abstract Optional<Map<String, Object>> metadata();

/**
* If the value is `false`, it means the operation is still in progress. If `true`, the operation
* is completed, and either `error` or `response` is available.
*/
@JsonProperty("done")
public abstract Optional<Boolean> done();

/** The error result of the operation in case of failure or cancellation. */
@JsonProperty("error")
public abstract Optional<Map<String, Object>> error();

public abstract class GenerateVideosOperation
extends Operation<GenerateVideosResponse, GenerateVideosOperation> {
/** The generated videos. */
@JsonProperty("response")
@Override
public abstract Optional<GenerateVideosResponse> response();

@Override
public GenerateVideosOperation fromApiResponse(JsonNode apiResponse, boolean isVertexAi) {
OperationsConverters converter = new OperationsConverters(null);
JsonNode response = null;
if (isVertexAi) {
response = converter.generateVideosOperationFromVertex(apiResponse, null);
} else {
response = converter.generateVideosOperationFromMldev(apiResponse, null);
}
return JsonSerializable.fromJsonNode(response, GenerateVideosOperation.class);
}

/** Instantiates a builder for GenerateVideosOperation. */
@ExcludeFromGeneratedCoverageReport
public static Builder builder() {
Expand Down
Loading