diff --git a/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ErrorCodeConstants.java b/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ErrorCodeConstants.java index fb622efdc..830b6bc0e 100644 --- a/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ErrorCodeConstants.java +++ b/yudao-module-llm/yudao-module-llm-api/src/main/java/cn/iocoder/yudao/module/llm/enums/ErrorCodeConstants.java @@ -71,4 +71,6 @@ public interface ErrorCodeConstants { ErrorCode TRAINING_NOT_EXISTS = new ErrorCode(10029, "训练不存在"); + ErrorCode MODEL_COMPLETIONS_ERROR = new ErrorCode(10030, "模型推理失败"); + } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/basemodel/BaseModelController.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/basemodel/BaseModelController.java index b6ad1fc87..b987e9ba8 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/basemodel/BaseModelController.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/basemodel/BaseModelController.java @@ -85,7 +85,7 @@ public class BaseModelController { @Operation(summary = "获得基座模型") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('llm:base-model:query')") - public CommonResult getBaseModel(@RequestParam("id") Integer id) { + public CommonResult getBaseModel(@RequestParam("id") Long id) { BaseModelDO baseModel = baseModelService.getBaseModel(id); return success(BeanUtils.toBean(baseModel, BaseModelRespVO.class)); } @@ -94,7 +94,7 @@ public class BaseModelController { @Operation(summary = "获取参数模板") @Parameter(name = "id", description = "编号", required = true, example = "1024") @PreAuthorize("@ss.hasPermission('llm:base-model:query')") - public CommonResult getParamModel(@RequestParam("id") Integer id) { + public CommonResult getParamModel(@RequestParam("id") Long id) { BaseModelDO baseModel = baseModelService.getBaseModel(id); //todo 获取参数模板api return success(new JSONObject()); diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/ConversationController.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/ConversationController.java index 2096f9a2e..787c34b61 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/ConversationController.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/ConversationController.java @@ -92,4 +92,9 @@ public class ConversationController { BeanUtils.toBean(list, ConversationRespVO.class)); } + @PostMapping("/chat") + @Operation(summary = "对话推理接口") + public CommonResult chat(@Valid @RequestBody ChatReqVO chatReqVO) { + return success(conversationService.chat(chatReqVO)); + } } \ No newline at end of file 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 new file mode 100644 index 000000000..49415091c --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatReqVO.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.llm.controller.admin.conversation.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 大模型对话推理聊天 Request VO") +@Data +public class ChatReqVO { + + @Schema(description = "模型类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "模型类型不能为空") + private Integer modelType; + @Schema(description = "模型ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "模型ID不能为空") + private Long modelId; + @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "应用ID不能为空") + private Long applicationId; + @Schema(description = "对话的内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "对话的内容不能为空") + private String prompt; + @Schema(description = "对话ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String uuid; +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatRespVO.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatRespVO.java new file mode 100644 index 000000000..ec42463e8 --- /dev/null +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/controller/admin/conversation/vo/ChatRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.llm.controller.admin.conversation.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; + +@Schema(description = "管理后台 - 大模型对话推理聊天 Response VO") +@Data +public class ChatRespVO { + + @Schema(description = "对话ID", requiredMode = Schema.RequiredMode.REQUIRED) + private String uuid; + @Schema(description = "模型类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "模型类型不能为空") + private Integer modelType; + @Schema(description = "模型ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "模型ID不能为空") + private Long modelId; + @Schema(description = "应用ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "应用ID不能为空") + private Long applicationId; + @Schema(description = "对话的内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "对话的内容不能为空") + private String prompt; + @Schema(description = "回答的内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "回答的内容不能为空") + private String response; + +} diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelService.java index 8eec53a09..e469fdaa5 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelService.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelService.java @@ -42,7 +42,7 @@ public interface BaseModelService { * @param id 编号 * @return 基座模型 */ - BaseModelDO getBaseModel(Integer id); + BaseModelDO getBaseModel(Long id); /** * 获得基座模型分页 diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelServiceImpl.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelServiceImpl.java index a98823cc5..69d7e5cea 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelServiceImpl.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/basemodel/BaseModelServiceImpl.java @@ -63,7 +63,7 @@ public class BaseModelServiceImpl implements BaseModelService { } @Override - public BaseModelDO getBaseModel(Integer id) { + public BaseModelDO getBaseModel(Long id) { return baseModelMapper.selectById(id); } diff --git a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationService.java b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationService.java index f1cdabc6b..2e3072cb8 100644 --- a/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationService.java +++ b/yudao-module-llm/yudao-module-llm-biz/src/main/java/cn/iocoder/yudao/module/llm/service/conversation/ConversationService.java @@ -52,4 +52,5 @@ public interface ConversationService { */ PageResult getConversationPage(ConversationPageReqVO pageReqVO); + ChatRespVO chat(@Valid ChatReqVO chatReqVO); } \ No newline at end of file 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 294aa64f4..e99b0376f 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 @@ -1,11 +1,21 @@ package cn.iocoder.yudao.module.llm.service.conversation; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO; +import cn.iocoder.yudao.module.llm.service.basemodel.BaseModelService; +import cn.iocoder.yudao.module.llm.service.http.ModelService; +import cn.iocoder.yudao.module.llm.service.http.vo.ModelCompletionsReqVO; +import cn.iocoder.yudao.module.llm.service.http.vo.ModelCompletionsRespVO; +import com.alibaba.excel.util.StringUtils; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; import org.springframework.validation.annotation.Validated; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.concurrent.TimeUnit; + import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.*; import cn.iocoder.yudao.module.llm.dal.dataobject.conversation.ConversationDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -28,6 +38,17 @@ public class ConversationServiceImpl implements ConversationService { @Resource private ConversationMapper conversationMapper; + @Resource + private StringRedisTemplate stringRedisTemplate; + @Resource + private ModelService modelService; + @Resource + private BaseModelService baseModelService; + + // 聊天会话历史记录缓存Key + private final static String CHAT_HIStORY_REDIS_KEY = "llm:chat:history"; + // 聊天会话历史记录缓存时间 + private final static Long CHAT_HISTORY_REDIS_EXPIRE_SECONDS = 60 * 60 * 24L; @Override public Integer createConversation(ConversationSaveReqVO createReqVO) { @@ -71,4 +92,41 @@ public class ConversationServiceImpl implements ConversationService { return conversationMapper.selectPage(pageReqVO); } + @Override + public ChatRespVO chat(ChatReqVO chatReqVO) { + if (StringUtils.isBlank(chatReqVO.getUuid())) { + // 如果没有uuid,就生成一个 + chatReqVO.setUuid(UUID.randomUUID().toString()); + } + String model = null; + if (Objects.equals(1, chatReqVO.getModelType())) { + // 预制模型 + BaseModelDO baseModelDO = baseModelService.getBaseModel(chatReqVO.getModelId()); + if (baseModelDO == null) { + throw exception(BASE_MODEL_NOT_EXISTS); + } + model = baseModelDO.getModelName(); + } + ModelCompletionsReqVO.ModelCompletionsMessage message = new ModelCompletionsReqVO.ModelCompletionsMessage(); + message.setRole("user"); + message.setContent(chatReqVO.getPrompt()); + // TODO: 聊天推理 + 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) { + messages.add(JsonUtils.parseObject(messageHistory, ModelCompletionsReqVO.ModelCompletionsMessage.class)); + } + } + messages.add(message); + ModelCompletionsReqVO modelCompletionsReqVO = new ModelCompletionsReqVO(); + modelCompletionsReqVO.setMessages(messages); + modelCompletionsReqVO.setModel(model); + ModelCompletionsRespVO modelCompletionsRespVO = modelService.modelCompletions(modelCompletionsReqVO); + if (modelCompletionsRespVO == null) { + throw exception(MODEL_COMPLETIONS_ERROR); + } + stringRedisTemplate.opsForList().rightPush(CHAT_HIStORY_REDIS_KEY + ":" + chatReqVO.getUuid(), JsonUtils.toJsonString(message)); + return null; + } } \ No newline at end of file