Compare commits

..

53 Commits

Author SHA1 Message Date
lwj
35a8f6a3f8 修复1155报错、阶段性审核信息 2025-12-24 14:05:23 +08:00
joshen
b867c37f28 commit 2025-12-19 23:11:38 +08:00
joshen
0b9f95fab8 commit 2025-12-19 23:06:58 +08:00
joshen
04fea4b530 commit 2025-12-19 22:56:25 +08:00
joshen
97288c73b4 commit 2025-12-19 22:53:38 +08:00
joshen
2a07973c81 commit 2025-12-19 21:09:41 +08:00
joshen
5e9a40330c commit 2025-12-19 20:16:41 +08:00
joshen
e521b3fbe8 commit 2025-12-19 20:14:39 +08:00
joshen
1f5e9769f9 Merge remote-tracking branch 'nyx/release-20250328-master-20251219-lwj' into release-20250328-master 2025-12-19 20:05:19 +08:00
joshen
63d5e09170 Merge branch 'player-20251117' into release-20250328-master
# Conflicts:
#	servers/boe-server-all/src/main/java/com/xboe/module/course/api/CourseAuditApi.java
#	servers/boe-server-all/src/main/java/com/xboe/module/course/api/CourseFullTextApi.java
#	servers/boe-server-all/src/main/java/com/xboe/module/course/api/CourseManageApi.java
#	servers/boe-server-all/src/main/java/com/xboe/module/course/service/impl/CourseServiceImpl.java
#	servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseApi.java
2025-12-19 20:03:44 +08:00
huangrun
4bcef7a327 修改冲突 2025-12-19 18:59:22 +08:00
lwj
255864204e 修改1155审核时间格式 2025-12-19 18:31:17 +08:00
liu.zixi
34681bab97 Merge remote-tracking branch 'origin/release-20250328-master-20251219' into release-20250328-master-20251219 2025-12-19 17:35:21 +08:00
lwj
9852b24983 修改1155逻辑 2025-12-19 17:20:10 +08:00
肖建涛
02788430e9 1155增加审批人审批时间 2025-12-19 17:16:45 +08:00
liu.zixi
b396926e16 fix: 密级高于内部的案例处理 2025-12-19 16:58:22 +08:00
郭诚奇
94939824bd feat: 新增初始化会话接口,给前端返回初始化会话id 2025-12-19 16:58:20 +08:00
liu.zixi
8d0ee29cf7 feat: 丰富一下导出excel的内容和样式 2025-12-19 16:58:19 +08:00
huangrun
e97d589423 提交注释 2025-12-11 10:47:05 +08:00
huangrun
39d2681d4c 提交注释 2025-12-10 19:36:48 +08:00
huangrun
9b86026473 课程详情接口优化 2025-12-10 17:07:40 +08:00
huangrun
9219b77895 课程详情接口优化 2025-12-09 10:19:32 +08:00
huangrun
e727f266ec 课程详情接口优化 2025-12-09 10:06:23 +08:00
huangrun
49e42edf6f 课程AI设置优化 2025-12-08 19:38:26 +08:00
huangrun
f4d9847e8b 课程AI设置优化 2025-12-08 18:48:14 +08:00
huangrun
a0e1fea805 课程AI设置优化 2025-12-08 17:55:29 +08:00
huangrun
d0c5d2d561 课程详情 2025-12-08 15:45:45 +08:00
huangrun
951f2b0105 课程详情 2025-12-08 14:56:41 +08:00
huangrun
aa14fffd6c 课程详情 2025-12-08 14:55:07 +08:00
huangrun
1d7e478aac 课程详情 2025-12-08 14:47:41 +08:00
huangrun
973bbffc3c 课程AI设置单独保存(原先是提交审核之后) 2025-12-08 11:01:11 +08:00
huangrun
6c3f380bcb 批量课程AI设置 2025-12-08 10:05:37 +08:00
huangrun
80b444c188 kjb接口添加配置 2025-11-21 14:27:21 +08:00
huangrun
b0a0725373 管理端端添加课程AI设置信息 2025-11-21 11:27:43 +08:00
huangrun
59e42cda4f 管理端端添加课程AI设置信息 2025-11-21 10:34:49 +08:00
huangrun
ec6d9100c2 学员端添加课程摘要信息 2025-11-20 16:04:46 +08:00
huangrun
562a4cc862 学员端添加课程摘要信息 2025-11-20 15:13:02 +08:00
huangrun
ae11017d67 学员端添加课程摘要信息 2025-11-20 14:43:11 +08:00
huangrun
fd473445de 学员端添加课程摘要信息 2025-11-20 14:38:56 +08:00
huangrun
bfdbd4d38e 学员端添加课程摘要信息 2025-11-20 14:36:45 +08:00
huangrun
640786391d 学员端添加课程摘要信息 2025-11-20 13:51:02 +08:00
huangrun
71b00372f6 参数添加字段 2025-11-19 20:07:00 +08:00
huangrun
2e4b04d1d1 AI字幕数据查询 2025-11-19 19:33:21 +08:00
huangrun
bffb85848f AI字幕数据查询 2025-11-19 18:07:46 +08:00
huangrun
a9e34e42b9 AI字幕数据查询 2025-11-19 17:49:38 +08:00
huangrun
84bd63ec0e AI字幕数据查询 2025-11-19 17:07:58 +08:00
huangrun
1aba83a1b8 参数添加字段 2025-11-19 15:28:06 +08:00
huangrun
2b1211c83d 参数添加字段 2025-11-19 14:34:30 +08:00
huangrun
fe3e8df37c 请求头指定编码 2025-11-19 12:43:52 +08:00
huangrun
8d9b360654 修改远程接口地址 2025-11-19 11:38:35 +08:00
huangrun
3379acdd1e 实体字段添加非表字段注解 2025-11-19 10:41:36 +08:00
huangrun
9a3b394e03 添加接口日志打印 2025-11-19 09:57:37 +08:00
huangrun
7beb046d6d 添加接口调用 2025-11-18 19:20:38 +08:00
23 changed files with 1179 additions and 201 deletions

View File

@@ -266,6 +266,10 @@
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version> <!-- 请根据实际需求选择版本 -->
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
<build>

View File

