网站开发所需技术,二手建筑铝模板哪里有卖,wordpress自动采集源码,小程序网站建设目录
引言
代码完整地址
入参 出参
Controller
Service
Service实现类 模型Service 入参转换类
文心一言实现类
讯飞星火实现类 通义千问实现类
智谱清言实现类 引言 本文将介绍如何使用Java语言#xff0c;结合Spring Boot框架#xff0c;集成国内热门大模型API结合Spring Boot框架集成国内热门大模型API包括文心一言、讯飞星火、通义千问、智谱清言。 在开始前请确保您已经按照各模型官网的指引完成了相应的资源申请和配置。这些资源是调用大模型API的必要凭证务必妥善保管。接下来我们将通过具体的代码示例和步骤说明引导您完成Spring Boot项目和大模型API集成。 代码完整地址
https://github.com/wangsilingwsl/model-integrate.git
入参
package com.wsl.model.llm.api.dto;import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;/*** 聊天请求 DTO** author wsl* date 2024/2/20*/
Data
public class ChatRequestDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 聊天上下文信息, notes 1最后一个message为当前请求的信息前面的message为历史对话信息\n 2成员数目必须为奇数\n 3示例中message中的role值分别为user、assistant奇数位message中的role值为user偶数位值为assistant,example [{\role\:\user\,\content\:\你好\},{\role\:\assistant\,\content\:\需要什么帮助\},{\role\:\user\,\content\:\自我介绍下\}])NotNull(message 聊天上下文信息不能为空)private ListMessageDTO messages;ApiModelProperty(value 模型人设, notes 主要用于人设设定,例如你是xxx公司制作的AI助手最大20000字符, example 你是一名天气助手需要提供天气查询服务)private String system;ApiModelProperty(value 请求参数, notes 请求参数, example {\key\:\value\})private JSONObject params;
}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;import java.io.Serializable;/*** 消息 DTO** author wsl* date 2024/2/20*/
Data
AllArgsConstructor
public class MessageDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 角色, notes 说明: user-用户, assistant-助手, example user)private String role;ApiModelProperty(value 消息内容, notes 说明: 消息内容, example 你好)private String content;}出参
package com.wsl.model.llm.api.vo;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 聊天响应 VO** author wsl* date 2024/2/20*/
Data
public class ChatResponseVO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 结果, notes 结果)private String result;}Controller
package com.wsl.model.llm.api.controller;import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.service.IAiAppService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** AI应用Controller** author wsl* date 2024/02/19*/
Slf4j
RestController
Api(tags AI应用)
RequestMapping(/llm/middle)
public class AiAppController {Autowiredprivate IAiAppService service;PostMapping(/chat-message)ApiOperation(向大模型发起对话请求)public ChatResponseVO chatMessage(ApiParam(value 模型类型(ErnieBot/SparkDesk/ChatGlm/QianWen), required true) RequestParam String modelType,ApiParam(value 消息参数, required true) RequestBody ChatRequestDTO dto) {try {return service.chatMessage(modelType, dto);} catch (Exception e) {throw new RuntimeException(e);}}}Service
package com.wsl.model.llm.api.service;import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.vo.ChatResponseVO;/*** AI应用Service** author wsl* date 2024/02/19*/
public interface IAiAppService {/*** 向大模型发起对话请求-根据模型编码、用户ID** param modelType 模型类型* param dto 消息参数* return ChatResponseVO* throws Exception 异常*/ChatResponseVO chatMessage(String modelType, ChatRequestDTO dto) throws Exception;}
Service实现类
package com.wsl.model.llm.api.service.impl;import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.wsl.model.llm.api.constant.enums.ModelTypeEnum;
import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.dto.MessageDTO;
import com.wsl.model.llm.api.service.IAiAppService;
import com.wsl.model.llm.api.service.ModelService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import org.springframework.stereotype.Service;import java.util.List;/*** AI应用ServiceImpl** author wsl* date 2024/02/19*/
Service(aiAppService)
public class AiAppServiceImpl implements IAiAppService {Overridepublic ChatResponseVO chatMessage(String modelType, ChatRequestDTO dto) throws Exception {this.checkMessages(dto.getMessages());// 根据枚举类ModelTypeEnum中的枚举值判断模型类型并调用对应的模型实现类的方法ModelService modelService getModelService(modelType);return modelService.chatMessage(dto);}/*** 检查消息参数是否符合规范** param messages 消息参数*/private void checkMessages(ListMessageDTO messages) {if (CollUtil.isNotEmpty(messages)) {// messages参数个数必须为奇数并且奇数个数的消息role必须为user偶数个数的消息role必须为assistantif (messages.size() % 2 0) {throw new RuntimeException(messages参数个数必须为奇数);}for (int i 0; i messages.size(); i) {if (i % 2 0) {if (!user.equals(messages.get(i).getRole())) {throw new RuntimeException(messages奇数参数的role必须为user);}} else {if (!assistant.equals(messages.get(i).getRole())) {throw new RuntimeException(messages偶数参数的role必须为assistant);}}}}}/*** 根据模型类型获取对应的模型服务** param modelType 模型类型* return 模型服务*/private ModelService getModelService(String modelType) {try {// 将模型类型字符串转换为枚举值ModelTypeEnum modelTypeEnum ModelTypeEnum.valueOf(modelType);// 根据枚举值获取对应的实现类Bean的名称String beanName modelTypeEnum.name();beanName StrUtil.toCamelCase(beanName) Service;return SpringUtil.getBean(beanName);} catch (IllegalArgumentException e) {throw new RuntimeException(模型类型错误);}}} 模型Service
package com.wsl.model.llm.api.service;import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.vo.ChatResponseVO;/*** 模型服务** author wsl* date 2024/2/19*/
public interface ModelService {/*** 发起请求** param dto 请求参数* return 返回值* throws Exception 异常*/ChatResponseVO chatMessage(ChatRequestDTO dto) throws Exception;}入参转换类
package com.wsl.model.llm.api.convert;import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.wsl.model.llm.api.dto.*;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;import java.util.ArrayList;
import java.util.List;/*** 聊天请求转换器** author wsl* date 2024/2/22*/
Mapper
public interface ChatRequestConvert {ChatRequestConvert INSTANCE Mappers.getMapper(ChatRequestConvert.class);/*** 通用请求转换为文心一言请求** param dto 通用请求* return 文心一言请求*/default JSONObject convertErnieBot(ChatRequestDTO dto) {ErnieBotDTO ernieBotDTO new ErnieBotDTO();ernieBotDTO.setMessages(dto.getMessages());ernieBotDTO.setSystem(dto.getSystem());JSONObject jsonObject new JSONObject();BeanUtil.copyProperties(ernieBotDTO, jsonObject);BeanUtil.copyProperties(dto.getParams(), jsonObject);return jsonObject;}/*** 通用请求转换为通义千问请求** param dto 通用请求* return 通义千问请求*/default QianWenDTO convertQianwen(ChatRequestDTO dto) {QianWenDTO qianWenDTO new QianWenDTO();qianWenDTO.setModel(qwen-turbo);QianWenInputDTO input new QianWenInputDTO();String system dto.getSystem();if (StrUtil.isNotBlank(system)) {MessageDTO messageDTO new MessageDTO(system, system);dto.getMessages().add(0, messageDTO);}input.setMessages(dto.getMessages());JSONObject parametersJsonObject new JSONObject();BeanUtil.copyProperties(dto.getParams(), parametersJsonObject);qianWenDTO.setInput(input);qianWenDTO.setParameters(parametersJsonObject);return qianWenDTO;}/*** 通用请求转换为智谱清言请求** param dto 通用请求* return 智谱清言请求*/default JSONObject convertChatGlm(ChatRequestDTO dto) {ChatGlmDTO chatGlmDTO new ChatGlmDTO();String system dto.getSystem();if (StrUtil.isNotBlank(system)) {MessageDTO messageDTO new MessageDTO(system, system);dto.getMessages().add(0, messageDTO);}chatGlmDTO.setMessages(dto.getMessages());chatGlmDTO.setModel(glm-4);JSONObject jsonObject new JSONObject();BeanUtil.copyProperties(chatGlmDTO, jsonObject);BeanUtil.copyProperties(dto.getParams(), jsonObject);return jsonObject;}/*** 通用请求转换为讯飞星火请求** param dto 通用请求* return 讯飞星火请求*/default SparkDeskDTO convertSparkDesk(ChatRequestDTO dto) {SparkDeskDTO sparkDeskDTO new SparkDeskDTO();SparkDeskPayloadDTO payload new SparkDeskPayloadDTO();SparkDeskPayloadMessageDTO payloadMessage new SparkDeskPayloadMessageDTO();String system dto.getSystem();if (StrUtil.isNotBlank(system)) {MessageDTO messageDTO new MessageDTO(system, system);dto.getMessages().add(0, messageDTO);}payloadMessage.setText(dto.getMessages());payload.setMessage(payloadMessage);SparkDeskParameterChatDTO parameterChat new SparkDeskParameterChatDTO();parameterChat.setDomain(generalv3.5);JSONObject parameterChatJsonObject new JSONObject();BeanUtil.copyProperties(parameterChat, parameterChatJsonObject);BeanUtil.copyProperties(dto.getParams(), parameterChatJsonObject);SparkDeskParameterDTO parameter new SparkDeskParameterDTO();parameter.setChat(parameterChatJsonObject);sparkDeskDTO.setPayload(payload);sparkDeskDTO.setParameter(parameter);return sparkDeskDTO;}/*** 通用请求转换为通义千问请求** param dto 通用请求* return 通义千问请求*/default FaRuiDTO convertFaRui(ChatRequestDTO dto) {FaRuiDTO faRuiDTO new FaRuiDTO();ListMessageDTO messages dto.getMessages();String prompt messages.get(messages.size() - 1).getContent();FaRuiInputDTO input new FaRuiInputDTO();if (messages.size() 1) {messages new ArrayList();}if (CollUtil.isNotEmpty(messages)) {messages.remove(messages.size() - 1);ListFaRuiHistoryDTO history convertFaRuiHistory(messages);input.setHistory(history);}input.setPrompt(prompt);faRuiDTO.setParameters(dto.getParams());faRuiDTO.setInput(input);return faRuiDTO;}/*** 通用消息转换为通义法睿历史消息** param messages 通用消息* return 通义法睿历史消息*/default ListFaRuiHistoryDTO convertFaRuiHistory(ListMessageDTO messages) {ListFaRuiHistoryDTO history new ArrayList();int size messages.size();for (int i 0; i size; i 2) {FaRuiHistoryDTO messagePair new FaRuiHistoryDTO();messagePair.setUser(messages.get(i).getContent());if (i 1 size) {messagePair.setBot(messages.get(i 1).getContent());}history.add(messagePair);}return history;}}文心一言实现类
package com.wsl.model.llm.api.service.impl;import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wsl.model.llm.api.convert.ChatRequestConvert;
import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.service.ModelService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;/*** 文心一言 大模型服务** author wsl* link https://console.bce.baidu.com/tools/?_1708497709522uqfdc#/api?productAIproject%E5%8D%83%E5%B8%86%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%B9%B3%E5%8F%B0parentERNIE-Botapirpc%2F2.0%2Fai_custom%2Fv1%2Fwenxinworkshop%2Fchat%2Fcompletionsmethodpost* date 2024/2/19*/
Service(ErnieBotService)
Slf4j
public class ErnieBotServiceImpl implements ModelService {private String appSecret ?;private String apiKey ?;private static final String TOKEN_URL_TEMPLATE https://aip.baidubce.com/oauth/2.0/token?grant_typeclient_credentialsclient_id%sclient_secret%s;private static final String CHAT_URL https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token%s;Overridepublic ChatResponseVO chatMessage(ChatRequestDTO dto) {JSONObject ernieBot ChatRequestConvert.INSTANCE.convertErnieBot(dto);String requestBody JSONUtil.toJsonStr(ernieBot);log.info(文心一言请求参数 ernieBot request:{}, requestBody);HttpResponse response HttpUtil.createPost(String.format(CHAT_URL, getAccessToken(apiKey, appSecret))).body(requestBody).header(Content-Type, application/json).execute();if (response null) {throw new RuntimeException(HTTP response is null);}log.info(文心一言返回结果 ernieBot response:{}, response.body());if (response.body() null || response.body().trim().isEmpty()) {throw new RuntimeException(HTTP response body is null or empty);}JSONObject jsonObject JSON.parseObject(response.body());if (!jsonObject.containsKey(result)) {throw new RuntimeException(JSONObject.toJSONString(jsonObject));}ChatResponseVO vo new ChatResponseVO();vo.setResult(jsonObject.getString(result));return vo;}/*** 从用户的AKSK生成鉴权签名Access Token** param appId 应用ID* param appSecret 应用密钥* return token*/public String getAccessToken(String appId, String appSecret) {String url String.format(TOKEN_URL_TEMPLATE, apiKey, appSecret);try (HttpResponse response HttpRequest.post(url).header(Content-Type, application/json).header(Accept, application/json).execute()) {JSONObject jsonObject JSON.parseObject(response.body());String accessToken jsonObject.getString(access_token);return accessToken;}}}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;/*** 文心一言 请求 DTO** author wsl* date 2024/2/20*/
Data
public class ErnieBotDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 聊天上下文信息, notes 说明\n 1messages成员不能为空1个成员表示单轮对话多个成员表示多轮对话例如\n · 1个成员示例\messages\: [ {\role\: \user\,\content\: \你好\}]\n · 3个成员示例\messages\: [ {\role\: \user\,\content\: \你好\},{\role\:\assistant\,\content\:\需要什么帮助\},{\role\:\user\,\content\:\自我介绍下\}]\n 2最后一个message为当前请求的信息前面的message为历史对话信息\n 3成员数目必须为奇数成员中message的role值说明如下奇数位messsage的role值必须为user或function偶数位message的role值为assistant第一个message的role不能是function。例如\n 示例中message中的role值分别为user、assistant、user、assistant、user奇数位红框message中的role值为user即第1、3、5个message中的role值为user偶数位蓝框值为assistant即第2、4个message中的role值为assistant,example [{\role\:\system\,\content\:\您好我是智谱清言我可以帮您查询天气您可以输入查询{{destination}}的天气查询{{destination}}未来{{num_day}}天的天气\},{\role\:\user\,\content\:\查询三亚未来5天的天气\},{\role\:\assistant\,\content\:\正在查询三亚未来5天的天气\},{\role\:\assistant\,\content\:\三亚未来5天的天气是晴天\}])NotNull(message 聊天上下文信息不能为空)private ListMessageDTO messages;ApiModelProperty(value 模型人设, notes 主要用于人设设定,例如你是xxx公司制作的AI助手最大20000字符, example qwen-turbo)private String system;ApiModelProperty(value 温度, notes 较高的数值会使输出更加随机而较低的数值会使其更加集中和确定。默认0.8范围 [0, 1.0]不能为0, example 0.8)private Float temperature;}讯飞星火实现类
package com.wsl.model.llm.api.service.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.wsl.model.llm.api.convert.ChatRequestConvert;
import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.dto.SparkDeskDTO;
import com.wsl.model.llm.api.dto.SparkDeskHeaderDTO;
import com.wsl.model.llm.api.service.ModelService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;/*** 讯飞星火 大模型服务** author wsl* link https://www.xfyun.cn/doc/spark/Web.html* date 2024/2/19*/
Service(SparkDeskService)
Slf4j
public class SparkDeskServiceImpl implements ModelService {private String appId ?;private String appSecret ?;private String appKey ?;public static final String HOST_URL https://spark-api.xf-yun.com/v3.5/chat;Overridepublic ChatResponseVO chatMessage(ChatRequestDTO dto) throws Exception {ChatResponseVO vo new ChatResponseVO();SparkDeskDTO sparkDeskDTO ChatRequestConvert.INSTANCE.convertSparkDesk(dto);sparkDeskDTO.setHeader(new SparkDeskHeaderDTO(appId));String authUrl getAuthUrl(HOST_URL, appKey, appSecret).replace(http://, ws://).replace(https://, wss://);Request request new Request.Builder().url(authUrl).build();OkHttpClient client new OkHttpClient.Builder().build();StringBuilder sb new StringBuilder();CompletableFutureString messageReceived new CompletableFuture();String body JSON.toJSONString(sparkDeskDTO);WebSocket webSocket client.newWebSocket(request, new WebSocketListener() {Overridepublic void onOpen(WebSocket webSocket, Response response) {//发送消息log.info(讯飞星火请求参数 sparkDesk request:{}, body);webSocket.send(body);}Overridepublic void onMessage(WebSocket webSocket, String text) {try {JSONObject obj JSON.parseObject(text);// 使用Optional来避免空指针异常并在内容不存在时抛出异常OptionalString contentOptional Optional.ofNullable(obj).map(jsonObject - jsonObject.getJSONObject(payload)).map(payload - payload.getJSONObject(choices)).map(choices - choices.getJSONArray(text)).map(jsonArray - jsonArray.getJSONObject(0)).map(jsonObject - jsonObject.getString(content));String str contentOptional.orElseThrow(() - new RuntimeException(JSONObject.toJSONString(obj)));sb.append(str);// 检查header和status字段OptionalLong statusOptional Optional.ofNullable(obj).map(jsonObject - jsonObject.getJSONObject(header)).map(header - header.getLong(status));// 如果status为2则关闭WebSocket并完成CompletableFutureif (statusOptional.isPresent() statusOptional.get() 2) {webSocket.close(1000, Closing WebSocket connection);messageReceived.complete(text);}} catch (JSONException e) {throw new RuntimeException(e);}}});messageReceived.get(60, TimeUnit.SECONDS);webSocket.close(1000, Closing WebSocket connection);log.info(讯飞星火返回结果 sparkDesk response:{}, sb);vo.setResult(sb.toString());return vo;}/*** 鉴权方法** param hostUrl 服务地址* param apiKey apiKey* param apiSecret apiSecret* return 返回鉴权url* throws Exception 异常*/public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws Exception {URL url new URL(hostUrl);// 时间SimpleDateFormat format new SimpleDateFormat(EEE, dd MMM yyyy HH:mm:ss z, Locale.US);format.setTimeZone(TimeZone.getTimeZone(GMT));String date format.format(new Date());// 拼接String preStr host: url.getHost() \n date: date \n GET url.getPath() HTTP/1.1;// SHA256加密Mac mac Mac.getInstance(hmacsha256);SecretKeySpec spec new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), hmacsha256);mac.init(spec);byte[] hexDigits mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8));// Base64加密String sha Base64.getEncoder().encodeToString(hexDigits);String authorization String.format(api_key\%s\, algorithm\%s\, headers\%s\, signature\%s\, apiKey, hmac-sha256, host date request-line, sha);// 拼接地址HttpUrl httpUrl Objects.requireNonNull(HttpUrl.parse(https:// url.getHost() url.getPath())).newBuilder().addQueryParameter(authorization, Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))).addQueryParameter(date, date).addQueryParameter(host, url.getHost()).build();return httpUrl.toString();}
}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 讯飞星火 请求 DTO** author wsl* date 2024/2/20*/
Data
public class SparkDeskDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 头部, notes 头部)private SparkDeskHeaderDTO header;ApiModelProperty(value 参数, notes 参数)private SparkDeskParameterDTO parameter;ApiModelProperty(value 有效载荷, notes 有效载荷)private SparkDeskPayloadDTO payload;}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.io.Serializable;/*** 讯飞星火 Header DTO** author wsl* date 2024/2/20*/
Data
NoArgsConstructor
AllArgsConstructor
public class SparkDeskHeaderDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 应用appid, notes 从开放平台控制台创建的应用中获取)private String app_id;}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 讯飞星火 聊天 参数 DTO** author wsl* date 2024/2/20*/
Data
public class SparkDeskParameterChatDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 指定访问的领域, notes generalv3指向V3版本;generalv3.5指向V3.5版本)private String domain;ApiModelProperty(value 温度, notes 较高的数值会使输出更加随机而较低的数值会使其更加集中和确定。默认0.8范围 [0, 2.0]不能为0, example 0.8)private Float temperature;ApiModelProperty(value 最大标记, notes 模型回答的tokens的最大长度取值范围[1,8192]默认为2048, example 2048)private Integer max_tokens;}package com.wsl.model.llm.api.dto;import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 讯飞星火 参数 DTO** author wsl* date 2024/2/20*/
Data
public class SparkDeskParameterDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 聊天参数, notes 聊天参数)private JSONObject chat;}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import java.io.Serializable;/*** 讯飞星火 有效载荷 DTO** author wsl* date 2024/2/20*/
Data
public class SparkDeskPayloadDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 消息, notes 消息)private SparkDeskPayloadMessageDTO message;}package com.wsl.model.llm.api.dto;import lombok.Data;import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;/*** 讯飞星火 有效载荷 消息 DTO** author wsl* date 2024/2/20*/
Data
public class SparkDeskPayloadMessageDTO implements Serializable {private static final long serialVersionUID 1L;NotNull(message 聊天上下文信息不能为空)private ListMessageDTO text;}通义千问实现类
package com.wsl.model.llm.api.service.impl;import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wsl.model.llm.api.convert.ChatRequestConvert;
import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.dto.QianWenDTO;
import com.wsl.model.llm.api.service.ModelService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.Optional;/*** 通义千问 大模型服务** author wsl* link https://help.aliyun.com/zh/dashscope/developer-reference/api-details?spma2c4g.11186623.0.0.6922140bTYj6qJ#602895ef3dtl1* date 2024/2/19*/
Slf4j
Service(QianWenService)
public class QianWenServiceImpl implements ModelService {private String apiKey ?;Overridepublic ChatResponseVO chatMessage(ChatRequestDTO dto) {QianWenDTO qianwen ChatRequestConvert.INSTANCE.convertQianwen(dto);String url https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation;String json JSON.toJSONString(qianwen);log.info(通义千问请求参数 qianwen request:{}, json);String result HttpRequest.post(url).header(Authorization, Bearer apiKey).header(Content-Type, application/json).body(json).execute().body();log.info(通义千问返回结果 qianwen response:{}, result);ChatResponseVO vo new ChatResponseVO();JSONObject jsonObject JSON.parseObject(result);OptionalString textOptional Optional.ofNullable(jsonObject.getJSONObject(output)).map(output - output.getString(text));if (!textOptional.isPresent()) {throw new RuntimeException(JSONObject.toJSONString(jsonObject));}vo.setResult(textOptional.get());return vo;}}package com.wsl.model.llm.api.dto;import io.swagger.annotations.ApiModelProperty;
import lombok.Data;import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.List;/*** 通义千问 输入 DTO** author wsl* date 2024/2/20*/
Data
public class QianWenInputDTO implements Serializable {private static final long serialVersionUID 1L;ApiModelProperty(value 聊天上下文信息, notes 说明\n 1messages成员不能为空1个成员表示单轮对话多个成员表示多轮对话例如\n · 1个成员示例\messages\: [ {\role\: \user\,\content\: \你好\}]\n · 3个成员示例\messages\: [ {\role\: \user\,\content\: \你好\},{\role\:\assistant\,\content\:\需要什么帮助\},{\role\:\user\,\content\:\自我介绍下\}]\n 2最后一个message为当前请求的信息前面的message为历史对话信息\n 3成员数目必须为奇数成员中message的role值说明如下奇数位messsage的role值必须为user或function偶数位message的role值为assistant第一个message的role不能是function。例如\n 示例中message中的role值分别为user、assistant、user、assistant、user奇数位红框message中的role值为user即第1、3、5个message中的role值为user偶数位蓝框值为assistant即第2、4个message中的role值为assistant,example [{\role\:\system\,\content\:\您好我是智谱清言我可以帮您查询天气您可以输入查询{{destination}}的天气查询{{destination}}未来{{num_day}}天的天气\},{\role\:\user\,\content\:\查询三亚未来5天的天气\},{\role\:\assistant\,\content\:\正在查询三亚未来5天的天气\},{\role\:\assistant\,\content\:\三亚未来5天的天气是晴天\}])NotNull(message 聊天上下文信息不能为空)private ListMessageDTO messages;}智谱清言实现类
package com.wsl.model.llm.api.service.impl;import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.wsl.model.llm.api.convert.ChatRequestConvert;
import com.wsl.model.llm.api.dto.ChatRequestDTO;
import com.wsl.model.llm.api.service.ModelService;
import com.wsl.model.llm.api.vo.ChatResponseVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;/*** 智谱清言 大模型服务** author wsl* link https://open.bigmodel.cn/dev/api#glm-4* date 2024/2/19*/
Slf4j
Service(ChatGlmService)
public class ChatGlmServiceImpl implements ModelService {private String apiKey ?;Overridepublic ChatResponseVO chatMessage(ChatRequestDTO dto) throws Exception {JSONObject chatGlm ChatRequestConvert.INSTANCE.convertChatGlm(dto);String url https://open.bigmodel.cn/api/paas/v4/chat/completions;String requestBody JSONUtil.toJsonStr(chatGlm);log.info(智谱清言请求参数 chatGlm request:{}, requestBody);HttpResponse response HttpUtil.createPost(url).body(requestBody).header(Content-Type, application/json).header(Authorization, Bearer generateToken(apiKey, 3600)).execute();log.info(智谱清言返回结果 chatGlm response:{}, Optional.ofNullable(response).map(HttpResponse::body).orElse());ChatResponseVO vo new ChatResponseVO();OptionalJSONObject jsonObject Optional.ofNullable(JSON.parseObject(response.body()));jsonObject.ifPresent(json - {OptionalJSONArray choices Optional.ofNullable(json.getJSONArray(choices));choices.ifPresent(choiceArray - {if (!choiceArray.isEmpty()) {OptionalJSONObject firstChoiceMessage Optional.ofNullable(choiceArray.getJSONObject(0).getJSONObject(message));firstChoiceMessage.ifPresent(message - {String content message.getString(content);if (content ! null) {vo.setResult(content);} else {throw new RuntimeException(response.body());}});}});throw new RuntimeException(response.body());});return vo;}/*** 生成token** param apikey apikey* param expSeconds 过期时间* return token* throws Exception 异常*/public static String generateToken(String apikey, int expSeconds) throws Exception {String[] parts apikey.split(\\.);if (parts.length ! 2) {throw new Exception(Invalid apikey);}String id parts[0];String secret parts[1];MapString, Object payload new HashMap(16);payload.put(api_key, id);payload.put(exp, new Date(System.currentTimeMillis() expSeconds * 1000));payload.put(timestamp, new Date(System.currentTimeMillis()));Algorithm algorithm Algorithm.HMAC256(secret);return JWT.create().withHeader(new HashMapString, Object(16) {{put(alg, HS256);put(sign_type, SIGN);}}).withPayload(payload).sign(algorithm);}}