Stream in Java
stream_options.include_usage is Preview (not available yet). Until it ships, leave it out; the code below simply prints no usage line.Print a reply as it is generated with java.net.http and Jackson.
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.*;
import java.util.stream.Stream;
public class StreamDemo {
public static void main(String[] args) throws Exception {
ObjectMapper m = new ObjectMapper();
String body = """
{"model": "Amara S1.2", "stream": true, "stream_options": {"include_usage": true},
"messages": [{"role": "user", "content": "Explain idempotency keys in three sentences."}]}
""";
HttpRequest req = HttpRequest.newBuilder(URI.create("https://app.syntic.ai/v1/chat/completions"))
.header("Authorization", "Bearer " + System.getenv("SYNTIC_API_KEY"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body)).build();
HttpResponse<Stream<String>> res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofLines());
if (res.statusCode() != 200) {
throw new RuntimeException(res.statusCode() + ": " + String.join("", res.body().toList()));
}
for (String line : (Iterable<String>) res.body()::iterator) {
if (!line.startsWith("data: ")) continue;
String payload = line.substring(6);
if (payload.equals("[DONE]")) break;
JsonNode chunk = m.readTree(payload);
if (chunk.has("error")) throw new RuntimeException("stream interrupted: " + chunk.path("error").path("message").asText());
JsonNode choices = chunk.path("choices");
if (choices.size() > 0) System.out.print(choices.get(0).path("delta").path("content").asText(""));
if (chunk.hasNonNull("usage")) {
System.out.printf("%n[%d in / %d out tokens]%n", chunk.path("usage").path("prompt_tokens").asInt(), chunk.path("usage").path("completion_tokens").asInt());
}
}
}
}BodyHandlers.ofLines() delivers lines as they arrive, so text prints while the model is still writing.
What the code handles
- Lines that start with
data:carry JSON chunks; other lines (blank lines,: keep-alivecomments) are skipped. data: [DONE]ends the stream.- A chunk with an
errorobject means the stream broke after it started; the text so far may be incomplete, so retry the whole request. - The last chunk before
[DONE]carriesusagewhen you sendstream_options.include_usage.
See Stream format for every field.
Was this page helpful?