@@ -12,6 +12,7 @@ import com.xboe.module.boecase.service.ICaseAiPermissionService;
import com.xboe.module.boecase.service.IElasticSearchIndexService;
import com.xboe.module.boecase.vo.CaseAiMessageVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
@@ -46,6 +47,25 @@ public class CaseAiChatApi extends ApiBaseController {
@Autowired
private IElasticSearchIndexService elasticSearchIndexService;
/**
* 初始化会话
* @return 会话id
*/
@GetMapping("/initChat")
public JsonResponse<String> initChat() {
try {
String conversationId = caseAiChatService.initChat(getCurrent());
if (StringUtils.isNotBlank(conversationId)) {
return success(conversationId, "初始化会话成功");
} else {
return success(conversationId, "初始化会话失败");
}
} catch (Exception e) {
log.error("初始化会话异常", e);
return error("初始化会话失败", e.getMessage());
}
}
/**
* 聊天
* @param caseAiChatDto

View File

@@ -17,6 +17,13 @@ import java.util.List;
*/
public interface ICaseAiChatService {
/**
* 初始化会话
*
* @return {@link String } 会话id
*/
String initChat(CurrentUser currentUser);
/**
* 聊天
*

View File

@@ -1,5 +1,6 @@
package com.xboe.module.boecase.service.impl;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSON;
@@ -39,9 +40,7 @@ import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jetbrains.annotations.NotNull;
@@ -114,6 +113,16 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
// 用于存储会话ID与EventSource的映射关系以便能够中断特定会话
private final Map<String, EventSource> conversationEventSourceMap = new ConcurrentHashMap<>();
/**
* 初始化会话
*
* @return {@link String } 会话id
*/
@Override
public String initChat(CurrentUser currentUser) {
return getOrCreateConversationId(new CaseAiChatDto(), currentUser);
}
@Override
@Transactional
public SseEmitter chat(CaseAiChatDto caseAiChatDto, CurrentUser currentUser) {
@@ -387,7 +396,7 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
if (StringUtils.isEmpty(conversationId)) {
// 新会话,调用创建会话接口
String conversationName = "AI案例咨询-" + LocalDateTime.now().toString();
CaseAiConversations newConversation = createNewConversation(currentUser.getCode(), conversationName);
CaseAiConversations newConversation = SpringUtil.getBean(ICaseAiChatService.class).createNewConversation(currentUser.getCode(), conversationName);
return newConversation.getAiConversationId();
} else {
// 已存在会话,从数据库查询
@@ -933,18 +942,89 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
// 写入Excel文件
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("AI会话数据");
// 样式
CellStyle headerStyle = workbook.createCellStyle();
Font headerFont = workbook.createFont();
headerFont.setBold(true);
headerFont.setColor(IndexedColors.WHITE.getIndex());
headerStyle.setFont(headerFont);
headerStyle.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
headerStyle.setAlignment(HorizontalAlignment.CENTER);
headerStyle.setVerticalAlignment(VerticalAlignment.CENTER);
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setAlignment(HorizontalAlignment.CENTER);
dataStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 增加一个汇总Sheet
Sheet summarySheet = workbook.createSheet("汇总");
Row summaryHeaderRow = summarySheet.createRow(0);
Cell monthHeaderCell = summaryHeaderRow.createCell(0);
monthHeaderCell.setCellValue("月份");
monthHeaderCell.setCellStyle(headerStyle);
Cell sessionCountHeaderCell = summaryHeaderRow.createCell(1);
sessionCountHeaderCell.setCellValue("会话总次数");
sessionCountHeaderCell.setCellStyle(headerStyle);
Cell userCountHeaderCell = summaryHeaderRow.createCell(2);
userCountHeaderCell.setCellValue("会话总人数");
userCountHeaderCell.setCellStyle(headerStyle);
Row summaryDataRow = summarySheet.createRow(1);
Cell monthDataCell = summaryDataRow.createCell(0);
monthDataCell.setCellValue(startTime.format(DateTimeFormatter.ofPattern("yyyy年MM月")));
monthDataCell.setCellStyle(dataStyle);
Cell sessionCountDataCell = summaryDataRow.createCell(1);
sessionCountDataCell.setCellValue(conversations.size());
sessionCountDataCell.setCellStyle(dataStyle);
Cell userCountDataCell = summaryDataRow.createCell(2);
userCountDataCell.setCellValue(conversations.stream().map(CaseAiConversations::getConversationUser).distinct().count());
userCountDataCell.setCellStyle(dataStyle);
// 列宽
for (int i = 0; i < 3; i++) {
summarySheet.autoSizeColumn(i);
summarySheet.setColumnWidth(i, summarySheet.getColumnWidth(i) + 500);
}
Sheet dataSheet = workbook.createSheet("AI会话数据");
// 标题行
Row headerRow = sheet.createRow(0);
headerRow.createCell(0).setCellValue("会话ID");
headerRow.createCell(1).setCellValue("会话名称");
headerRow.createCell(2).setCellValue("用户");
headerRow.createCell(3).setCellValue("提问");
headerRow.createCell(4).setCellValue("回答");
headerRow.createCell(5).setCellValue("开始时间");
headerRow.createCell(6).setCellValue("问答时长(秒)");
headerRow.createCell(7).setCellValue("消息状态");
headerRow.createCell(8).setCellValue("错误信息");
Row dataHeaderRow = dataSheet.createRow(0);
Cell conversationIdHeaderCell = dataHeaderRow.createCell(0);
conversationIdHeaderCell.setCellValue("会话ID");
conversationIdHeaderCell.setCellStyle(headerStyle);
Cell conversationNameHeaderCell = dataHeaderRow.createCell(1);
conversationNameHeaderCell.setCellValue("会话名称");
conversationNameHeaderCell.setCellStyle(headerStyle);
Cell userHeaderCell = dataHeaderRow.createCell(2);
userHeaderCell.setCellValue("用户ID");
userHeaderCell.setCellStyle(headerStyle);
Cell queryHeaderCell = dataHeaderRow.createCell(3);
queryHeaderCell.setCellValue("提问");
queryHeaderCell.setCellStyle(headerStyle);
Cell answerHeaderCell = dataHeaderRow.createCell(4);
answerHeaderCell.setCellValue("回答");
answerHeaderCell.setCellStyle(headerStyle);
Cell startTimeHeaderCell = dataHeaderRow.createCell(5);
startTimeHeaderCell.setCellValue("开始时间");
startTimeHeaderCell.setCellStyle(headerStyle);
Cell durationHeaderCell = dataHeaderRow.createCell(6);
durationHeaderCell.setCellValue("问答时长(秒)");
durationHeaderCell.setCellStyle(headerStyle);
Cell statusHeaderCell = dataHeaderRow.createCell(7);
statusHeaderCell.setCellValue("消息状态");
statusHeaderCell.setCellStyle(headerStyle);
Cell errorMsgHeaderCell = dataHeaderRow.createCell(8);
errorMsgHeaderCell.setCellValue("错误信息");
errorMsgHeaderCell.setCellStyle(headerStyle);
// 内容行
if (!excelDataList.isEmpty()) {
@@ -958,48 +1038,78 @@ public class CaseAiChatServiceImpl implements ICaseAiChatService {
// 遍历每个消息
for (CaseAiMessageVo message : messages) {
Row row = sheet.createRow(rowNum++);
Row row = dataSheet.createRow(rowNum++);
// 填充每行数据
row.createCell(0).setCellValue(excelData.getConversationId());
row.createCell(1).setCellValue(excelData.getConversationName());
row.createCell(2).setCellValue(excelData.getUser());
row.createCell(3).setCellValue(message.getQuery() != null ? message.getQuery() : "");
row.createCell(4).setCellValue(message.getAnswer() != null ? message.getAnswer() : "");
Cell conversationIdCell = row.createCell(0);
conversationIdCell.setCellValue(excelData.getConversationId());
conversationIdCell.setCellStyle(dataStyle);
Cell conversationNameCell = row.createCell(1);
conversationNameCell.setCellValue(excelData.getConversationName());
conversationNameCell.setCellStyle(dataStyle);
Cell userCell = row.createCell(2);
userCell.setCellValue(excelData.getUser());
userCell.setCellStyle(dataStyle);
Cell queryCell = row.createCell(3);
queryCell.setCellValue(message.getQuery() != null ? message.getQuery() : "");
queryCell.setCellStyle(dataStyle);
Cell answerCell = row.createCell(4);
answerCell.setCellValue(message.getAnswer() != null ? message.getAnswer() : "");
answerCell.setCellStyle(dataStyle);
Cell startTimeCell = row.createCell(5);
LocalDateTime messageStartTime = message.getStartTime();
if (messageStartTime != null) {
String startTimeStr = messageStartTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
row.createCell(5).setCellValue(startTimeStr);
startTimeCell.setCellValue(startTimeStr);
} else {
row.createCell(5).setCellValue("");
startTimeCell.setCellValue("");
}
row.createCell(6).setCellValue(message.getDurationSeconds() != null ? message.getDurationSeconds() : 0);
startTimeCell.setCellStyle(dataStyle);
Cell durationCell = row.createCell(6);
durationCell.setCellValue(message.getDurationSeconds() != null ? message.getDurationSeconds() : 0);
durationCell.setCellStyle(dataStyle);
Cell statusCell = row.createCell(7);
if (message.getStatus() != null) {
int status = message.getStatus();
CaseAiChatErrCodeEnum errCodeEnum = CaseAiChatErrCodeEnum.getByCode(status);
row.createCell(7).setCellValue(errCodeEnum.getLabel());
statusCell.setCellValue(errCodeEnum.getLabel());
}
statusCell.setCellStyle(dataStyle);
Cell errorMsgCell = row.createCell(8);
if (StringUtils.isNotBlank(message.getErrorMsg())) {
row.createCell(8).setCellValue(message.getErrorMsg());
errorMsgCell.setCellValue(message.getErrorMsg());
}
errorMsgCell.setCellStyle(dataStyle);
}
// 合并单元格会话ID、会话名称、用户三列
// 参数说明:起始行号,结束行号,起始列号,结束列号
if (rowNum > startRow + 1) { // 只有当有多行时才合并
sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 0, 0));
sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 1, 1));
sheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 2, 2));
dataSheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 0, 0));
dataSheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 1, 1));
dataSheet.addMergedRegion(new CellRangeAddress(startRow, rowNum - 1, 2, 2));
}
} else {
// 如果没有消息,则仍然创建一行显示基本信息
Row row = sheet.createRow(rowNum++);
row.createCell(0).setCellValue(excelData.getConversationId());
row.createCell(1).setCellValue(excelData.getConversationName());
row.createCell(2).setCellValue(excelData.getUser());
Row row = dataSheet.createRow(rowNum++);
Cell conversationIdCell = row.createCell(0);
conversationIdCell.setCellValue(excelData.getConversationId());
conversationIdCell.setCellStyle(dataStyle);
Cell conversationNameCell = row.createCell(1);
conversationNameCell.setCellValue(excelData.getConversationName());
conversationNameCell.setCellStyle(dataStyle);
Cell userCell = row.createCell(2);
userCell.setCellValue(excelData.getUser());
userCell.setCellStyle(dataStyle);
}
}
}
// 列宽
for (int i = 0; i < 9; i++) {
summarySheet.autoSizeColumn(i);
summarySheet.setColumnWidth(i, summarySheet.getColumnWidth(i) + 500);
}
return workbook;
}

