#AI
Junjie
15 小时以前 70af762aa04fccfd68f211a9991c9a36f0228dfd
src/main/java/com/zy/ai/service/LlmChatService.java
@@ -10,8 +10,13 @@
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.function.Consumer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
@Slf4j
@Service
@@ -60,4 +65,52 @@
        return response.getChoices().get(0).getMessage().getContent();
    }
}
    public void chatStream(List<ChatCompletionRequest.Message> messages,
                           Double temperature,
                           Integer maxTokens,
                           Consumer<String> onChunk,
                           Runnable onComplete,
                           Consumer<Throwable> onError) {
        ChatCompletionRequest req = new ChatCompletionRequest();
        req.setModel(model);
        req.setMessages(messages);
        req.setTemperature(temperature != null ? temperature : 0.3);
        req.setMax_tokens(maxTokens != null ? maxTokens : 1024);
        req.setStream(true);
        Flux<String> flux = llmWebClient.post()
                .uri("/chat/completions")
                .header(HttpHeaders.AUTHORIZATION, "Bearer " + apiKey)
                .contentType(MediaType.APPLICATION_JSON)
                .accept(MediaType.TEXT_EVENT_STREAM)
                .bodyValue(req)
                .retrieve()
                .bodyToFlux(String.class)
                .doOnError(ex -> log.error("调用 LLM 流式失败", ex));
        flux.subscribe(payload -> {
            String s = payload == null ? null : payload.trim();
            if (s == null || s.isEmpty()) return;
            if (s.startsWith("data:")) s = s.substring(5).trim();
            if ("[DONE]".equals(s)) return;
            try {
                JSONObject obj = JSON.parseObject(s);
                JSONArray choices = obj.getJSONArray("choices");
                if (choices != null && !choices.isEmpty()) {
                    JSONObject c0 = choices.getJSONObject(0);
                    JSONObject delta = c0.getJSONObject("delta");
                    if (delta != null) {
                        String content = delta.getString("content");
                        if (content != null) onChunk.accept(content);
                    }
                }
            } catch (Exception ignore) {}
        }, err -> {
            if (onError != null) onError.accept(err);
        }, () -> {
            if (onComplete != null) onComplete.run();
        });
    }
}