Springboot --- 使用国内的 AI 大模型 对话
作者:mmseoamin日期:2024-02-24
  • 实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧

    尝试使用 国内给出的 AI 大模型做出一个 可以和 AI 对话的 网站出来

    • 使用 智普AI 只能 在控制台中输出 对应的信息 不如就做一个 maven 的 项目调用对应的API

      https://open.bigmodel.cn/dev/api#glm-4

          
              cn.bigmodel.openapi
              oapi-java-sdk
              release-V4-2.0.0
          
      
      • 使用 普通的 java – Maven项目 只能在控制台 查看结果 也就是 说没有办法在其他平台 使

        用 制作出来的 AI ChatRobot

      • 思来想去 不如 将这个东西写成 QQ 机器人
      • 但是因为我找到的 那个 不更新了 或者 腾讯不支持了 让我放弃了 写成 QQ 机器人的想法
      • 于是我就尝试将这个写成一个本地的 AI 对话机器人 但是 在翻看 官方给出的 Demo 我偶然发现了一个方法 他的 输出似乎是一个 json 转换成的 String
      • 这个方法并没有将这个String 返回出来 而是 直接在控制台打印
        package com.codervibe.utils;
        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.image.CreateImageRequest;
        import com.zhipu.oapi.service.v4.image.ImageApiResponse;
        import com.zhipu.oapi.service.v4.model.*;
        import io.reactivex.Flowable;
        import java.util.ArrayList;
        import java.util.HashMap;
        import java.util.List;
        import java.util.Map;
        import java.util.concurrent.atomic.AtomicBoolean;
        public class ChatAPIUtils {
            private static final String API_KEY = "cb11ad7f3b68ce03ed9be6e13573aa19";
            private static final String API_SECRET = "nG7UQrrXqsXtqD1S";
            private static final ClientV4 client = new ClientV4.Builder(API_KEY, API_SECRET).build();
            private static final ObjectMapper mapper = defaultObjectMapper();
            public static ObjectMapper defaultObjectMapper() {
                ObjectMapper mapper = new ObjectMapper();
                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
                mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
                mapper.addMixIn(ChatFunction.class, ChatFunctionMixIn.class);
                mapper.addMixIn(ChatCompletionRequest.class, ChatCompletionRequestMixIn.class);
                mapper.addMixIn(ChatFunctionCall.class, ChatFunctionCallMixIn.class);
                return mapper;
            }
            // 请自定义自己的业务id
            private static final String requestIdTemplate = "mycompany-%d";
            /**
             * 同步调用
             */
            public static String InvokeApi(String content) throws JsonProcessingException {
                List messages = new ArrayList<>();
                ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), content);
                messages.add(chatMessage);
                String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
                // 函数调用参数构建部分
                List chatToolList = new ArrayList<>();
                ChatTool chatTool = new ChatTool();
                chatTool.setType(ChatToolType.FUNCTION.value());
                ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();
                chatFunctionParameters.setType("object");
                Map properties = new HashMap<>();
                properties.put("location", new HashMap() {{
                    put("type", "string");
                    put("description", "城市,如:北京");
                }});
                properties.put("unit", new HashMap() {{
                    put("type", "string");
                    put("enum", new ArrayList() {{
                        add("celsius");
                        add("fahrenheit");
                    }});
                }});
                chatFunctionParameters.setProperties(properties);
                ChatFunction chatFunction = ChatFunction.builder()
                        .name("get_weather")
                        .description("Get the current weather of a location")
                        .parameters(chatFunctionParameters)
                        .build();
                chatTool.setFunction(chatFunction);
                chatToolList.add(chatTool);
                ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                        .model(Constants.ModelChatGLM4)
                        .stream(Boolean.FALSE)
                        .invokeMethod(Constants.invokeMethod)
                        .messages(messages)
                        .requestId(requestId)
                        .tools(chatToolList)
                        .toolChoice("auto")
                        .build();
                ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
                try {
                // 这里返回出去是一个 json 
                    return mapper.writeValueAsString(invokeModelApiResp);
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
                return mapper.writeValueAsString(new ModelApiResponse());
            }
            public static void CreateImage(String content) {
                CreateImageRequest createImageRequest = new CreateImageRequest();
                createImageRequest.setModel(Constants.ModelCogView);
                createImageRequest.setPrompt(content);
                ImageApiResponse imageApiResponse = client.createImage(createImageRequest);
                System.out.println("imageApiResponse:" + JSON.toJSONString(imageApiResponse));
            }
        }
        
        • 工具类中 InvokeApi 方法 最后获得的是一个 ModelApiResponse类 这个类有点类似于 统一返回类型 但是我在这里 只需要里面的具体方法 请求状态和 信息 并不需要 (有另外一个统一返回类型定义 ) 所以在 后面我将这个方法 修改 改为 将我需要的数据返回给controller
        • 实际上这是不应该直接返回给 controller 的 而是 应该 通过 service 的 因为service中才是真正的业务代码
        • 修改后的方法 代码如下
              /**
               * 同步调用
               */
              public static ModelData InvokeApi(String content) throwsJsonProcessingException{
                  List messages = new ArrayList<>();
                  ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), content);
                  messages.add(chatMessage);
                  String requestId = String.format(requestIdTemplate, System.currentTimeMillis());
                  // 函数调用参数构建部分
                  List chatToolList = new ArrayList<>();
                  ChatTool chatTool = new ChatTool();
                  chatTool.setType(ChatToolType.FUNCTION.value());
                  ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();
                  chatFunctionParameters.setType("object");
                  Map properties = new HashMap<>();
                  properties.put("location", new HashMap() {{
                      put("type", "string");
                      put("description", "城市,如:北京");
                  }});
                  properties.put("unit", new HashMap() {{
                      put("type", "string");
                      put("enum", new ArrayList() {{
                          add("celsius");
                          add("fahrenheit");
                      }});
                  }});
                  chatFunctionParameters.setProperties(properties);
                  ChatFunction chatFunction = ChatFunction.builder()
                          .name("get_weather")
                          .description("Get the current weather of a location")
                          .parameters(chatFunctionParameters)
                          .build();
                  chatTool.setFunction(chatFunction);
                  chatToolList.add(chatTool);
                  ChatCompletionRequest chatCompletionRequest = ChatCompletionRequest.builder()
                          .model(Constants.ModelChatGLM4)
                          .stream(Boolean.FALSE)
                          .invokeMethod(Constants.invokeMethod)
                          .messages(messages)
                          .requestId(requestId)
                          .tools(chatToolList)
                          .toolChoice("auto")
                          .build();
                  ModelApiResponse invokeModelApiResp = client.invokeModelApi(chatCompletionRequest);
                  ModelData data = invokeModelApiResp.getData();
                  return data;
          
          • 而这里的信息实际上是一层层 抽丝剥茧 剥离出来的
                List choices = data.getChoices();
                System.out.println("choices.toString() = " + choices.toString());
                for (Choice choice : choices) {
                    ChatMessage message = choice.getMessage();
                    System.out.println("message.getContent() = " + message.getContent());
                    //本来这里想返回具体的信息类但是发现 上面的的那个ModelApiResponse类 也是一个 统一返回类型 也包含这 请求状态码 之类的定义
                    return message;
                }
                return new ChatMessage();
                try {
                    return mapper.writeValueAsString(invokeModelApiResp);
                } catch (JsonProcessingException e) {
                        e.printStackTrace();
                }
                return mapper.writeValueAsString(new ModelApiResponse());    
            
            • 可以看到我的这段代码 有多个 return 所以这实际上是一段假 代码
            • 每一个return 实际上官方都 对应的 model 或者说 resoponse
            • controller 代码
                  @PostMapping("/chat")
                  public R chat(@RequestParam("content") String content) throws JsonProcessingException {
                      /**
                       * data 中的 choices 是一个 List 类型但是实际上只有一个所以索性直接获取数组下标0的对象
                       */
                      logger.info(ChatAPIUtils.InvokeApi(content).getChoices().get(0).getMessage().getContent().toString());
                      return R.ok().data("content", ChatAPIUtils.InvokeApi(content));
                  }
              
              • 修改 由 service 层 调用 工具类
              • service 代码
              • service 接口
                package com.codervibe.server.service;
                import com.zhipu.oapi.service.v4.image.ImageResult;
                import com.zhipu.oapi.service.v4.model.ModelData;
                public interface ChatService {
                    /**
                     * AI 对话
                     */
                    ModelData AIdialogue(String content);
                    /**
                     * AI  画图
                     */
                    ImageResult AIcreateimage(String content);
                }
                
                • service 接口实现
                  package com.codervibe.server.Impl;
                  import com.codervibe.server.service.ChatService;
                  import com.codervibe.utils.ChatAPIUtils;
                  import com.fasterxml.jackson.core.JsonProcessingException;
                  import com.zhipu.oapi.service.v4.image.ImageResult;
                  import com.zhipu.oapi.service.v4.model.ModelData;
                  import org.slf4j.Logger;
                  import org.slf4j.LoggerFactory;
                  import org.springframework.stereotype.Service;
                  @Service("chatService")
                  public class ChatServiceImpl implements ChatService {
                      Logger logger = LoggerFactory.getLogger(ChatServiceImpl.class);
                      /**
                       * AI 对话
                       * @param content
                       */
                      @Override
                      public ModelData AIdialogue(String content) {
                          logger.info(ChatAPIUtils.InvokeApi(content).getChoices().get(0).getMessage().getContent().toString());
                          return ChatAPIUtils.InvokeApi(content);
                      }
                      /**
                       * AI  画图
                       *
                       * @param content
                       */
                      @Override
                      public ImageResult AIcreateimage(String content) {
                          logger.info(ChatAPIUtils.CreateImage(content).getData().get(0).getUrl());
                          return ChatAPIUtils.CreateImage(content);
                      }
                  }
                  
                  • controller 层调用 service
                    ****package com.codervibe.web.controller;
                    import com.codervibe.server.service.ChatService;
                    import com.codervibe.utils.ChatAPIUtils;
                    import com.codervibe.web.common.response.R;
                    import com.fasterxml.jackson.core.JsonProcessingException;
                    import org.springframework.web.bind.annotation.PostMapping;
                    import org.springframework.web.bind.annotation.RequestMapping;
                    import org.springframework.web.bind.annotation.RequestParam;
                    import org.springframework.web.bind.annotation.RestController;
                    import org.slf4j.Logger;
                    import org.slf4j.LoggerFactory;
                    import javax.annotation.Resource;
                    @RestController
                    @RequestMapping("/chat")
                    public class ChatController {
                        Logger logger = LoggerFactory.getLogger(ChatController.class);
                        @Resource
                        private ChatService chatService;
                        @PostMapping("/content")
                        public R chat(@RequestParam("content") String content) {
                            return R.ok().data("content", chatService.AIdialogue(content));
                        }
                        @PostMapping("/AIcreateimage")
                        public R AIcreateimage(@RequestParam("content") String content){
                            return R.ok().data("image",chatService.AIcreateimage(content));
                        }
                    }
                    
                    • 现在 虽然可以 和 AI 进行对话 但是 数据返回的速度实在是太慢 所以我打算 将 常见的问题和答案 存储在本地的数据库中以提升 数据返回的速度 这只是一个初步的想法
                    • 最后的想法 还未实现 先这样
                    • 粉丝群 企鹅 179469398