From 52cb5633839f2edb36ffa647de42141de87bc129 Mon Sep 17 00:00:00 2001 From: ageer <ageerle@163.com> Date: 星期一, 21 四月 2025 20:16:53 +0800 Subject: [PATCH] fix(1.修复/store/appList404 2.修复无法查询数据库 3.修复请求地址'/chat/config/configKey/logoImage',发生系统异常): --- ruoyi-admin/src/main/resources/mcp-server.json | 2 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java | 64 +++++ ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IChatConfigService.java | 6 ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatStoreController.java | 44 +++ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java | 2 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java | 16 + /dev/null | 120 ---------- ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatConfigController.java | 26 ++ ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java | 232 +++++++++++++++++++ ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/ChatConfigServiceImpl.java | 14 + ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java | 154 ++++++++++++ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoUploadBo.java | 16 + ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java | 14 + ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java | 1 14 files changed, 588 insertions(+), 123 deletions(-) diff --git a/ruoyi-admin/src/main/resources/mcp-server.json b/ruoyi-admin/src/main/resources/mcp-server.json index ab8ad18..36fef0e 100644 --- a/ruoyi-admin/src/main/resources/mcp-server.json +++ b/ruoyi-admin/src/main/resources/mcp-server.json @@ -5,7 +5,7 @@ "args": [ "-y", "@modelcontextprotocol/server-filesystem", - "D:\\software" + "D:\\test" ] }, "search1api": { diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java index c5c4052..fae1b65 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/KnowledgeFragment.java @@ -45,7 +45,7 @@ /** * 鐗囨绱㈠紩涓嬫爣 */ - private Long idx; + private Integer idx; /** * 鏂囨。鍐呭 diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoUploadBo.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoUploadBo.java new file mode 100644 index 0000000..d576b59 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/bo/KnowledgeInfoUploadBo.java @@ -0,0 +1,16 @@ +package org.ruoyi.domain.bo; + +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; + +/** + * @author ageer + */ +@Data +public class KnowledgeInfoUploadBo { + + private String kid; + + private MultipartFile file; + +} diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java index ee3640b..6a3fca8 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeAttachService.java @@ -5,6 +5,7 @@ import org.ruoyi.domain.vo.KnowledgeAttachVo; import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.core.page.PageQuery; +import org.springframework.web.multipart.MultipartFile; import java.util.Collection; import java.util.List; @@ -46,4 +47,17 @@ * 鏍¢獙骞舵壒閲忓垹闄ょ煡璇嗗簱闄勪欢淇℃伅 */ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); + + /** + * 鍒犻櫎鐭ヨ瘑闄勪欢 + */ + void removeKnowledgeAttach(String docId); + + /** + * 缈昏瘧鏂囦欢 + * + * @param file 鏂囦欢 + * @param targetLanguage 鐩爣璇煶 + */ + String translationByFile(MultipartFile file, String targetLanguage); } diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java index 4619d1d..79ce870 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/IKnowledgeInfoService.java @@ -2,6 +2,7 @@ import org.ruoyi.domain.bo.KnowledgeInfoBo; +import org.ruoyi.domain.bo.KnowledgeInfoUploadBo; import org.ruoyi.domain.vo.KnowledgeInfoVo; import org.ruoyi.core.page.TableDataInfo; import org.ruoyi.core.page.PageQuery; @@ -46,4 +47,19 @@ * 鏍¢獙骞舵壒閲忓垹闄ょ煡璇嗗簱淇℃伅 */ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); + + /** + * 鏂板鐭ヨ瘑搴� + */ + void saveOne(KnowledgeInfoBo bo); + + /** + * 鍒犻櫎鐭ヨ瘑搴� + */ + void removeKnowledge(String id); + + /** + * 涓婁紶闄勪欢 + */ + void upload(KnowledgeInfoUploadBo bo); } diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java index a219462..46869cb 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeAttachServiceImpl.java @@ -9,13 +9,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import org.ruoyi.domain.vo.KnowledgeAttachVo; +import org.ruoyi.mapper.KnowledgeFragmentMapper; import org.springframework.stereotype.Service; import org.ruoyi.domain.bo.KnowledgeAttachBo; import org.ruoyi.domain.KnowledgeAttach; import org.ruoyi.mapper.KnowledgeAttachMapper; import org.ruoyi.service.IKnowledgeAttachService; +import org.springframework.web.multipart.MultipartFile; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Collection; @@ -31,6 +34,7 @@ public class KnowledgeAttachServiceImpl implements IKnowledgeAttachService { private final KnowledgeAttachMapper baseMapper; + private final KnowledgeFragmentMapper fragmentMapper; /** * 鏌ヨ鐭ヨ瘑搴撻檮浠� @@ -111,4 +115,64 @@ } return baseMapper.deleteBatchIds(ids) > 0; } + + @Override + public void removeKnowledgeAttach(String docId) { + Map<String,Object> map = new HashMap<>(); + map.put("doc_id",docId); + baseMapper.deleteByMap(map); + fragmentMapper.deleteByMap(map); + } + + @Override + public String translationByFile(MultipartFile file, String targetLanguage) { + /*String fileName = file.getOriginalFilename(); + String docType = fileName.substring(fileName.lastIndexOf(".")+1); + String content = ""; + ResourceLoader resourceLoader = resourceLoaderFactory.getLoaderByFileType(docType); + try { + content = resourceLoader.getContent(file.getInputStream()); + } catch (IOException e) { + throw new BaseException("璇ユ枃浠剁被鍨嬫殏涓嶆敮鎸侊紒"); + } + // 缈昏瘧妯″瀷鍥哄畾涓篻pt-4o-mini + String model = "gpt-4o-mini"; + ChatMessageBo chatMessageBo = new ChatMessageBo(); + chatMessageBo.setUserId(getUserId()); + chatMessageBo.setModelName(model); + chatMessageBo.setContent(content); + chatMessageBo.setDeductCost(0.01); + chatMessageBo.setTotalTokens(0); + OpenAiStreamClient openAiStreamClient = chatConfig.getOpenAiStreamClient(); + List<Message> messageList = new ArrayList<>(); + Message sysMessage = Message.builder().role(Message.Role.SYSTEM).content("浣犳槸涓�浣嶇簿閫氬悇鍥借瑷�鐨勭炕璇戝ぇ甯圽n" + + "\n" + + "璇峰皢鐢ㄦ埛杈撳叆璇嶈缈昏瘧鎴恵" + targetLanguage + "}\n" + + "\n" + + "==绀轰緥杈撳嚭==\n" + + "**鍘熸枃** : <杩欓噷鏄剧ず瑕佺炕璇戠殑鍘熸枃淇℃伅>\n" + + "**缈昏瘧** : <杩欓噷鏄剧ず缈昏瘧涔嬪悗鐨勭粨鏋�>\n" + + "**鎬荤粨** : <杩欓噷鏄鍏抽敭淇℃伅涓�涓�荤粨>\n" + + "**鎻愬彇鐨勫叧閿俊鎭�** : <杩欓噷杩斿洖鍏抽敭淇℃伅>\n" + + "==绀轰緥缁撴潫==\n" + + "\n" + + "娉ㄦ剰锛氳涓ユ牸鎸夌ず渚嬭繘琛岃緭鍑猴紝杩斿洖markdown鏍煎紡").build(); + messageList.add(sysMessage); + Message message = Message.builder().role(Message.Role.USER).content(content).build(); + messageList.add(message); + ChatCompletionResponse chatCompletionResponse = null; + try { + ChatCompletion chatCompletion = ChatCompletion + .builder() + .messages(messageList) + .model(model) + .stream(false) + .build(); + chatCompletionResponse = openAiStreamClient.chatCompletion(chatCompletion); + }catch (Exception e) { + throw new BaseException("璋冪敤澶фā鍨嬪け璐ワ紝璇锋鏌ュ瘑閽ユ槸鍚︽纭紒"); + } + return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString();*/ + return "鎺ュ彛寮�鍙戜腑!"; + } } diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeInfoServiceImpl.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeInfoServiceImpl.java deleted file mode 100644 index 254085a..0000000 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/KnowledgeInfoServiceImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.ruoyi.service.impl; - -import org.ruoyi.common.core.utils.MapstructUtils; -import org.ruoyi.common.core.utils.StringUtils; -import org.ruoyi.core.page.TableDataInfo; -import org.ruoyi.core.page.PageQuery; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.Wrappers; -import lombok.RequiredArgsConstructor; -import org.ruoyi.domain.vo.KnowledgeInfoVo; -import org.springframework.stereotype.Service; -import org.ruoyi.domain.bo.KnowledgeInfoBo; -import org.ruoyi.domain.KnowledgeInfo; -import org.ruoyi.mapper.KnowledgeInfoMapper; -import org.ruoyi.service.IKnowledgeInfoService; - -import java.util.List; -import java.util.Map; -import java.util.Collection; - -/** - * 鐭ヨ瘑搴揝ervice涓氬姟灞傚鐞� - * - * @author ageerle - * @date 2025-04-08 - */ -@RequiredArgsConstructor -@Service -public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService { - - private final KnowledgeInfoMapper baseMapper; - - /** - * 鏌ヨ鐭ヨ瘑搴� - */ - @Override - public KnowledgeInfoVo queryById(Long id){ - return baseMapper.selectVoById(id); - } - - /** - * 鏌ヨ鐭ヨ瘑搴撳垪琛� - */ - @Override - public TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery) { - LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo); - Page<KnowledgeInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); - return TableDataInfo.build(result); - } - - /** - * 鏌ヨ鐭ヨ瘑搴撳垪琛� - */ - @Override - public List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo) { - LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo); - return baseMapper.selectVoList(lqw); - } - - private LambdaQueryWrapper<KnowledgeInfo> buildQueryWrapper(KnowledgeInfoBo bo) { - Map<String, Object> params = bo.getParams(); - LambdaQueryWrapper<KnowledgeInfo> lqw = Wrappers.lambdaQuery(); - lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeInfo::getKid, bo.getKid()); - lqw.eq(bo.getUid() != null, KnowledgeInfo::getUid, bo.getUid()); - lqw.like(StringUtils.isNotBlank(bo.getKname()), KnowledgeInfo::getKname, bo.getKname()); - lqw.eq(bo.getShare() != null, KnowledgeInfo::getShare, bo.getShare()); - lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription()); - lqw.eq(StringUtils.isNotBlank(bo.getKnowledgeSeparator()), KnowledgeInfo::getKnowledgeSeparator, bo.getKnowledgeSeparator()); - lqw.eq(StringUtils.isNotBlank(bo.getQuestionSeparator()), KnowledgeInfo::getQuestionSeparator, bo.getQuestionSeparator()); - lqw.eq(bo.getOverlapChar() != null, KnowledgeInfo::getOverlapChar, bo.getOverlapChar()); - lqw.eq(bo.getRetrieveLimit() != null, KnowledgeInfo::getRetrieveLimit, bo.getRetrieveLimit()); - lqw.eq(bo.getTextBlockSize() != null, KnowledgeInfo::getTextBlockSize, bo.getTextBlockSize()); - lqw.eq(StringUtils.isNotBlank(bo.getVector()), KnowledgeInfo::getVector, bo.getVector()); - lqw.eq(StringUtils.isNotBlank(bo.getVectorModel()), KnowledgeInfo::getVectorModel, bo.getVectorModel()); - return lqw; - } - - /** - * 鏂板鐭ヨ瘑搴� - */ - @Override - public Boolean insertByBo(KnowledgeInfoBo bo) { - KnowledgeInfo add = MapstructUtils.convert(bo, KnowledgeInfo.class); - validEntityBeforeSave(add); - boolean flag = baseMapper.insert(add) > 0; - if (flag) { - bo.setId(add.getId()); - } - return flag; - } - - /** - * 淇敼鐭ヨ瘑搴� - */ - @Override - public Boolean updateByBo(KnowledgeInfoBo bo) { - KnowledgeInfo update = MapstructUtils.convert(bo, KnowledgeInfo.class); - validEntityBeforeSave(update); - return baseMapper.updateById(update) > 0; - } - - /** - * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙 - */ - private void validEntityBeforeSave(KnowledgeInfo entity){ - //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫 - } - - /** - * 鎵归噺鍒犻櫎鐭ヨ瘑搴� - */ - @Override - public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { - if(isValid){ - //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠� - } - return baseMapper.deleteBatchIds(ids) > 0; - } -} diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IChatConfigService.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IChatConfigService.java index e99c77a..3f91faf 100644 --- a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IChatConfigService.java +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/IChatConfigService.java @@ -46,4 +46,10 @@ * 鏍¢獙骞舵壒閲忓垹闄ら厤缃俊鎭俊鎭� */ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); + + + /** + * 鏌ヨ绯荤粺鍙傛暟 + */ + List<ChatConfigVo> getSysConfigValue(String category); } diff --git a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/ChatConfigServiceImpl.java b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/ChatConfigServiceImpl.java index b03a288..353dd1c 100644 --- a/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/ChatConfigServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-system-api/src/main/java/org/ruoyi/system/service/impl/ChatConfigServiceImpl.java @@ -129,4 +129,18 @@ return baseMapper.deleteBatchIds(ids) > 0; } + /** + * 鏍规嵁閰嶇疆绫诲瀷鍜岄厤缃甼ey鑾峰彇鍊� + * + * @param category + * @return + */ + @Override + public List<ChatConfigVo> getSysConfigValue(String category) { + ChatConfigBo bo = new ChatConfigBo(); + bo.setCategory(category); + LambdaQueryWrapper<ChatConfig> lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatConfigController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatConfigController.java index e44a083..bf3569b 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatConfigController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatConfigController.java @@ -6,6 +6,7 @@ import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; +import org.ruoyi.common.core.service.ConfigService; import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.idempotent.annotation.RepeatSubmit; import org.ruoyi.core.page.TableDataInfo; @@ -31,10 +32,13 @@ @Validated @RequiredArgsConstructor @RestController -@RequestMapping("/system/chatConfig") +@RequestMapping("/chat/config") public class ChatConfigController extends BaseController { private final IChatConfigService chatConfigService; + + + private final ConfigService configService; /** * 鏌ヨ閰嶇疆淇℃伅鍒楄〃 @@ -102,4 +106,24 @@ @PathVariable Long[] ids) { return toAjax(chatConfigService.deleteWithValidByIds(List.of(ids), true)); } + + /** + * 鏍规嵁鍙傛暟閿悕鏌ヨ绯荤粺鍙傛暟鍊� + * + * @param configKey 鍙傛暟Key + */ + @GetMapping(value = "/configKey/{configKey}") + public R<String> getConfigKey(@PathVariable String configKey) { + return R.ok(configService.getConfigValue("sys",configKey)); + } + + /** + * 鏌ヨ绯荤粺鍙傛暟 + * + */ + @GetMapping(value = "/sysConfigKey") + public R<List<ChatConfigVo>> getSysConfigKey() { + return R.ok(chatConfigService.getSysConfigValue("sys")); + } + } diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatStoreController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatStoreController.java new file mode 100644 index 0000000..3886902 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatStoreController.java @@ -0,0 +1,44 @@ +package org.ruoyi.chat.controller.chat; + +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.domain.bo.ChatAppStoreBo; +import org.ruoyi.domain.vo.ChatAppStoreVo; +import org.ruoyi.service.IChatAppStoreService; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import java.util.List; + + +/** + * 搴旂敤鍟嗗簵 + * + * @author Lion Li + * @date 2024-03-19 + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/store") +public class ChatStoreController extends BaseController { + + private final IChatAppStoreService appStoreService; + + /** + * 搴旂敤鍟嗗簵 + */ + @GetMapping("/appList") + public R<List<ChatAppStoreVo>> appList(ChatAppStoreBo bo) { + return R.ok(appStoreService.queryList(bo)); + } + + /** + * 鏀惰棌搴旂敤 + */ + @PostMapping("/copyApp") + public R<String> copyApp() { + return R.ok(); + } +} diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java new file mode 100644 index 0000000..1a11d01 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java @@ -0,0 +1,154 @@ +package org.ruoyi.chat.controller.knowledge; + +import cn.dev33.satoken.stp.StpUtil; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.common.core.validate.AddGroup; +import org.ruoyi.common.excel.utils.ExcelUtil; +import org.ruoyi.common.log.annotation.Log; +import org.ruoyi.common.log.enums.BusinessType; +import org.ruoyi.common.satoken.utils.LoginHelper; +import org.ruoyi.common.web.core.BaseController; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.domain.bo.KnowledgeAttachBo; +import org.ruoyi.domain.bo.KnowledgeFragmentBo; +import org.ruoyi.domain.bo.KnowledgeInfoBo; +import org.ruoyi.domain.bo.KnowledgeInfoUploadBo; +import org.ruoyi.domain.vo.KnowledgeAttachVo; +import org.ruoyi.domain.vo.KnowledgeFragmentVo; +import org.ruoyi.domain.vo.KnowledgeInfoVo; +import org.ruoyi.service.IKnowledgeAttachService; +import org.ruoyi.service.IKnowledgeFragmentService; +import org.ruoyi.service.IKnowledgeInfoService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.util.List; + +/** + * @author ageer + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/knowledge") +public class KnowledgeController extends BaseController { + + private final IKnowledgeInfoService knowledgeInfoService; + + private final IKnowledgeAttachService attachService; + + private final IKnowledgeFragmentService fragmentService; + + /** + * 鏍规嵁鐢ㄦ埛淇℃伅鏌ヨ鏈湴鐭ヨ瘑搴� + */ + @GetMapping("/list") + public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) { + if (!StpUtil.isLogin()) { + throw new SecurityException("璇峰厛鍘荤櫥褰�!"); + } + bo.setUid(LoginHelper.getUserId()); + return knowledgeInfoService.queryPageList(bo, pageQuery); + } + + /** + * 鏂板鐭ヨ瘑搴� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.INSERT) + @PostMapping("/save") + public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) { + knowledgeInfoService.saveOne(bo); + return R.ok(); + } + + /** + * 鍒犻櫎鐭ヨ瘑搴� + */ + @PostMapping("/remove/{id}") + public R<String> remove(@PathVariable String id) { + knowledgeInfoService.removeKnowledge(id); + return R.ok("鍒犻櫎鐭ヨ瘑搴撴垚鍔�!"); + } + + /** + * 淇敼鐭ヨ瘑搴� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + public R<Void> edit(@RequestBody KnowledgeInfoBo bo) { + return toAjax(knowledgeInfoService.updateByBo(bo)); + } + + /** + * 瀵煎嚭鐭ヨ瘑搴撳垪琛� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(KnowledgeInfoBo bo, HttpServletResponse response) { + List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "鐭ヨ瘑搴�", KnowledgeInfoVo.class, response); + } + + /** + * 鏌ヨ鐭ヨ瘑闄勪欢淇℃伅 + */ + @GetMapping("/detail/{kid}") + public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery, @PathVariable String kid) { + bo.setKid(kid); + return attachService.queryPageList(bo, pageQuery); + } + + /** + * 涓婁紶鐭ヨ瘑搴撻檮浠� + */ + @PostMapping(value = "/attach/upload") + public R<String> upload(KnowledgeInfoUploadBo bo) { + knowledgeInfoService.upload(bo); + return R.ok("涓婁紶鐭ヨ瘑搴撻檮浠舵垚鍔�!"); + } + + /** + * 鑾峰彇鐭ヨ瘑搴撻檮浠惰缁嗕俊鎭� + * + * @param id 涓婚敭 + */ + @GetMapping("attach/info/{id}") + public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖") + @PathVariable Long id) { + return R.ok(attachService.queryById(id)); + } + + /** + * 鍒犻櫎鐭ヨ瘑搴撻檮浠� + */ + @PostMapping("attach/remove/{kid}") + public R<Void> removeAttach(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") + @PathVariable String kid) { + attachService.removeKnowledgeAttach(kid); + return R.ok(); + } + + + /** + * 鏌ヨ鐭ヨ瘑鐗囨 + */ + @GetMapping("/fragment/list/{docId}") + public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, PageQuery pageQuery, @PathVariable String docId) { + bo.setDocId(docId); + return fragmentService.queryPageList(bo, pageQuery); + } + + /** + * 涓婁紶鏂囦欢缈昏瘧 + */ + @PostMapping("/translationByFile") + @ResponseBody + public String translationByFile(@RequestParam("file") MultipartFile file, String targetLanguage) { + return attachService.translationByFile(file, targetLanguage); + } +} diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java index 03fb18a..6f7f977 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/OpenAIServiceImpl.java @@ -20,6 +20,7 @@ @Service @Slf4j public class OpenAIServiceImpl implements IChatService { + @Autowired private OpenAiStreamClient openAiStreamClient; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java new file mode 100644 index 0000000..7a489a6 --- /dev/null +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java @@ -0,0 +1,232 @@ +package org.ruoyi.chat.service.knowledge; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.RandomUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import lombok.RequiredArgsConstructor; +import org.ruoyi.chain.loader.ResourceLoader; +import org.ruoyi.chain.loader.ResourceLoaderFactory; +import org.ruoyi.common.core.domain.model.LoginUser; +import org.ruoyi.common.core.utils.MapstructUtils; +import org.ruoyi.common.core.utils.StringUtils; +import org.ruoyi.common.satoken.utils.LoginHelper; +import org.ruoyi.core.page.PageQuery; +import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.domain.KnowledgeAttach; +import org.ruoyi.domain.KnowledgeFragment; +import org.ruoyi.domain.KnowledgeInfo; +import org.ruoyi.domain.bo.KnowledgeInfoBo; +import org.ruoyi.domain.bo.KnowledgeInfoUploadBo; +import org.ruoyi.domain.vo.KnowledgeInfoVo; +import org.ruoyi.mapper.KnowledgeAttachMapper; +import org.ruoyi.mapper.KnowledgeFragmentMapper; +import org.ruoyi.mapper.KnowledgeInfoMapper; +import org.ruoyi.service.EmbeddingService; +import org.ruoyi.service.IKnowledgeInfoService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; +import java.util.*; + +/** + * 鐭ヨ瘑搴揝ervice涓氬姟灞傚鐞� + * + * @author ageerle + * @date 2025-04-08 + */ +@RequiredArgsConstructor +@Service +public class KnowledgeInfoServiceImpl implements IKnowledgeInfoService { + + private final KnowledgeInfoMapper baseMapper; + + private final EmbeddingService embeddingService; + + private final ResourceLoaderFactory resourceLoaderFactory; + + private final KnowledgeFragmentMapper fragmentMapper; + + private final KnowledgeAttachMapper attachMapper; + + /** + * 鏌ヨ鐭ヨ瘑搴� + */ + @Override + public KnowledgeInfoVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 鏌ヨ鐭ヨ瘑搴撳垪琛� + */ + @Override + public TableDataInfo<KnowledgeInfoVo> queryPageList(KnowledgeInfoBo bo, PageQuery pageQuery) { + LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo); + Page<KnowledgeInfoVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 鏌ヨ鐭ヨ瘑搴撳垪琛� + */ + @Override + public List<KnowledgeInfoVo> queryList(KnowledgeInfoBo bo) { + LambdaQueryWrapper<KnowledgeInfo> lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper<KnowledgeInfo> buildQueryWrapper(KnowledgeInfoBo bo) { + Map<String, Object> params = bo.getParams(); + LambdaQueryWrapper<KnowledgeInfo> lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeInfo::getKid, bo.getKid()); + lqw.eq(bo.getUid() != null, KnowledgeInfo::getUid, bo.getUid()); + lqw.like(StringUtils.isNotBlank(bo.getKname()), KnowledgeInfo::getKname, bo.getKname()); + lqw.eq(bo.getShare() != null, KnowledgeInfo::getShare, bo.getShare()); + lqw.eq(StringUtils.isNotBlank(bo.getDescription()), KnowledgeInfo::getDescription, bo.getDescription()); + lqw.eq(StringUtils.isNotBlank(bo.getKnowledgeSeparator()), KnowledgeInfo::getKnowledgeSeparator, bo.getKnowledgeSeparator()); + lqw.eq(StringUtils.isNotBlank(bo.getQuestionSeparator()), KnowledgeInfo::getQuestionSeparator, bo.getQuestionSeparator()); + lqw.eq(bo.getOverlapChar() != null, KnowledgeInfo::getOverlapChar, bo.getOverlapChar()); + lqw.eq(bo.getRetrieveLimit() != null, KnowledgeInfo::getRetrieveLimit, bo.getRetrieveLimit()); + lqw.eq(bo.getTextBlockSize() != null, KnowledgeInfo::getTextBlockSize, bo.getTextBlockSize()); + lqw.eq(StringUtils.isNotBlank(bo.getVector()), KnowledgeInfo::getVector, bo.getVector()); + lqw.eq(StringUtils.isNotBlank(bo.getVectorModel()), KnowledgeInfo::getVectorModel, bo.getVectorModel()); + return lqw; + } + + /** + * 鏂板鐭ヨ瘑搴� + */ + @Override + public Boolean insertByBo(KnowledgeInfoBo bo) { + KnowledgeInfo add = MapstructUtils.convert(bo, KnowledgeInfo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 淇敼鐭ヨ瘑搴� + */ + @Override + public Boolean updateByBo(KnowledgeInfoBo bo) { + KnowledgeInfo update = MapstructUtils.convert(bo, KnowledgeInfo.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙 + */ + private void validEntityBeforeSave(KnowledgeInfo entity){ + //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫 + } + + /** + * 鎵归噺鍒犻櫎鐭ヨ瘑搴� + */ + @Override + public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { + if(isValid){ + //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠� + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOne(KnowledgeInfoBo bo) { + KnowledgeInfo knowledgeInfo = MapstructUtils.convert(bo, KnowledgeInfo.class); + if (StringUtils.isBlank(bo.getKid())){ + String kid = RandomUtil.randomString(10); + if (knowledgeInfo != null) { + knowledgeInfo.setKid(kid); + knowledgeInfo.setUid(LoginHelper.getLoginUser().getUserId()); + } + baseMapper.insert(knowledgeInfo); + embeddingService.createSchema(String.valueOf(knowledgeInfo.getId())); + }else { + baseMapper.updateById(knowledgeInfo); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void removeKnowledge(String id) { + Map<String,Object> map = new HashMap<>(); + map.put("kid",id); + List<KnowledgeInfoVo> knowledgeInfoList = baseMapper.selectVoByMap(map); + check(knowledgeInfoList); + // 鍒犻櫎鍚戦噺搴撲俊鎭� + knowledgeInfoList.forEach(knowledgeInfoVo -> { + embeddingService.removeByKid(String.valueOf(knowledgeInfoVo.getId())); + }); + // 鍒犻櫎闄勪欢鍜岀煡璇嗙墖娈� + fragmentMapper.deleteByMap(map); + attachMapper.deleteByMap(map); + // 鍒犻櫎鐭ヨ瘑搴� + baseMapper.deleteByMap(map); + } + + @Override + public void upload(KnowledgeInfoUploadBo bo) { + storeContent(bo.getFile(), bo.getKid()); + } + + public void storeContent(MultipartFile file, String kid) { + String fileName = file.getOriginalFilename(); + List<String> chunkList = new ArrayList<>(); + KnowledgeAttach knowledgeAttach = new KnowledgeAttach(); + knowledgeAttach.setKid(kid); + String docId = RandomUtil.randomString(10); + knowledgeAttach.setDocId(docId); + knowledgeAttach.setDocName(fileName); + knowledgeAttach.setDocType(fileName.substring(fileName.lastIndexOf(".")+1)); + String content = ""; + ResourceLoader resourceLoader = resourceLoaderFactory.getLoaderByFileType(knowledgeAttach.getDocType()); + List<String> fids = new ArrayList<>(); + try { + content = resourceLoader.getContent(file.getInputStream()); + chunkList = resourceLoader.getChunkList(content, kid); + List<KnowledgeFragment> knowledgeFragmentList = new ArrayList<>(); + if (CollUtil.isNotEmpty(chunkList)) { + for (int i = 0; i < chunkList.size(); i++) { + String fid = RandomUtil.randomString(16); + fids.add(fid); + KnowledgeFragment knowledgeFragment = new KnowledgeFragment(); + knowledgeFragment.setKid(kid); + knowledgeFragment.setDocId(docId); + knowledgeFragment.setFid(fid); + knowledgeFragment.setIdx(i); + knowledgeFragment.setContent(chunkList.get(i)); + knowledgeFragment.setCreateTime(new Date()); + knowledgeFragmentList.add(knowledgeFragment); + } + } + fragmentMapper.insertBatch(knowledgeFragmentList); + } catch (IOException e) { + e.printStackTrace(); + } + knowledgeAttach.setContent(content); + knowledgeAttach.setCreateTime(new Date()); + attachMapper.insert(knowledgeAttach); + embeddingService.storeEmbeddings(chunkList,kid,docId,fids); + } + + + public void check(List<KnowledgeInfoVo> knowledgeInfoList){ + LoginUser loginUser = LoginHelper.getLoginUser(); + for (KnowledgeInfoVo knowledgeInfoVo : knowledgeInfoList) { + if(!knowledgeInfoVo.getUid().equals(loginUser.getUserId())){ + throw new SecurityException("鏉冮檺涓嶈冻"); + } + } + } + +} -- Gitblit v1.9.3