View File

@@ -765,186 +765,191 @@ public class CaseKnowledgeServiceImpl implements ICaseKnowledgeService {
}
}
JSONObject requestBody = new JSONObject();
String userId = getCurrentUserId();
requestBody.put("userId", userId);
requestBody.put("kId", caseAiProperties.getCaseKnowledgeId());
requestBody.put("parseType", "AUTO");
// 2. 检查文件路径
if (StringUtil.isBlank(cases.getFilePath())) {
log.error("上传案例文档失败案例文件路径为空caseId: {}", caseId);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败,案例文件路径为空",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
if (StringUtils.equals(cases.getConfidentialityLevel(), "内部")) {
JSONObject requestBody = new JSONObject();
String userId = getCurrentUserId();
requestBody.put("userId", userId);
requestBody.put("kId", caseAiProperties.getCaseKnowledgeId());
requestBody.put("parseType", "AUTO");
// 2. 检查文件路径
if (StringUtil.isBlank(cases.getFilePath())) {
log.error("上传案例文档失败案例文件路径为空caseId: {}", caseId);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败,案例文件路径为空",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
String savePath = fileUploader.getSavePath();
String filePath = savePath + cases.getFilePath();
File file = new File(filePath);
if (!file.exists()) {
log.error("上传案例文档失败案例文件不存在filePath: {}", filePath);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败案例文件不存在filePath: " + filePath,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
String savePath = fileUploader.getSavePath();
String filePath = savePath + cases.getFilePath();
File file = new File(filePath);
if (!file.exists()) {
log.error("上传案例文档失败案例文件不存在filePath: {}", filePath);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败案例文件不存在filePath: " + filePath,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
// 4. 构建上传参数
String fileName = file.getName();
// 4. 构建上传参数
String fileName = file.getName();
String fileType = getFileType(fileName);
String fileType = getFileType(fileName);
// 5. 重试逻辑最多3次机会
int uploadMaxRetries = 3;
// 5. 重试逻辑最多3次机会
int uploadMaxRetries = 3;
// 构建multipart/form-data请求体
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody("file", file);
builder.addTextBody("userId", userId, ContentType.TEXT_PLAIN);
builder.addTextBody("kId", caseAiProperties.getCaseKnowledgeId(), ContentType.TEXT_PLAIN);
builder.addTextBody("fileName", fileName, ContentType.TEXT_PLAIN);
requestBody.put("fileName", fileName);
builder.addTextBody("fileType", fileType, ContentType.TEXT_PLAIN);
requestBody.put("fileType", fileType);
builder.addTextBody("parseType", "AUTO", ContentType.TEXT_PLAIN);
// 构建multipart/form-data请求体
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addBinaryBody("file", file);
builder.addTextBody("userId", userId, ContentType.TEXT_PLAIN);
builder.addTextBody("kId", caseAiProperties.getCaseKnowledgeId(), ContentType.TEXT_PLAIN);
builder.addTextBody("fileName", fileName, ContentType.TEXT_PLAIN);
requestBody.put("fileName", fileName);
builder.addTextBody("fileType", fileType, ContentType.TEXT_PLAIN);
requestBody.put("fileType", fileType);
builder.addTextBody("parseType", "AUTO", ContentType.TEXT_PLAIN);
String url = caseAiProperties.getCaseDetailUrlBase() + caseId;
requestBody.put("url", url);
String downloadUrl = fileUploader.getHttpPath() + cases.getFilePath();
requestBody.put("downloadUrl", downloadUrl);
builder.addTextBody("url", url, ContentType.TEXT_PLAIN);
builder.addTextBody("downloadUrl", downloadUrl, ContentType.TEXT_PLAIN);
// metadata
JSONObject fileMetaData = new JSONObject();
fileMetaData.put("标题", cases.getTitle());
fileMetaData.put("作者", cases.getAuthorName());
fileMetaData.put("年份", String.valueOf(cases.getSysCreateTime().getYear()));
fileMetaData.put("摘要", cases.getSummary());
// 组织领域orgDomainParent
String orgDomainParent = cases.getOrgDomainParent();
List<DictItem> orgDomainParentItems = sysDictionaryService.findByKey("org_domain");
Optional<DictItem> orgDomainParentItem = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(orgDomainParent, item.getCode()))
.findFirst();
if (orgDomainParentItem.isPresent()) {
StringBuilder sb = new StringBuilder();
sb.append(orgDomainParentItem.get().getName());
if (StringUtils.isNotBlank(cases.getOrgDomainParent2())) {
Optional<DictItem> orgDomainParent2Item = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(cases.getOrgDomainParent2(), item.getCode()))
.findFirst();
orgDomainParent2Item.ifPresent(dictItem -> sb.append(" - ").append(dictItem.getName()));
if (StringUtils.isNotBlank(cases.getOrgDomainParent3())) {
Optional<DictItem> orgDomainParent3Item = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(cases.getOrgDomainParent3(), item.getCode()))
String url = caseAiProperties.getCaseDetailUrlBase() + caseId;
requestBody.put("url", url);
String downloadUrl = fileUploader.getHttpPath() + cases.getFilePath();
requestBody.put("downloadUrl", downloadUrl);
builder.addTextBody("url", url, ContentType.TEXT_PLAIN);
builder.addTextBody("downloadUrl", downloadUrl, ContentType.TEXT_PLAIN);
// metadata
JSONObject fileMetaData = new JSONObject();
fileMetaData.put("标题", cases.getTitle());
fileMetaData.put("作者", cases.getAuthorName());
fileMetaData.put("年份", String.valueOf(cases.getSysCreateTime().getYear()));
fileMetaData.put("摘要", cases.getSummary());
// 组织领域orgDomainParent
String orgDomainParent = cases.getOrgDomainParent();
List<DictItem> orgDomainParentItems = sysDictionaryService.findByKey("org_domain");
Optional<DictItem> orgDomainParentItem = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(orgDomainParent, item.getCode()))
.findFirst();
if (orgDomainParentItem.isPresent()) {
StringBuilder sb = new StringBuilder();
sb.append(orgDomainParentItem.get().getName());
if (StringUtils.isNotBlank(cases.getOrgDomainParent2())) {
Optional<DictItem> orgDomainParent2Item = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(cases.getOrgDomainParent2(), item.getCode()))
.findFirst();
orgDomainParent3Item.ifPresent(dictItem -> sb.append(" - ").append(dictItem.getName()));
orgDomainParent2Item.ifPresent(dictItem -> sb.append(" - ").append(dictItem.getName()));
if (StringUtils.isNotBlank(cases.getOrgDomainParent3())) {
Optional<DictItem> orgDomainParent3Item = orgDomainParentItems.stream()
.filter(item -> StringUtils.equals(cases.getOrgDomainParent3(), item.getCode()))
.findFirst();
orgDomainParent3Item.ifPresent(dictItem -> sb.append(" - ").append(dictItem.getName()));
}
}
fileMetaData.put("组织领域", sb.toString());
}
// 分类majorIds
List<CasesMajorType> cmtList = casesMajorTypeDao.findList(FieldFilters.eq("caseId", cases.getId()));
if (cmtList != null && !cmtList.isEmpty()) {
List<String> majorIds = cmtList.stream().map(CasesMajorType::getMajorId).collect(Collectors.toList());
List<DictItem> majorItems = sysDictionaryService.findByKey("major_type");
if (majorItems != null && !majorItems.isEmpty()) {
List<String> majorNames = majorItems.stream()
.filter(item -> majorIds.contains(item.getCode()))
.map(DictItem::getName)
.collect(Collectors.toList());
fileMetaData.put("组织领域", String.join(", ", majorNames));
}
}
fileMetaData.put("组织领域", sb.toString());
}
// 分类majorIds
List<CasesMajorType> cmtList = casesMajorTypeDao.findList(FieldFilters.eq("caseId", cases.getId()));
if (cmtList != null && !cmtList.isEmpty()) {
List<String> majorIds = cmtList.stream().map(CasesMajorType::getMajorId).collect(Collectors.toList());
List<DictItem> majorItems = sysDictionaryService.findByKey("major_type");
if (majorItems != null && !majorItems.isEmpty()) {
List<String> majorNames = majorItems.stream()
.filter(item -> majorIds.contains(item.getCode()))
.map(DictItem::getName)
.collect(Collectors.toList());
fileMetaData.put("组织领域", String.join(", ", majorNames));
ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);
builder.addTextBody("fileMetaData", fileMetaData.toJSONString(), contentType);
requestBody.put("fileMetaData", fileMetaData);
// 由于接口权限,目前采用不回调,而是通过批处理的方式,处理文件状态
if (caseAiProperties.isFileUploadUseCallback()) {
builder.addTextBody("callbackUrl", caseAiProperties.getFileUploadCallbackUrl(), ContentType.TEXT_PLAIN);
requestBody.put("callbackUrl", caseAiProperties.getFileUploadCallbackUrl());
}
}
ContentType contentType = ContentType.create("text/plain", StandardCharsets.UTF_8);
builder.addTextBody("fileMetaData", fileMetaData.toJSONString(), contentType);
requestBody.put("fileMetaData", fileMetaData);
// 由于接口权限,目前采用不回调,而是通过批处理的方式,处理文件状态
if (caseAiProperties.isFileUploadUseCallback()) {
builder.addTextBody("callbackUrl", caseAiProperties.getFileUploadCallbackUrl(), ContentType.TEXT_PLAIN);
requestBody.put("callbackUrl", caseAiProperties.getFileUploadCallbackUrl());
}
String uploadUrl = caseAiProperties.getBaseUrl() + "/apigateway/knowledge/v1/file/upload";
String uploadUrl = caseAiProperties.getBaseUrl() + "/apigateway/knowledge/v1/file/upload";
// 3. 获取access_token
String accessToken = aiAccessTokenService.getAccessToken();
if (StringUtil.isBlank(accessToken)) {
log.error("上传案例文档失败获取access_token失败");
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败获取access_token失败",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
for (int attempt = 1; attempt <= uploadMaxRetries; attempt++) {
log.info("上传案例文档第{}次尝试caseId: {}", attempt, caseId);
// 3. 获取access_token
String accessToken = aiAccessTokenService.getAccessToken();
if (StringUtil.isBlank(accessToken)) {
log.error("上传案例文档失败,获取access_token失败");
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "上传案例文档失败获取access_token失败",
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
return false;
}
for (int attempt = 1; attempt <= uploadMaxRetries; attempt++) {
log.info("上传案例文档第{}次尝试caseId: {}", attempt, caseId);
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(uploadUrl);
httpPost.setHeader("X-AI-ApiCode", caseAiProperties.getAiApiCode());
httpPost.setHeader("access_token", accessToken);
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(uploadUrl);
httpPost.setHeader("X-AI-ApiCode", caseAiProperties.getAiApiCode());
httpPost.setHeader("access_token", accessToken);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
HttpEntity multipart = builder.build();
httpPost.setEntity(multipart);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
if (statusCode == 200) {
JSONObject result = JSON.parseObject(responseBody);
if (result.getBooleanValue("success")) {
// 业务处理成功
JSONObject data = result.getJSONObject("data");
String taskId = data.getString("taskId");
if (statusCode == 200) {
JSONObject result = JSON.parseObject(responseBody);
if (result.getBooleanValue("success")) {
// 业务处理成功
JSONObject data = result.getJSONObject("data");
String taskId = data.getString("taskId");
// 保存成功的CaseDocumentLog记录
// 保存成功的CaseDocumentLog记录
// saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
// requestBody.toJSONString(), responseBody,
// CaseDocumentLogRunStatusEnum.RUNNING.getCode(), null, null, taskId);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.SUCCESS.getCode(), CaseDocumentLogCaseStatusEnum.FAILED.getCode(), taskId);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.SUCCESS.getCode(), CaseDocumentLogCaseStatusEnum.FAILED.getCode(), taskId);
log.info("上传案例文档成功,等待文档状态变更. caseId: {}, taskId: {}, 尝试次数: {}", caseId, taskId, attempt);
return true;
log.info("上传案例文档成功,等待文档状态变更. caseId: {}, taskId: {}, 尝试次数: {}", caseId, taskId, attempt);
return true;
} else {
// 业务处理失败,不重试
log.error("上传案例文档业务处理失败不重试response: {}", responseBody);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.SUCCESS.getCode(), CaseDocumentLogCaseStatusEnum.FAILED.getCode(), null);
return false;
}
} else {
// 业务处理失败,不重试
log.error("上传案例文档业务处理失败不重试response: {}", responseBody);
// 接口调用失败
log.error("上传案例文档接口调用失败,第{}次尝试status: {}, response: {}", attempt, statusCode, responseBody);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.SUCCESS.getCode(), CaseDocumentLogCaseStatusEnum.FAILED.getCode(), null);
return false;
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然失败
return false;
}
// 继续下一次重试
}
} else {
// 接口调用失败
log.error("上传案例文档接口调用失败,第{}次尝试status: {}, response: {}", attempt, statusCode, responseBody);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), responseBody,
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然失败
return false;
}
// 继续下一次重试
}
} catch (Exception e) {
// 接口调用异常
log.error("上传案例文档接口调用异常,第{}次尝试", attempt, e);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "接口调用异常: " + e.getMessage(),
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然异常
log.error("上传案例文档最终失败,已重试{}次", uploadMaxRetries);
return false;
}
// 继续下一次重试
}
} catch (Exception e) {
// 接口调用异常
log.error("上传案例文档接口调用异常,第{}次尝试", attempt, e);
saveCaseDocumentLog(caseId, cases.getTitle(), CaseDocumentLogOptTypeEnum.UPDATE.getCode(), CaseAiConstants.CASE_DOC_UPLOAD_INTERFACE_NAME,
requestBody.toJSONString(), "接口调用异常: " + e.getMessage(),
CaseDocumentLogRunStatusEnum.COMPLETED.getCode(), CaseDocumentLogOptStatusEnum.FAILED.getCode(), null, null);
if (attempt == uploadMaxRetries) {
// 最后一次尝试仍然异常
log.error("上传案例文档最终失败,已重试{}次", uploadMaxRetries);
return false;
}
// 继续下一次重试
}
} else {
log.info("非【内部】密级案例,不进行上传");
return true;
}
return false;

