LangChain4j integration for Google AI Gemini models providing chat, streaming, embeddings, image generation, and batch processing capabilities
File management API for uploading files to the Gemini Files API, enabling batch processing and large file handling. Supports up to 20GB total project storage, 2GB per file, with 48-hour persistence for uploaded files.
Main class for managing file uploads, retrievals, and deletions with the Gemini Files API.
/**
* Manager for file operations with Gemini Files API.
* Supports uploading, listing, and deleting files for use in batch operations.
* Files persist for 48 hours and count toward 20GB project storage limit.
*/
public class GeminiFiles {
/**
* Creates a new builder for configuring the files manager.
* @return Builder instance
*/
public static Builder builder();
/**
* Uploads a file from a file system path.
* @param filePath Path to the file to upload
* @param displayName Human-readable name for the file (optional, uses filename if null)
* @return GeminiFile record with metadata about the uploaded file
* @throws IOException if an I/O error occurs reading the file
* @throws InterruptedException if the upload operation is interrupted
* @throws GeminiUploadFailureException if upload fails
*/
public GeminiFile uploadFile(Path filePath, String displayName) throws IOException, InterruptedException;
/**
* Uploads a file from byte array with explicit MIME type.
* @param fileBytes File content as byte array
* @param mimeType MIME type of the file (e.g., "application/json")
* @param name Name identifier for the file
* @return GeminiFile record with metadata about the uploaded file
* @throws InterruptedException if the upload operation is interrupted
* @throws GeminiUploadFailureException if upload fails
*/
public GeminiFile uploadFile(byte[] fileBytes, String mimeType, String name) throws InterruptedException;
/**
* Retrieves metadata for an uploaded file.
* @param name File name/identifier (format: "files/{file-id}")
* @return GeminiFile record with current metadata
* @throws IOException if an I/O error occurs during the request
* @throws InterruptedException if the operation is interrupted
*/
public GeminiFile getMetadata(String name) throws IOException, InterruptedException;
/**
* Lists all uploaded files in the project.
* @return List of GeminiFile records
* @throws IOException if an I/O error occurs during the request
* @throws InterruptedException if the operation is interrupted
*/
public List<GeminiFile> listFiles() throws IOException, InterruptedException;
/**
* Deletes an uploaded file.
* @param name File name/identifier (format: "files/{file-id}")
* @throws IOException if an I/O error occurs during the request
* @throws InterruptedException if the operation is interrupted
*/
public void deleteFile(String name) throws IOException, InterruptedException;
}Builder class for constructing GeminiFiles instances.
/**
* Builder for GeminiFiles manager.
*/
public static class Builder {
/**
* Sets the API key for authentication (required).
* @param apiKey Google AI API key
* @return Builder instance for chaining
*/
public Builder apiKey(String apiKey);
/**
* Sets a custom HTTP client for requests.
* @param httpClient HTTP client instance
* @return Builder instance for chaining
*/
public Builder httpClient(HttpClient httpClient);
/**
* Sets the base URL for the API endpoint.
* @param baseUrl Custom base URL (optional)
* @return Builder instance for chaining
*/
public Builder baseUrl(String baseUrl);
/**
* Builds the GeminiFiles manager instance.
* @return Configured GeminiFiles instance
* @throws IllegalArgumentException if required fields are missing
*/
public GeminiFiles build();
}Record containing metadata about an uploaded file.
/**
* Metadata record for an uploaded file.
* Contains file information and status.
*/
public record GeminiFile(
/**
* Unique identifier for the file (format: "files/{file-id}").
*/
String name,
/**
* Human-readable display name.
*/
String displayName,
/**
* MIME type of the file.
*/
String mimeType,
/**
* Size of the file in bytes.
*/
Long sizeBytes,
/**
* Timestamp when the file was created.
*/
String createTime,
/**
* Timestamp when the file was last updated.
*/
String updateTime,
/**
* Timestamp when the file will expire and be automatically deleted.
*/
String expirationTime,
/**
* SHA-256 hash of the file content.
*/
String sha256Hash,
/**
* URI for accessing the file.
*/
String uri,
/**
* Current processing state of the file.
*/
String state
) {
/**
* Checks if the file is active and ready to use.
* @return True if file state is "ACTIVE"
*/
public boolean isActive();
/**
* Checks if the file is still being processed.
* @return True if file state is "PROCESSING"
*/
public boolean isProcessing();
/**
* Checks if the file upload or processing failed.
* @return True if file state is "FAILED"
*/
public boolean isFailed();
}Exception thrown when file upload fails.
/**
* Exception thrown when file upload or file operations fail.
* Extends RuntimeException for unchecked exception handling.
*/
public static class GeminiUploadFailureException extends RuntimeException {
// Standard exception constructors inherited from RuntimeException
}import dev.langchain4j.model.googleai.GeminiFiles;
import dev.langchain4j.model.googleai.GeminiFiles.GeminiFile;
import java.nio.file.Path;
// Create files manager
GeminiFiles filesManager = GeminiFiles.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.build();
// Upload a file
Path batchFile = Path.of("data/batch-requests.jsonl");
GeminiFile uploadedFile = filesManager.uploadFile(batchFile, "Batch Requests January");
System.out.println("File uploaded successfully!");
System.out.println("File ID: " + uploadedFile.name());
System.out.println("Size: " + uploadedFile.sizeBytes() + " bytes");
System.out.println("Expires: " + uploadedFile.expirationTime());Path dataFile = Path.of("/path/to/training-data.json");
// Upload without explicit display name (uses filename)
GeminiFile file = filesManager.uploadFile(dataFile, null);
System.out.println("Display name: " + file.displayName()); // "training-data.json"import java.nio.charset.StandardCharsets;
// Create JSON Lines content
String jsonlContent = """
{"key": "req1", "request": {"prompt": "Hello"}}
{"key": "req2", "request": {"prompt": "World"}}
""";
byte[] fileBytes = jsonlContent.getBytes(StandardCharsets.UTF_8);
// Upload from bytes
GeminiFile file = filesManager.uploadFile(
fileBytes,
"application/jsonl", // MIME type
"inline-batch-requests"
);
System.out.println("Uploaded from memory: " + file.name());GeminiFile file = filesManager.uploadFile(Path.of("large-file.jsonl"), "Large Batch");
// Check if file is ready
if (file.isProcessing()) {
System.out.println("File is still being processed...");
// Poll until active
while (!file.isActive()) {
Thread.sleep(1000);
file = filesManager.getMetadata(file.name());
if (file.isFailed()) {
System.err.println("File processing failed!");
break;
}
}
}
if (file.isActive()) {
System.out.println("File is ready to use!");
}List<GeminiFile> files = filesManager.listFiles();
System.out.println("Uploaded files (" + files.size() + "):");
for (GeminiFile file : files) {
System.out.println("- " + file.displayName() +
" (" + file.sizeBytes() / 1024 + " KB)" +
" - State: " + file.state());
}// Get file by name/ID
String fileId = "files/abc123xyz";
GeminiFile file = filesManager.getMetadata(fileId);
System.out.println("File details:");
System.out.println(" Name: " + file.displayName());
System.out.println(" MIME: " + file.mimeType());
System.out.println(" Size: " + file.sizeBytes() + " bytes");
System.out.println(" Created: " + file.createTime());
System.out.println(" Expires: " + file.expirationTime());
System.out.println(" SHA-256: " + file.sha256Hash());// Delete a specific file
String fileId = "files/abc123xyz";
filesManager.deleteFile(fileId);
System.out.println("File deleted: " + fileId);
// Clean up old files
List<GeminiFile> files = filesManager.listFiles();
for (GeminiFile file : files) {
if (file.displayName().startsWith("temp-")) {
filesManager.deleteFile(file.name());
System.out.println("Deleted temp file: " + file.displayName());
}
}try {
GeminiFile file = filesManager.uploadFile(
Path.of("non-existent-file.json"),
"Test File"
);
} catch (GeminiUploadFailureException e) {
System.err.println("Upload failed: " + e.getMessage());
// Handle upload failure
} catch (Exception e) {
System.err.println("Unexpected error: " + e.getMessage());
}import dev.langchain4j.model.googleai.GoogleAiGeminiBatchChatModel;
import dev.langchain4j.model.googleai.jsonl.JsonLinesWriters;
import dev.langchain4j.model.googleai.jsonl.JsonLinesWriter;
import dev.langchain4j.model.googleai.BatchRequestResponse.BatchFileRequest;
import dev.langchain4j.data.message.UserMessage;
import dev.langchain4j.model.chat.request.ChatRequest;
// Step 1: Create batch file locally
Path batchFile = Path.of("chat-batch.jsonl");
GoogleAiGeminiBatchChatModel batchModel = GoogleAiGeminiBatchChatModel.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.modelName("gemini-2.5-flash")
.build();
try (JsonLinesWriter writer = JsonLinesWriters.streaming(batchFile)) {
List<BatchFileRequest<ChatRequest>> requests = List.of(
new BatchFileRequest<>("req1", ChatRequest.builder()
.messages(UserMessage.from("What is AI?"))
.build()),
new BatchFileRequest<>("req2", ChatRequest.builder()
.messages(UserMessage.from("Explain machine learning"))
.build())
);
batchModel.writeBatchToFile(writer, requests);
}
// Step 2: Upload file
GeminiFiles filesManager = GeminiFiles.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.build();
GeminiFile uploadedFile = filesManager.uploadFile(batchFile, "AI Questions Batch");
System.out.println("File uploaded: " + uploadedFile.name());
// Wait for file to be active
while (uploadedFile.isProcessing()) {
Thread.sleep(1000);
uploadedFile = filesManager.getMetadata(uploadedFile.name());
}
// Step 3: Create batch from uploaded file
var response = batchModel.createBatchFromFile("AI Questions", uploadedFile);
System.out.println("Batch job created!");
// Step 4: Clean up file after batch is submitted (optional)
// Note: File is needed for batch processing, delete only after batch completes
// filesManager.deleteFile(uploadedFile.name());import java.nio.file.Files;
Path largeFile = Path.of("data/large-dataset.json");
long fileSize = Files.size(largeFile);
if (fileSize > 2L * 1024 * 1024 * 1024) { // 2GB limit
System.err.println("File exceeds 2GB limit: " + fileSize + " bytes");
} else {
GeminiFile file = filesManager.uploadFile(largeFile, "Large Dataset");
System.out.println("Large file uploaded: " + file.sizeBytes() + " bytes");
}// List all files and calculate total storage used
List<GeminiFile> files = filesManager.listFiles();
long totalBytes = files.stream()
.mapToLong(GeminiFile::sizeBytes)
.sum();
double totalGB = totalBytes / (1024.0 * 1024.0 * 1024.0);
System.out.printf("Total storage used: %.2f GB / 20 GB%n", totalGB);
if (totalGB > 18.0) {
System.out.println("Warning: Approaching storage limit!");
}import java.time.Instant;
import java.time.temporal.ChronoUnit;
List<GeminiFile> files = filesManager.listFiles();
for (GeminiFile file : files) {
// Parse expiration time (ISO 8601 format)
Instant expiration = Instant.parse(file.expirationTime());
Instant now = Instant.now();
long hoursUntilExpiration = ChronoUnit.HOURS.between(now, expiration);
System.out.println(file.displayName() + " expires in " + hoursUntilExpiration + " hours");
if (hoursUntilExpiration < 4) {
System.out.println(" Warning: Expiring soon!");
}
}import java.net.http.HttpClient;
import java.time.Duration;
// Configure custom HTTP client with timeouts
HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(30))
.build();
GeminiFiles filesManager = GeminiFiles.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.httpClient(httpClient)
.build();
GeminiFile file = filesManager.uploadFile(Path.of("data.json"), "Data File");List<Path> filesToUpload = List.of(
Path.of("batch1.jsonl"),
Path.of("batch2.jsonl"),
Path.of("batch3.jsonl")
);
List<GeminiFile> uploadedFiles = new ArrayList<>();
for (Path filePath : filesToUpload) {
try {
GeminiFile file = filesManager.uploadFile(
filePath,
"Batch " + filePath.getFileName()
);
uploadedFiles.add(file);
System.out.println("Uploaded: " + file.displayName());
} catch (GeminiUploadFailureException e) {
System.err.println("Failed to upload " + filePath + ": " + e.getMessage());
}
}
System.out.println("Successfully uploaded " + uploadedFiles.size() + " files");import java.security.MessageDigest;
import java.nio.file.Files;
Path localFile = Path.of("important-data.json");
// Upload file
GeminiFile uploadedFile = filesManager.uploadFile(localFile, "Important Data");
// Calculate local SHA-256
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] fileBytes = Files.readAllBytes(localFile);
byte[] hashBytes = digest.digest(fileBytes);
String localHash = bytesToHex(hashBytes);
// Compare with uploaded file hash
if (localHash.equalsIgnoreCase(uploadedFile.sha256Hash())) {
System.out.println("File integrity verified - hashes match!");
} else {
System.err.println("Warning: File hashes don't match!");
}
// Helper method
static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}import dev.langchain4j.model.googleai.GoogleAiGeminiBatchEmbeddingModel;
import dev.langchain4j.data.segment.TextSegment;
// Create embedding batch file
Path embeddingBatch = Path.of("embeddings-batch.jsonl");
GoogleAiGeminiBatchEmbeddingModel batchEmbedding = GoogleAiGeminiBatchEmbeddingModel.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.modelName("text-embedding-004")
.build();
// Write batch requests to file
try (JsonLinesWriter writer = JsonLinesWriters.streaming(embeddingBatch)) {
List<BatchFileRequest<TextSegment>> requests = List.of(
new BatchFileRequest<>("embed1", TextSegment.from("First text")),
new BatchFileRequest<>("embed2", TextSegment.from("Second text")),
new BatchFileRequest<>("embed3", TextSegment.from("Third text"))
);
batchEmbedding.writeBatchToFile(writer, requests);
}
// Upload the batch file
GeminiFile uploadedBatch = filesManager.uploadFile(
embeddingBatch,
"Embeddings Batch " + Instant.now()
);
System.out.println("Batch file ready: " + uploadedBatch.name());Files can be in one of these states:
Always check the state before using a file in batch operations.
application/jsonl or application/x-ndjsonapplication/jsontext/plaintext/csvGeminiFile instances are used directly with batch models:
// Upload batch file
GeminiFile batchFile = filesManager.uploadFile(Path.of("batch.jsonl"), "My Batch");
// Use with batch chat model
GoogleAiGeminiBatchChatModel batchModel = GoogleAiGeminiBatchChatModel.builder()
.apiKey(System.getenv("GOOGLE_AI_API_KEY"))
.modelName("gemini-2.5-flash")
.build();
var response = batchModel.createBatchFromFile("Batch Job", batchFile);Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-google-ai-gemini