mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	【修复】AI:解决 spring-ai 与 webflux 集成时,SSE 存在乱序的问题
This commit is contained in:
		@@ -6,7 +6,7 @@ Authorization: {{token}}
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "conversationId": "1781604279872581649",
 | 
					  "conversationId": "1781604279872581649",
 | 
				
			||||||
  "content": "中国好看吗?"
 | 
					  "content": "你是 OpenAI 么?"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -16,11 +16,10 @@ Content-Type: application/json
 | 
				
			|||||||
Authorization: {{token}}
 | 
					Authorization: {{token}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "conversationId": "1781604279872581651",
 | 
					  "conversationId": "1781604279872581690",
 | 
				
			||||||
  "content": "苹果是什么颜色?"
 | 
					  "content": "1+1=?"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
### message list
 | 
					### message list
 | 
				
			||||||
GET {{baseUrl}}/admin-api/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649
 | 
					GET {{baseUrl}}/admin-api/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649
 | 
				
			||||||
Authorization: {{token}}
 | 
					Authorization: {{token}}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,12 +15,11 @@ import java.util.List;
 | 
				
			|||||||
@Mapper
 | 
					@Mapper
 | 
				
			||||||
public interface AiChatConversationMapper extends BaseMapperX<AiChatConversationDO> {
 | 
					public interface AiChatConversationMapper extends BaseMapperX<AiChatConversationDO> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO @fan:建议这里不排序哈;交给他们前端排序
 | 
				
			||||||
    default List<AiChatConversationDO> selectListByUserId(Long userId) {
 | 
					    default List<AiChatConversationDO> selectListByUserId(Long userId) {
 | 
				
			||||||
        return selectList(
 | 
					        return selectList(new LambdaQueryWrapperX<AiChatConversationDO>()
 | 
				
			||||||
                new LambdaQueryWrapperX<AiChatConversationDO>()
 | 
					                .eq(AiChatConversationDO::getUserId, userId)
 | 
				
			||||||
                        .eq(AiChatConversationDO::getUserId, userId)
 | 
					                .orderByAsc(AiChatConversationDO::getCreateTime));
 | 
				
			||||||
                        .orderByAsc(AiChatConversationDO::getCreateTime)
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j;
 | 
				
			|||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.transaction.annotation.Transactional;
 | 
					import org.springframework.transaction.annotation.Transactional;
 | 
				
			||||||
import reactor.core.publisher.Flux;
 | 
					import reactor.core.publisher.Flux;
 | 
				
			||||||
 | 
					import reactor.core.scheduler.Schedulers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					import java.time.LocalDateTime;
 | 
				
			||||||
import java.util.*;
 | 
					import java.util.*;
 | 
				
			||||||
@@ -125,9 +126,10 @@ public class AiChatServiceImpl implements AiChatService {
 | 
				
			|||||||
        Flux<ChatResponse> streamResponse = chatClient.stream(prompt);
 | 
					        Flux<ChatResponse> streamResponse = chatClient.stream(prompt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 3.3 流式返回
 | 
					        // 3.3 流式返回
 | 
				
			||||||
 | 
					        // 注意:Schedulers.immediate() 目的是,避免默认 Schedulers.parallel() 并发消费 chunk 导致 SSE 响应前端会乱序问题
 | 
				
			||||||
        StringBuffer contentBuffer = new StringBuffer();
 | 
					        StringBuffer contentBuffer = new StringBuffer();
 | 
				
			||||||
        return streamResponse.map(response -> {
 | 
					        return streamResponse.publishOn(Schedulers.immediate()).map(chunk -> {
 | 
				
			||||||
            String newContent = response.getResult() != null ? response.getResult().getOutput().getContent() : null;
 | 
					            String newContent = chunk.getResult() != null ? chunk.getResult().getOutput().getContent() : null;
 | 
				
			||||||
            newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况
 | 
					            newContent = StrUtil.nullToDefault(newContent, ""); // 避免 null 的 情况
 | 
				
			||||||
            contentBuffer.append(newContent);
 | 
					            contentBuffer.append(newContent);
 | 
				
			||||||
            // 响应结果
 | 
					            // 响应结果
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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<String> result = client.stream("未来,英文是什么?");
 | 
					 | 
				
			||||||
        result.map(new Function<String, String>() {
 | 
					 | 
				
			||||||
            @Override
 | 
					 | 
				
			||||||
            public String apply(String s) {
 | 
					 | 
				
			||||||
                System.out.println(s);
 | 
					 | 
				
			||||||
                return s;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }).blockLast();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,6 +156,9 @@ spring.ai:
 | 
				
			|||||||
#    base-url: https://api.chatanywhere.tech
 | 
					#    base-url: https://api.chatanywhere.tech
 | 
				
			||||||
    api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z
 | 
					    api-key: sk-yzKea6d8e8212c3bdd99f9f44ced1cae37c097e5aa3BTS7z
 | 
				
			||||||
    base-url: https://api.gptsapi.net
 | 
					    base-url: https://api.gptsapi.net
 | 
				
			||||||
 | 
					#    chat:
 | 
				
			||||||
 | 
					#      options:
 | 
				
			||||||
 | 
					#        model: gpt-4-0125-preview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
yudao.ai:
 | 
					yudao.ai:
 | 
				
			||||||
  yiyan:
 | 
					  yiyan:
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user