View File

@@ -1,5 +1,6 @@
package com.xboe.module.course.api;
import java.io.IOException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@@ -7,10 +8,25 @@ import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xboe.api.ThirdApi;
import com.xboe.module.course.dto.CourseParam;
import com.xboe.module.course.service.*;
import com.xboe.module.course.dto.*;
import com.xboe.module.course.entity.*;
import com.xboe.module.course.utils.HttpUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -29,6 +45,10 @@ import com.xboe.module.course.entity.Course;
import com.xboe.module.course.entity.CourseAudit;
import com.xboe.module.course.entity.CourseContent;
import com.xboe.module.course.entity.CourseHRBPAudit;
import com.xboe.module.course.service.ICourseAuditService;
import com.xboe.module.course.service.ICourseContentService;
import com.xboe.module.course.service.ICourseHRBPAuditService;
import com.xboe.module.course.service.ICourseService;
import com.xboe.standard.enums.BoedxContentType;
import com.xboe.standard.enums.BoedxCourseType;
@@ -60,6 +80,12 @@ public class CourseAuditApi extends ApiBaseController{
@Resource
private ICourseTagService tagService;
@Value("${kjb.aicoreUrl}")
private String aicoreUrl;
@Value("${kjb.videoUrlPrefix}")
private String videoUrlPerfix;
/**
* 教师需要审核的课程
* @param pager
@@ -448,16 +474,84 @@ public class CourseAuditApi extends ApiBaseController{
param.setOrgName(dto.getCourse().getOrgName());
thirdApi.updateOrSaveCourse(param,token);
log.info("---------------在线课同步到讲师管理完毕 -------");
//AI视频处理-调用接口
//需求调整-课程AI设置放在课程提交审核之前
this.sendMessageToKJB(dto);
log.info("---------------**审核**AI视频处理-调用接口完毕 -------");
return success(true);
} catch (Exception e) {
log.error("默认管理员提交直接发布处理失败",e);
e.printStackTrace();
return error("发布课程失败",e.getMessage());
}
}
}
public void sendMessageToKJB(CourseFullDto dto) throws JsonProcessingException {
Course course = dto.getCourse();
//log.info("---------------AI视频处理-调用接口 -------");
log.info("aiSet:"+course.getAiSet()+",aiAbstract:"+course.getAiAbstract()+",aiDraft:"+course.getAiDraft()+",aiTranslate:"+course.getAiTranslate()+",languageCode:"+course.getLanguageCode());
List<CourseTeacher> teachers = dto.getTeachers();
StringBuilder teacherNames = new StringBuilder();
if(!CollectionUtils.isEmpty(teachers)){
for (CourseTeacher teacher : teachers) {
teacherNames.append(teacher.getTeacherName()).append(",");
}
}
List<CourseContent> cclist = ccontentService.getByCourseId(course.getId());
List<String> languageCode = course.getLanguageCode();
String code = String.join(",", languageCode);
List<BoeaiCourseDto> courseDtos = new ArrayList<>();
BoeaiCourseDto boeaiCourseDto = new BoeaiCourseDto();
List<BoeaiVideoResourceDto> videoList = new ArrayList<>();
boeaiCourseDto = BoeaiCourseDto.builder()
.courseId(course.getId())
.title(course.getName())
.description(course.getSummary())
.instructor(teacherNames.toString())
.chapterCount(1) //章节数
.languageCode(code) //语言
.aiTranslate(course.getAiTranslate())
.aiAbstract(course.getAiAbstract())
.aiDraft(course.getAiDraft())
.aiSet(course.getAiSet())
.languageStatus(course.getLanguageStatus())
.build() ;
if(cclist != null && !cclist.isEmpty()){
for (CourseContent cc : cclist) {
//筛选视频资源
if(cc.getContentType() == 10 ){
JSONObject json = JSONObject.parseObject(cc.getContent());
if(json == null || json.getString("url") == null) {
continue;
}
String videoUrl = json.getString("url");
//String videoUrlPerfix = "https://u-pre.boe.com/upload"; //测试
//String videoUrlPerfix = "https://u.boe.com/upload"; //生产
String videoType = videoUrl.substring(videoUrl.lastIndexOf(".")+1);
videoList.add(BoeaiVideoResourceDto.builder()
.courseId(cc.getCourseId())
.videoId(cc.getId())
.title(cc.getContentName())
.originalUrl(videoUrlPerfix+videoUrl)
.duration(cc.getDuration())
.format(videoType)
.build());
}
}
}
boeaiCourseDto.setBoeaiVideoResourceReqList(videoList);
boeaiCourseDto.setVideoCount(videoList.size());
courseDtos.add(boeaiCourseDto);
BoeaiCourseParamsReq paramReq = new BoeaiCourseParamsReq();
paramReq.setBoeaiCourseReqList(courseDtos);
ObjectMapper objectMapper = new ObjectMapper();
String message = objectMapper.writeValueAsString(paramReq);
String url = aicoreUrl +"/aiVideo/saveCourse";
HttpUtils.sendMessage(message,url);
}
/***
* 审核
* @param dto
@@ -488,5 +582,4 @@ public class CourseAuditApi extends ApiBaseController{
}
}

View File

@@ -7,6 +7,9 @@ import java.util.stream.Collectors;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Opt;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boe.feign.api.serverall.entity.UserData;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -17,12 +20,15 @@ import com.xboe.core.orm.QueryBuilder;
import com.xboe.data.outside.IOutSideDataService;
import com.xboe.module.course.entity.CourseTag;
import com.xboe.module.course.service.*;
import com.xboe.module.course.dto.BoeaiCourseDto;
import com.xboe.module.course.utils.HttpUtils;
import com.xboe.module.course.vo.TeacherVo;
import com.xboe.school.study.entity.StudyCourse;
import com.xboe.school.study.service.IStudyCourseService;
import com.xboe.system.organization.service.IOrganizationService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -44,7 +50,7 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
//课程AI设置
@Slf4j
@RestController
@RequestMapping(value="/xboe/m/course/fulltext")
@@ -77,6 +83,9 @@ public class CourseFullTextApi extends ApiBaseController{
@Autowired
StringRedisTemplate redisTemplate;
@Value("${kjb.aicoreUrl}")
private String aicoreUrl;
/**
@@ -354,6 +363,8 @@ public class CourseFullTextApi extends ApiBaseController{
if(c.getSource()==2) {
cids.add(c.getId());
}
log.info("---- KJB 开始获取课程摘要信息 ---");
this.getCourseFromKJB(c,new Course());
}
List<Course> clist=null;
if(!cids.isEmpty()) {
@@ -451,6 +462,48 @@ public class CourseFullTextApi extends ApiBaseController{
}
public void getCourseFromKJB(CourseFullText courseFull,Course course){
String courseId = courseFull.getId();
log.info("------------KJB---获取课程详情 start ---------courseId = " + courseId);
//String url = env.getProperty("kjb.url") + "/api/course/getCourseFromKJB?courseId=" + courseId;
String url = aicoreUrl + "/aiVideo/getCourseList";
JSONObject jsonObject = new JSONObject();
JSONArray courseIds = new JSONArray();
courseIds.add(courseId);
jsonObject.put("courseIds", courseIds);
String result = HttpUtils.sendMessage(jsonObject.toJSONString(), url);
//将返回string 转为json对象
log.info("---KJB --摘要接口返回结果result: "+result);
JSONObject jsonResult = JSONObject.parseObject(result);
String data = jsonResult.getString("rows");
//json字符串转为实体对象
// 直接解析为 List<Course>
List<BoeaiCourseDto> boeaiCourseDto = JSON.parseArray(data, BoeaiCourseDto.class);
//List<BoeaiCourseDto> aiVideoResourceRsp = Collections.singletonList(JSON.parseObject(data, BoeaiCourseDto.class));
if(boeaiCourseDto != null && !boeaiCourseDto.isEmpty()){
//log.info("KJB摘要信息"+boeaiCourseDto.get(0).getSummaryContent());
courseFull.setAiAbstract(boeaiCourseDto.get(0).getAiAbstract());
courseFull.setSummaryContent(boeaiCourseDto.get(0).getSummaryContent());
courseFull.setAiSet(boeaiCourseDto.get(0).getAiSet());
courseFull.setAiDraft(boeaiCourseDto.get(0).getAiDraft());
courseFull.setAiTranslate(boeaiCourseDto.get(0).getAiTranslate());
courseFull.setLanguageStatus(boeaiCourseDto.get(0).getLanguageStatus());
courseFull.setLanguageCode(boeaiCourseDto.get(0).getLanguageCode() == null ? new ArrayList<>() :Arrays.asList(boeaiCourseDto.get(0).getLanguageCode().split(",")));
course.setAiSet(boeaiCourseDto.get(0).getAiSet());
course.setAiAbstract(boeaiCourseDto.get(0).getAiAbstract());
//course.setSummaryStatus(boeaiCourseDto.get(0).getSummaryStatus());
course.setSummaryContent(boeaiCourseDto.get(0).getSummaryContent());
course.setAiDraft(boeaiCourseDto.get(0).getAiDraft());
course.setAiTranslate(boeaiCourseDto.get(0).getAiTranslate());
course.setLanguageStatus(boeaiCourseDto.get(0).getLanguageStatus());
course.setLanguageCode(boeaiCourseDto.get(0).getLanguageCode() == null ? new ArrayList<>() :Arrays.asList(boeaiCourseDto.get(0).getLanguageCode().split(",")));
}
log.info("------------KJB---获取课程详情 end ---------");
}
private void getTeacherStatusByCode(String token, PageList<CourseFullText> coursePageList) {
log.info("获取教师信息通过工号 ");
List<String> teacherCoeds = new ArrayList<>();

View File

@@ -17,6 +17,7 @@ import com.xboe.module.course.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -93,6 +94,11 @@ public class CourseManageApi extends ApiBaseController{
IDataUserSyncService userSyncService;
@Resource
private ThirdApi thirdApi;
@Resource
CourseAuditApi courseAuditApi;
@Resource
CourseFullTextApi courseFullTextApi;
// @PostMapping("/test")
// public JsonResponse<PageList<Course>> findTest(Pagination pager,CourseQueryDto dto){
@@ -138,6 +144,10 @@ public class CourseManageApi extends ApiBaseController{
dto.setOrgIds(ids);
dto.setReadIds(userOrgIds.getReadIds());
PageList<Course> coursePageList = courseService.findPage(pager.getPageIndex(), pager.getPageSize(),dto);
//补充审核人,审核时间字段
if(CollectionUtils.isNotEmpty(coursePageList.getList())){
fullAuditInfo(coursePageList.getList());
}
return success(coursePageList);
}catch(Exception e) {
log.error("管理课程列表查询错误",e);
@@ -145,7 +155,45 @@ public class CourseManageApi extends ApiBaseController{
}
}
public void fullAuditInfo(List<Course> list){
List<String> courseIdList = list.stream().map(Course::getId).collect(Collectors.toList());
List<CourseHRBPAudit> auditList = hrbpAuditService.listByCourseIds(courseIdList);
Map<String,CourseHRBPAudit> map = new HashMap<>();
for(CourseHRBPAudit audit : auditList){
CourseHRBPAudit r = map.get(audit.getCourseId());
//可能存在多个审核记录,取时间最新的那一条
if(r == null || r.getAddTime().isBefore(audit.getAddTime())){
map.put(audit.getCourseId(),audit);
}
}
list.forEach(item ->{
CourseHRBPAudit audit = map.get(item.getId());
if(audit != null){
//公开课审核完成取公开课的审核信息
if(StringUtils.isNotEmpty(audit.getLastAname())){
item.setAuditUser(audit.getLastAname());
item.setAuditTime(audit.getLastTime());
}else if(CourseHRBPAudit.FORWARD_TEACHER == audit.getForward()){
//转发到教师审核取教师审核信息
item.setAuditUser(audit.getToName());
}else if (CourseHRBPAudit.FORWARD_TO_FINISH == audit.getForward()){
//老师审核完成
item.setAuditUser(audit.getAuditUser());
if(CourseHRBPAudit.STATUS_NOPASS ==audit.getStatus()){
//老师审核不通过时取老师的审核时间
item.setAuditTime(audit.getToAuditTime());
}
}else {
item.setAuditUser(audit.getAuditUser());
item.setAuditTime(audit.getAuditTime());
}
}
});
}
@GetMapping("/detail")
public JsonResponse<Map<String,Object>> detail(String id){
if(StringUtils.isBlank(id)) {
@@ -174,6 +222,13 @@ public class CourseManageApi extends ApiBaseController{
isPermission = dicts.contains(course.getOrgId());
rs.put("dicts",dicts);
}
//void getCourseFromKJB(CourseFullText courseFull,Course course){
log.info("-------课程详情(KJB)查询开始-------");
CourseFullText courseFull = new CourseFullText();
courseFull.setId(course.getId());
courseFullTextApi.getCourseFromKJB(courseFull,course);
log.info("-------课程详情(KJB)查询结束-------");
log.error("-------是否仅内网查看 = " + isPermission);
if (StringUtils.isNotBlank(course.getTags()) && course.getTags().matches("[0-9,]+")){
List<CourseTag> tagList = tagService.getTagsByIds(course.getTags());
@@ -210,7 +265,7 @@ public class CourseManageApi extends ApiBaseController{
}
return success(rs);
}
/**
* 管理员审核列表教师的审核不在这里此审核也应该移动CourseAuditApi中去
* @param pager
@@ -359,6 +414,11 @@ public class CourseManageApi extends ApiBaseController{
param.setOrgName(dto.getCourse().getOrgName());
thirdApi.updateOrSaveCourse(param,token);
log.info("---------------在线课同步到讲师管理完毕 -------");
//AI视频处理-调用接口
log.info("---------------AI视频处理-调用接口开始 -------");
courseAuditApi.sendMessageToKJB(dto);
log.info("---------------AI视频处理-调用接口结束 -------");
return success(dto);
} catch (Exception e) {
log.error("整体保存课程信息错误",e);
@@ -404,7 +464,29 @@ public class CourseManageApi extends ApiBaseController{
return error("保存失败",e.getMessage());
}
}
@PostMapping("/benchAiSet")
@AutoLog(module = "课程",action = "批量课程AI设置",info = "")
public JsonResponse<CourseFullDto> benchAiSet(@RequestBody CourseFullDto dto){
log.info("--------------- 批量课程AI设置 ----------");
if(CollectionUtils.isEmpty(dto.getCourseList())) {
return badRequest("请选择要设置的课程");
}
try {
CourseFullDto item;
for (Course course : dto.getCourseList()) {
item = new CourseFullDto();
item.setCourse(course);
courseAuditApi.sendMessageToKJB(item);
}
return success(dto);
} catch (Exception e) {
log.error("批量课程AI设置错误",e);
return error("保存失败",e.getMessage());
}
}
private String checkForSubmit(Course c) {
String error=null;
if(StringUtils.isBlank(c.getName())) {
@@ -632,7 +714,7 @@ public class CourseManageApi extends ApiBaseController{
String email = userBasicInfoVoList.get(0).getEmail();
log.info("审批获取邮箱 userBasicInfoVoList.get(0).getEmail(){}", email);
return email;
} catch (Exception e) {
log.error("获取用户邮箱错误",e);

View File

@@ -0,0 +1,86 @@
package com.xboe.module.course.dto;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* @author Huang Run
* @date 2025年11月04日
*/
@Data
public class AiVideoResourceRsp {
//多语言字幕信息
List<BoeaiSubtitleRsp> boeaiSubtitleRspList;
private Long id;
/**
* 视频业务ID
*/
private String videoId;
/**
* 视频语言编码 如 zh-CN, en-US
*/
//private String languageCode;
/**
* 课程ID
*/
private String courseId;
/**
* 视频标题
*/
private String title;
/**
* 原始视频URL
*/
private String originalUrl;
/**
* 视频时长(秒)
*/
private Integer duration;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 视频格式 mp4/avi等
*/
private String format;
/**
* 状态 0-待处理 1-处理中 2-已完成 3-失败
*/
private Integer status;
/**
* 是否已审核 0-否 1-是
*/
private Integer isReviewed;
/**
* 审核人ID
*/
private String reviewerId;
/**
* 审核时间
*/
private Date reviewedAt;
/**
*
*/
private Date createdAt;
/**
*
*/
private Date updatedAt;
}

View File

@@ -0,0 +1,103 @@
package com.xboe.module.course.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Transient;
import java.util.Date;
import java.util.List;
/**
* @author
* @date 2025年11月18日
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BoeaiCourseDto {
List<BoeaiVideoResourceDto> boeaiVideoResourceReqList;
List<String> courseVideoIds;
private Long id;
/**
* 课程ID
*/
private String courseId;
/**
* 视频ID
*/
private String videoId;
/**
* 课程标题
*/
private String title;
/**
* 讲师名称
*/
private String instructor;
/**
* 章节数
*/
private Integer chapterCount;
/**
* 视频数
*/
private Integer videoCount;
/**
* 总时长(秒)
*/
private Integer totalDuration;
private Date createdAt;
private Date updatedAt;
/**
* 课程描述
*/
private String description;
/**
* 视频语言编码 如 zh-CN, en-US
*/
private String languageCode;
/**
* 0关闭1打开
* */
private Integer aiSet;
/**
* 摘要 0:上架1下架
* */
private Integer aiAbstract;
/**
* 文稿 0:上架1下架
* */
private Integer aiDraft;
/**
* 翻译 0:上架1下架
* */
private Integer aiTranslate;
private Integer languageStatus;
//摘要
private String summaryContent;
//摘要状态 0:下架1上架
private Integer summaryStatus;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,15 @@
package com.xboe.module.course.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author Huang Run
* @date 2025年11月19日
*/
@Data
public class BoeaiCourseParamsReq implements Serializable {
List<BoeaiCourseDto> boeaiCourseReqList;
}

View File

@@ -0,0 +1,80 @@
package com.xboe.module.course.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @author
* 视频字幕表
*/
@Data
public class BoeaiSubtitleRsp implements Serializable {
/**
* 主键ID
*/
private Long id;
/**
* 关联视频ID
*/
private String videoId;
/**
* 字幕语言(如 zh-CN, en-US
*/
private String language;
/**
* WebVTT字幕文件URLOSS地址
*/
private String subtitleUrl;
/**
* 是否原始字幕 0-翻译 1-原始
*/
private Byte isOriginal;
/**
* 源语言/翻译来源(如 zh-CN
*/
private String sourceLanguage;
/**
* 翻译引擎llm/google/deepl
*/
private String translateEngine;
/**
* 状态0-待生成 1-生成中 2-已完成 3-失败)
*/
private Boolean status;
/**
* 创建时间
*/
private Date createdAt;
/**
* 更新时间
*/
private Date updatedAt;
/**
* 字幕数据JSON 数组格式,包含时间戳和翻译文本)
*/
private String subtitleData;
/**
* WebVTT 格式字幕内容
*/
private String vttContent;
/**
* 错误信息
*/
private String errorMsg;
private static final long serialVersionUID = 1L;
}

View File

@@ -0,0 +1,88 @@
package com.xboe.module.course.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author
* @date 2025年11月18日
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BoeaiVideoResourceDto {
/**
*
*/
private Long id;
/**
* 视频业务ID
*/
private String videoId;
/**
* 课程ID
*/
private String courseId;
/**
* 视频标题
*/
private String title;
/**
* 原始视频URL
*/
private String originalUrl;
/**
* 视频时长(秒)
*/
private Integer duration;
/**
* 文件大小(字节)
*/
private Long fileSize;
/**
* 视频格式 mp4/avi等
*/
private String format;
/**
* 状态 0-待处理 1-处理中 2-已完成 3-失败
*/
private Integer status;
/**
* 是否已审核 0-否 1-是
*/
private Integer isReviewed;
/**
* 审核人ID
*/
private String reviewerId;
/**
* 审核时间
*/
private Date reviewedAt;
/**
*
*/
private Date createdAt;
/**
*
*/
private Date updatedAt;
}

View File

@@ -31,6 +31,11 @@ public class CourseFullDto {
* 课程的信息
*/
private Course course;
/**
* 批量课程AI设置课
*/
private List<Course> courseList;
/**
* 课程资源信息

View File

@@ -1,6 +1,7 @@
package com.xboe.module.course.entity;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -216,6 +217,47 @@ public class Course extends BaseEntity {
@Column(name = "device",length = 1)
private Integer device;
/**
* 0关闭1打开
* */
// @Column(name = "ai_set",length = 1)
@Transient
private Integer aiSet;
/**
* 摘要 0:上架1下架
* */
//@Column(name = "ai_abstract",length = 1)
@Transient
private Integer aiAbstract;
/**
* 文稿 0:上架1下架
* */
// @Column(name = "ai_draft",length = 1)
@Transient
private Integer aiDraft;
/**
* 翻译 0:上架1下架
* */
//@Column(name = "ai_translate",length = 1)
@Transient
private Integer aiTranslate;
@Transient
private Integer languageStatus;
/**
* 语言 zh-CN,en-US,ja-JP,ko-KR
* */
//Column(name = "language_code",length = 120)
@Transient
private List<String> languageCode;
//摘要
@Transient
private String summaryContent;
//摘要状态 0:下架1上架
@Transient
private Integer summaryStatus;
/**
* 课程状态,多人审核机制,所以这里并没有审核通过与不通过的状态了
* 课程状态 1:未提交(草稿);2:已提交;3: 审核未通过5审核完成
@@ -406,6 +448,13 @@ public class Course extends BaseEntity {
@Transient
private Boolean isTip;
@Transient
private String auditUser;
@Transient
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime auditTime;
public Course(String id,String name,String summary,String coverImg,String sysCreateAid,String sysCreateBy,Integer type,LocalDateTime publishTime){
super.setId(id);
this.name=name;

View File

@@ -8,9 +8,12 @@ import javax.persistence.Transient;
import com.xboe.core.SysConstant;
import com.xboe.core.orm.BaseEntity;
import com.xboe.module.course.dto.BoeaiSubtitleRsp;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 课程内容表
* */
@@ -93,6 +96,9 @@ public class CourseContent extends BaseEntity {
/**用于学习时的状态显示,非存储字段*/
@Transient
private Integer status;
@Transient
List<BoeaiSubtitleRsp> boeaiSubtitleRspList;
public CourseContent() {

View File

@@ -55,6 +55,8 @@ public interface ICourseHRBPAuditService {
* @return
*/
PageList<CourseHRBPAudit> pageList(Integer pageIndex, Integer pageSize,int userType, CourseHRBPAudit info);
List<CourseHRBPAudit> listByCourseIds(List<String> courseIdList);
}

View File

@@ -263,4 +263,7 @@ public class CourseHRBPAuditServiceImpl implements ICourseHRBPAuditService {
return courseHRBPAuditDao.get(id);
}
public List<CourseHRBPAudit> listByCourseIds(List<String> courseIdList){
return courseHRBPAuditDao.findList(FieldFilters.in("courseId",courseIdList));
}
}

View File

@@ -24,14 +24,19 @@ import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
//import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xboe.api.ThirdApi;
import com.xboe.core.orm.*;
import com.xboe.module.course.dao.*;
import com.xboe.module.course.dto.*;
import com.xboe.module.course.entity.*;
import com.xboe.module.course.dao.*;
import com.xboe.module.course.dto.CourseTagRelationDto;
import com.xboe.module.course.entity.*;
import com.xboe.module.course.service.ICourseTagService;
import com.xboe.module.course.utils.HttpUtils;
import com.xboe.school.study.dao.StudyCourseDao;
import com.xboe.school.study.entity.StudyCourse;
import org.apache.commons.lang3.StringUtils;
@@ -43,6 +48,7 @@ import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.hibernate.mapping.IdGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
@@ -56,9 +62,6 @@ import com.xboe.common.beans.KeyValue;
import com.xboe.common.utils.IDGenerator;
import com.xboe.common.utils.StringUtil;
import com.xboe.core.event.IEventDataSender;
import com.xboe.module.course.dto.CourseFullDto;
import com.xboe.module.course.dto.CourseQueryDto;
import com.xboe.module.course.dto.RankingDto;
import com.xboe.module.course.service.ICourseFullTextSearch;
import com.xboe.module.course.service.ICourseService;
import com.xboe.module.interaction.service.ICourseGradeService;
@@ -134,6 +137,9 @@ public class CourseServiceImpl implements ICourseService {
@Resource
private ModifyLogDao modifyLogDao;
@Value("${kjb.aicoreUrl}")
private String aicoreUrl;
/**
* 生成过滤条件
*
@@ -460,6 +466,13 @@ public class CourseServiceImpl implements ICourseService {
PageList<Course> rs = new PageList<>();
rs.setCount(collect.size());
rs.setList(paginate);
//log.info("78888888888888888888 "+paginate.isEmpty());
if (paginate != null && !paginate.isEmpty()) {
log.info("-----KJB------ getCourse");
for (Course course : paginate) {
this.getCourseFromKJB(course);
}
}
return rs;
}
}
@@ -469,9 +482,46 @@ public class CourseServiceImpl implements ICourseService {
rs.setCount(listByFilters2.size());
rs.setPageSize(pageSize);
rs.setList(paginate);
if (paginate != null && !paginate.isEmpty()) {
log.info("-----KJB------ getCourse");
for (Course course : paginate) {
this.getCourseFromKJB(course);
}
}
return rs;
}
public void getCourseFromKJB(Course course){
String courseId = course.getId();
log.info("------------KJB---获取课程信息---------: courseId = " + courseId);
//String url = env.getProperty("kjb.url") + "/api/course/getCourseFromKJB?courseId=" + courseId;
String url = aicoreUrl + "/aiVideo/getCourseList";
JSONObject jsonObject = new JSONObject();
JSONArray courseIds = new JSONArray();
courseIds.add(courseId);
jsonObject.put("courseIds", courseIds);
String result = HttpUtils.sendMessage(jsonObject.toJSONString(), url);
log.info("---KJB --getCourseList 接口返回结果result: "+result);
JSONObject jsonResult = JSONObject.parseObject(result);
String data = jsonResult.getString("rows");
List<BoeaiCourseDto> boeaiCourseDto = JSON.parseArray(data, BoeaiCourseDto.class);
//List<BoeaiCourseDto> aiVideoResourceRsp = Collections.singletonList(JSON.parseObject(data, BoeaiCourseDto.class));
if(boeaiCourseDto != null && !boeaiCourseDto.isEmpty()){
log.info("KJB摘要信息"+boeaiCourseDto.get(0).getSummaryContent());
course.setSummaryContent(boeaiCourseDto.get(0).getSummaryContent());
course.setSummaryStatus(boeaiCourseDto.get(0).getSummaryStatus());
course.setAiSet(boeaiCourseDto.get(0).getAiSet());
course.setAiAbstract(boeaiCourseDto.get(0).getAiAbstract());
course.setAiDraft(boeaiCourseDto.get(0).getAiDraft());
course.setAiTranslate(boeaiCourseDto.get(0).getAiTranslate());
course.setLanguageStatus(boeaiCourseDto.get(0).getLanguageStatus());
course.setLanguageCode(boeaiCourseDto.get(0).getLanguageCode() == null ? new ArrayList<>() :Arrays.asList(boeaiCourseDto.get(0).getLanguageCode().split(",")));
}
}
private Set<String> getSeache(CourseQueryDto dto) {
//需要设置为隐藏的课程id
Set<String> list = new HashSet<>();
@@ -1114,6 +1164,7 @@ public class CourseServiceImpl implements ICourseService {
hrbpAudit.setCourseId(c.getId());
hrbpAudit.setAddTime(LocalDateTime.now());
hrbpAudit.setAid(full.getAuditUser().getAid());
hrbpAudit.setAuditUser(full.getAuditUser().getName());//提前保存审核hrbp的名字用于显示下一步审核人
hrbpAudit.setAuditRemark("");
hrbpAudit.setForward(CourseHRBPAudit.FORWARD_NONE);
hrbpAudit.setStatus(CourseHRBPAudit.STATUS_NONE);

View File

@@ -0,0 +1,49 @@
package com.xboe.module.course.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.nio.charset.StandardCharsets;
/**
* @author
* @date 2025年11月18日
*/
@Slf4j
public class HttpUtils {
public static String sendMessage(String message,String url) {
//log.info("----------------发送消息开始 -------");
log.info("----------------发送消息参数 -------{}url:{}",message,url);
// POST 请求
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// POST 请求
HttpPost httpPost = new HttpPost(url);
//HttpPost httpPost = new HttpPost("https://jsonplaceholder.typicode.com/posts");
httpPost.setEntity(new StringEntity(message, StandardCharsets.UTF_8));
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
httpPost.setHeader("Accept", "application/json");
CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity responseEntity = response.getEntity();
String responseBody = "";
if (responseEntity != null) {
responseBody = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
System.out.println("Response Body: " + responseBody);
}
log.info("---------------发送消息响应 -------{}",responseBody);
return responseBody;
// System.out.println("状态码: " + response.getCode());
// System.out.println("响应体: " + EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
log.error("KJB-接口调用失败",e);
throw new RuntimeException(e);
}
}
}

View File

@@ -9,6 +9,9 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.shaded.com.google.common.util.concurrent.RateLimiter;
import com.boe.feign.api.infrastructure.entity.CommonSearchVo;
import com.boe.feign.api.infrastructure.entity.Dict;
@@ -16,6 +19,11 @@ import com.xboe.api.ThirdApi;
import com.xboe.constants.CacheName;
import com.xboe.module.course.entity.*;
import com.xboe.module.course.service.ICourseTagService;
import com.xboe.module.course.api.CourseFullTextApi;
import com.xboe.module.course.dto.AiVideoResourceRsp;
import com.xboe.module.course.dto.BoeaiSubtitleRsp;
import com.xboe.module.course.dto.CourseFullText;
import com.xboe.module.course.utils.HttpUtils;
import com.xboe.module.course.vo.TeacherVo;
import com.xboe.module.usergroup.service.IUserGroupService;
import com.xboe.school.study.dao.StudyCourseDao;
@@ -24,6 +32,7 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -62,7 +71,7 @@ import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
//添加AI课程学习内容
/**
* 课程学习的内容
*/
@@ -103,6 +112,12 @@ public class StudyCourseApi extends ApiBaseController{
@Resource
private ICourseTagService courseTagService;
@Autowired
CourseFullTextApi courseFullTextApi;
@Value("${kjb.aicoreUrl}")
private String aicoreUrl;
/**
* 用于查询课程的学习记录
* @param pager
@@ -176,8 +191,15 @@ public class StudyCourseApi extends ApiBaseController{
String tags = tagList.stream().map(CourseTag::getTagName).collect(Collectors.joining(","));
course1.setTags(tags);
}
//获取课程AI详情
log.info("---- KJB 获取课程详情 ---");
CourseFullText courseFullText = new CourseFullText();
courseFullText.setId(cid);
courseFullTextApi.getCourseFromKJB(courseFullText,course);
rs.put("course",course1);
//rs.put("course",course);
List<CourseCrowd> courseCrowdList = courseService.findCrowdByCourseId(cid);
if(crowd!=null && crowd) {
rs.put("crowds",courseCrowdList);
@@ -213,7 +235,14 @@ public class StudyCourseApi extends ApiBaseController{
List<CourseContent> cclist=contentService.getByCourseId(cid);
List<CourseSection> sectionlist=sectionService.getByCourseId(cid);
List<CourseTeacher> teachers=courseService.findTeachersByCourseId(cid);
if(cclist!=null && !cclist.isEmpty()){
for (CourseContent cc : cclist) {
log.info("根据视频信息查询AI字幕数据cc = " + cc.toString());
this.getVtt( cid , cc);
}
}
//获取教师的介绍信息,因为一门课程 的教师不会太多,所以这里简单直接遍历查询,后续再优化
for(CourseTeacher ct : teachers) {
Teacher t = teacherService.get(ct.getTeacherId());
@@ -239,6 +268,7 @@ public class StudyCourseApi extends ApiBaseController{
}
}
rs.put("isCrowd",pass);
rs.put("contents",cclist);
rs.put("sections",sectionlist);
@@ -328,6 +358,35 @@ public class StudyCourseApi extends ApiBaseController{
return success(rs);
}
public void getVtt(String couirseId, CourseContent cc){
log.info("------KJB --------- getVtt couirseId = " + couirseId + " videoId = " + cc.getId());
String url = aicoreUrl + "/aiVideo/getVideoVtt";
JSONObject message = new JSONObject();
message.put("courseId", couirseId);
message.put("videoId", cc.getId());
String result = HttpUtils.sendMessage(message.toJSONString(), url);
if(StringUtils.isBlank(result)){
log.error("未获取到AI字幕信息");
return;
}
//将返回string 转为json对象
JSONObject jsonObject = JSONObject.parseObject(result);
String data = jsonObject.getString("data");
//json字符串转为实体对象
AiVideoResourceRsp aiVideoResourceRsp = JSON.parseObject(data, AiVideoResourceRsp.class);
log.info("aiVideoResourceRsp:"+aiVideoResourceRsp);
//循环json对象
if(aiVideoResourceRsp != null){
cc.setBoeaiSubtitleRspList(aiVideoResourceRsp.getBoeaiSubtitleRspList());
// for (int i = 0; i < rows.size(); i++) {
// JSONObject row = rows.getJSONObject(i);
// //将json对象转为实体对象 CourseContentVtt
// BoeaiSubtitleRsp vtt = row.toJavaObject(BoeaiSubtitleRsp.class);
// boeaiSubtitleRspList.add(vtt);
// }
}
}
/**
* 在打开课程详细页面的时候,调用此接口,返回学习课程信息,上次学习的位置。<br/>
* 如果没有就返回空<br>

View File

@@ -343,4 +343,8 @@ aop-log-record:
password: admin
elasticsearch:
host: 10.251.88.218
port: 9200
port: 9200
kjb:
aicoreUrl: http://10.232.28.95:8080
videoUrlPrefix: https://u.boe.com/upload

View File

@@ -160,6 +160,10 @@ jasypt:
boe:
domain: http://10.251.186.27
kjb:
aicoreUrl: http://10.251.186.27:8088
videoUrlPrefix: https://u-pre.boe.com/upload
ok:
http:
connect-timeout: 30