LLM(大语言模型)——Springboot集成文心一言、讯飞星火、通义千问、智谱清言

目录

引言

代码完整地址

入参

 出参

Controller

Service

Service实现类

 模型Service

 入参转换类

文心一言实现类

讯飞星火实现类

 通义千问实现类

智谱清言实现类


引言

本文将介绍如何使用Java语言,结合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 List<MessageDTO> 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(List<MessageDTO> 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();List<MessageDTO> 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);List<FaRuiHistoryDTO> history = convertFaRuiHistory(messages);input.setHistory(history);}input.setPrompt(prompt);faRuiDTO.setParameters(dto.getParams());faRuiDTO.setInput(input);return faRuiDTO;}/*** 通用消息转换为通义法睿历史消息** @param messages 通用消息* @return 通义法睿历史消息*/default List<FaRuiHistoryDTO> convertFaRuiHistory(List<MessageDTO> messages) {List<FaRuiHistoryDTO> 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/?_=1708497709522&u=qfdc#/api?product=AI&project=%E5%8D%83%E5%B8%86%E5%A4%A7%E6%A8%A1%E5%9E%8B%E5%B9%B3%E5%8F%B0&parent=ERNIE-Bot&api=rpc%2F2.0%2Fai_custom%2Fv1%2Fwenxinworkshop%2Fchat%2Fcompletions&method=post* @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_type=client_credentials&client_id=%s&client_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;}/*** 从用户的AK,SK生成鉴权签名(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" +"(1)messages成员不能为空,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 List<MessageDTO> 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();CompletableFuture<String> 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来避免空指针异常,并在内容不存在时抛出异常Optional<String> 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字段Optional<Long> 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 List<MessageDTO> 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?spm=a2c4g.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);Optional<String> 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" +"(1)messages成员不能为空,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 List<MessageDTO> 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();Optional<JSONObject> jsonObject = Optional.ofNullable(JSON.parseObject(response.body()));jsonObject.ifPresent(json -> {Optional<JSONArray> choices = Optional.ofNullable(json.getJSONArray("choices"));choices.ifPresent(choiceArray -> {if (!choiceArray.isEmpty()) {Optional<JSONObject> 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];Map<String, 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 HashMap<String, Object>(16) {{put("alg", "HS256");put("sign_type", "SIGN");}}).withPayload(payload).sign(algorithm);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/745202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Zabbix 监控 tomcat

zabbix-java-gateway服务组件 zabbix监控tomcat需要用到zabbix-java-gateway组件&#xff0c;它充当zabbix服务和java应用程序之间的网关。它允许zabbix服务器用过java网关与java应用程序进行通信&#xff0c;从而监控和收集java应用程序的性能数据。 zabbix-agent服务&#xf…

数据仓库原理(二)

目录 四、数据仓库的概念模型&#xff08;一&#xff09;多维数据模型&#xff08;二&#xff09;维度与粒度 五、数据仓库的逻辑模型&#xff08;一&#xff09;多维模型&#xff08;二&#xff09;星形模型&#xff08;三&#xff09;雪花模型 六、数据仓库的物理模型&#x…

如何使用IDE端通义灵码

如何使用IDE端通义灵码 第一步&#xff1a;安装IDE插件&#xff08; VS Code 和 JetBrains 二选一&#xff09; 如何下载安装VS Code &#xff1a;https://code.visualstudio.com 如何下载安装JetBrains&#xff1a;https://www.jetbrains.com/idea/download 第二步&#x…

CVPR2023 | 3D Data Augmentation for Driving Scenes on Camera

3D Data Augmentation for Driving Scenes on Camera 摄像机驾驶场景的 3D 数据增强 摘要翻译 驾驶场景极其多样和复杂&#xff0c;仅靠人力不可能收集到所有情况。虽然数据扩增是丰富训练数据的有效技术&#xff0c;但自动驾驶应用中现有的摄像头数据扩增方法仅限于二维图像…

Flutter 多语言自动化本地化生成器

Flutter 多语言自动化本地化生成器 这是一个为Flutter设计的插件&#xff0c;通过从Excel表格提取的CSV文件自动生成Dart本地化文件&#xff0c;以简化应用程序本地化的流程。这个工具通过自动化创建多语言资源文件&#xff0c;简化了开发人员和翻译人员的工作流程。 特点 默…

国外visa卡怎么办理,可充ChatGPTPLUS、Claude、Midjourney

很多小伙都在使用ChatGPT&#xff0c;但是想充值ChatGPTPLUS缺需要国外的visa卡&#xff0c;拿自己的银联卡&#xff0c;尝试了好多次还是不行&#xff0c;其实用一张国外的visa卡几分钟就可以升级好 办理国外visa卡&#xff0c;点击获取 国外的visa卡&#xff0c;具体要看你…

实现两栏布局

1. 利用浮动 将左边元素宽度设为200px&#xff0c;并设置向左浮动将右边元素的margin-left设为200px&#xff0c;宽度为auto&#xff08;默认为auto&#xff0c;撑满整个父元素&#xff09; .outer {height: 100px; } .left {float: left;width: 200px; } .right {margin-lef…

ORM Bee数据源的使用, Bee有自己的数据源吗?

Bee实现了几种简单的数据源&#xff0c;用于开发/测试&#xff1b; 生产上一般都是选用性能比较好的数据源工具&#xff0c;Bee内置实现的&#xff0c;主要是为了方便开发/测试&#xff1b; 1. SimpleDataSource 参考: 参考bee-exam工程&#xff0c;I nitSameDsUtil.DruidDa…

springboot配置文件Tomcat和mvc详细配置

tomcat相关配置参数 (ServerProperties) server.port8080 server.address # bind to a specific NIC server.session-timeout # session timeout in seconds server.context-path # the context path, defaults to ‘/’ server.servlet-path # the servlet path, defaults to…

ArcGIS全系列实战视频教程——9个单一课程组合+系列直播回放

《ArcGIS全系列实战视频教程》是由9个单一课程组合合成。组成一条ArcGIS入门实战各项专题深入应用学习全链条&#xff0c;让你学有方向、学有目的&#xff0c;系统全面掌握ArcGIS。 ArcGIS全系列实战视频教程——9个单一课程组合https://edu.csdn.net/combo/detail/2569 《Ar…

SpringBoot之Bean扫描、Bean注册

目录 Bean扫描 Bean注册 Bean lmport 自定义注解 注册条件 Bean扫描 Bean扫描有两种方式 1、标签:<context:component-scan base-package"com.mybatis"/> 2、注解: ComponentScan(basePackages "com.mybatis") springboot启动类注解可以自…

HTML世界之input标签

<input> 元素在 <form> 元素中使用&#xff0c;用来声明允许用户输入数据的 input 控件。 <input> 元素是空的,它只包含标签属性&#xff0c;规定了用户可以在其中输入数据的输入字段。输入字段可通过多种方式改变&#xff0c;取决于 type 属性。 属性 值 …

Postman定义全局变量和环境

Postman定义全局变量和环境 一. 问题二. 配置环境解决 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 一. 问题 问题前因&#xff1a;在使用postman调用elasticsearch接口的时候&…

目标检测——YOLOv3算法解读

论文&#xff1a;YOLOv3&#xff1a;An Incremental Improvement 作者&#xff1a;Joseph Redmon, Ali Farhadi 链接&#xff1a;https://arxiv.org/abs/1804.02767 代码&#xff1a;http://pjreddie.com/yolo/ YOLO系列其他文章&#xff1a; YOLOv1通俗易懂版解读SSD算法解读…

rust学习(简单链表)

编写一个简单链表&#xff0c;主要遇到的问题就是next指针&#xff08;按照C的写法&#xff09;的数据如何定义。按照网上的建议&#xff0c;一般定义如下&#xff1a; struct Node {pub value:u32,pub next:Option<Rc<RefCell<Node>>>, //1 }1.用Option主要…

pearlCTF——少部分WP

题型新颖&#xff0c;见识了不少 目录 b4by_jailExcel MayhemRick Roll3 spiesjail_timeWiFi brokenSoundScape b4by_jail 一道沙箱逃逸的题 源代码 #!/usr/local/bin/python import time flag"pearl{f4k3_fl4g}" blacklistlist("abcdefghijklmnopqrstuvwxyz…

设计模式学习笔记 - 规范与重构 - 7.实践:通过一段ID生成器代码,学习如何发现代码质量问题

前言 前面讲了重构相关的知识点。用一句话总结&#xff1a;重构就是发现代码质量问题&#xff0c;并且对其进行优化的过程。 今天借助一个 ID 生成器代码&#xff0c;给你展示以下重构的大致过程。 背景介绍 在软件开发中&#xff0c;ID 常用来表示一些业务信息的唯一标识&…

【计算机图形学】End-to-End Affordance Learning for Robotic Manipulation

对RLAfford&#xff1a;End-to-End Affordance Learning for Robotic Manipulation的简单理解 1. 为什么要做这件事 在交互环境中学习如何操纵3D物体是RL中的挑战性问题。很难去训练出一个能够泛化到具有不同语义类别、不同几何形状和不同功能物体上的策略。 Visual Afforda…

Jmeter(七) - 从入门到精通 - 建立数据库测试计划实战<MySQL数据库>(详解教程)

1.简介 在实际工作中&#xff0c;我们经常会听到数据库的性能和稳定性等等&#xff0c;这些有时候也需要测试工程师去评估和测试&#xff0c;上一篇文章主要介绍了jmeter连接和创建数据库测试计划的过程,在文中通过示例和代码非常详细地介绍给大家&#xff0c;希望对各位小伙伴…

在 Java 中,如何使用文件保存包含文字和数字的 Swing 表格?

要在Java中使用文件保存包含文字和数字的Swing表格&#xff0c;您可以按照以下步骤进行&#xff1a; 1. 首先&#xff0c;您需要创建一个Swing表格&#xff0c;并向其中添加包含文字和数字的数据。 2. 接下来&#xff0c;您可以使用Java中的文件操作类&#xff08;如FileWrit…