diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http index 2d417a55f..463e61207 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/chat/AiChatMessageController.http @@ -6,7 +6,7 @@ Authorization: {{token}} { "conversationId": "1781604279872581649", - "content": "中国好看吗?" + "content": "你是 OpenAI 么?" } @@ -16,11 +16,10 @@ Content-Type: application/json Authorization: {{token}} { - "conversationId": "1781604279872581651", - "content": "苹果是什么颜色?" + "conversationId": "1781604279872581690", + "content": "1+1=?" } - ### message list GET {{baseUrl}}/admin-api/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649 Authorization: {{token}} diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java index 181b136ef..dd4901bdf 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/chat/AiChatConversationMapper.java @@ -15,12 +15,11 @@ import java.util.List; @Mapper public interface AiChatConversationMapper extends BaseMapperX { + // TODO @fan:建议这里不排序哈;交给他们前端排序 default List selectListByUserId(Long userId) { - return selectList( - new LambdaQueryWrapperX() - .eq(AiChatConversationDO::getUserId, userId) - .orderByAsc(AiChatConversationDO::getCreateTime) - ); + return selectList(new LambdaQueryWrapperX() + .eq(AiChatConversationDO::getUserId, userId) + .orderByAsc(AiChatConversationDO::getCreateTime)); } } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java index e1fe760f0..7c7e37954 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/AiChatServiceImpl.java @@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; import java.time.LocalDateTime; import java.util.*; @@ -125,9 +126,10 @@ public class AiChatServiceImpl implements AiChatService { Flux streamResponse = chatClient.stream(prompt); // 3.3 流式返回 + // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题 StringBuffer contentBuffer = new StringBuffer(); - return streamResponse.map(response -> { - String newContent = response.getResult() != null ? response.getResult().getOutput().getContent() : null; + return streamResponse.publishOn(Schedulers.immediate()).map(chunk -> { + String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null; newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况 contentBuffer.append(newContent); // 响应结果 diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/openAiImage/OpenAiImageClientTests.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/openAiImage/OpenAiImageClientTests.java index bf184a849..828f7dc2d 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/openAiImage/OpenAiImageClientTests.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/openAiImage/OpenAiImageClientTests.java @@ -71,21 +71,4 @@ public class OpenAiImageClientTests { } } - public static void main(String[] args) { -// OpenAiApi api = new OpenAiApi("https://api.gptsapi.net", "sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z"); -// OpenAiApi api = new OpenAiApi("https://openkey.cloud", "sk-QmgIIPc5xiYd8lPb076b1b7774Ea49Af9eD2Ef172c8f7e43"); - OpenAiApi api = new OpenAiApi("https://api.chatanywhere.tech", "sk-gkgfYxhX9FxyZJznwxRZSJwKeGQYNPDVWjhby2PRRf17GHeT"); - OpenAiChatClient client = new OpenAiChatClient(api); -// String result = client.call("未来,英文是什么?"); -// System.out.println(result); - Flux result = client.stream("未来,英文是什么?"); - result.map(new Function() { - @Override - public String apply(String s) { - System.out.println(s); - return s; - } - }).blockLast(); - } - } diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index e8e07c675..6bb087d81 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -156,6 +156,9 @@ spring.ai: # base-url: https://api.chatanywhere.tech api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z base-url: https://api.gptsapi.net +# chat: +# options: +# model: gpt-4-0125-preview yudao.ai: yiyan: