diff --git a/pom.xml b/pom.xml
index ee63fc0..c64a5b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -363,6 +363,11 @@
spring-boot-starter-websocket
+
+ com.aliyun
+ bailian20231229
+ 2.4.0
+
@@ -402,6 +407,13 @@
17
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ true
+
+
diff --git a/src/main/java/com/gxwebsoft/ai/config/KnowledgeBaseConfig.java b/src/main/java/com/gxwebsoft/ai/config/KnowledgeBaseConfig.java
new file mode 100644
index 0000000..d34d1ae
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/config/KnowledgeBaseConfig.java
@@ -0,0 +1,16 @@
+package com.gxwebsoft.ai.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "aliyun.knowledge-base")
+public class KnowledgeBaseConfig {
+
+ private String accessKeyId;
+ private String accessKeySecret;
+ private String workspaceId;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/ai/config/TemplateConfig.java b/src/main/java/com/gxwebsoft/ai/config/TemplateConfig.java
new file mode 100644
index 0000000..354fc51
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/config/TemplateConfig.java
@@ -0,0 +1,12 @@
+package com.gxwebsoft.ai.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "ai.template")
+public class TemplateConfig {
+ private String wordTemplatePath;
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/ai/constants/KnowledgeBaseConstants.java b/src/main/java/com/gxwebsoft/ai/constants/KnowledgeBaseConstants.java
new file mode 100644
index 0000000..340b215
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/constants/KnowledgeBaseConstants.java
@@ -0,0 +1,19 @@
+package com.gxwebsoft.ai.constants;
+
+public class KnowledgeBaseConstants {
+
+ public static final String[] KEY_WORDS = {
+ "",
+ "审计依据 法律法规 审计业务约定书 经济责任审计管理办法 中共中央办公厅 国务院办公厅 党政主要领导干部审计规定 国家法规 公司管理制度 年度工作目标 党政主要领导干部经济责任审计规定",
+ "审计目标 经济责任审计目标 资产负债损益真实性 合法性 效益性 经济指标完成情况 重大决策执行 遵守财经法规 国有资产保值增值 经济责任评价 任职期间履职评价 责任界定 业绩评价",
+ "审计对象 审计范围 被审计领导干部 [职务] [姓名] 任职期间 [开始日期]至[结束日期] 职务任期 重大问题追溯 重要事项延伸 审计时限 下属子公司 代管企业",
+ "被审计单位基本情况 单位概况 组织机构 人员结构 财务会计政策 合并口径财务数据 资产总额 负债总额 营业收入 利润 内部控制制度 子公司 代管企业 职能部门设置 合并财务报表",
+ "审计内容 审计重点 贯彻执行经济方针 重大决策执行 发展战略 年度目标完成 法人治理结构 内部控制 财务真实性 风险管控 党风廉政建设 以往审计整改 三重一大经济决策 资产管理 采购管理 债权债务",
+ "审计风险 证据不充分 评价不客观 内部控制失效 法律法规变化 风险应对策略 审计证据充分性 评价客观性 内部控制审查 法规政策跟踪 重要性水平",
+ "审计方法 穿行测试 趋势分析 比率分析 访谈法 数据分析 分析性程序 检查 监盘 观察 询问 函证 计算 重新执行",
+ "审计步骤 时间安排 准备阶段 实施阶段 报告阶段 归档阶段 审计人员安排 资料收集 实质性程序 审计报告编写 交换意见 审计归档 进点会 进度表",
+ "审计组织实施 审计组人员分工 职责分配 审计工作计划 前期调研 审前培训 实地审计 质量控制 内部培训 沟通协调 分级复核 集体讨论 重大事项汇报 里程碑事件清单 审计工作组 项目负责人 主审"
+ };
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java b/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java
new file mode 100644
index 0000000..ec8a757
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/controller/AuditReportController.java
@@ -0,0 +1,144 @@
+package com.gxwebsoft.ai.controller;
+
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.poi.openxml4j.util.ZipSecureFile;
+import org.apache.poi.xwpf.usermodel.XWPFDocument;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.alibaba.fastjson.JSONObject;
+import com.gxwebsoft.ai.config.TemplateConfig;
+import com.gxwebsoft.ai.dto.AuditReportRequest;
+import com.gxwebsoft.ai.dto.KnowledgeBaseRequest;
+import com.gxwebsoft.ai.enums.AuditReportEnum;
+import com.gxwebsoft.common.core.web.ApiResult;
+import com.gxwebsoft.common.core.web.BaseController;
+import com.gxwebsoft.common.system.entity.User;
+
+import cn.afterturn.easypoi.word.WordExportUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * 审计报告控制器
+ * @author GIIT-YC
+ *
+ */
+@Tag(name = "审计报告")
+@RestController
+@RequestMapping("/api/ai/auditReport")
+public class AuditReportController extends BaseController {
+
+ @Autowired
+ private TemplateConfig templateConfig;
+
+ @Autowired
+ private KnowledgeBaseController knowledgeBaseController;
+
+ private String invok(String query, String knowledge, String history, String suggestion, String userName) {
+ // 构建请求体
+ JSONObject requestBody = new JSONObject();
+ JSONObject inputs = new JSONObject();
+ inputs.put("query", query);
+ inputs.put("knowledge", knowledge);
+ inputs.put("history", history);
+ inputs.put("suggestion", suggestion);
+
+ requestBody.put("inputs", inputs);
+ requestBody.put("response_mode", "blocking");
+ requestBody.put("user", userName);
+
+ // 发送 POST 请求
+ String result = HttpUtil.createPost("http://1.14.159.185:8180/v1/workflows/run")
+ .header("Authorization", "Bearer app-d7Ok9FECVZG2Ybw9wpg7tGu9")
+ .header("Content-Type", "application/json")
+ .body(requestBody.toString())
+ .timeout(600000)
+ .execute()
+ .body();
+ // 解析返回的JSON字符串
+ JSONObject jsonResponse = JSONObject.parseObject(result);
+ // 获取data字段
+ JSONObject data = jsonResponse.getJSONObject("data");
+ // 获取outputs字段
+ JSONObject outputs = data.getJSONObject("outputs");
+ // 获取outputs中的result字符串
+ String resultStr = outputs.getString("result");
+ return resultStr;
+ }
+
+ /**
+ * 生成审计报告-单一模块
+ */
+ @Operation(summary = "生成审计报告-单一模块")
+ @PostMapping("/generate")
+ public ApiResult> generateAuditReport(@RequestBody AuditReportRequest req) {
+ final User loginUser = getLoginUser();
+
+ KnowledgeBaseRequest knowledgeBaseRequest = new KnowledgeBaseRequest();
+ knowledgeBaseRequest.setKbId(req.getKbId());
+ knowledgeBaseRequest.setFormCommit((req.getFormCommit() > 10) ? req.getFormCommit() / 10 : req.getFormCommit());
+ String knowledge = knowledgeBaseController.query(knowledgeBaseRequest).getData().toString();
+
+ String query = AuditReportEnum.getByCode(req.getFormCommit()).getDesc();
+ String ret = this.invok(query, knowledge, req.getHistory(), req.getSuggestion(), loginUser.getUsername());
+
+ return success(ret);
+ }
+
+ /**
+ * 生成并下载审计报告
+ */
+ @Operation(summary = "生成并下载审计报告")
+ @PostMapping("/download")
+ public void downloadAuditReport(@RequestBody AuditReportRequest req, HttpServletResponse response) {
+ // 保存原始的安全阈值
+ double originalMinInflateRatio = ZipSecureFile.getMinInflateRatio();
+
+ try {
+ // 降低Zip bomb检测的阈值,解决模板文件的安全检测问题
+ ZipSecureFile.setMinInflateRatio(0.001);
+
+ // 准备模板数据
+ Map map = new HashMap<>();
+ map.put(AuditReportEnum.AUDIT_TITLE.getCode().toString(), req.getFrom0());
+ map.put(AuditReportEnum.AUDIT_BASIS.getCode().toString(), req.getFrom1());
+ map.put(AuditReportEnum.AUDIT_OBJECTIVE.getCode().toString(), req.getFrom2());
+ map.put(AuditReportEnum.AUDIT_SCOPE.getCode().toString(), req.getFrom3());
+ map.put(AuditReportEnum.UNIT_OVERVIEW.getCode().toString(), req.getFrom41());
+ map.put(AuditReportEnum.ORG_AND_PERSONNEL.getCode().toString(), req.getFrom42());
+ map.put(AuditReportEnum.AUDIT_CONTENT_METHODS.getCode().toString(), req.getFrom5());
+
+ // 使用Easypoi的Word模板功能
+ XWPFDocument document = WordExportUtil.exportWord07(templateConfig.getWordTemplatePath(), map);
+
+ // 设置响应头
+ response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
+ response.setHeader("Content-Disposition", "attachment; filename=audit_report.docx");
+
+ // 输出到响应流
+ OutputStream out = response.getOutputStream();
+ document.write(out);
+ out.flush();
+ out.close();
+
+ } catch (Exception e) {
+ throw new RuntimeException("生成审计报告失败", e);
+ } finally {
+ // 恢复原始的安全阈值
+ ZipSecureFile.setMinInflateRatio(originalMinInflateRatio);
+ }
+ }
+
+}
diff --git a/src/main/java/com/gxwebsoft/ai/controller/KnowledgeBaseController.java b/src/main/java/com/gxwebsoft/ai/controller/KnowledgeBaseController.java
new file mode 100644
index 0000000..ed819e4
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/controller/KnowledgeBaseController.java
@@ -0,0 +1,59 @@
+package com.gxwebsoft.ai.controller;
+
+import com.aliyun.bailian20231229.Client;
+import com.aliyun.bailian20231229.models.RetrieveResponse;
+import com.aliyun.bailian20231229.models.RetrieveResponseBody.RetrieveResponseBodyDataNodes;
+import com.gxwebsoft.ai.config.KnowledgeBaseConfig;
+import com.gxwebsoft.ai.constants.KnowledgeBaseConstants;
+import com.gxwebsoft.ai.factory.KnowledgeBaseClientFactory;
+import com.gxwebsoft.ai.util.KnowledgeBaseRetrieve;
+import com.gxwebsoft.ai.dto.KnowledgeBaseRequest;
+import com.gxwebsoft.common.core.web.ApiResult;
+import com.gxwebsoft.common.core.web.BaseController;
+import cn.hutool.core.util.StrUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+@Tag(name = "知识库")
+@RestController
+@RequestMapping("/api/ai/knowledgeBase")
+public class KnowledgeBaseController extends BaseController {
+
+ @Autowired
+ private KnowledgeBaseConfig config;
+
+ @Autowired
+ private KnowledgeBaseClientFactory clientFactory;
+
+ @Operation(summary = "查询知识库")
+ @GetMapping("/query")
+ public ApiResult> query(KnowledgeBaseRequest req) {
+ Set ret = new LinkedHashSet<>();
+ String workspaceId = config.getWorkspaceId();
+ List keyWords = Arrays.asList(KnowledgeBaseConstants.KEY_WORDS);
+ String indexId = req.getKbId();
+ String query = StrUtil.isEmpty(req.getQuery()) ? keyWords.get(req.getFormCommit()) : req.getQuery();
+ Integer topK = req.getTopK() == null ? 10 : req.getTopK();
+
+ try {
+ Client client = clientFactory.createClient();
+ RetrieveResponse resp = KnowledgeBaseRetrieve.retrieveIndex(client, workspaceId, indexId, query);
+ for (RetrieveResponseBodyDataNodes node : resp.getBody().getData().getNodes()) {
+ ret.add(node.getText());
+ if (ret.size() >= topK) {
+ break;
+ }
+ }
+ } catch (Exception e) {
+ return fail("查询失败:" + e.getMessage());
+ }
+ return success(ret);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/ai/dto/AuditReportRequest.java b/src/main/java/com/gxwebsoft/ai/dto/AuditReportRequest.java
new file mode 100644
index 0000000..1fa78be
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/dto/AuditReportRequest.java
@@ -0,0 +1,42 @@
+package com.gxwebsoft.ai.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class AuditReportRequest{
+
+ @Schema(description = "审计标题")
+ private String from0;
+
+ @Schema(description = "审计依据")
+ private String from1;
+
+ @Schema(description = "审计目标")
+ private String from2;
+
+ @Schema(description = "审计对象和范围")
+ private String from3;
+
+ @Schema(description = "被审计单位基本情况-单位概况")
+ private String from41;
+
+ @Schema(description = "被审计单位基本情况-机构和人员相关情况")
+ private String from42;
+
+ @Schema(description = "审计内容和重点及审计方法")
+ private String from5;
+
+ @Schema(description = "知识库ID")
+ private String kbId;
+
+ @Schema(description = "生成模块:AuditReportEnum.code")
+ private Integer formCommit;
+
+ @Schema(description = "历史内容")
+ private String history;
+
+ @Schema(description = "修改建议")
+ private String suggestion;
+
+}
diff --git a/src/main/java/com/gxwebsoft/ai/dto/KnowledgeBaseRequest.java b/src/main/java/com/gxwebsoft/ai/dto/KnowledgeBaseRequest.java
new file mode 100644
index 0000000..bee6ee3
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/dto/KnowledgeBaseRequest.java
@@ -0,0 +1,20 @@
+package com.gxwebsoft.ai.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class KnowledgeBaseRequest {
+
+ @Schema(description = "知识库ID")
+ private String kbId;
+
+ @Schema(description = "召回内容")
+ private String query;
+
+ @Schema(description = "召回模块(1~9)")
+ private Integer formCommit;
+
+ @Schema(description = "返回TOP切片数量")
+ private Integer topK;
+}
diff --git a/src/main/java/com/gxwebsoft/ai/enums/AuditReportEnum.java b/src/main/java/com/gxwebsoft/ai/enums/AuditReportEnum.java
new file mode 100644
index 0000000..d66b145
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/enums/AuditReportEnum.java
@@ -0,0 +1,45 @@
+package com.gxwebsoft.ai.enums;
+
+public enum AuditReportEnum {
+
+ AUDIT_TITLE(0, "审计标题"),
+ AUDIT_BASIS(1, "审计依据"),
+ AUDIT_OBJECTIVE(2, "审计目标"),
+ AUDIT_SCOPE(3, "审计对象和范围"),
+ UNIT_OVERVIEW(41, "被审计单位基本情况-单位概况"),
+ ORG_AND_PERSONNEL(42, "被审计单位基本情况-机构和人员相关情况"),
+ AUDIT_CONTENT_METHODS(5, "审计内容和重点及审计方法");
+
+ private final Integer code;
+ private final String desc;
+
+ AuditReportEnum(Integer code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public static AuditReportEnum getByCode(Integer code) {
+ for (AuditReportEnum value : values()) {
+ if (value.code.equals(code)) {
+ return value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 根据代码获取描述信息
+ */
+ public static String getDescByCode(Integer code) {
+ AuditReportEnum enumValue = getByCode(code);
+ return enumValue != null ? enumValue.getDesc() : null;
+ }
+}
diff --git a/src/main/java/com/gxwebsoft/ai/factory/KnowledgeBaseClientFactory.java b/src/main/java/com/gxwebsoft/ai/factory/KnowledgeBaseClientFactory.java
new file mode 100644
index 0000000..5c4beeb
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/factory/KnowledgeBaseClientFactory.java
@@ -0,0 +1,23 @@
+package com.gxwebsoft.ai.factory;
+
+import com.aliyun.bailian20231229.Client;
+import com.aliyun.teaopenapi.models.Config;
+import com.gxwebsoft.ai.config.KnowledgeBaseConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class KnowledgeBaseClientFactory {
+
+ @Autowired
+ private KnowledgeBaseConfig config;
+
+ public Client createClient() throws Exception {
+ com.aliyun.teaopenapi.models.Config authConfig = new com.aliyun.teaopenapi.models.Config()
+ .setAccessKeyId(config.getAccessKeyId())
+ .setAccessKeySecret(config.getAccessKeySecret());
+ // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
+ authConfig.endpoint = "bailian.cn-beijing.aliyuncs.com";
+ return new com.aliyun.bailian20231229.Client(authConfig);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseCreate.java b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseCreate.java
new file mode 100644
index 0000000..7ef388a
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseCreate.java
@@ -0,0 +1,384 @@
+package com.gxwebsoft.ai.util;
+
+import com.aliyun.bailian20231229.models.*;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 创建知识库
+ * @author GIIT-YC
+ *
+ */
+public class KnowledgeBaseCreate {
+
+ String ALIBABA_CLOUD_ACCESS_KEY_ID = "LTAI5tD5YRKuxWz6Eg7qrM4P";
+ String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "bO8TBDXflOwbtSKimPpG8XrJnyzgTk";
+ String WORKSPACE_ID = "llm-4pf5auwewoz34zqu";
+
+ /**
+ * 检查并提示设置必要的环境变量。
+ *
+ * @return true 如果所有必需的环境变量都已设置,否则 false
+ */
+ public static boolean checkEnvironmentVariables() {
+ Map requiredVars = new HashMap<>();
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_ID", "阿里云访问密钥ID");
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "阿里云访问密钥密码");
+ requiredVars.put("WORKSPACE_ID", "阿里云百炼业务空间ID");
+
+ List missingVars = new ArrayList<>();
+ for (Map.Entry entry : requiredVars.entrySet()) {
+ String value = System.getenv(entry.getKey());
+ if (value == null || value.isEmpty()) {
+ missingVars.add(entry.getKey());
+ System.out.println("错误:请设置 " + entry.getKey() + " 环境变量 (" + entry.getValue() + ")");
+ }
+ }
+
+ return missingVars.isEmpty();
+ }
+
+ /**
+ * 计算文档的MD5值。
+ *
+ * @param filePath 文档本地路径
+ * @return 文档的MD5值
+ * @throws Exception 如果计算过程中发生错误
+ */
+ public static String calculateMD5(String filePath) throws Exception {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ try (FileInputStream fis = new FileInputStream(filePath)) {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = fis.read(buffer)) != -1) {
+ md.update(buffer, 0, bytesRead);
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ for (byte b : md.digest()) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 获取文档大小(以字节为单位)。
+ *
+ * @param filePath 文档本地路径
+ * @return 文档大小(以字节为单位)
+ */
+ public static String getFileSize(String filePath) {
+ File file = new File(filePath);
+ long fileSize = file.length();
+ return String.valueOf(fileSize);
+ }
+
+ /**
+ * 初始化客户端(Client)。
+ *
+ * @return 配置好的客户端对象
+ */
+ public static com.aliyun.bailian20231229.Client createClient() throws Exception {
+ com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+ .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
+ .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
+ // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
+ config.endpoint = "bailian.cn-beijing.aliyuncs.com";
+ return new com.aliyun.bailian20231229.Client(config);
+ }
+
+ /**
+ * 申请文档上传租约。
+ *
+ * @param client 客户端对象
+ * @param categoryId 类目ID
+ * @param fileName 文档名称
+ * @param fileMd5 文档的MD5值
+ * @param fileSize 文档大小(以字节为单位)
+ * @param workspaceId 业务空间ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static ApplyFileUploadLeaseResponse applyLease(com.aliyun.bailian20231229.Client client, String categoryId,
+ String fileName, String fileMd5, String fileSize, String workspaceId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest applyFileUploadLeaseRequest = new com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest();
+ applyFileUploadLeaseRequest.setFileName(fileName);
+ applyFileUploadLeaseRequest.setMd5(fileMd5);
+ applyFileUploadLeaseRequest.setSizeInBytes(fileSize);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ ApplyFileUploadLeaseResponse applyFileUploadLeaseResponse = null;
+ applyFileUploadLeaseResponse = client.applyFileUploadLeaseWithOptions(categoryId, workspaceId,
+ applyFileUploadLeaseRequest, headers, runtime);
+ return applyFileUploadLeaseResponse;
+ }
+
+ /**
+ * 上传文档到临时存储。
+ *
+ * @param preSignedUrl 上传租约中的 URL
+ * @param headers 上传请求的头部
+ * @param filePath 文档本地路径
+ * @throws Exception 如果上传过程中发生错误
+ */
+ public static void uploadFile(String preSignedUrl, Map headers, String filePath) throws Exception {
+ File file = new File(filePath);
+ if (!file.exists() || !file.isFile()) {
+ throw new IllegalArgumentException("文件不存在或不是普通文件: " + filePath);
+ }
+
+ try (FileInputStream fis = new FileInputStream(file)) {
+ URL url = new URL(preSignedUrl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("PUT");
+ conn.setDoOutput(true);
+
+ // 设置上传请求头
+ conn.setRequestProperty("X-bailian-extra", headers.get("X-bailian-extra"));
+ conn.setRequestProperty("Content-Type", headers.get("Content-Type"));
+
+ // 分块读取并上传文档
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = fis.read(buffer)) != -1) {
+ conn.getOutputStream().write(buffer, 0, bytesRead);
+ }
+
+ int responseCode = conn.getResponseCode();
+ if (responseCode != 200) {
+ throw new RuntimeException("上传失败: " + responseCode);
+ }
+ }
+ }
+
+ /**
+ * 将文档添加到类目中。
+ *
+ * @param client 客户端对象
+ * @param leaseId 租约ID
+ * @param parser 用于文档的解析器
+ * @param categoryId 类目ID
+ * @param workspaceId 业务空间ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static AddFileResponse addFile(com.aliyun.bailian20231229.Client client, String leaseId, String parser,
+ String categoryId, String workspaceId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.AddFileRequest addFileRequest = new com.aliyun.bailian20231229.models.AddFileRequest();
+ addFileRequest.setLeaseId(leaseId);
+ addFileRequest.setParser(parser);
+ addFileRequest.setCategoryId(categoryId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.addFileWithOptions(workspaceId, addFileRequest, headers, runtime);
+ }
+
+ /**
+ * 查询文档的基本信息。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param fileId 文档ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static DescribeFileResponse describeFile(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String fileId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.describeFileWithOptions(workspaceId, fileId, headers, runtime);
+ }
+
+ /**
+ * 在阿里云百炼服务中创建知识库(初始化)。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param fileId 文档ID
+ * @param name 知识库名称
+ * @param structureType 知识库的数据类型
+ * @param sourceType 应用数据的数据类型,支持类目类型和文档类型
+ * @param sinkType 知识库的向量存储类型
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static CreateIndexResponse createIndex(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String fileId, String name, String structureType, String sourceType, String sinkType) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.CreateIndexRequest createIndexRequest = new com.aliyun.bailian20231229.models.CreateIndexRequest();
+ createIndexRequest.setStructureType(structureType);
+ createIndexRequest.setName(name);
+ createIndexRequest.setSourceType(sourceType);
+ createIndexRequest.setSinkType(sinkType);
+ createIndexRequest.setDocumentIds(Collections.singletonList(fileId));
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.createIndexWithOptions(workspaceId, createIndexRequest, headers, runtime);
+ }
+
+ /**
+ * 向阿里云百炼服务提交索引任务。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param indexId 知识库ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static SubmitIndexJobResponse submitIndex(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String indexId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.SubmitIndexJobRequest submitIndexJobRequest = new com.aliyun.bailian20231229.models.SubmitIndexJobRequest();
+ submitIndexJobRequest.setIndexId(indexId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.submitIndexJobWithOptions(workspaceId, submitIndexJobRequest, headers, runtime);
+ }
+
+ /**
+ * 查询索引任务状态。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param jobId 任务ID
+ * @param indexId 知识库ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static GetIndexJobStatusResponse getIndexJobStatus(com.aliyun.bailian20231229.Client client,
+ String workspaceId, String jobId, String indexId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.GetIndexJobStatusRequest getIndexJobStatusRequest = new com.aliyun.bailian20231229.models.GetIndexJobStatusRequest();
+ getIndexJobStatusRequest.setIndexId(indexId);
+ getIndexJobStatusRequest.setJobId(jobId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ GetIndexJobStatusResponse getIndexJobStatusResponse = null;
+ getIndexJobStatusResponse = client.getIndexJobStatusWithOptions(workspaceId, getIndexJobStatusRequest, headers,
+ runtime);
+ return getIndexJobStatusResponse;
+ }
+
+ /**
+ * 使用阿里云百炼服务创建知识库。
+ *
+ * @param filePath 文档本地路径
+ * @param workspaceId 业务空间ID
+ * @param name 知识库名称
+ * @return 如果成功,返回知识库ID;否则返回 null
+ */
+ public static String createKnowledgeBase(String filePath, String workspaceId, String name) {
+ // 设置默认值
+ String categoryId = "default";
+ String parser = "DASHSCOPE_DOCMIND";
+ String sourceType = "DATA_CENTER_FILE";
+ String structureType = "unstructured";
+ String sinkType = "DEFAULT";
+ try {
+ // 步骤1:初始化客户端(Client)
+ System.out.println("步骤1:初始化Client");
+ com.aliyun.bailian20231229.Client client = createClient();
+
+ // 步骤2:准备文档信息
+ System.out.println("步骤2:准备文档信息");
+ String fileName = new File(filePath).getName();
+ String fileMd5 = calculateMD5(filePath);
+ String fileSize = getFileSize(filePath);
+
+ // 步骤3:申请上传租约
+ System.out.println("步骤3:向阿里云百炼申请上传租约");
+ ApplyFileUploadLeaseResponse leaseResponse = applyLease(client, categoryId, fileName, fileMd5, fileSize,
+ workspaceId);
+ String leaseId = leaseResponse.getBody().getData().getFileUploadLeaseId();
+ String uploadUrl = leaseResponse.getBody().getData().getParam().getUrl();
+ Object uploadHeaders = leaseResponse.getBody().getData().getParam().getHeaders();
+
+ // 步骤4:上传文档
+ System.out.println("步骤4:上传文档到阿里云百炼");
+ // 请自行安装jackson-databind
+ // 将上一步的uploadHeaders转换为Map(Key-Value形式)
+ ObjectMapper mapper = new ObjectMapper();
+ Map uploadHeadersMap = (Map) mapper
+ .readValue(mapper.writeValueAsString(uploadHeaders), Map.class);
+ uploadFile(uploadUrl, uploadHeadersMap, filePath);
+
+ // 步骤5:将文档添加到服务器
+ System.out.println("步骤5:将文档添加到阿里云百炼服务器");
+ AddFileResponse addResponse = addFile(client, leaseId, parser, categoryId, workspaceId);
+ String fileId = addResponse.getBody().getData().getFileId();
+
+ // 步骤6:检查文档状态
+ System.out.println("步骤6:检查阿里云百炼中的文档状态");
+ while (true) {
+ DescribeFileResponse describeResponse = describeFile(client, workspaceId, fileId);
+ String status = describeResponse.getBody().getData().getStatus();
+ System.out.println("当前文档状态:" + status);
+
+ if (status.equals("INIT")) {
+ System.out.println("文档待解析,请稍候...");
+ } else if (status.equals("PARSING")) {
+ System.out.println("文档解析中,请稍候...");
+ } else if (status.equals("PARSE_SUCCESS")) {
+ System.out.println("文档解析完成!");
+ break;
+ } else {
+ System.out.println("未知的文档状态:" + status + ",请联系技术支持。");
+ return null;
+ }
+ TimeUnit.SECONDS.sleep(5);
+ }
+
+ // 步骤7:初始化知识库
+ System.out.println("步骤7:在阿里云百炼中创建知识库");
+ CreateIndexResponse indexResponse = createIndex(client, workspaceId, fileId, name, structureType,
+ sourceType, sinkType);
+ String indexId = indexResponse.getBody().getData().getId();
+
+ // 步骤8:提交索引任务
+ System.out.println("步骤8:向阿里云百炼提交索引任务");
+ SubmitIndexJobResponse submitResponse = submitIndex(client, workspaceId, indexId);
+ String jobId = submitResponse.getBody().getData().getId();
+
+ // 步骤9:获取索引任务状态
+ System.out.println("步骤9:获取阿里云百炼索引任务状态");
+ while (true) {
+ GetIndexJobStatusResponse getStatusResponse = getIndexJobStatus(client, workspaceId, jobId, indexId);
+ String status = getStatusResponse.getBody().getData().getStatus();
+ System.out.println("当前索引任务状态:" + status);
+
+ if (status.equals("COMPLETED")) {
+ break;
+ }
+ TimeUnit.SECONDS.sleep(5);
+ }
+
+ System.out.println("阿里云百炼知识库创建成功!");
+ return indexId;
+
+ } catch (Exception e) {
+ System.out.println("发生错误:" + e.getMessage());
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * 主函数。
+ */
+ public static void main(String[] args) {
+ Scanner scanner = new Scanner(System.in);
+ if (!checkEnvironmentVariables()) {
+ return;
+ }
+
+ System.out.print("请输入您需要上传文档的实际本地路径(以Linux为例:/xxx/xxx/阿里云百炼系列手机产品介绍.docx):");
+ String filePath = scanner.nextLine();
+
+ System.out.print("请为您的知识库输入一个名称:");
+ String kbName = scanner.nextLine();
+
+ String workspaceId = System.getenv("WORKSPACE_ID");
+ String result = createKnowledgeBase(filePath, workspaceId, kbName);
+ if (result != null) {
+ System.out.println("知识库ID: " + result);
+ }
+ }
+}
diff --git a/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseManage.java b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseManage.java
new file mode 100644
index 0000000..c669d52
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseManage.java
@@ -0,0 +1,145 @@
+package com.gxwebsoft.ai.util;
+
+import com.aliyun.bailian20231229.models.DeleteIndexResponse;
+import com.aliyun.bailian20231229.models.ListIndicesResponse;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.*;
+
+/**
+ * 管理知识库
+ * @author GIIT-YC
+ *
+ */
+public class KnowledgeBaseManage {
+
+ String ALIBABA_CLOUD_ACCESS_KEY_ID = "LTAI5tD5YRKuxWz6Eg7qrM4P";
+ String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "bO8TBDXflOwbtSKimPpG8XrJnyzgTk";
+ String WORKSPACE_ID = "llm-4pf5auwewoz34zqu";
+
+ /**
+ * 检查并提示设置必要的环境变量。
+ *
+ * @return true 如果所有必需的环境变量都已设置,否则 false
+ */
+ public static boolean checkEnvironmentVariables() {
+ Map requiredVars = new HashMap<>();
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_ID", "阿里云访问密钥ID");
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "阿里云访问密钥密码");
+ requiredVars.put("WORKSPACE_ID", "阿里云百炼业务空间ID");
+
+ List missingVars = new ArrayList<>();
+ for (Map.Entry entry : requiredVars.entrySet()) {
+ String value = System.getenv(entry.getKey());
+ if (value == null || value.isEmpty()) {
+ missingVars.add(entry.getKey());
+ System.out.println("错误:请设置 " + entry.getKey() + " 环境变量 (" + entry.getValue() + ")");
+ }
+ }
+
+ return missingVars.isEmpty();
+ }
+
+ /**
+ * 创建并配置客户端(Client)
+ *
+ * @return 配置好的客户端(Client)
+ */
+ public static com.aliyun.bailian20231229.Client createClient() throws Exception {
+ com.aliyun.credentials.Client credential = new com.aliyun.credentials.Client();
+ com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+ .setCredential(credential);
+ // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
+ config.endpoint = "bailian.cn-beijing.aliyuncs.com";
+ return new com.aliyun.bailian20231229.Client(config);
+ }
+
+ /**
+ * 获取指定业务空间下一个或多个知识库的详细信息
+ *
+ * @param client 客户端(Client)
+ * @param workspaceId 业务空间ID
+ * @return 阿里云百炼服务的响应
+ */
+ public static ListIndicesResponse listIndices(com.aliyun.bailian20231229.Client client, String workspaceId)
+ throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.ListIndicesRequest listIndicesRequest = new com.aliyun.bailian20231229.models.ListIndicesRequest();
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.listIndicesWithOptions(workspaceId, listIndicesRequest, headers, runtime);
+ }
+
+ /**
+ * 永久性删除指定的知识库
+ *
+ * @param client 客户端(Client)
+ * @param workspaceId 业务空间ID
+ * @param indexId 知识库ID
+ * @return 阿里云百炼服务的响应
+ */
+ public static DeleteIndexResponse deleteIndex(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String indexId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.DeleteIndexRequest deleteIndexRequest = new com.aliyun.bailian20231229.models.DeleteIndexRequest();
+ deleteIndexRequest.setIndexId(indexId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.deleteIndexWithOptions(workspaceId, deleteIndexRequest, headers, runtime);
+ }
+
+ /**
+ * 主函数
+ */
+ public static void main(String[] args) {
+ if (!checkEnvironmentVariables()) {
+ System.out.println("环境变量校验未通过。");
+ return;
+ }
+
+ try {
+ Scanner scanner = new Scanner(System.in);
+ System.out.print("请选择要执行的操作:\n1. 查看知识库\n2. 删除知识库\n请输入选项(1或2):");
+ String startOption = scanner.nextLine();
+ com.aliyun.bailian20231229.Client client = createClient();
+ if (startOption.equals("1")) {
+ // 查看知识库
+ System.out.println("\n执行查看知识库");
+ String workspaceId = System.getenv("WORKSPACE_ID");
+ ListIndicesResponse response = listIndices(client, workspaceId);
+ // 请自行安装jackson-databind。将响应转换为 JSON 字符串
+ ObjectMapper mapper = new ObjectMapper();
+ String result = mapper.writeValueAsString(response.getBody().getData());
+ System.out.println(result);
+ } else if (startOption.equals("2")) {
+ System.out.println("\n执行删除知识库");
+ String workspaceId = System.getenv("WORKSPACE_ID");
+ System.out.print("请输入知识库ID:"); // 即 CreateIndex 接口返回的 Data.Id,您也可以在阿里云百炼控制台的知识库页面获取。
+ String indexId = scanner.nextLine();
+ // 删除前二次确认
+ boolean confirm = false;
+ while (!confirm) {
+ System.out.print("您确定要永久性删除该知识库 " + indexId + " 吗?(y/n): ");
+ String input = scanner.nextLine().trim().toLowerCase();
+ if (input.equals("y")) {
+ confirm = true;
+ } else if (input.equals("n")) {
+ System.out.println("已取消删除操作。");
+ return;
+ } else {
+ System.out.println("无效输入,请输入 y 或 n。");
+ }
+ }
+ DeleteIndexResponse resp = deleteIndex(client, workspaceId, indexId);
+ if (resp.getBody().getStatus().equals("200")) {
+ System.out.println("知识库" + indexId + "删除成功!");
+ } else {
+ ObjectMapper mapper = new ObjectMapper();
+ System.out.println("发生错误:" + mapper.writeValueAsString(resp.getBody()));
+ }
+ } else {
+ System.out.println("无效的选项,程序退出。");
+ }
+ } catch (Exception e) {
+ System.out.println("发生错误:" + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseRetrieve.java b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseRetrieve.java
new file mode 100644
index 0000000..a7b568e
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseRetrieve.java
@@ -0,0 +1,110 @@
+package com.gxwebsoft.ai.util;
+
+import com.aliyun.bailian20231229.models.RetrieveRequest;
+import com.aliyun.bailian20231229.models.RetrieveResponse;
+import com.aliyun.teautil.models.RuntimeOptions;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.util.*;
+
+/**
+ * 检索知识库
+ * @author GIIT-YC
+ *
+ */
+public class KnowledgeBaseRetrieve {
+
+ static String ALIBABA_CLOUD_ACCESS_KEY_ID = "LTAI5tD5YRKuxWz6Eg7qrM4P";
+ static String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "bO8TBDXflOwbtSKimPpG8XrJnyzgTk";
+ static String WORKSPACE_ID = "llm-4pf5auwewoz34zqu";
+
+
+ /**
+ * 检查并提示设置必要的环境变量。
+ *
+ * @return true 如果所有必需的环境变量都已设置,否则 false
+ */
+ public static boolean checkEnvironmentVariables() {
+ Map requiredVars = new HashMap<>();
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_ID", "阿里云访问密钥ID");
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "阿里云访问密钥密码");
+ requiredVars.put("WORKSPACE_ID", "阿里云百炼业务空间ID");
+
+ List missingVars = new ArrayList<>();
+ for (Map.Entry entry : requiredVars.entrySet()) {
+ String value = System.getenv(entry.getKey());
+ if (value == null || value.isEmpty()) {
+ missingVars.add(entry.getKey());
+ System.out.println("错误:请设置 " + entry.getKey() + " 环境变量 (" + entry.getValue() + ")");
+ }
+ }
+
+ return missingVars.isEmpty();
+ }
+
+ /**
+ * 初始化客户端(Client)。
+ *
+ * @return 配置好的客户端对象
+ */
+ public static com.aliyun.bailian20231229.Client createClient() throws Exception {
+ com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+ .setAccessKeyId(ALIBABA_CLOUD_ACCESS_KEY_ID)
+ .setAccessKeySecret(ALIBABA_CLOUD_ACCESS_KEY_SECRET);
+ // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
+ config.endpoint = "bailian.cn-beijing.aliyuncs.com";
+ return new com.aliyun.bailian20231229.Client(config);
+ }
+
+ /**
+ * 在指定的知识库中检索信息。
+ *
+ * @param client 客户端对象(bailian20231229Client)
+ * @param workspaceId 业务空间ID
+ * @param indexId 知识库ID
+ * @param query 检索查询语句
+ * @return 阿里云百炼服务的响应
+ */
+ public static RetrieveResponse retrieveIndex(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String indexId, String query) throws Exception {
+ RetrieveRequest retrieveRequest = new RetrieveRequest();
+ retrieveRequest.setIndexId(indexId);
+ retrieveRequest.setQuery(query);
+ retrieveRequest.setDenseSimilarityTopK(null);
+ RuntimeOptions runtime = new RuntimeOptions();
+ return client.retrieveWithOptions(workspaceId, retrieveRequest, null, runtime);
+ }
+
+ /**
+ * 使用阿里云百炼服务检索知识库。
+ */
+ public static void main(String[] args) {
+// if (!checkEnvironmentVariables()) {
+// System.out.println("环境变量校验未通过。");
+// return;
+// }
+
+ try {
+ // 步骤1:初始化客户端(Client)
+ System.out.println("步骤1:创建Client");
+ com.aliyun.bailian20231229.Client client = createClient();
+
+ // 步骤2:检索知识库
+ System.out.println("步骤2:检索知识库");
+ Scanner scanner = new Scanner(System.in);
+ System.out.print("请输入知识库ID:"); // 即 CreateIndex 接口返回的 Data.Id,您也可以在阿里云百炼控制台的知识库页面获取。
+ String indexId = scanner.nextLine();
+ System.out.print("请输入检索query:");
+ String query = scanner.nextLine();
+ String workspaceId = WORKSPACE_ID;
+ RetrieveResponse resp = retrieveIndex(client, workspaceId, indexId, query);
+
+ // 请自行安装jackson-databind。将响应体responsebody转换为 JSON 字符串
+ ObjectMapper mapper = new ObjectMapper();
+ String result = mapper.writeValueAsString(resp.getBody());
+ System.out.println(result);
+ } catch (Exception e) {
+ System.out.println("发生错误:" + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseUpdate.java b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseUpdate.java
new file mode 100644
index 0000000..518d3e6
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/ai/util/KnowledgeBaseUpdate.java
@@ -0,0 +1,384 @@
+package com.gxwebsoft.ai.util;
+
+import com.aliyun.bailian20231229.models.*;
+import com.aliyun.teautil.models.RuntimeOptions;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.security.MessageDigest;
+import java.util.*;
+
+/**
+ * 更新知识库
+ * @author GIIT-YC
+ *
+ */
+public class KnowledgeBaseUpdate {
+
+ String ALIBABA_CLOUD_ACCESS_KEY_ID = "LTAI5tD5YRKuxWz6Eg7qrM4P";
+ String ALIBABA_CLOUD_ACCESS_KEY_SECRET = "bO8TBDXflOwbtSKimPpG8XrJnyzgTk";
+ String WORKSPACE_ID = "llm-4pf5auwewoz34zqu";
+
+ /**
+ * 检查并提示设置必要的环境变量。
+ *
+ * @return true 如果所有必需的环境变量都已设置,否则 false
+ */
+ public static boolean checkEnvironmentVariables() {
+ Map requiredVars = new HashMap<>();
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_ID", "阿里云访问密钥ID");
+ requiredVars.put("ALIBABA_CLOUD_ACCESS_KEY_SECRET", "阿里云访问密钥密码");
+ requiredVars.put("WORKSPACE_ID", "阿里云百炼业务空间ID");
+
+ List missingVars = new ArrayList<>();
+ for (Map.Entry entry : requiredVars.entrySet()) {
+ String value = System.getenv(entry.getKey());
+ if (value == null || value.isEmpty()) {
+ missingVars.add(entry.getKey());
+ System.out.println("错误:请设置 " + entry.getKey() + " 环境变量 (" + entry.getValue() + ")");
+ }
+ }
+
+ return missingVars.isEmpty();
+ }
+
+ /**
+ * 创建并配置客户端(Client)
+ *
+ * @return 配置好的客户端(Client)
+ */
+ public static com.aliyun.bailian20231229.Client createClient() throws Exception {
+ com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+ .setAccessKeyId(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID"))
+ .setAccessKeySecret(System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET"));
+ // 下方接入地址以公有云的公网接入地址为例,可按需更换接入地址。
+ config.endpoint = "bailian.cn-beijing.aliyuncs.com";
+ return new com.aliyun.bailian20231229.Client(config);
+ }
+
+ /**
+ * 计算文档的MD5值
+ *
+ * @param filePath 文档本地路径
+ * @return 文档的MD5值
+ */
+ public static String calculateMD5(String filePath) throws Exception {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ try (FileInputStream fis = new FileInputStream(filePath)) {
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = fis.read(buffer)) != -1) {
+ md.update(buffer, 0, bytesRead);
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ for (byte b : md.digest()) {
+ sb.append(String.format("%02x", b & 0xff));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 获取文档大小(以字节为单位)
+ *
+ * @param filePath 文档本地路径
+ * @return 文档大小(以字节为单位)
+ */
+ public static String getFileSize(String filePath) {
+ File file = new File(filePath);
+ long fileSize = file.length();
+ return String.valueOf(fileSize);
+ }
+
+ /**
+ * 申请文档上传租约。
+ *
+ * @param client 客户端对象
+ * @param categoryId 类目ID
+ * @param fileName 文档名称
+ * @param fileMd5 文档的MD5值
+ * @param fileSize 文档大小(以字节为单位)
+ * @param workspaceId 业务空间ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static ApplyFileUploadLeaseResponse applyLease(com.aliyun.bailian20231229.Client client, String categoryId,
+ String fileName, String fileMd5, String fileSize, String workspaceId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest applyFileUploadLeaseRequest = new com.aliyun.bailian20231229.models.ApplyFileUploadLeaseRequest();
+ applyFileUploadLeaseRequest.setFileName(fileName);
+ applyFileUploadLeaseRequest.setMd5(fileMd5);
+ applyFileUploadLeaseRequest.setSizeInBytes(fileSize);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ ApplyFileUploadLeaseResponse applyFileUploadLeaseResponse = null;
+ applyFileUploadLeaseResponse = client.applyFileUploadLeaseWithOptions(categoryId, workspaceId,
+ applyFileUploadLeaseRequest, headers, runtime);
+ return applyFileUploadLeaseResponse;
+ }
+
+ /**
+ * 上传文档到临时存储。
+ *
+ * @param preSignedUrl 上传租约中的 URL
+ * @param headers 上传请求的头部
+ * @param filePath 文档本地路径
+ * @throws Exception 如果上传过程中发生错误
+ */
+ public static void uploadFile(String preSignedUrl, Map headers, String filePath) throws Exception {
+ File file = new File(filePath);
+ if (!file.exists() || !file.isFile()) {
+ throw new IllegalArgumentException("文件不存在或不是普通文件: " + filePath);
+ }
+
+ try (FileInputStream fis = new FileInputStream(file)) {
+ URL url = new URL(preSignedUrl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setRequestMethod("PUT");
+ conn.setDoOutput(true);
+
+ // 设置上传请求头
+ conn.setRequestProperty("X-bailian-extra", headers.get("X-bailian-extra"));
+ conn.setRequestProperty("Content-Type", headers.get("Content-Type"));
+
+ // 分块读取并上传文档
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = fis.read(buffer)) != -1) {
+ conn.getOutputStream().write(buffer, 0, bytesRead);
+ }
+
+ int responseCode = conn.getResponseCode();
+ if (responseCode != 200) {
+ throw new RuntimeException("上传失败: " + responseCode);
+ }
+ }
+ }
+
+ /**
+ * 将文档添加到类目中。
+ *
+ * @param client 客户端对象
+ * @param leaseId 租约ID
+ * @param parser 用于文档的解析器
+ * @param categoryId 类目ID
+ * @param workspaceId 业务空间ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static AddFileResponse addFile(com.aliyun.bailian20231229.Client client, String leaseId, String parser,
+ String categoryId, String workspaceId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.AddFileRequest addFileRequest = new com.aliyun.bailian20231229.models.AddFileRequest();
+ addFileRequest.setLeaseId(leaseId);
+ addFileRequest.setParser(parser);
+ addFileRequest.setCategoryId(categoryId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.addFileWithOptions(workspaceId, addFileRequest, headers, runtime);
+ }
+
+ /**
+ * 查询文档的基本信息。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param fileId 文档ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static DescribeFileResponse describeFile(com.aliyun.bailian20231229.Client client, String workspaceId,
+ String fileId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.describeFileWithOptions(workspaceId, fileId, headers, runtime);
+ }
+
+ /**
+ * 向一个非结构化知识库追加导入已解析的文档
+ *
+ * @param client 客户端(Client)
+ * @param workspaceId 业务空间ID
+ * @param indexId 知识库ID
+ * @param fileId 文档ID
+ * @param sourceType 数据类型
+ * @return 阿里云百炼服务的响应
+ */
+ public static SubmitIndexAddDocumentsJobResponse submitIndexAddDocumentsJob(
+ com.aliyun.bailian20231229.Client client, String workspaceId, String indexId, String fileId,
+ String sourceType) throws Exception {
+ Map headers = new HashMap<>();
+ SubmitIndexAddDocumentsJobRequest submitIndexAddDocumentsJobRequest = new SubmitIndexAddDocumentsJobRequest();
+ submitIndexAddDocumentsJobRequest.setIndexId(indexId);
+ submitIndexAddDocumentsJobRequest.setDocumentIds(Collections.singletonList(fileId));
+ submitIndexAddDocumentsJobRequest.setSourceType(sourceType);
+ RuntimeOptions runtime = new RuntimeOptions();
+ return client.submitIndexAddDocumentsJobWithOptions(workspaceId, submitIndexAddDocumentsJobRequest, headers,
+ runtime);
+ }
+
+ /**
+ * 查询索引任务状态。
+ *
+ * @param client 客户端对象
+ * @param workspaceId 业务空间ID
+ * @param jobId 任务ID
+ * @param indexId 知识库ID
+ * @return 阿里云百炼服务的响应对象
+ */
+ public static GetIndexJobStatusResponse getIndexJobStatus(com.aliyun.bailian20231229.Client client,
+ String workspaceId, String jobId, String indexId) throws Exception {
+ Map headers = new HashMap<>();
+ com.aliyun.bailian20231229.models.GetIndexJobStatusRequest getIndexJobStatusRequest = new com.aliyun.bailian20231229.models.GetIndexJobStatusRequest();
+ getIndexJobStatusRequest.setIndexId(indexId);
+ getIndexJobStatusRequest.setJobId(jobId);
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ GetIndexJobStatusResponse getIndexJobStatusResponse = null;
+ getIndexJobStatusResponse = client.getIndexJobStatusWithOptions(workspaceId, getIndexJobStatusRequest, headers,
+ runtime);
+ return getIndexJobStatusResponse;
+ }
+
+ /**
+ * 从指定的非结构化知识库中永久删除一个或多个文档
+ *
+ * @param client 客户端(Client)
+ * @param workspaceId 业务空间ID
+ * @param indexId 知识库ID
+ * @param fileId 文档ID
+ * @return 阿里云百炼服务的响应
+ */
+ public static DeleteIndexDocumentResponse deleteIndexDocument(com.aliyun.bailian20231229.Client client,
+ String workspaceId, String indexId, String fileId) throws Exception {
+ Map headers = new HashMap<>();
+ DeleteIndexDocumentRequest deleteIndexDocumentRequest = new DeleteIndexDocumentRequest();
+ deleteIndexDocumentRequest.setIndexId(indexId);
+ deleteIndexDocumentRequest.setDocumentIds(Collections.singletonList(fileId));
+ com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+ return client.deleteIndexDocumentWithOptions(workspaceId, deleteIndexDocumentRequest, headers, runtime);
+ }
+
+ /**
+ * 使用阿里云百炼服务更新知识库
+ *
+ * @param filePath 文档(更新后的)的实际本地路径
+ * @param workspaceId 业务空间ID
+ * @param indexId 需要更新的知识库ID
+ * @param oldFileId 需要更新的文档的FileID
+ * @return 如果成功,返回知识库ID;否则返回 null
+ */
+ public static String updateKnowledgeBase(String filePath, String workspaceId, String indexId, String oldFileId) {
+ // 设置默认值
+ String categoryId = "default";
+ String parser = "DASHSCOPE_DOCMIND";
+ String sourceType = "DATA_CENTER_FILE";
+ try {
+ // 步骤1:初始化客户端(Client)
+ System.out.println("步骤1:创建Client");
+ com.aliyun.bailian20231229.Client client = createClient();
+
+ // 步骤2:准备文档信息(更新后的文档)
+ System.out.println("步骤2:准备文档信息");
+ String fileName = Paths.get(filePath).getFileName().toString();
+ String fileMd5 = calculateMD5(filePath);
+ String fileSize = getFileSize(filePath);
+
+ // 步骤3:申请上传租约
+ System.out.println("步骤3:向阿里云百炼申请上传租约");
+ ApplyFileUploadLeaseResponse leaseResponse = applyLease(client, categoryId, fileName, fileMd5, fileSize,
+ workspaceId);
+ String leaseId = leaseResponse.getBody().getData().getFileUploadLeaseId();
+ String uploadUrl = leaseResponse.getBody().getData().getParam().getUrl();
+ Object uploadHeaders = leaseResponse.getBody().getData().getParam().getHeaders();
+
+ // 步骤4:上传文档到临时存储
+ System.out.println("步骤4:上传文档到临时存储");
+ // 请自行安装jackson-databind
+ // 将上一步的uploadHeaders转换为Map(Key-Value形式)
+ ObjectMapper mapper = new ObjectMapper();
+ Map uploadHeadersMap = (Map) mapper
+ .readValue(mapper.writeValueAsString(uploadHeaders), Map.class);
+ uploadFile(uploadUrl, uploadHeadersMap, filePath);
+
+ // 步骤5:添加文档到类目中
+ System.out.println("步骤5:添加文档到类目中");
+ AddFileResponse addResponse = addFile(client, leaseId, parser, categoryId, workspaceId);
+ String fileId = addResponse.getBody().getData().getFileId();
+
+ // 步骤6:检查更新后的文档状态
+ System.out.println("步骤6:检查阿里云百炼中的文档状态");
+ while (true) {
+ DescribeFileResponse describeResponse = describeFile(client, workspaceId, fileId);
+ String status = describeResponse.getBody().getData().getStatus();
+ System.out.println("当前文档状态:" + status);
+ if ("INIT".equals(status)) {
+ System.out.println("文档待解析,请稍候...");
+ } else if ("PARSING".equals(status)) {
+ System.out.println("文档解析中,请稍候...");
+ } else if ("PARSE_SUCCESS".equals(status)) {
+ System.out.println("文档解析完成!");
+ break;
+ } else {
+ System.out.println("未知的文档状态:" + status + ",请联系技术支持。");
+ return null;
+ }
+ Thread.sleep(5000);
+ }
+
+ // 步骤7:提交追加文档任务
+ System.out.println("步骤7:提交追加文档任务");
+ SubmitIndexAddDocumentsJobResponse indexAddResponse = submitIndexAddDocumentsJob(client, workspaceId,
+ indexId, fileId, sourceType);
+ String jobId = indexAddResponse.getBody().getData().getId();
+
+ // 步骤8:等待追加任务完成
+ System.out.println("步骤8:等待追加任务完成");
+ while (true) {
+ GetIndexJobStatusResponse jobStatusResponse = getIndexJobStatus(client, workspaceId, jobId, indexId);
+ String status = jobStatusResponse.getBody().getData().getStatus();
+ System.out.println("当前索引任务状态:" + status);
+ if ("COMPLETED".equals(status)) {
+ break;
+ }
+ Thread.sleep(5000);
+ }
+
+ // 步骤9:删除旧文档
+ System.out.println("步骤9:删除旧文档");
+ deleteIndexDocument(client, workspaceId, indexId, oldFileId);
+
+ System.out.println("阿里云百炼知识库更新成功!");
+ return indexId;
+ } catch (Exception e) {
+ System.out.println("发生错误:" + e.getMessage());
+ return null;
+ }
+ }
+
+ /**
+ * 主函数。
+ */
+ public static void main(String[] args) {
+ if (!checkEnvironmentVariables()) {
+ System.out.println("环境变量校验未通过。");
+ return;
+ }
+
+ Scanner scanner = new Scanner(System.in);
+ System.out.print("请输入您需要上传文档(更新后的)的实际本地路径(以Linux为例:/xxx/xxx/阿里云百炼系列手机产品介绍.docx):");
+ String filePath = scanner.nextLine();
+
+ System.out.print("请输入需要更新的知识库ID:"); // 即 CreateIndex 接口返回的 Data.Id,您也可以在阿里云百炼控制台的知识库页面获取。
+ String indexId = scanner.nextLine(); // 即 AddFile 接口返回的 FileId。您也可以在阿里云百炼控制台的应用数据页面,单击文件名称旁的 ID 图标获取。
+
+ System.out.print("请输入需要更新的文档的 FileID:");
+ String oldFileId = scanner.nextLine();
+
+ String workspaceId = System.getenv("WORKSPACE_ID");
+ String result = updateKnowledgeBase(filePath, workspaceId, indexId, oldFileId);
+ if (result != null) {
+ System.out.println("知识库更新成功,返回知识库ID: " + result);
+ } else {
+ System.out.println("知识库更新失败。");
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/enterprise/controller/EnterpriseController.java b/src/main/java/com/gxwebsoft/enterprise/controller/EnterpriseController.java
new file mode 100644
index 0000000..819568a
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/controller/EnterpriseController.java
@@ -0,0 +1,147 @@
+package com.gxwebsoft.enterprise.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.gxwebsoft.common.core.web.BaseController;
+import com.gxwebsoft.common.core.web.ApiResult;
+import com.gxwebsoft.common.core.web.PageResult;
+import com.gxwebsoft.common.core.annotation.OperationLog;
+import com.gxwebsoft.common.system.entity.User;
+import com.gxwebsoft.enterprise.entity.Enterprise;
+import com.gxwebsoft.enterprise.service.EnterpriseService;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ *
+ * @author GIIT-YC
+ *
+ */
+@Tag(name = "企业信息管理")
+@RestController
+@RequestMapping("/api/enterprise/enterprise")
+public class EnterpriseController extends BaseController {
+
+ @Resource
+ private EnterpriseService enterpriseService;
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:list')")
+ @Operation(summary = "分页查询企业信息")
+ @GetMapping("/page")
+ public ApiResult> page(Enterprise enterprise) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.like(StrUtil.isNotBlank(enterprise.getName()), Enterprise::getName, enterprise.getName());
+ wrapper.like(StrUtil.isNotBlank(enterprise.getCreditCode()), Enterprise::getCreditCode, enterprise.getCreditCode());
+ wrapper.orderByAsc(Enterprise::getName);
+
+ final Page page = new Page<>(enterprise.getPage(), enterprise.getLimit());
+ final IPage p = enterpriseService.page(page, wrapper);
+
+ return success(new PageResult(p.getRecords(), p.getTotal()));
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:list')")
+ @Operation(summary = "查询全部企业信息")
+ @GetMapping("/list")
+ public ApiResult> list(Enterprise enterprise) {
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
+ wrapper.like(StrUtil.isNotBlank(enterprise.getName()), Enterprise::getName, enterprise.getName());
+ wrapper.like(StrUtil.isNotBlank(enterprise.getCreditCode()), Enterprise::getCreditCode, enterprise.getCreditCode());
+ return success(enterpriseService.list(wrapper));
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:list')")
+ @Operation(summary = "根据id查询企业信息")
+ @GetMapping("/{id}")
+ public ApiResult get(@PathVariable("id") Integer id) {
+ return success(enterpriseService.getById(id));
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:list')")
+ @Operation(summary = "根据CreditCode查询企业信息")
+ @GetMapping("/creditCode/{creditCode}")
+ public ApiResult getByCreditCode(@PathVariable("creditCode") String creditCode) {
+ Enterprise enterprise = enterpriseService.getOne(new LambdaQueryWrapper().eq(Enterprise::getCreditCode, creditCode));
+ return success(enterprise);
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:save')")
+ @OperationLog
+ @Operation(summary = "添加企业信息")
+ @PostMapping()
+ public ApiResult> save(@RequestBody Enterprise enterprise) {
+ // 记录当前登录用户id
+ User loginUser = getLoginUser();
+ if (loginUser != null) {
+ enterprise.setUserId(loginUser.getUserId());
+ final Enterprise one = enterpriseService.getOne(new LambdaQueryWrapper().eq(Enterprise::getCreditCode, enterprise.getCreditCode()));
+ if (!ObjectUtil.isEmpty(one)) {
+ return fail("企业统一信用代码已存在");
+ }
+ if (enterpriseService.save(enterprise)) {
+ //TODO 查询知识库(kb_name=enterprise.getCreditCode)
+
+ //TODO 新建知识库
+ String kbId = "pggi9mpair";
+
+ //绑定知识库
+ enterprise.setKbId(kbId);
+ enterpriseService.updateById(enterprise);
+ return success("添加成功");
+ }
+ }
+ return fail("添加失败");
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:update')")
+ @OperationLog
+ @Operation(summary = "修改企业信息")
+ @PutMapping()
+ public ApiResult> update(@RequestBody Enterprise enterprise) {
+ if(StrUtil.isEmpty(enterprise.getKbId())) {
+ //TODO 查询知识库
+
+ //TODO 新建知识库
+ String kbId = "pggi9mpair";
+
+ //绑定知识库
+ enterprise.setKbId(kbId);
+ }
+ if (enterpriseService.updateById(enterprise)) {
+ return success("修改成功");
+ }
+ return fail("修改失败");
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:remove')")
+ @OperationLog
+ @Operation(summary = "删除企业信息")
+ @DeleteMapping("/{id}")
+ public ApiResult> remove(@PathVariable("id") Integer id) {
+ if (enterpriseService.removeById(id)) {
+ return success("删除成功");
+ }
+ return fail("删除失败");
+ }
+
+// @PreAuthorize("hasAuthority('enterprise:enterprise:remove')")
+ @OperationLog
+ @Operation(summary = "批量删除企业信息")
+ @DeleteMapping("/batch")
+ public ApiResult> removeBatch(@RequestBody List ids) {
+ if (enterpriseService.removeByIds(ids)) {
+ return success("删除成功");
+ }
+ return fail("删除失败");
+ }
+
+}
diff --git a/src/main/java/com/gxwebsoft/enterprise/entity/Enterprise.java b/src/main/java/com/gxwebsoft/enterprise/entity/Enterprise.java
new file mode 100644
index 0000000..9e99efd
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/entity/Enterprise.java
@@ -0,0 +1,67 @@
+package com.gxwebsoft.enterprise.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.gxwebsoft.common.core.web.BaseParam;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 企业信息
+ * @author GIIT-YC
+ */
+@Data
+@TableName("enterprise")
+@EqualsAndHashCode(callSuper = false)
+@Schema(name = "Enterprise对象", description = "企业信息表")
+public class Enterprise extends BaseParam implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ @Schema(description = "ID")
+ @TableId(value = "id", type = IdType.AUTO)
+ private Integer id;
+
+ @Schema(description = "企业名称")
+ private String name;
+
+ @Schema(description = "统一代码")
+ private String creditCode;
+
+ @Schema(description = "企业性质(国企、行政事业单位、民间非营利组织)")
+ private String enterpriseType;
+
+ @Schema(description = "所属行业(使用插件)")
+ private String industry;
+
+ @Schema(description = "知识库ID")
+ private String kbId;
+
+ @Schema(description = "客户ID")
+ private Integer userId;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+
+ @Schema(description = "创建时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime createTime;
+
+ @Schema(description = "修改时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime updateTime;
+
+ @Schema(description = "状态, 0正常, 1冻结")
+ private Integer status;
+
+ @Schema(description = "是否删除, 0否, 1是")
+ @TableLogic
+ private Integer deleted;
+}
\ No newline at end of file
diff --git a/src/main/java/com/gxwebsoft/enterprise/mapper/EnterpriseMapper.java b/src/main/java/com/gxwebsoft/enterprise/mapper/EnterpriseMapper.java
new file mode 100644
index 0000000..33ca945
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/mapper/EnterpriseMapper.java
@@ -0,0 +1,13 @@
+package com.gxwebsoft.enterprise.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.gxwebsoft.enterprise.entity.Enterprise;
+
+/**
+ *
+ * @author GIIT-YC
+ *
+ */
+public interface EnterpriseMapper extends BaseMapper {
+
+}
diff --git a/src/main/java/com/gxwebsoft/enterprise/mapper/xml/EnterpriseMapper.xml b/src/main/java/com/gxwebsoft/enterprise/mapper/xml/EnterpriseMapper.xml
new file mode 100644
index 0000000..b543162
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/mapper/xml/EnterpriseMapper.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/main/java/com/gxwebsoft/enterprise/service/EnterpriseService.java b/src/main/java/com/gxwebsoft/enterprise/service/EnterpriseService.java
new file mode 100644
index 0000000..daf3ff8
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/service/EnterpriseService.java
@@ -0,0 +1,13 @@
+package com.gxwebsoft.enterprise.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.gxwebsoft.enterprise.entity.Enterprise;
+
+/**
+ *
+ * @author GIIT-YC
+ *
+ */
+public interface EnterpriseService extends IService {
+
+}
diff --git a/src/main/java/com/gxwebsoft/enterprise/service/impl/EnterpriseServiceImpl.java b/src/main/java/com/gxwebsoft/enterprise/service/impl/EnterpriseServiceImpl.java
new file mode 100644
index 0000000..a6eedda
--- /dev/null
+++ b/src/main/java/com/gxwebsoft/enterprise/service/impl/EnterpriseServiceImpl.java
@@ -0,0 +1,17 @@
+package com.gxwebsoft.enterprise.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.gxwebsoft.enterprise.entity.Enterprise;
+import com.gxwebsoft.enterprise.mapper.EnterpriseMapper;
+import com.gxwebsoft.enterprise.service.EnterpriseService;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * @author GIIT-YC
+ *
+ */
+@Service
+public class EnterpriseServiceImpl extends ServiceImpl implements EnterpriseService {
+
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index d0f9922..057cb94 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -63,3 +63,16 @@ certificate:
private-key-file: "apiclient_key.pem"
apiclient-cert-file: "apiclient_cert.pem"
wechatpay-cert-file: "wechatpay_cert.pem"
+
+aliyun:
+ knowledge-base:
+ access-key-id: LTAI5tD5YRKuxWz6Eg7qrM4P
+ access-key-secret: bO8TBDXflOwbtSKimPpG8XrJnyzgTk
+ workspace-id: llm-4pf5auwewoz34zqu
+
+ai:
+ template:
+ # Word 模板路径
+ word-template-path: classpath:templates/audit_report_template.docx
+ # 或者使用绝对路径
+ # word-template-path: D:\\公司经济责任审计方案模板.docx
\ No newline at end of file
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
index fbff897..c27504d 100644
--- a/src/main/resources/application-prod.yml
+++ b/src/main/resources/application-prod.yml
@@ -69,3 +69,16 @@ payment:
key-prefix: "Payment:1"
# 缓存过期时间(小时)
expire-hours: 24
+
+aliyun:
+ knowledge-base:
+ access-key-id: LTAI5tD5YRKuxWz6Eg7qrM4P
+ access-key-secret: bO8TBDXflOwbtSKimPpG8XrJnyzgTk
+ workspace-id: llm-4pf5auwewoz34zqu
+
+ai:
+ template:
+ # Word 模板路径
+ word-template-path: classpath:templates/audit_report_template.docx
+ # 或者使用绝对路径
+ # word-template-path: D:\\公司经济责任审计方案模板.docx
\ No newline at end of file
diff --git a/src/main/resources/templates/audit_report_template.docx b/src/main/resources/templates/audit_report_template.docx
new file mode 100644
index 0000000..0608b9d
Binary files /dev/null and b/src/main/resources/templates/audit_report_template.docx differ