Commit 9ee4fd91 by Shucai Chen

智能客服分析界面开发

parent 2a8229c8
...@@ -88,6 +88,8 @@ public interface ErrorCodeConstants { ...@@ -88,6 +88,8 @@ public interface ErrorCodeConstants {
ErrorCode FASTGPT_REF_ERROR = new ErrorCode(1_022_009_005, "未找到知识库引用"); ErrorCode FASTGPT_REF_ERROR = new ErrorCode(1_022_009_005, "未找到知识库引用");
ErrorCode FASTGPT_DETAIL_ERROR = new ErrorCode(1_022_009_005, "未找到知识库详情"); ErrorCode FASTGPT_DETAIL_ERROR = new ErrorCode(1_022_009_005, "未找到知识库详情");
ErrorCode FASTGPT_CONFIG_ERROR = new ErrorCode(1_022_009_006, "FastGPT 知识库配置错误,未找到对应的知识库");
ErrorCode FASTGPT_UPLOAD_FAILED = new ErrorCode(1_022_009_007, "上传至 FastGPT 知识库失败");
ErrorCode AGENT_POLICY_NOTIFY_NOT_EXISTS = new ErrorCode(1_043_001_001, "操作失败,找不到该记录"); ErrorCode AGENT_POLICY_NOTIFY_NOT_EXISTS = new ErrorCode(1_043_001_001, "操作失败,找不到该记录");
} }
...@@ -144,4 +144,27 @@ public class AiChatAnalysisController { ...@@ -144,4 +144,27 @@ public class AiChatAnalysisController {
return success(true); return success(true);
} }
@PostMapping("/upload-to-fastgpt")
@Operation(summary = "上传对话总结至 FastGPT 测试知识库")
public CommonResult<Boolean> uploadToFastGpt(
@Valid @RequestBody AiChatSummaryUploadReqVO reqVO) {
chatAnalysisService.uploadToFastGpt(reqVO);
return success(true);
}
@PostMapping("/upload-to-production-fastgpt")
@Operation(summary = "上传对话总结至 FastGPT 正式知识库(测试通过后调用)")
public CommonResult<Boolean> uploadToProductionFastGpt(
@Valid @RequestBody AiChatSummaryUploadReqVO reqVO) {
chatAnalysisService.uploadToProductionFastGpt(reqVO);
return success(true);
}
@PostMapping("/test-fastgpt")
@Operation(summary = "测试 FastGPT 知识库连接")
public CommonResult<String> testFastGpt(@Valid @RequestBody AiChatTestFastGptReqVO reqVO) {
String result = chatAnalysisService.testFastGpt(reqVO.getQuestion(), reqVO.getCategory());
return success(result);
}
} }
...@@ -4,6 +4,8 @@ import com.fhs.core.trans.vo.VO; ...@@ -4,6 +4,8 @@ import com.fhs.core.trans.vo.VO;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 对话分析记录 Response VO") @Schema(description = "管理后台 - 对话分析记录 Response VO")
@Data @Data
public class AiChatSummaryRespVO implements VO { public class AiChatSummaryRespVO implements VO {
...@@ -21,4 +23,16 @@ public class AiChatSummaryRespVO implements VO { ...@@ -21,4 +23,16 @@ public class AiChatSummaryRespVO implements VO {
@Schema(description = "状态", example = "0") @Schema(description = "状态", example = "0")
private Integer status; private Integer status;
@Schema(description = "分析时间")
private LocalDateTime summaryTime;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "修改时间(测试通过时间)")
private LocalDateTime updateTime;
@Schema(description = "处理人昵称")
private String modifierName;
} }
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.analysis;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
@Schema(description = "管理后台 - 对话分析总结上传至 FastGPT 知识库 Request VO")
@Data
public class AiChatSummaryUploadReqVO {
@Schema(description = "总结记录编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
@NotNull(message = "总结记录编号不能为空")
private Long id;
@Schema(description = "知识库标题(用户问题)", requiredMode = Schema.RequiredMode.REQUIRED, example = "公租房申请条件是什么")
@NotBlank(message = "知识库标题不能为空")
private String kbTitle;
@Schema(description = "知识库正文内容(AI 回答)", requiredMode = Schema.RequiredMode.REQUIRED, example = "公租房申请需要满足以下条件...")
@NotBlank(message = "知识库正文内容不能为空")
private String kbContent;
@Schema(description = "分类(公租房/长租房)", requiredMode = Schema.RequiredMode.REQUIRED, example = "公租房")
@NotBlank(message = "分类不能为空")
private String category;
}
...@@ -52,4 +52,9 @@ public class AiChatSummaryDO extends BaseDO { ...@@ -52,4 +52,9 @@ public class AiChatSummaryDO extends BaseDO {
private Integer status; private Integer status;
/**
* 处理人昵称(测试通过时的操作人)
*/
private String modifierName;
} }
...@@ -94,7 +94,7 @@ public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocume ...@@ -94,7 +94,7 @@ public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocume
.in(AiKnowledgeDocumentDO::getId, ids)); .in(AiKnowledgeDocumentDO::getId, ids));
} }
@Select("SELECT COALESCE(SUM(content_length), 0) FROM ai_knowledge_document WHERE creator = #{userId} AND is_dir = 0 AND knowledge_id = 6 AND deleted = 0") @Select("SELECT COALESCE(SUM(content_length), 0) FROM ai_knowledge_document WHERE creator = #{userId} AND is_dir = 0 AND deleted = 0")
Long selectCountKBSize(Long userId); Long selectCountKBSize(Long userId);
default List<AiKnowledgeDocumentDO> selectListByParentId(Long id) { default List<AiKnowledgeDocumentDO> selectListByParentId(Long id) {
......
...@@ -34,4 +34,27 @@ public interface AiChatAnalysisService { ...@@ -34,4 +34,27 @@ public interface AiChatAnalysisService {
PageResult<AiChatSummaryDO> getChatSummaryPage(AiChatSummaryPageReqVO pageReqVO); PageResult<AiChatSummaryDO> getChatSummaryPage(AiChatSummaryPageReqVO pageReqVO);
void updateSummaryStatus(AiSummaryUpdateStatusReqVO reqVO); void updateSummaryStatus(AiSummaryUpdateStatusReqVO reqVO);
/**
* 上传总结至 FastGPT 测试知识库
*
* @param reqVO 上传请求
*/
void uploadToFastGpt(AiChatSummaryUploadReqVO reqVO);
/**
* 上传总结至 FastGPT 正式知识库(测试通过后调用)
*
* @param reqVO 上传请求
*/
void uploadToProductionFastGpt(AiChatSummaryUploadReqVO reqVO);
/**
* 测试 FastGPT 知识库连接
*
* @param question 测试问题
* @param category 分类(公租房/长租房)
* @return FastGPT 的回复内容
*/
String testFastGpt(String question, String category);
} }
...@@ -476,7 +476,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic ...@@ -476,7 +476,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
if(userId == null){ if(userId == null){
throw exception(USER_NOT_EXISTS); throw exception(USER_NOT_EXISTS);
} }
AiKnowledgeDO aiKnowledgeDO = knowledgeService.getKnowledge(pageReqVO.getKnowledgeId()); AiKnowledgeDO aiKnowledgeDO = knowledgeService.validateKnowledgeExists(pageReqVO.getKnowledgeId());
String permission = KnowledgePermissionUtils.checkSeeKBPermission(aiKnowledgeDO.getEmbeddingModel(), userId); String permission = KnowledgePermissionUtils.checkSeeKBPermission(aiKnowledgeDO.getEmbeddingModel(), userId);
PageResult<AiKnowledgeDocumentDO> pageResult; PageResult<AiKnowledgeDocumentDO> pageResult;
...@@ -541,7 +541,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic ...@@ -541,7 +541,7 @@ public class AiKnowledgeDocumentServiceImpl implements AiKnowledgeDocumentServic
if(userId == null){ if(userId == null){
throw exception(USER_NOT_EXISTS); throw exception(USER_NOT_EXISTS);
} }
AiKnowledgeDO aiKnowledgeDO = knowledgeService.getKnowledge(pageReqVO.getKnowledgeId()); AiKnowledgeDO aiKnowledgeDO = knowledgeService.validateKnowledgeExists(pageReqVO.getKnowledgeId());
PageResult<AiKnowledgeDocumentDO> pageResult; PageResult<AiKnowledgeDocumentDO> pageResult;
......
package cn.iocoder.yudao.server; package cn.iocoder.yudao.server;
import org.springframework.ai.autoconfigure.transformers.TransformersEmbeddingModelAutoConfiguration;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
...@@ -13,13 +14,16 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; ...@@ -13,13 +14,16 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
* @author 芋道源码 * @author 芋道源码
*/ */
@SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package} @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${yudao.info.base-package}
@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}.server", "${yudao.info.base-package}.module"}) @SpringBootApplication(
scanBasePackages = {"${yudao.info.base-package}.server", "${yudao.info.base-package}.module"},
exclude = {TransformersEmbeddingModelAutoConfiguration.class}
)
public class YudaoServerApplication { public class YudaoServerApplication {
public static void main(String[] args) { public static void main(String[] args) {
// 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 System.out.println("====== 真正有效的密文 ======");
// 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 System.out.println(new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder().encode("admin123"));
// 如果你碰到启动的问题,请认真阅读 https://doc.iocoder.cn/quick-start/ 文章 System.out.println("===========================");
SpringApplication.run(YudaoServerApplication.class, args); SpringApplication.run(YudaoServerApplication.class, args);
// new SpringApplicationBuilder(YudaoServerApplication.class) // new SpringApplicationBuilder(YudaoServerApplication.class)
......
...@@ -104,7 +104,109 @@ const include = [ ...@@ -104,7 +104,109 @@ const include = [
'element-plus/es/components/collapse/style/css', 'element-plus/es/components/collapse/style/css',
'element-plus/es/components/collapse-item/style/css', 'element-plus/es/components/collapse-item/style/css',
'element-plus/es/components/button-group/style/css', 'element-plus/es/components/button-group/style/css',
'element-plus/es/components/text/style/css' 'element-plus/es/components/text/style/css',
'element-plus/es/components/input-tag/style/css',
'element-plus/es/components/transfer/style/css',
'element-plus/es/components/calendar/style/css',
'element-plus/es/components/tabs/style/css',
'element-plus/es/components/tab-pane/style/css',
'element-plus/es/components/result/style/css',
'element-plus/es/components/steps/style/css',
'element-plus/es/components/step/style/css',
'element-plus/es/components/divider/style/css',
'element-plus/es/components/empty/style/css',
'element-plus/es/components/infinite-scroll/style/css',
'element-plus/es/components/page-header/style/css',
'element-plus/es/components/timeline/style/css',
'element-plus/es/components/timeline-item/style/css',
'element-plus/es/components/alert/style/css',
'element-plus/es/components/badge/style/css',
'element-plus/es/components/progress/style/css',
'element-plus/es/components/skeleton/style/css',
'element-plus/es/components/spinner/style/css',
'element-plus/es/components/statistic/style/css',
'element-plus/es/components/avatar-group/style/css',
'element-plus/es/components/date-picker/style/css',
'element-plus/es/components/time-picker/style/css',
'element-plus/es/components/autocomplete/style/css',
'element-plus/es/components/cascader/style/css',
'element-plus/es/components/checkbox/style/css',
'element-plus/es/components/checkbox-group/style/css',
'element-plus/es/components/checkbox-button/style/css',
'element-plus/es/components/color-picker/style/css',
'element-plus/es/components/input/style/css',
'element-plus/es/components/input-number/style/css',
'element-plus/es/components/radio/style/css',
'element-plus/es/components/radio-group/style/css',
'element-plus/es/components/radio-button/style/css',
'element-plus/es/components/rate/style/css',
'element-plus/es/components/select/style/css',
'element-plus/es/components/select-v2/style/css',
'element-plus/es/components/option/style/css',
'element-plus/es/components/option-group/style/css',
'element-plus/es/components/switch/style/css',
'element-plus/es/components/time-select/style/css',
'element-plus/es/components/tree-select/style/css',
'element-plus/es/components/upload/style/css',
'element-plus/es/components/form/style/css',
'element-plus/es/components/form-item/style/css',
'element-plus/es/components/dialog/style/css',
'element-plus/es/components/drawer/style/css',
'element-plus/es/components/message-box/style/css',
'element-plus/es/components/loading/style/css',
'element-plus/es/components/message/style/css',
'element-plus/es/components/notification/style/css',
'element-plus/es/components/breadcrumb/style/css',
'element-plus/es/components/breadcrumb-item/style/css',
'element-plus/es/components/page-header/style/css',
'element-plus/es/components/tabs/style/css',
'element-plus/es/components/tab-pane/style/css',
'element-plus/es/components/tag/style/css',
'element-plus/es/components/tooltip/style/css',
'element-plus/es/components/pagination/style/css',
'element-plus/es/components/table/style/css',
'element-plus/es/components/table-column/style/css',
'element-plus/es/components/table-v2/style/css',
'element-plus/es/components/card/style/css',
'element-plus/es/components/collapse/style/css',
'element-plus/es/components/collapse-item/style/css',
'element-plus/es/components/divider/style/css',
'element-plus/es/components/empty/style/css',
'element-plus/es/components/result/style/css',
'element-plus/es/components/space/style/css',
'element-plus/es/components/steps/style/css',
'element-plus/es/components/step/style/css',
'element-plus/es/components/timeline/style/css',
'element-plus/es/components/timeline-item/style/css',
'element-plus/es/components/transfer/style/css',
'element-plus/es/components/calendar/style/css',
'element-plus/es/components/affix/style/css',
'element-plus/es/components/backtop/style/css',
'element-plus/es/components/infinite-scroll/style/css',
'element-plus/es/components/scrollbar/style/css',
'element-plus/es/components/skeleton/style/css',
'element-plus/es/components/avatar/style/css',
'element-plus/es/components/avatar-group/style/css',
'element-plus/es/components/badge/style/css',
'element-plus/es/components/progress/style/css',
'element-plus/es/components/spinner/style/css',
'element-plus/es/components/statistic/style/css',
'element-plus/es/components/button/style/css',
'element-plus/es/components/button-group/style/css',
'element-plus/es/components/dropdown/style/css',
'element-plus/es/components/dropdown-menu/style/css',
'element-plus/es/components/dropdown-item/style/css',
'element-plus/es/components/menu/style/css',
'element-plus/es/components/sub-menu/style/css',
'element-plus/es/components/menu-item/style/css',
'element-plus/es/components/tree/style/css',
'element-plus/es/components/image/style/css',
'element-plus/es/components/image-viewer/style/css',
'element-plus/es/components/link/style/css',
'element-plus/es/components/descriptions/style/css',
'element-plus/es/components/descriptions-item/style/css',
'element-plus/es/components/collapse-transition/style/css',
'element-plus/es/components/slider/style/css'
] ]
const exclude = ['@iconify/json'] const exclude = ['@iconify/json']
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
"dev": "vite --mode env.local", "dev": "vite --mode env.local",
"dev-server": "vite --mode dev", "dev-server": "vite --mode dev",
"ts:check": "vue-tsc --noEmit", "ts:check": "vue-tsc --noEmit",
"build:local": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build", "build:local": "node node_modules/vite/bin/vite.js build",
"build:dev": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode dev", "build:dev": "node node_modules/vite/bin/vite.js build --mode dev",
"build:test": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode test", "build:test": "node node_modules/vite/bin/vite.js build --mode test",
"build:stage": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode stage", "build:stage": "node node_modules/vite/bin/vite.js build --mode stage",
"build:prod": "node --max_old_space_size=8192 ./node_modules/vite/bin/vite.js build --mode prod", "build:prod": "node node_modules/vite/bin/vite.js build --mode prod",
"serve:dev": "vite preview --mode dev", "serve:dev": "vite preview --mode dev",
"serve:prod": "vite preview --mode prod", "serve:prod": "vite preview --mode prod",
"preview": "pnpm build:local && vite preview", "preview": "pnpm build:local && vite preview",
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
"driver.js": "^1.3.1", "driver.js": "^1.3.1",
"echarts": "^5.5.0", "echarts": "^5.5.0",
"echarts-wordcloud": "^2.1.0", "echarts-wordcloud": "^2.1.0",
"element-plus": "2.8.0", "element-plus": "2.14.2",
"fast-xml-parser": "^4.3.2", "fast-xml-parser": "^4.3.2",
"highlight.js": "^11.9.0", "highlight.js": "^11.9.0",
"jsencrypt": "^3.3.2", "jsencrypt": "^3.3.2",
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
"unplugin-auto-import": "^0.16.7", "unplugin-auto-import": "^0.16.7",
"unplugin-element-plus": "^0.8.0", "unplugin-element-plus": "^0.8.0",
"unplugin-vue-components": "^0.25.2", "unplugin-vue-components": "^0.25.2",
"vite": "5.1.4", "vite": "4.5.0",
"vite-plugin-compression": "^0.5.1", "vite-plugin-compression": "^0.5.1",
"vite-plugin-ejs": "^1.7.0", "vite-plugin-ejs": "^1.7.0",
"vite-plugin-eslint": "^1.8.1", "vite-plugin-eslint": "^1.8.1",
......
...@@ -73,4 +73,35 @@ export const ChatAnalysisApi = { ...@@ -73,4 +73,35 @@ export const ChatAnalysisApi = {
data data
}) })
}, },
// 上传至 FastGPT 测试知识库
uploadToFastGpt: async (data: {
id: number
kbTitle: string
kbContent: string
category: string
}) => {
return await request.post({
url: `/ai/chat/analysis/upload-to-fastgpt`,
data
})
},
// 上传至 FastGPT 正式知识库(测试通过后调用)
uploadToProductionFastGpt: async (data: {
id: number
kbTitle: string
kbContent: string
category: string
}) => {
return await request.post({
url: `/ai/chat/analysis/upload-to-production-fastgpt`,
data
})
},
// 测试 FastGPT 知识库连接
testFastGpt: async (data: { question: string; category: string }) => {
return await request.post({
url: `/ai/chat/analysis/test-fastgpt`,
data
})
},
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment