Springboot --

cnblogs 2024-10-12 14:43:00 阅读 54

    <li>实在是不知道标题写什么了 可以在评论区给个建议哈哈哈哈 先用这个作为标题吧

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

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

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

<code> <dependency>

<groupId>cn.bigmodel.openapi</groupId>

<artifactId>oapi-java-sdk</artifactId>

<version>release-V4-2.0.0</version>

</dependency>

    <li>使用 普通的 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<ChatMessage> messages = new ArrayList<>();

ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), content);

messages.add(chatMessage);

String requestId = String.format(requestIdTemplate, System.currentTimeMillis());

// 函数调用参数构建部分

List<ChatTool> chatToolList = new ArrayList<>();

ChatTool chatTool = new ChatTool();

chatTool.setType(ChatToolType.FUNCTION.value());

ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();

chatFunctionParameters.setType("object");

Map<String, Object> properties = new HashMap<>();

properties.put("location", new HashMap<String, Object>() {{

put("type", "string");

put("description", "城市,如:北京");

}});

properties.put("unit", new HashMap<String, Object>() {{

put("type", "string");

put("enum", new ArrayList<String>() {{

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<ChatMessage> messages = new ArrayList<>();

ChatMessage chatMessage = new ChatMessage(ChatMessageRole.USER.value(), content);

messages.add(chatMessage);

String requestId = String.format(requestIdTemplate, System.currentTimeMillis());

// 函数调用参数构建部分

List<ChatTool> chatToolList = new ArrayList<>();

ChatTool chatTool = new ChatTool();

chatTool.setType(ChatToolType.FUNCTION.value());

ChatFunctionParameters chatFunctionParameters = new ChatFunctionParameters();

chatFunctionParameters.setType("object");

Map<String, Object> properties = new HashMap<>();

properties.put("location", new HashMap<String, Object>() {{

put("type", "string");

put("description", "城市,如:北京");

}});

properties.put("unit", new HashMap<String, Object>() {{

put("type", "string");

put("enum", new ArrayList<String>() {{

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<Choice> 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<Choice> 类型但是实际上只有一个所以索性直接获取数组下标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


声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。