CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-dev-langchain4j--langchain4j-google-ai-gemini

LangChain4j integration for Google AI Gemini models providing chat, streaming, embeddings, image generation, and batch processing capabilities

Overview
Eval results
Files

file-management.mddocs/

File Management

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.

Capabilities

GeminiFiles Class

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

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();
}

GeminiFile Record

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();
}

GeminiUploadFailureException

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
}

Usage Examples

Basic File Upload from Path

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());

Upload with Auto-Generated Display Name

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"

Upload from Byte Array

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());

Checking File Status

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!");
}

Listing All Files

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());
}

Getting File Metadata

// 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());

Deleting Files

// 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());
    }
}

Error Handling

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());
}

Complete Batch Workflow with File Upload

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());

File Size Management

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");
}

Checking Storage Quota

// 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!");
}

File Expiration Management

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!");
    }
}

Custom HTTP Client Configuration

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");

Uploading Multiple Files

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");

Verifying File Integrity

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();
}

Batch File Generation and Upload

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());

File States

Files can be in one of these states:

  • PROCESSING - File is being uploaded or processed
  • ACTIVE - File is ready to use in batch operations
  • FAILED - File upload or processing failed

Always check the state before using a file in batch operations.

Storage Limits

  • Per file: Maximum 2GB
  • Total project: Maximum 20GB across all files
  • Persistence: Files automatically expire after 48 hours
  • Cleanup: Delete files when no longer needed to free up quota

Best Practices

  1. Display names: Use descriptive display names for easy identification
  2. State checking: Always verify file is ACTIVE before using in batch operations
  3. Error handling: Wrap upload operations in try-catch for GeminiUploadFailureException
  4. Quota management: Monitor total storage and delete old files regularly
  5. Expiration: Be aware files expire after 48 hours; plan batch operations accordingly
  6. File verification: Use SHA-256 hash to verify file integrity after upload
  7. Cleanup: Delete files after batch completion to free storage
  8. MIME types: Specify correct MIME type when uploading from bytes

Common MIME Types

  • JSON Lines: application/jsonl or application/x-ndjson
  • JSON: application/json
  • Text: text/plain
  • CSV: text/csv

Integration with Batch Processing

GeminiFile 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@1.11.0

docs

advanced-configuration.md

batch-processing.md

chat-streaming.md

chat-synchronous.md

configuration.md

embeddings.md

file-management.md

images.md

index.md

model-catalog.md

response-metadata.md

token-counting.md

tile.json