server-sent events 说明

content-type: text/event-stream
格式

  • event : the event type defined by application
    event:应用程序定义的事件类型
  • data : the data field for the event or message.
    data:事件或消息的数据字段。
  • retry : The browser attempts to reconnect to the resource after a defined time when the connection is lost or closed.
    重试:当连接丢失或关闭时,浏览器在定义的时间后尝试重新连接到资源。
  • id : id for each event/message
    id:每个事件/消息的 id

chatgpt 应用

终止符

|500

结束语

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}

….

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":" today"},"finish_reason":null}]}

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"?"},"finish_reason":null}]}

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0613", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

spring-boot-webflux DEMO

GitHub - G-khan/server-sent-events: Sample Live Score app - Spring Boot Reactive Webflux Server-Sent Events

@RestController  
@RequestMapping("/api/v1")  
public class LiveScoreController {  
    private static final Logger LOGGER = LoggerFactory.getLogger(LiveScoreController.class);  
    private final LiveScoreHandler processor;  
    public LiveScoreController(LiveScoreHandler processor) {  
        this.processor = processor;  
    }  
    @PostMapping("/live-scores")  
    @ResponseStatus(HttpStatus.CREATED)  
    public Mono<LiveScore> send(@RequestBody LiveScore liveScore) {  
        LOGGER.info("Received '{}'", liveScore);  
        processor.publish(liveScore);  
        return Mono.just(liveScore);  
    }  
    @GetMapping(path = "/live-scores", produces = MediaType.TEXT_EVENT_STREAM_VALUE)  
    public Flux<ServerSentEvent<Object>> consumer() {  
        return Flux.create(sink -> processor.subscribe(sink::next)).map(  
                liveScore -> ServerSentEvent.builder().data(liveScore).event("goal").build());  
    }  
}