效果展示
提问效果:
回答效果:
1、Maven配置
<dependency>
<groupId>cn.bigmodel.openapi</groupId>
<artifactId>oapi-java-sdk</artifactId>
<version>release-V4-2.3.0</version>
</dependency>
2、yml配置
zm:
zhipu:
api-key: "申请一个key"
3、工具实体
package com.zm.naviTech.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/*
* @Author 落梨
* @Date 2024-09-14 13:42
* @Description:
**/
@Configuration
@Data
public class ZhiPuKey {
@Value("${zm.zhipu.api-key}")
private String ApiKey;
}
4、controller层
注意这里的callWithMessage里的方法可以自己设置自定义参数。
流式方法这里我做了内容的组合,方便插入数据库,后面插入的mapper可以不用看了,按照你自己的业务逻辑去处理,主要看异步流式方式。
package com.zm.naviTech.AIController;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.zhipu.oapi.ClientV4;
import com.zhipu.oapi.Constants;
import com.zhipu.oapi.service.v4.model.*;
import com.zm.naviTech.config.ZhiPuKey;
import com.zm.naviTech.constants.MessageDirectionConstant;
import com.zm.naviTech.entity.po.ChatgptMessage;
import com.zm.naviTech.mapper.ConversationMapper;
import com.zm.naviTech.utils.ThreadLocalUtil;
import io.reactivex.Flowable;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.angus.mail.imap.MessageCache;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
/*
* @Author 落梨
* @Date 2024-09-14 13:39
* @Description: 质谱AI
**/
@Component
@Slf4j
public class ZhiPuAiChatController {
@Resource
private ZhiPuKey zhiPuKey;
@Resource
private ConversationMapper conversationMapper;
private static final ObjectMapper mapper = new ObjectMapper();
/**
* @author 落梨
* @description 调用接口
**/
public ModelApiResponse callWithMessage(String conversationId, String prompt) throws JsonProcessingException {
log.info("==============质谱AI准备回答===================");
//获取key
String key = zhiPuKey.getApiKey();
//生成客户端
ClientV4 client = new ClientV4.Builder(key).build();
//业务id
String requestIdTemplate = conversationId;
String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
//参数工具
List<ChatTool> chatToolList = new ArrayList<>();
ChatTool chatTool = new ChatTool();
chatTool.setType("code_interpreter");
chatToolList.add(chatTool);
//携带消息体,这个实例 是 官方提供
List<ChatMessage> messages = new ArrayList<>();
ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), prompt);
messages.add(chatMessage);
ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
.model(Constants.ModelChatGLM4)
.stream(Boolean.TRUE)
.invokeMethod(Constants.invokeMethod)
.messages(messages)
.tools(chatToolList)
.toolChoice("auto")
.requestId(requestId)
.build();
//使用流式
ModelApiResponse sseModelApiResp = client.invokeModelApi(chatCompletionRequest);
if (sseModelApiResp.isSuccess()) {
AtomicBoolean isFirst = new AtomicBoolean(true);
List<Choice> choices = new ArrayList<>();
AtomicReference<ChatMessageAccumulator> lastAccumulator = new AtomicReference<>();
mapStreamToAccumulator(sseModelApiResp.getFlowable())
.doOnNext(accumulator -> {
{
if (isFirst.getAndSet(false)) {
log.info("Response: ");
}
if (accumulator.getDelta() != null && accumulator.getDelta().getTool_calls() != null) {
String jsonString = mapper.writeValueAsString(accumulator.getDelta().getTool_calls());
log.info("tool_calls: {}", jsonString);
}
if (accumulator.getDelta() != null && accumulator.getDelta().getContent() != null) {
log.info(accumulator.getDelta().getContent());
}
choices.add(accumulator.getChoice());
lastAccumulator.set(accumulator);
}
})
.doOnComplete(System.out::println)
.lastElement()
.blockingGet();
ChatMessageAccumulator chatMessageAccumulator = lastAccumulator.get();
ModelData data = new ModelData();
data.setChoices(choices);
if (chatMessageAccumulator != null) {
data.setUsage(chatMessageAccumulator.getUsage());
data.setId(chatMessageAccumulator.getId());
data.setCreated(chatMessageAccumulator.getCreated());
}
data.setRequestId(chatCompletionRequest.getRequestId());
sseModelApiResp.setFlowable(null);// 打印前置空
sseModelApiResp.setData(data);
}
//组合内容
StringBuilder stringBuilder = new StringBuilder();
List<Choice> choices = sseModelApiResp.getData().getChoices();
for (Choice choice : choices) {
stringBuilder.append(choice.getDelta().getContent());
}
log.info(stringBuilder.toString());
String content = stringBuilder.toString();
log.info("质谱ai的回答是:{}",content);
//插入询问语句到数据库
ChatgptMessage chatgptMessage = ChatgptMessage.builder()
.userId(ThreadLocalUtil.getCurrentId())
.messageDirection(MessageDirectionConstant.USER)
.createTime(LocalDateTime.now())
.conversationId(Long.valueOf(conversationId))
.content(prompt).build();
conversationMapper.insert(chatgptMessage);
//插入回答语句到数据库
ChatgptMessage chatgptMessage2 = ChatgptMessage.builder()
.userId(ThreadLocalUtil.getCurrentId())
.messageDirection(MessageDirectionConstant.AI)
.createTime(LocalDateTime.now())
.content(content)
.conversationId(Long.valueOf(conversationId)).build();
conversationMapper.insert(chatgptMessage2);
log.info("==============回答完毕===================");
return sseModelApiResp;
}
//流式操作
public static Flowable<ChatMessageAccumulator> mapStreamToAccumulator(Flowable<ModelData> flowable) {
return flowable.map(chunk -> {
return new ChatMessageAccumulator(chunk.getChoices().get(0).getDelta(), null, chunk.getChoices().get(0), chunk.getUsage(), chunk.getCreated(), chunk.getId());
});
}
}