Now, send the request to the API and handle the response with proper JSON parsing using Jackson.
public String transcribeWithOptions(File audioFile, String language, String prompt) throws Exception {
// Generate unique boundary for this request using current timestamp
String boundary = "----boundary" + System.currentTimeMillis();
// Build the multipart form data with all parameters
byte[] formData = buildFormData(audioFile, boundary, language, prompt);
// Create HTTP POST request to the transcription API endpoint
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/v1/audio/transcriptions"))
.header("Authorization", "Bearer " + apiKey) // Authenticate with API key
.header("Content-Type", "multipart/form-data; boundary=" + boundary) // Specify content type
.POST(HttpRequest.BodyPublishers.ofByteArray(formData)) // Send form data as request body
.build();
// Send the request and receive the response
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
// Check if the request was successful (HTTP 200)
if (response.statusCode() == 200) {
// Parse the JSON response safely using Jackson
JsonNode jsonResponse = objectMapper.readTree(response.body());
// Extract the transcribed text from the "text" field
return jsonResponse.get("text").asText();
} else {
// Handle API errors by throwing an exception with error details
throw new RuntimeException("API request failed: " + response.body());
}
}
Understanding the Boundary Generation:
The boundary ("----boundary" + System.currentTimeMillis()) is a unique string that separates different parts of the multipart form data. Here's why we use a timestamp:
- Uniqueness:
System.currentTimeMillis() returns the current time in milliseconds since January 1, 1970, making each boundary unique across different requests
- Simplicity: It's a simple way to generate a unique identifier without additional dependencies
- HTTP Standard Compliance: The boundary must not appear in the actual data being sent, and using a timestamp makes this extremely unlikely
Alternative approaches you might see include:
- UUID:
UUID.randomUUID().toString() would provide better randomness but requires importing java.util.UUID
- Random numbers: Using
Math.random() or Random class for generating unique identifiers
The timestamp approach is preferred here because it's lightweight, requires no additional imports, and provides sufficient uniqueness for HTTP requests.
Key points about the request:
- We create a unique boundary for the multipart request using the current timestamp
- The Authorization header includes the Bearer token with our API key
- The Content-Type header specifies multipart/form-data with the boundary
- We use Jackson's
ObjectMapper to parse the JSON response safely, which handles escaped characters and malformed JSON much better than string manipulation
- The
readTree() method parses the JSON into a JsonNode, and we extract the "text" field using get("text").asText()
- Proper error handling throws an exception if the API call fails