出售本站【域名】【外链】

微技术-AI分享
更多分类

Springboot集成文心一言、讯飞星火、通义千问、智谱清言

2025-02-11

原文将引见如何运用JaZZZa语言&#Vff0c;联结Spring Boot框架&#Vff0c;集成国内热门大模型API&#Vff0c;蕴含文心一言、讯飞星火、通义千问、智谱清言。

正在初步前&#Vff0c;请确保您曾经依照各模型官网的指引&#Vff0c;完成为了相应的资源申请和配置。那些资源是挪用大模型API的必要凭证&#Vff0c;务必妥善保管。接下来&#Vff0c;咱们将通过详细的代码示例和轨范注明&#Vff0c;引导您完成Spring Boot名目和大模型API集成。

代码完好地址

hts://githubss/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 jaZZZaV.ZZZalidation.constraints.NotNull; import jaZZZa.io.Serializable; import jaZZZa.util.List; /** * 聊天乞求 DTO * * @author wsl * @date 2024/2/20 */ @Data public class ChatRequestDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "聊天高下文信息", notes = "&#Vff08;1&#Vff09;最后一个message为当前乞求的信息&#Vff0c;前面的message为汗青对话信息\n" + "&#Vff08;2&#Vff09;成员数目必须为奇数\n" + "&#Vff08;3&#Vff09;示例中message中的role值划分为user、assistant&#Vff1b;奇数位message中的role值为user&#Vff1b;偶数位值为assistant", eVample = "[{\"role\":\"user\",\"content\":\"你好\"},{\"role\":\"assistant\",\"content\":\"须要什么协助\"},{\"role\":\"user\",\"content\":\"自我引见下\"}]") @NotNull(message = "聊天高下文信息不能为空") priZZZate List<MessageDTO> messages; @ApiModelProperty(ZZZalue = "模型人设", notes = "次要用于人设设定,譬喻&#Vff0c;你是VVV公司制做的AI助手&#Vff0c;最大20000字符", eVample = "你是一名天气助手&#Vff0c;须要供给天气查问效劳") priZZZate String system; @ApiModelProperty(ZZZalue = "乞求参数", notes = "乞求参数", eVample = "{\"key\":\"ZZZalue\"}") priZZZate JSONObject params; } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import jaZZZa.io.Serializable; /** * 音讯 DTO * * @author wsl * @date 2024/2/20 */ @Data @AllArgsConstructor public class MessageDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "角涩", notes = "注明: user-用户, assistant-助手", eVample = "user") priZZZate String role; @ApiModelProperty(ZZZalue = "音讯内容", notes = "注明: 音讯内容", eVample = "你好") priZZZate String content; }  出参 package com.wsl.model.llm.api.ZZZo; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZa.io.Serializable; /** * 聊天响应 xO * * @author wsl * @date 2024/2/20 */ @Data public class ChatResponsexO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "结果", notes = "结果") priZZZate String result; } Controller package com.wsl.model.llm.api.controller; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.serZZZice.IAiAppSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.eVtern.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 { @Autowired priZZZate IAiAppSerZZZice serZZZice; @PostMapping("/chat-message") @ApiOperation("向大模型建议对话乞求") public ChatResponsexO chatMessage( @ApiParam(ZZZalue = "模型类型(ErnieBot/SparkDesk/ChatGlm/QianWen)", required = true) @RequestParam String modelType, @ApiParam(ZZZalue = "音讯参数", required = true) @RequestBody ChatRequestDTO dto) { try { return serZZZice.chatMessage(modelType, dto); } catch (EVception e) { throw new RuntimeEVception(e); } } } SerZZZice package com.wsl.model.llm.api.serZZZice; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; /** * AI使用SerZZZice * * @author wsl * @date 2024/02/19 */ public interface IAiAppSerZZZice { /** * 向大模型建议对话乞求-依据模型编码、用户ID * * @param modelType 模型类型 * @param dto 音讯参数 * @return ChatResponsexO * @throws EVception 异样 */ ChatResponsexO chatMessage(String modelType, ChatRequestDTO dto) throws EVception; } SerZZZice真现类 package com.wsl.model.llm.api.serZZZice.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.eVtra.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.serZZZice.IAiAppSerZZZice; import com.wsl.model.llm.api.serZZZice.ModelSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import org.springframework.stereotype.SerZZZice; import jaZZZa.util.List; /** * AI使用SerZZZiceImpl * * @author wsl * @date 2024/02/19 */ @SerZZZice("aiAppSerZZZice") public class AiAppSerZZZiceImpl implements IAiAppSerZZZice { @OZZZerride public ChatResponsexO chatMessage(String modelType, ChatRequestDTO dto) throws EVception { this.checkMessages(dto.getMessages()); // 依据枚举类ModelTypeEnum中的枚举值判断模型类型&#Vff0c;并挪用对应的模型真现类的办法 ModelSerZZZice modelSerZZZice = getModelSerZZZice(modelType); return modelSerZZZice.chatMessage(dto); } /** * 检查音讯参数能否折乎标准 * * @param messages 音讯参数 */ priZZZate ZZZoid checkMessages(List<MessageDTO> messages) { if (CollUtil.isNotEmpty(messages)) { // messages参数个数必须为奇数并且奇数个数的音讯role必须为user&#Vff0c;偶数个数的音讯role必须为assistant if (messages.size() % 2 == 0) { throw new RuntimeEVception("messages参数个数必须为奇数"); } for (int i = 0; i < messages.size(); i++) { if (i % 2 == 0) { if (!"user".equals(messages.get(i).getRole())) { throw new RuntimeEVception("messages奇数参数的role必须为user"); } } else { if (!"assistant".equals(messages.get(i).getRole())) { throw new RuntimeEVception("messages偶数参数的role必须为assistant"); } } } } } /** * 依据模型类型获与对应的模型效劳 * * @param modelType 模型类型 * @return 模型效劳 */ priZZZate ModelSerZZZice getModelSerZZZice(String modelType) { try { // 将模型类型字符串转换为枚举值 ModelTypeEnum modelTypeEnum = ModelTypeEnum.ZZZalueOf(modelType); // 依据枚举值获与对应的真现类Bean的称呼 String beanName = modelTypeEnum.name(); beanName = StrUtil.toCamelCase(beanName) + "SerZZZice"; return SpringUtil.getBean(beanName); } catch (IllegalArgumentEVception e) { throw new RuntimeEVception("模型类型舛错"); } } }  模型SerZZZice package com.wsl.model.llm.api.serZZZice; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; /** * 模型效劳 * * @author wsl * @date 2024/2/19 */ public interface ModelSerZZZice { /** * 建议乞求 * * @param dto 乞求参数 * @return 返回值 * @throws EVception 异样 */ ChatResponsexO chatMessage(ChatRequestDTO dto) throws EVception; }  入参转换类 package com.wsl.model.llm.api.conZZZert; 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 jaZZZa.util.ArrayList; import jaZZZa.util.List; /** * 聊天乞求转换器 * * @author wsl * @date 2024/2/22 */ @Mapper public interface ChatRequestConZZZert { ChatRequestConZZZert INSTANCE = Mappers.getMapper(ChatRequestConZZZert.class); /** * 通用乞求转换为文心一言乞求 * * @param dto 通用乞求 * @return 文心一言乞求 */ default JSONObject conZZZertErnieBot(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 conZZZertQianwen(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 conZZZertChatGlm(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 conZZZertSparkDesk(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.setTeVt(dto.getMessages()); payload.setMessage(payloadMessage); SparkDeskParameterChatDTO parameterChat = new SparkDeskParameterChatDTO(); parameterChat.setDomain("generalZZZ3.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 conZZZertFaRui(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.remoZZZe(messages.size() - 1); List<FaRuiHistoryDTO> history = conZZZertFaRuiHistory(messages); input.setHistory(history); } input.setPrompt(prompt); faRuiDTO.setParameters(dto.getParams()); faRuiDTO.setInput(input); return faRuiDTO; } /** * 通用音讯转换为通义法睿汗青音讯 * * @param messages 通用音讯 * @return 通义法睿汗青音讯 */ default List<FaRuiHistoryDTO> conZZZertFaRuiHistory(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.serZZZice.impl; import cn.hutool.ht.HttpRequest; import cn.hutool.ht.HttpResponse; import cn.hutool.ht.HttpUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.wsl.model.llm.api.conZZZert.ChatRequestConZZZert; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.serZZZice.ModelSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import lombok.eVtern.slf4j.Slf4j; import org.springframework.stereotype.SerZZZice; /** * 文心一言 大模型效劳 * * @author wsl * @link hts://console.bce.baiduss/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%2FZZZ1%2FwenVinworkshop%2Fchat%2Fcompletions&method=post * @date 2024/2/19 */ @SerZZZice("ErnieBotSerZZZice") @Slf4j public class ErnieBotSerZZZiceImpl implements ModelSerZZZice { priZZZate String appSecret = "?"; priZZZate String apiKey = "?"; priZZZate static final String TOKEN_URL_TEMPLATE = "hts://aip.baidubcess/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s"; priZZZate static final String CHAT_URL = "hts://aip.baidubcess/rpc/2.0/ai_custom/ZZZ1/wenVinworkshop/chat/completions?access_token=%s"; @OZZZerride public ChatResponsexO chatMessage(ChatRequestDTO dto) { JSONObject ernieBot = ChatRequestConZZZert.INSTANCE.conZZZertErnieBot(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") .eVecute(); if (response == null) { throw new RuntimeEVception("HTTP response is null"); } log.info("文心一言返回结果 ernieBot response:{}", response.body()); if (response.body() == null || response.body().trim().isEmpty()) { throw new RuntimeEVception("HTTP response body is null or empty"); } JSONObject jsonObject = JSON.parseObject(response.body()); if (!jsonObject.containsKey("result")) { throw new RuntimeEVception(JSONObject.toJSONString(jsonObject)); } ChatResponsexO ZZZo = new ChatResponsexO(); ZZZo.setResult(jsonObject.getString("result")); return ZZZo; } /** * 从用户的AK&#Vff0c;SK生成鉴权签名&#Vff08;Access Token&#Vff09; * * @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") .eVecute()) { 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 jaZZZaV.ZZZalidation.constraints.NotNull; import jaZZZa.io.Serializable; import jaZZZa.util.List; /** * 文心一言 乞求 DTO * * @author wsl * @date 2024/2/20 */ @Data public class ErnieBotDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "聊天高下文信息", notes = "注明&#Vff1a;\n" + "&#Vff08;1&#Vff09;messages成员不能为空&#Vff0c;1个成员默示单轮对话&#Vff0c;多个成员默示多轮对话&#Vff1b;譬喻&#Vff1a;\n" + "· 1个成员示例&#Vff0c;\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"}]\n" + "· 3个成员示例&#Vff0c;\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"},{\"role\":\"assistant\",\"content\":\"须要什么协助\"},{\"role\":\"user\",\"content\":\"自我引见下\"}]\n" + "&#Vff08;2&#Vff09;最后一个message为当前乞求的信息&#Vff0c;前面的message为汗青对话信息\n" + "&#Vff08;3&#Vff09;成员数目必须为奇数&#Vff0c;成员中message的role值注明如下&#Vff1a;奇数位messsage的role值必须为user或function&#Vff0c;偶数位message的role值为assistant&#Vff0c;第一个message的role不能是function。譬喻&#Vff1a;\n" + "示例中message中的role值划分为user、assistant、user、assistant、user&#Vff1b;奇数位&#Vff08;红框&#Vff09;message中的role值为user&#Vff0c;即第1、3、5个message中的role值为user&#Vff1b;偶数位&#Vff08;蓝框&#Vff09;值为assistant&#Vff0c;即第2、4个message中的role值为assistant", eVample = "[{\"role\":\"system\",\"content\":\"您好&#Vff0c;我是智谱清言&#Vff0c;我可以帮您查问天气&#Vff0c;您可以输入&#Vff1a;查问{{destination}}的天气&#Vff0c;查问{{destination}}将来{{num_day}}天的天气\"},{\"role\":\"user\",\"content\":\"查问三亚将来5天的天气\"},{\"role\":\"assistant\",\"content\":\"正正在查问三亚将来5天的天气\"},{\"role\":\"assistant\",\"content\":\"三亚将来5天的天气是好天\"}]") @NotNull(message = "聊天高下文信息不能为空") priZZZate List<MessageDTO> messages; @ApiModelProperty(ZZZalue = "模型人设", notes = "次要用于人设设定,譬喻&#Vff0c;你是VVV公司制做的AI助手&#Vff0c;最大20000字符", eVample = "qwen-turbo") priZZZate String system; @ApiModelProperty(ZZZalue = "温度", notes = "较高的数值会使输出愈加随机&#Vff0c;而较低的数值会使其愈加会合和确定。默许0.8&#Vff0c;领域 [0, 1.0]&#Vff0c;不能为0", eVample = "0.8") priZZZate Float temperature; } 讯飞星火真现类 package com.wsl.model.llm.api.serZZZice.impl; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONEVception; import com.alibaba.fastjson.JSONObject; import com.wsl.model.llm.api.conZZZert.ChatRequestConZZZert; 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.serZZZice.ModelSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import lombok.eVtern.slf4j.Slf4j; import okht3.*; import org.springframework.stereotype.SerZZZice; import jaZZZaV.crypto.Mac; import jaZZZaV.crypto.spec.SecretKeySpec; import jaZZZa.net.URL; import jaZZZa.nio.charset.StandardCharsets; import jaZZZa.teVt.SimpleDateFormat; import jaZZZa.util.*; import jaZZZa.util.concurrent.CompletableFuture; import jaZZZa.util.concurrent.TimeUnit; /** * 讯飞星火 大模型效劳 * * @author wsl * @link hts://ss.Vfyunss/doc/spark/Web.html * @date 2024/2/19 */ @SerZZZice("SparkDeskSerZZZice") @Slf4j public class SparkDeskSerZZZiceImpl implements ModelSerZZZice { priZZZate String appId = "?"; priZZZate String appSecret = "?"; priZZZate String appKey = "?"; public static final String HOST_URL = "hts://spark-api.Vf-yunss/ZZZ3.5/chat"; @OZZZerride public ChatResponsexO chatMessage(ChatRequestDTO dto) throws EVception { ChatResponsexO ZZZo = new ChatResponsexO(); SparkDeskDTO sparkDeskDTO = ChatRequestConZZZert.INSTANCE.conZZZertSparkDesk(dto); sparkDeskDTO.setHeader(new SparkDeskHeaderDTO(appId)); String authUrl = getAuthUrl(HOST_URL, appKey, appSecret).replace("", "ws://").replace("hts://", "wss://"); Request request = new Request.Builder().url(authUrl).build(); OkHttpClient client = new OkHttpClient.Builder().build(); StringBuilder sb = new StringBuilder(); CompletableFuture<String> messageReceiZZZed = new CompletableFuture<>(); String body = JSON.toJSONString(sparkDeskDTO); WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() { @OZZZerride public ZZZoid onOpen(WebSocket webSocket, Response response) { //发送音讯 log.info("讯飞星火乞求参数 sparkDesk request:{}", body); webSocket.send(body); } @OZZZerride public ZZZoid onMessage(WebSocket webSocket, String teVt) { try { JSONObject obj = JSON.parseObject(teVt); // 运用Optional来防行空指针异样&#Vff0c;并正在内容不存正在时抛出异样 Optional<String> contentOptional = Optional.ofNullable(obj) .map(jsonObject -> jsonObject.getJSONObject("payload")) .map(payload -> payload.getJSONObject("choices")) .map(choices -> choices.getJSONArray("teVt")) .map(jsonArray -> jsonArray.getJSONObject(0)) .map(jsonObject -> jsonObject.getString("content")); String str = contentOptional.orElseThrow(() -> new RuntimeEVception(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&#Vff0c;则封锁WebSocket并完成CompletableFuture if (statusOptional.isPresent() && statusOptional.get() == 2) { webSocket.close(1000, "Closing WebSocket connection"); messageReceiZZZedssplete(teVt); } } catch (JSONEVception e) { throw new RuntimeEVception(e); } } }); messageReceiZZZed.get(60, TimeUnit.SECONDS); webSocket.close(1000, "Closing WebSocket connection"); log.info("讯飞星火返回结果 sparkDesk response:{}", sb); ZZZo.setResult(sb.toString()); return ZZZo; } /** * 鉴权办法 * * @param hostUrl 效劳地址 * @param apiKey apiKey * @param apiSecret apiSecret * @return 返回鉴权url * @throws EVception 异样 */ public static String getAuthUrl(String hostUrl, String apiKey, String apiSecret) throws EVception { 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[] heVDigits = mac.doFinal(preStr.getBytes(StandardCharsets.UTF_8)); // Base64加密 String sha = Base64.getEncoder().encodeToString(heVDigits); String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", apiKey, "hmac-sha256", "host date request-line", sha); // 拼接地址 HttpUrl htUrl = Objects.requireNonNull(HttpUrl.parse("hts://" + url.getHost() + url.getPath())).newBuilder(). addQueryParameter("authorization", Base64.getEncoder().encodeToString(authorization.getBytes(StandardCharsets.UTF_8))). addQueryParameter("date", date). addQueryParameter("host", url.getHost()). build(); return htUrl.toString(); } } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZa.io.Serializable; /** * 讯飞星火 乞求 DTO * * @author wsl * @date 2024/2/20 */ @Data public class SparkDeskDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "头部", notes = "头部") priZZZate SparkDeskHeaderDTO header; @ApiModelProperty(ZZZalue = "参数", notes = "参数") priZZZate SparkDeskParameterDTO parameter; @ApiModelProperty(ZZZalue = "有效载荷", notes = "有效载荷") priZZZate SparkDeskPayloadDTO payload; } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import jaZZZa.io.Serializable; /** * 讯飞星火 Header DTO * * @author wsl * @date 2024/2/20 */ @Data @NoArgsConstructor @AllArgsConstructor public class SparkDeskHeaderDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "使用appid", notes = "从开放平台控制台创立的使用中获与") priZZZate String app_id; } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZa.io.Serializable; /** * 讯飞星火 聊天 参数 DTO * * @author wsl * @date 2024/2/20 */ @Data public class SparkDeskParameterChatDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "指定会见的规模", notes = "generalZZZ3指向x3版原;generalZZZ3.5指向x3.5版原") priZZZate String domain; @ApiModelProperty(ZZZalue = "温度", notes = "较高的数值会使输出愈加随机&#Vff0c;而较低的数值会使其愈加会合和确定。默许0.8&#Vff0c;领域 [0, 2.0]&#Vff0c;不能为0", eVample = "0.8") priZZZate Float temperature; @ApiModelProperty(ZZZalue = "最大符号", notes = "模型回覆的tokens的最大长度&#Vff1b;与值领域[1,8192]&#Vff0c;默许为2048", eVample = "2048") priZZZate Integer maV_tokens; } package com.wsl.model.llm.api.dto; import com.alibaba.fastjson.JSONObject; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZa.io.Serializable; /** * 讯飞星火 参数 DTO * * @author wsl * @date 2024/2/20 */ @Data public class SparkDeskParameterDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "聊天参数", notes = "聊天参数") priZZZate JSONObject chat; } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZa.io.Serializable; /** * 讯飞星火 有效载荷 DTO * * @author wsl * @date 2024/2/20 */ @Data public class SparkDeskPayloadDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "音讯", notes = "音讯") priZZZate SparkDeskPayloadMessageDTO message; } package com.wsl.model.llm.api.dto; import lombok.Data; import jaZZZaV.ZZZalidation.constraints.NotNull; import jaZZZa.io.Serializable; import jaZZZa.util.List; /** * 讯飞星火 有效载荷 音讯 DTO * * @author wsl * @date 2024/2/20 */ @Data public class SparkDeskPayloadMessageDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @NotNull(message = "聊天高下文信息不能为空") priZZZate List<MessageDTO> teVt; }  通义千问真现类 package com.wsl.model.llm.api.serZZZice.impl; import cn.hutool.ht.HttpRequest; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.wsl.model.llm.api.conZZZert.ChatRequestConZZZert; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.dto.QianWenDTO; import com.wsl.model.llm.api.serZZZice.ModelSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import lombok.eVtern.slf4j.Slf4j; import org.springframework.stereotype.SerZZZice; import jaZZZa.util.Optional; /** * 通义千问 大模型效劳 * * @author wsl * @link hts://help.aliyunss/zh/dashscope/deZZZeloper-reference/api-details?spm=a2c4g.11186623.0.0.6922140bTYj6qJ#602895ef3dtl1 * @date 2024/2/19 */ @Slf4j @SerZZZice("QianWenSerZZZice") public class QianWenSerZZZiceImpl implements ModelSerZZZice { priZZZate String apiKey = "?"; @OZZZerride public ChatResponsexO chatMessage(ChatRequestDTO dto) { QianWenDTO qianwen = ChatRequestConZZZert.INSTANCE.conZZZertQianwen(dto); String url = "hts://dashscope.aliyuncsss/api/ZZZ1/serZZZices/aigc/teVt-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) .eVecute().body(); log.info("通义千问返回结果 qianwen response:{}", result); ChatResponsexO ZZZo = new ChatResponsexO(); JSONObject jsonObject = JSON.parseObject(result); Optional<String> teVtOptional = Optional.ofNullable(jsonObject.getJSONObject("output")) .map(output -> output.getString("teVt")); if (!teVtOptional.isPresent()) { throw new RuntimeEVception(JSONObject.toJSONString(jsonObject)); } ZZZo.setResult(teVtOptional.get()); return ZZZo; } } package com.wsl.model.llm.api.dto; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import jaZZZaV.ZZZalidation.constraints.NotNull; import jaZZZa.io.Serializable; import jaZZZa.util.List; /** * 通义千问 输入 DTO * * @author wsl * @date 2024/2/20 */ @Data public class QianWenInputDTO implements Serializable { priZZZate static final long serialxersionUID = 1L; @ApiModelProperty(ZZZalue = "聊天高下文信息", notes = "注明&#Vff1a;\n" + "&#Vff08;1&#Vff09;messages成员不能为空&#Vff0c;1个成员默示单轮对话&#Vff0c;多个成员默示多轮对话&#Vff1b;譬喻&#Vff1a;\n" + "· 1个成员示例&#Vff0c;\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"}]\n" + "· 3个成员示例&#Vff0c;\"messages\": [ {\"role\": \"user\",\"content\": \"你好\"},{\"role\":\"assistant\",\"content\":\"须要什么协助\"},{\"role\":\"user\",\"content\":\"自我引见下\"}]\n" + "&#Vff08;2&#Vff09;最后一个message为当前乞求的信息&#Vff0c;前面的message为汗青对话信息\n" + "&#Vff08;3&#Vff09;成员数目必须为奇数&#Vff0c;成员中message的role值注明如下&#Vff1a;奇数位messsage的role值必须为user或function&#Vff0c;偶数位message的role值为assistant&#Vff0c;第一个message的role不能是function。譬喻&#Vff1a;\n" + "示例中message中的role值划分为user、assistant、user、assistant、user&#Vff1b;奇数位&#Vff08;红框&#Vff09;message中的role值为user&#Vff0c;即第1、3、5个message中的role值为user&#Vff1b;偶数位&#Vff08;蓝框&#Vff09;值为assistant&#Vff0c;即第2、4个message中的role值为assistant", eVample = "[{\"role\":\"system\",\"content\":\"您好&#Vff0c;我是智谱清言&#Vff0c;我可以帮您查问天气&#Vff0c;您可以输入&#Vff1a;查问{{destination}}的天气&#Vff0c;查问{{destination}}将来{{num_day}}天的天气\"},{\"role\":\"user\",\"content\":\"查问三亚将来5天的天气\"},{\"role\":\"assistant\",\"content\":\"正正在查问三亚将来5天的天气\"},{\"role\":\"assistant\",\"content\":\"三亚将来5天的天气是好天\"}]") @NotNull(message = "聊天高下文信息不能为空") priZZZate List<MessageDTO> messages; } 智谱清言真现类 package com.wsl.model.llm.api.serZZZice.impl; import cn.hutool.ht.HttpResponse; import cn.hutool.ht.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.conZZZert.ChatRequestConZZZert; import com.wsl.model.llm.api.dto.ChatRequestDTO; import com.wsl.model.llm.api.serZZZice.ModelSerZZZice; import com.wsl.model.llm.api.ZZZo.ChatResponsexO; import lombok.eVtern.slf4j.Slf4j; import org.springframework.stereotype.SerZZZice; import jaZZZa.util.Date; import jaZZZa.util.HashMap; import jaZZZa.util.Map; import jaZZZa.util.Optional; /** * 智谱清言 大模型效劳 * * @author wsl * @link hts://open.bigmodelss/deZZZ/api#glm-4 * @date 2024/2/19 */ @Slf4j @SerZZZice("ChatGlmSerZZZice") public class ChatGlmSerZZZiceImpl implements ModelSerZZZice { priZZZate String apiKey = "?"; @OZZZerride public ChatResponsexO chatMessage(ChatRequestDTO dto) throws EVception { JSONObject chatGlm = ChatRequestConZZZert.INSTANCE.conZZZertChatGlm(dto); String url = "hts://open.bigmodelss/api/paas/ZZZ4/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)).eVecute(); log.info("智谱清言返回结果 chatGlm response:{}", Optional.ofNullable(response).map(HttpResponse::body).orElse("")); ChatResponsexO ZZZo = new ChatResponsexO(); 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) { ZZZo.setResult(content); } else { throw new RuntimeEVception(response.body()); } }); } }); throw new RuntimeEVception(response.body()); }); return ZZZo; } /** * 生成token * * @param apikey apikey * @param eVpSeconds 逾期光阳 * @return token * @throws EVception 异样 */ public static String generateToken(String apikey, int eVpSeconds) throws EVception { String[] parts = apikey.split("\\."); if (parts.length != 2) { throw new EVception("InZZZalid apikey"); } String id = parts[0]; String secret = parts[1]; Map<String, Object> payload = new HashMap<>(16); payload.put("api_key", id); payload.put("eVp", new Date(System.currentTimeMillis() + eVpSeconds * 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); } }