http 流式输出（主要是指文本流式输出），需要使用响应式接口和支持流输出的 mime 声明。常见的有两种文本流式输出：

### 1、输出 sse（Server Sent Event）

输出的格式：以 sse 消息块为单位，以"空行"为识别间隔。

示例代码：

```java
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Produces;
import org.noear.solon.core.util.MimeType;
import org.noear.solon.web.sse.SseEvent;
import reactor.core.publisher.Flux;

import java.io.IOException;

@Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE)
@Mapping("case1")
public Flux<SseEvent> case1(String prompt) throws IOException {
    return chatModel.prompt(prompt)
                .stream()
                .filter(resp -> resp.hasContent())
                .map(resp -> new SseEvent().data(resp.getContent()));
}
```

输出效果如下（sse 消息块有多个属性，data 为必选，其它为可选）：

```
data:{"role":"ASSISTANT","content":"xxx"}

data:{"role":"ASSISTANT","content":"yyy"}

```


### 2、输出 ndjson（Newline-Delimited JSON）

输出的格式：以 json 消息块为单位，以"换行符"为识别间隔。

```java
import org.noear.solon.ai.chat.message.AssistantMessage;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Produces;
import org.noear.solon.core.util.MimeType;
import reactor.core.publisher.Flux;

import java.io.IOException;

@Produces(MimeType.APPLICATION_X_NDJSON_UTF8_VALUE)
@Mapping("case2")
public Flux<AssistantMessage> case2(String prompt) throws IOException {
    return chatModel.prompt(prompt)
                .stream()
                .map(resp -> resp.getMessage());
}
```

输出效果如下：

```
{"role":"ASSISTANT","content":"xxx"}
{"role":"ASSISTANT","content":"yyy"}
```

### 3、获取

上面讲的是作为 server 以流式输出。solon-net-httputils 则提供了，作为客户端接收流式获取（或接收）的能力：

* 使用 HttpUtils 获取文本行流（比如 ndjson）

```java
Flux<String> publisher = HttpUtils.http("http://localhost:8080/stream")
                .execAsLineStream("GET");
```

* 使用 HttpUtils 获取 ServerSentEvnet （简称：sse）文本流

```java
Flux<ServerSentEvent> publisher = HttpUtils.http("http://localhost:8080/sse")
                .execAsSseStream("GET");
```