diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java index 79b2e662c..16e424c95 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/http/HttpUtils.java @@ -12,6 +12,9 @@ import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import javax.servlet.http.HttpServletRequest; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; import java.nio.charset.Charset; import java.util.Map; @@ -142,6 +145,14 @@ public class HttpUtils { return response.body(); } } + public static InputStream postStream(String url, Map headers, String requestBody) { + try (HttpResponse response = HttpRequest.post(url) + .addHeaders(headers) + .body(requestBody) + .execute()) { + return response.bodyStream(); + } + } public static String postForm(String url, Map headers, Map form) { try (HttpResponse response = HttpRequest.post(url) diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatReqVO.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatReqVO.java index bb578fb9d..7d20ca342 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatReqVO.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatReqVO.java @@ -24,4 +24,6 @@ public class ChatReqVO { private String prompt; @Schema(description = "对话ID", requiredMode = Schema.RequiredMode.REQUIRED) private String uuid; + @Schema(description = "系统提示语") + private String systemPrompt; } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/framework/backend/config/LLMBackendProperties.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/framework/backend/config/LLMBackendProperties.java index f8369ed8f..de3761acf 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/framework/backend/config/LLMBackendProperties.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/framework/backend/config/LLMBackendProperties.java @@ -90,4 +90,6 @@ public class LLMBackendProperties { private String modelFileList; private String modelFileDownload; + + private String aigcModelCompletions; } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationServiceImpl.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationServiceImpl.java index c8d99b27c..83acb85c2 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationServiceImpl.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationServiceImpl.java @@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.llm.service.conversation; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.module.llm.controller.admin.datarefluxdata.vo.DataRefluxDataSaveReqVO; import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO; +import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO; +import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper; import cn.iocoder.yudao.module.llm.service.basemodel.BaseModelService; import cn.iocoder.yudao.module.llm.service.datarefluxdata.DataRefluxDataService; import cn.iocoder.yudao.module.llm.service.http.ModelService; @@ -28,6 +30,7 @@ import cn.iocoder.yudao.module.llm.dal.mysql.conversation.ConversationMapper; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.llm.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.module.llm.service.http.ModelService.PRIVATE_MODEL_ID; /** * 大模型对话记录 Service 实现类 @@ -48,6 +51,8 @@ public class ConversationServiceImpl implements ConversationService { private BaseModelService baseModelService; @Resource private DataRefluxDataService dataRefluxDataService; + @Resource + private ModelServiceMapper modelServiceMapper; // 聊天会话历史记录缓存Key private final static String CHAT_HIStORY_REDIS_KEY = "llm:chat:history"; @@ -98,6 +103,20 @@ public class ConversationServiceImpl implements ConversationService { @Override public ChatRespVO chat(ChatReqVO chatReqVO) { + if (Objects.equals(1, chatReqVO.getModelType())){ + return publicModelChat(chatReqVO); + }else { + return privateModelChat(chatReqVO); + } + } + + + /** + * 公共模型聊天 + * @param chatReqVO + * @return + */ + public ChatRespVO publicModelChat(ChatReqVO chatReqVO) { if (StringUtils.isBlank(chatReqVO.getUuid())) { // 如果没有uuid,就生成一个 chatReqVO.setUuid(UUID.randomUUID().toString()); @@ -143,4 +162,70 @@ public class ConversationServiceImpl implements ConversationService { dataRefluxDataService.saveDataRefluxData(dataRefluxDataSaveReqVO); return chatRespVO; } + /** + * 私有模型聊天 + * @param chatReqVO + * @return + */ + private ChatRespVO privateModelChat(ChatReqVO chatReqVO) { + if (StringUtils.isBlank(chatReqVO.getUuid())) { + // 如果没有uuid,就生成一个 + chatReqVO.setUuid(UUID.randomUUID().toString()); + } + String model = null; + if (Objects.equals(0, chatReqVO.getModelType())) { + // 模型管理 + ModelServiceDO modelServiceDO = modelServiceMapper.selectById(chatReqVO.getModelId()); + if (modelServiceDO == null) { + throw exception(MODEL_SERVICE_NOT_EXISTS); + } + model = modelServiceDO.getServiceName(); + } + ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage(); + message.setRole("user"); + message.setContent(chatReqVO.getPrompt()); + + List messageHistoryList = stringRedisTemplate.opsForList().range(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), 0, -1); + List messages = new ArrayList<>(); + if (messageHistoryList != null && !messageHistoryList.isEmpty()) { + for (String messageHistory : messageHistoryList) { + ModelCompletionsReqVO.ModelCompletionsMessage modelCompletionsMessage = JsonUtils.parseObject(messageHistory, ModelCompletionsReqVO.ModelCompletionsMessage.class); + if (modelCompletionsMessage.getRole().equals("system")){ + modelCompletionsMessage.setContent(StringUtils.isNotBlank(chatReqVO.getSystemPrompt())? chatReqVO.getSystemPrompt():""); + stringRedisTemplate.opsForList().set(CHAT_HIStORY_REDIS_KEY+ ":" + chatReqVO.getUuid(), 0, JsonUtils.toJsonString(modelCompletionsMessage)); + } + messages.add(modelCompletionsMessage); + } + }else { + ModelCompletionsReqVO.ModelCompletionsMessage systemMessage = new ModelCompletionsReqVO.ModelCompletionsMessage(); + systemMessage.setRole("system"); + systemMessage.setContent(StringUtils.isNotBlank(chatReqVO.getSystemPrompt())? chatReqVO.getSystemPrompt():""); + stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(systemMessage)); + messages.add(systemMessage); + } + messages.add(message); + ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO(); + modelCompletionsReqVO.setMessages(messages); + // TODO 先传固定的内容 后期和后端调通直接修改成 model + modelCompletionsReqVO.setModel(PRIVATE_MODEL_ID); + ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelPrivateCompletions(new HashMap<>(),modelCompletionsReqVO); + if (modelCompletionsRespVO == null) { + throw exception(MODEL_COMPLETIONS_ERROR); + } + ChatRespVO chatRespVO = BeanUtils.toBean(chatReqVO, ChatRespVO.class); + chatRespVO.setResponse(modelCompletionsRespVO.getAnswer()); + stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(message)); + ModelCompletionsReqVO.ModelCompletionsMessage responseMessage = new ModelCompletionsReqVO.ModelCompletionsMessage(); + responseMessage.setRole("assistant"); + responseMessage.setContent(modelCompletionsRespVO.getAnswer()); + stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(responseMessage)); + DataRefluxDataSaveReqVO dataRefluxDataSaveReqVO = new DataRefluxDataSaveReqVO(); + dataRefluxDataSaveReqVO.setModelServiceId(chatReqVO.getModelId()); + dataRefluxDataSaveReqVO.setModelType(chatReqVO.getModelType()); + dataRefluxDataSaveReqVO.setPrompt(chatReqVO.getPrompt()); + dataRefluxDataSaveReqVO.setResponse(modelCompletionsRespVO.getAnswer()); + dataRefluxDataSaveReqVO.setSystem(modelCompletionsRespVO.getSystem()); + dataRefluxDataService.saveDataRefluxData(dataRefluxDataSaveReqVO); + return chatRespVO; + } } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/ModelService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/ModelService.java index 1ce21f2ab..5083a8359 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/ModelService.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/ModelService.java @@ -6,11 +6,17 @@ import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties import cn.iocoder.yudao.module.llm.service.http.vo.*; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.util.List; import java.util.Map; @@ -19,9 +25,12 @@ import java.util.Map; public class ModelService { public final static String DEFAULT_MODEL_ID = "qwen2.5-instruct"; + public final static String PRIVATE_MODEL_ID = "llama3.1"; @Resource private LLMBackendProperties llmBackendProperties; + @Resource + private TrainHttpService trainHttpService; /** * 获取模型列表 @@ -87,4 +96,42 @@ public class ModelService { return JSONArray.parseArray(res, String.class); } + public ModelCompletionsRespVO modelPrivateCompletions(Map headers,ModelCompletionsReqVO req) { + trainHttpService.login(headers); + if (StringUtils.isBlank(req.getModel())) { + req.setModel(PRIVATE_MODEL_ID); + } + log.info("url: {}", llmBackendProperties.getAigcModelCompletions()); + log.info("request: {}", req); +/* String result = HttpUtils.postStream(llmBackendProperties.getAigcModelCompletions(), headers, JSON.toJSONString(req)); + log.info("response: {}", result); + if (StringUtils.isBlank(result)) { + return null; + }*/ + try { + StringBuilder fullContent = new StringBuilder(); + try (InputStream inputStream = HttpUtils.postStream(llmBackendProperties.getAigcModelCompletions(), headers, JSON.toJSONString(req)); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + String line; + while ((line = reader.readLine()) != null) { + JSONObject jsonObject = JSON.parseObject(line); + if (jsonObject.getBoolean("success")) { + AigcRespChatVO aigcRespVO = jsonObject.toJavaObject(AigcRespChatVO.class); + if (aigcRespVO.getData().size() != 0) { + AigcChatCompletion chatCompletion = aigcRespVO.getData().get(aigcRespVO.getData().size() - 1); + fullContent.append(chatCompletion.getContent()); + } + } + } + } + ModelCompletionsRespVO respVO = new ModelCompletionsRespVO(); + respVO.setSystem("助手"); + respVO.setQuestion(req.getMessages().get(req.getMessages().size() - 1).getContent()); + respVO.setAnswer(fullContent.toString()); + return respVO; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcChatCompletion.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcChatCompletion.java new file mode 100644 index 000000000..6506a41e6 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcChatCompletion.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.llm.service.http.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AigcChatCompletion { + /** + * 聊天返回内容 + */ + private String fullContent; + private String content; + private String createAt; + private String finishReason; + private String contentType; + private String messageId; + private String model; + private Integer topP; + private Integer temperature; + private Integer maxTokens; +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcRespChatVO.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcRespChatVO.java new file mode 100644 index 000000000..f9641042c --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/http/vo/AigcRespChatVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.llm.service.http.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AigcRespChatVO { + + private boolean success; + private int code; + private List data; + private String message; + private String traceId; +} diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml index 964f8b0d5..c17f0a8f4 100644 --- a/yudao-server/src/main/resources/application-dev.yaml +++ b/yudao-server/src/main/resources/application-dev.yaml @@ -259,6 +259,8 @@ llm: model_completions: http://api.xhllm.xinnuojinzhi.com/model/v1/chat/completions # aigc表数据查询接口 table_data_query: http://36.133.1.230:5123/table/%s + # aigc模型推理 + aigc_model_completions: http://36.133.1.230:8080/api/channels/chat/completions application_api: http://localhost:48100/admin-app/llm/application/api/apiKey/chat diff --git a/yudao-server/src/main/resources/application-local.yaml b/yudao-server/src/main/resources/application-local.yaml index 1c2d5353e..99c5c4c44 100644 --- a/yudao-server/src/main/resources/application-local.yaml +++ b/yudao-server/src/main/resources/application-local.yaml @@ -301,6 +301,8 @@ llm: model_completions: http://api.xhllm.xinnuojinzhi.com/model/v1/chat/completions # aigc表数据查询接口 table_data_query: http://36.133.1.230:5123/table/%s + # aigc模型推理 + aigc_model_completions: http://36.133.1.230:8080/api/channels/chat/completions application_api: http://localhost:48080/admin-app/llm/application/api/apiKey/chat