Commit da705bb9 authored by alex yao's avatar alex yao

feat:问答知识库

parent d91f5549
......@@ -3,6 +3,7 @@ package cn.com.poc.knowledge.aggregate;
import cn.com.poc.knowledge.entity.BizKnowledgeDocumentEntity;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.GetKnowledgeChunkInfoResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.SegmentationConfigRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.springframework.web.multipart.MultipartFile;
......@@ -103,6 +104,6 @@ public interface KnowledgeService {
*
* @param knowledgeInfoIds 知识库信息ID列表
*/
List<Integer> getKdIdsByKnowledgeInfoIds(Integer[] knowledgeInfoIds) throws Exception;
List<Integer> getKdIdsByKnowledgeInfoIds(Integer[] knowledgeInfoIds);
}
package cn.com.poc.knowledge.aggregate;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.ChunkInfo;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeChunkResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.data.model.PagingInfo;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
public interface QAKnowledgeService {
/**
* 获取知识库分片
*
* @param kdId 文档ID
* @param query 模糊查询
* @param pagingInfo 分页信息
*/
QAKnowledgeChunkResult getChunkInfo(Integer kdId, String query, PagingInfo pagingInfo);
/**
* 开关知识库分片
*
* @param kdId 文档ID
* @param chunkRelationId 分片关系id
* @param isOpen 是否开启 Y/N
*/
void openKnowledgeChunk(Integer kdId, String chunkRelationId, String isOpen);
/**
* 删除知识库分片
*
* @param kdId 文档ID
* @param chunkRelationId 分片关系id
*/
void deleteKnowledgeChunk(Integer kdId, String chunkRelationId);
/**
* 更新知识库分片内容
*
* @param kdId 文档ID
* @param chunkRelationId 分片关系id
* @param structId 结构id
* @param content 分片内容
*/
void updateKnowledgeChunkDoc(Integer kdId, String chunkRelationId, Long structId, String content);
/**
* 新增知识库分片
*
* @param kdId 文档ID
* @param chunkInfos 分片内容
* @param chunkSort 分片排序
*/
void addKnowledgeChunk(Integer kdId, List<ChunkInfo> chunkInfos, Integer chunkSort);
/**
* 更新知识库结构
*
* @param kdId 文档ID
* @param structId 结构id
* @param structName 结构名称
* @param isIndex 是否索引 Y/N
*/
void updateKnowledgeStruct(Integer kdId, Long structId, String structName, String isIndex);
/**
* 获取知识库结构
*
* @param kdId 文档ID
* @return
*/
List<QAKnowledgeConfig> getKnowledgeStruct(Integer kdId);
/**
* 更新分片排序
*/
void updateKnowledgeChunkSort(Integer kdId, String chunkRelationId, Integer chunkSort);
}
......@@ -19,20 +19,28 @@ import cn.com.poc.support.security.oauth.entity.UserBaseEntity;
import cn.com.poc.thirdparty.resource.demand.ai.aggregate.DemandKnowledgeService;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.GetKnowledgeChunkInfoResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.SegmentationConfigRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.core.i18n.I18nMessageException;
import cn.com.yict.framemax.data.model.PagingInfo;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
......@@ -194,8 +202,10 @@ public class KnowledgeServiceImpl implements KnowledgeService {
if (knowledgeInfoEntity == null) {
throw new I18nMessageException("exception/knowledge.base.information.does.not.exist");
}
String knowledgeType = knowledgeInfoEntity.getKnowledgeType();
for (Integer kdId : kdIds) {
List<QAKnowledgeConfig> qaKnowledgeConfigs = checkQAKnowledgeStruct(kdId, knowledgeType);
BizKnowledgeDocumentEntity bizKnowledgeDocumentEntity = bizKnowledgeDocumentService.get(kdId);
String currentStatus = bizKnowledgeDocumentEntity.getTrainStatus();
if (KnowledgeConstant.TrainStatus.COMPLETE.equals(currentStatus) ||
......@@ -210,9 +220,11 @@ public class KnowledgeServiceImpl implements KnowledgeService {
TrainKnowledgeMessage message = new TrainKnowledgeMessage();
message.setKid(kdId);
message.setKnowledgeType(knowledgeType);
message.setFileUrl(bizKnowledgeDocumentEntity.getDocumentUrl());
message.setSegmentationConfig(segmentationConfig);
message.setKnowledgeInfoId(knowledgeInfoId);
message.setQaKnowledgeConfigList(qaKnowledgeConfigs);
knowledgeProducerService.trainKnowledge(message);
}
......@@ -223,11 +235,50 @@ public class KnowledgeServiceImpl implements KnowledgeService {
}
knowledgeInfoEntity.setId(knowledgeInfoId);
knowledgeInfoEntity.setTrainStatus(KnowledgeConstant.TrainStatus.TRAINING);
knowledgeInfoEntity.setKdIds(JsonUtils.serialize(kdIds.stream().distinct().collect(Collectors.toList())));
knowledgeInfoEntity.setKdIds(JsonUtils.serialize(kdIds.stream().
distinct().
collect(Collectors.toList())));
bizKnowledgeInfoService.update(knowledgeInfoEntity);
return true;
}
/**
* 获取问答知识库结构
*
* @param kdId
* @param knowledgeType
* @return
* @throws IOException
*/
private List<QAKnowledgeConfig> checkQAKnowledgeStruct(Integer kdId, String knowledgeType) throws IOException {
List<QAKnowledgeConfig> qaKnowledgeConfigs = new ArrayList<>();
if (knowledgeType.equals(KnowledgeConstant.KnowledgeType.QA)) {
BizKnowledgeDocumentEntity bizKnowledgeDocumentEntity = bizKnowledgeDocumentService.get(kdId);
String documentUrl = bizKnowledgeDocumentEntity.getDocumentUrl();
File file = DocumentLoad.downloadURLDocument(documentUrl);
ExcelReader excelReader = ExcelUtil.getReader(file);
Workbook workbook = excelReader.getWorkbook();
Sheet sheetAt = workbook.getSheetAt(0);
Row row = sheetAt.getRow(1);
Iterator<Cell> cellIterator = row.cellIterator();
int maxCellNum = 10;//最大列数限制
while (cellIterator.hasNext()) {
Cell next = cellIterator.next();
if (next.getColumnIndex() >= maxCellNum) {
break;
}
QAKnowledgeConfig qaKnowledgeConfig = new QAKnowledgeConfig();
qaKnowledgeConfig.setColumn(next.getColumnIndex());
qaKnowledgeConfig.setKeyName(next.toString());
qaKnowledgeConfig.setIndex(next.getColumnIndex() == 0);
qaKnowledgeConfigs.add(qaKnowledgeConfig);
}
workbook.close();
excelReader.close();
}
return qaKnowledgeConfigs;
}
@Override
public List<BizKnowledgeDocumentEntity> searchDocuments(String search, String trainStatus, List<Integer> kdIds, String memberId, PagingInfo pagingInfo) {
List<BizKnowledgeDocumentEntity> result = new ArrayList<>();
......@@ -308,6 +359,7 @@ public class KnowledgeServiceImpl implements KnowledgeService {
throw new I18nMessageException("exception/knowledge.base.does.not.exist");
}
String knowledgeId = bizKnowledgeDocumentEntity.getKnowledgeId();
demandKnowledgeService.updateKnowledgeChunkDoc(knowledgeId, chunkRelationId, content);
}
......@@ -322,7 +374,7 @@ public class KnowledgeServiceImpl implements KnowledgeService {
}
@Override
public List<Integer> getKdIdsByKnowledgeInfoIds(Integer[] knowledgeInfoIds) throws Exception {
public List<Integer> getKdIdsByKnowledgeInfoIds(Integer[] knowledgeInfoIds) {
//获取知识库配置
List<Integer> kdIdList = new ArrayList<>();
if (ArrayUtils.isNotEmpty(knowledgeInfoIds)) {
......
package cn.com.poc.knowledge.aggregate.impl;
import cn.com.poc.knowledge.aggregate.QAKnowledgeService;
import cn.com.poc.knowledge.entity.BizKnowledgeDocumentEntity;
import cn.com.poc.knowledge.service.BizKnowledgeDocumentService;
import cn.com.poc.thirdparty.resource.demand.ai.aggregate.DemandQAKnowledgeService;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.ChunkInfo;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeChunkResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
@Service
public class QAKnowledgeServiceImpl implements QAKnowledgeService {
final private Logger logger = LoggerFactory.getLogger(QAKnowledgeService.class);
@Resource
private DemandQAKnowledgeService demandQAKnowledgeService;
@Resource
private BizKnowledgeDocumentService bizKnowledgeDocumentService;
@Override
public QAKnowledgeChunkResult getChunkInfo(Integer kdId, String query, PagingInfo pagingInfo) {
logger.info("getChunkInfo: kdId={}, query={}, pagingInfo={}", kdId, query, pagingInfo);
String knowledgeId = getKnowledgeId(kdId);
return demandQAKnowledgeService.getKnowledgeChunkInfos(knowledgeId, query, pagingInfo);
}
@Override
public void openKnowledgeChunk(Integer kdId, String chunkRelationId, String isOpen) {
logger.info("openKnowledgeChunk: kdId={}, chunkRelationId={}, isOpen={}", kdId, chunkRelationId, isOpen);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.openKnowledgeChunk(knowledgeId, chunkRelationId, isOpen);
}
@Override
public void deleteKnowledgeChunk(Integer kdId, String chunkRelationId) {
logger.info("deleteKnowledgeChunk: kdId={}, chunkRelationId={}", kdId, chunkRelationId);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.deleteKnowledgeChunk(knowledgeId, chunkRelationId);
}
@Override
public void updateKnowledgeChunkDoc(Integer kdId, String chunkRelationId, Long structId, String content) {
logger.info("updateKnowledgeChunkDoc: kdId={}, chunkRelationId={}, structId={}, content={}", kdId, chunkRelationId, structId, content);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.updateKnowledgeChunkDoc(knowledgeId, chunkRelationId, structId, content);
}
@Override
public void addKnowledgeChunk(Integer kdId, List<ChunkInfo> chunkInfos, Integer chunkSort) {
logger.info("addKnowledgeChunk: kdId={}, chunkInfos={}, chunkSort={}", kdId, chunkInfos, chunkSort);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.addKnowledgeChunk(knowledgeId, chunkInfos, chunkSort);
}
@Override
public void updateKnowledgeStruct(Integer kdId, Long structId, String structName, String isIndex) {
logger.info("updateKnowledgeStruct: kdId={}, structId={}, structName={}, isIndex={}", kdId, structId, structName, isIndex);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.updateKnowledgeStruct(knowledgeId, structId, structName, isIndex);
}
@Override
public List<QAKnowledgeConfig> getKnowledgeStruct(Integer kdId) {
logger.info("getKnowledgeStruct: kdId={}", kdId);
String knowledgeId = getKnowledgeId(kdId);
return demandQAKnowledgeService.getKnowledgeStruct(knowledgeId);
}
@Override
public void updateKnowledgeChunkSort(Integer kdId, String chunkRelationId, Integer chunkSort) {
logger.info("updateKnowledgeChunkSort: kdId={}, chunkRelationId={}, chunkSort={}", kdId, chunkRelationId, chunkSort);
String knowledgeId = getKnowledgeId(kdId);
demandQAKnowledgeService.updateKnowledgeChunkSort(knowledgeId, chunkRelationId, chunkSort);
}
private String getKnowledgeId(Integer kdId) {
BizKnowledgeDocumentEntity knowledgeDocumentEntity = bizKnowledgeDocumentService.get(kdId);
return knowledgeDocumentEntity.getKnowledgeId();
}
}
package cn.com.poc.knowledge.dto;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.SegmentationConfigRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import java.io.Serializable;
import java.util.List;
......@@ -13,6 +14,8 @@ public class TrainKnowledgeDto implements Serializable {
private SegmentationConfigRequest segmentationConfig;
private List<QAKnowledgeConfig> qaKnowledgeConfigs;
public Integer getKnowledgeInfoId() {
return knowledgeInfoId;
}
......@@ -36,4 +39,12 @@ public class TrainKnowledgeDto implements Serializable {
public void setSegmentationConfig(SegmentationConfigRequest segmentationConfig) {
this.segmentationConfig = segmentationConfig;
}
public List<QAKnowledgeConfig> getQaKnowledgeConfigs() {
return qaKnowledgeConfigs;
}
public void setQaKnowledgeConfigs(List<QAKnowledgeConfig> qaKnowledgeConfigs) {
this.qaKnowledgeConfigs = qaKnowledgeConfigs;
}
}
package cn.com.poc.knowledge.dto;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.ChunkInfo;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
import java.io.Serializable;
import java.util.List;
public class UpsertChunkInfoDto extends AbstractRequest<AbstractResult> implements Serializable {
......@@ -33,6 +35,32 @@ public class UpsertChunkInfoDto extends AbstractRequest<AbstractResult> implemen
private Integer chunkSort;
/**
* 结构ID
*/
private Long structId;
/**
* 问答知识库分片信息
*/
private List<ChunkInfo> chunkInfos;
public Long getStructId() {
return structId;
}
public void setStructId(Long structId) {
this.structId = structId;
}
public List<ChunkInfo> getChunkInfos() {
return chunkInfos;
}
public void setChunkInfos(List<ChunkInfo> chunkInfos) {
this.chunkInfos = chunkInfos;
}
public Integer getKdId() {
return kdId;
}
......
package cn.com.poc.knowledge.rest;
import cn.com.poc.knowledge.dto.UpsertChunkInfoDto;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeChunkResult;
import cn.com.yict.framemax.core.rest.BaseRest;
import cn.com.yict.framemax.data.model.PagingInfo;
import cn.com.yict.framemax.web.permission.Access;
import cn.com.yict.framemax.web.permission.Permission;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
@Permission(Access.Safety)
public interface QAKnowledgeRest extends BaseRest {
/**
* 开关知识库分片
*/
void openKnowledgeChunk(@RequestBody UpsertChunkInfoDto dto);
/**
* 删除知识库分片
*/
void deleteKnowledgeChunk(@RequestBody UpsertChunkInfoDto dto);
/**
* 更新知识库分片内容
*/
void updateKnowledgeChunkDoc(@RequestBody UpsertChunkInfoDto dto);
/**
* 新增知识库分片
*/
void addKnowledgeChunk(@RequestBody UpsertChunkInfoDto dto);
/**
* 获取问答知识库分片信息
*/
QAKnowledgeChunkResult getQAKnowledgeChunks(@RequestParam Integer kdId, @RequestParam(required = false) String query, PagingInfo pagingInfo);
/**
* 更新知识库结构信息
*/
void updateKnowledgeChunk(@RequestParam Integer kdId, @RequestParam Long structId, @RequestParam(required = false) String structName, @RequestParam(required = false) String isIndex);
/**
* 批量删除知识库分片
*/
void batchDeleteKnowledgeChunks(@RequestParam Integer kdId, @RequestParam List<String> chunkRelationIds);
/**
* 更新分片顺序
*/
void updateChunkSort(@RequestParam Integer kdId, @RequestParam String chunkRelationId, @RequestParam Integer sort);
}
......@@ -342,7 +342,6 @@ public class KnowledgeRestImpl implements KnowledgeRest {
return knowledgeService.getChunkInfo(kdIds, query, pagingInfo);
}
private void checkEquity(UserBaseEntity userBaseEntity) throws Exception {
MemberEquityInfo equityInfo = memberEquityService.getEquityInfo(userBaseEntity.getUserId());
if (equityInfo.getUsedKnowledgeNum() >= equityInfo.getKnowledgeNum()) {
......
package cn.com.poc.knowledge.rest.impl;
import cn.com.poc.knowledge.aggregate.QAKnowledgeService;
import cn.com.poc.knowledge.dto.UpsertChunkInfoDto;
import cn.com.poc.knowledge.rest.QAKnowledgeRest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeChunkResult;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
@Component
public class QAKnowledgeRestImpl implements QAKnowledgeRest {
@Resource
private QAKnowledgeService qaKnowledgeService;
@Override
public void openKnowledgeChunk(UpsertChunkInfoDto dto) {
qaKnowledgeService.openKnowledgeChunk(dto.getKdId(), dto.getChunkRelationId(), dto.getIsOpen());
}
@Override
public void deleteKnowledgeChunk(UpsertChunkInfoDto dto) {
qaKnowledgeService.deleteKnowledgeChunk(dto.getKdId(), dto.getChunkRelationId());
}
@Override
public void updateKnowledgeChunkDoc(UpsertChunkInfoDto dto) {
qaKnowledgeService.updateKnowledgeChunkDoc(dto.getKdId(), dto.getChunkRelationId(), dto.getStructId(), dto.getChunkContent());
}
@Override
public void addKnowledgeChunk(UpsertChunkInfoDto dto) {
qaKnowledgeService.addKnowledgeChunk(dto.getKdId(), dto.getChunkInfos(), dto.getChunkSort());
}
@Override
public QAKnowledgeChunkResult getQAKnowledgeChunks(Integer kdId, String query, PagingInfo pagingInfo) {
return qaKnowledgeService.getChunkInfo(kdId, query, pagingInfo);
}
@Override
public void updateKnowledgeChunk(Integer kdId, Long structId, String structName, String isIndex) {
qaKnowledgeService.updateKnowledgeStruct(kdId, structId, structName, isIndex);
}
@Override
public void batchDeleteKnowledgeChunks(Integer kdId, List<String> chunkRelationIds) {
for (String chunkRelationId : chunkRelationIds) {
qaKnowledgeService.deleteKnowledgeChunk(kdId, chunkRelationId);
}
}
@Override
public void updateChunkSort(Integer kdId, String chunkRelationId, Integer sort) {
qaKnowledgeService.updateKnowledgeChunkSort(kdId, chunkRelationId, sort);
}
}
package cn.com.poc.message.entity;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.SegmentationConfigRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
public class TrainKnowledgeMessage implements Serializable {
......@@ -15,8 +17,28 @@ public class TrainKnowledgeMessage implements Serializable {
private Map<Integer, Integer> reduced;
private String knowledgeType;
private SegmentationConfigRequest segmentationConfig;
private List<QAKnowledgeConfig> qaKnowledgeConfigList;
public String getKnowledgeType() {
return knowledgeType;
}
public void setKnowledgeType(String knowledgeType) {
this.knowledgeType = knowledgeType;
}
public List<QAKnowledgeConfig> getQaKnowledgeConfigList() {
return qaKnowledgeConfigList;
}
public void setQaKnowledgeConfigList(List<QAKnowledgeConfig> qaKnowledgeConfigList) {
this.qaKnowledgeConfigList = qaKnowledgeConfigList;
}
public Integer getKnowledgeInfoId() {
return knowledgeInfoId;
}
......
......@@ -3,6 +3,7 @@ package cn.com.poc.message.service.impl;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.Assert;
import cn.com.poc.common.utils.DocumentLoad;
import cn.com.poc.common.utils.JsonUtils;
import cn.com.poc.knowledge.constant.KnowledgeConstant;
import cn.com.poc.knowledge.entity.BizKnowledgeDocumentEntity;
......@@ -18,15 +19,25 @@ import cn.com.poc.message.service.KnowledgeProducerService;
import cn.com.poc.message.topic.KnowledgeTopic;
import cn.com.poc.thirdparty.resource.demand.ai.aggregate.DemandKnowledgeService;
import cn.com.poc.thirdparty.resource.demand.ai.constants.KnowledgeTrainStatusConstant;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.core.i18n.I18nMessageException;
import cn.com.yict.framemax.tumbleweed.client.annotation.Consumer;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.fastjson.TypeReference;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
......@@ -55,7 +66,13 @@ public class KnowledgeConsumerServiceImpl implements KnowledgeConsumerService {
@Consumer(topic = KnowledgeTopic.TRAIN_KNOWLEDGE, scale = 3, retry = true)
public void trainKnowledge(TrainKnowledgeMessage message) throws Exception {
//修改训练状态
String knowledgeId = demandKnowledgeService.trainKnowledgeEvent(message.getFileUrl(), message.getSegmentationConfig());
String knowledgeId;
if (message.getKnowledgeType().equals(KnowledgeConstant.KnowledgeType.QA)) {
knowledgeId = demandKnowledgeService.trainKnowledgeEvent(message.getFileUrl(), message.getKnowledgeType(), null, message.getQaKnowledgeConfigList());
} else {
knowledgeId = demandKnowledgeService.trainKnowledgeEvent(message.getFileUrl(), message.getKnowledgeType(), message.getSegmentationConfig(), null);
}
KnowledgeTrainStatusMessage trainStatusMessage = new KnowledgeTrainStatusMessage();
trainStatusMessage.setStatus(KnowledgeConstant.TrainStatus.TRAINING);
trainStatusMessage.setKdId(message.getKid());
......
......@@ -3,6 +3,7 @@ package cn.com.poc.thirdparty.resource.demand.ai.aggregate;
import cn.com.poc.thirdparty.resource.demand.ai.constants.KnowledgeSearchTypeEnum;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.GetKnowledgeChunkInfoResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.SegmentationConfigRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.data.model.PagingInfo;
import java.util.List;
......@@ -26,7 +27,7 @@ public interface DemandKnowledgeService {
* @param fileURL 训练文档
* @return 知识库id
*/
String trainKnowledgeEvent(String fileURL, SegmentationConfigRequest segmentationConfig);
String trainKnowledgeEvent(String fileURL, String knowledgeType, SegmentationConfigRequest segmentationConfig, List<QAKnowledgeConfig> qaKnowledgeConfigs);
/**
* 获取知识库训练状态
......
package cn.com.poc.thirdparty.resource.demand.ai.aggregate;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.ChunkInfo;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeChunkResult;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.yict.framemax.data.model.PagingInfo;
import java.util.List;
/**
* 问答知识服务接口
*
* @author alex.yao
* @date 2025/2/26
*/
public interface DemandQAKnowledgeService {
/**
* 获取知识库分片信息
*
* @param knowledgeId 知识库ID
* @param query 模糊查询
* @param pagingInfo 分页信息
* @return 知识库分片信息
*/
QAKnowledgeChunkResult getKnowledgeChunkInfos(String knowledgeId, String query, PagingInfo pagingInfo);
/**
* 开关知识库分片信息
*
* @param knowledgeId 知识库ID
* @param chunkRelationId 分片关系ID
* @param isOpen 是否开启 Y-开启 N-关闭
*/
void openKnowledgeChunk(String knowledgeId, String chunkRelationId, String isOpen);
/**
* 删除知识库分片
*
* @param knowledgeId 知识库ID
* @param chunkRelationId 分片关系ID
*/
void deleteKnowledgeChunk(String knowledgeId, String chunkRelationId);
/**
* 修改分片内容
*
* @param knowledgeId 知识库ID
* @param chunkRelationId 分片关系ID
* @param structId 结构ID
* @param content 内容
*/
void updateKnowledgeChunkDoc(String knowledgeId, String chunkRelationId, Long structId, String content);
/**
* 新增分片
*
* @param knowledgeId 知识库ID
* @param chunkInfos 分片信息
* @param sort 排序 0以上, 越小越大
*/
void addKnowledgeChunk(String knowledgeId, List<ChunkInfo> chunkInfos, Integer sort);
/**
* 更新分片排序
*
* @param knowledgeId 知识库ID
* @param chunkRelationId 分片关系ID
* @param sort 排序 0以上, 越小越大
*/
void updateKnowledgeChunkSort(String knowledgeId, String chunkRelationId, Integer sort);
/**
* 更新结构
*
* @param knowledgeId 知识库ID
* @param structId 结构ID
* @param structName 结构名称
* @param isIndex 是否索引 Y-是 N-否
*/
void updateKnowledgeStruct(String knowledgeId, Long structId, String structName, String isIndex);
/**
* 获取结构
*
* @param knowledgeId 知识库ID
*/
List<QAKnowledgeConfig> getKnowledgeStruct(String knowledgeId);
}
package cn.com.poc.thirdparty.resource.demand.ai.aggregate.impl;
import cn.com.poc.thirdparty.resource.demand.ai.constants.KnowledgeSearchTypeEnum;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.poc.thirdparty.resource.demand.dgTools.DgtoolsAbstractHttpClient;
import cn.com.poc.thirdparty.resource.demand.ai.route.DgtoolsApiRoute;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
......@@ -43,11 +44,13 @@ public class DemandKnowledgeServiceImpl implements DemandKnowledgeService {
}
@Override
public String trainKnowledgeEvent(String fileURL, SegmentationConfigRequest segmentationConfig) {
public String trainKnowledgeEvent(String fileURL, String knowledgeType, SegmentationConfigRequest segmentationConfig, List<QAKnowledgeConfig> qaKnowledgeConfigs){
Assert.notBlank(fileURL);
TrainKnowledgeRequest request = new TrainKnowledgeRequest();
request.setDocumentUrl(fileURL);
request.setSegmentationConfig(segmentationConfig);
request.setKnowledgeType(knowledgeType);
request.setQaKnowledgeConfigs(qaKnowledgeConfigs);
TrainKnowledgeResult trainKnowledgeResult = dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.TRAIN_KNOWLEDGE_EVENT, request, getHeaders());
if (null == trainKnowledgeResult) {
throw new I18nMessageException("exception/abnormal.knowledge.base.training");
......
package cn.com.poc.thirdparty.resource.demand.ai.aggregate.impl;
import cn.com.poc.common.constant.CommonConstant;
import cn.com.poc.common.utils.Assert;
import cn.com.poc.thirdparty.resource.demand.ai.aggregate.DemandQAKnowledgeService;
import cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge.UpsertChunkInfoRequest;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.*;
import cn.com.poc.thirdparty.resource.demand.ai.route.DgtoolsApiRoute;
import cn.com.poc.thirdparty.resource.demand.dgTools.DgtoolsAbstractHttpClient;
import cn.com.poc.thirdparty.resource.demand.member.service.DemandAuthService;
import cn.com.yict.framemax.data.model.PagingInfo;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
@Service
public class DemandQAKnowledgeServiceImpl implements DemandQAKnowledgeService {
@Resource
private DgtoolsAbstractHttpClient dgToolsAbstractHttpClient;
@Resource
private DemandAuthService demandAuthService;
@Override
public QAKnowledgeChunkResult getKnowledgeChunkInfos(String knowledgeId, String query, PagingInfo pagingInfo) {
Assert.notBlank(knowledgeId);
QAKnowledgeResponse response = new QAKnowledgeResponse();
response.setKnowledgeId(knowledgeId);
response.setQuery(query);
return dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.GET_QA_KNOWLEDGE_CHUNK_INFOS, response, getHeaders(), pagingInfo);
}
@Override
public void openKnowledgeChunk(String knowledgeId, String chunkRelationId, String isOpen) {
Assert.notBlank(knowledgeId);
Assert.notBlank(chunkRelationId);
Assert.notBlank(isOpen);
Assert.isTrue(isOpen.equals(CommonConstant.YOrN.N) || isOpen.equals(CommonConstant.YOrN.Y));
UpsertChunkInfoRequest request = new UpsertChunkInfoRequest();
request.setKnowledgeId(knowledgeId);
request.setChunkRelationId(chunkRelationId);
request.setIsOpen(isOpen);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.OPEN_QA_KNOWLEDGE_CHUNK, request, getHeaders());
}
@Override
public void deleteKnowledgeChunk(String knowledgeId, String chunkRelationId) {
Assert.notBlank(knowledgeId);
Assert.notBlank(chunkRelationId);
UpsertChunkInfoRequest request = new UpsertChunkInfoRequest();
request.setKnowledgeId(knowledgeId);
request.setChunkRelationId(chunkRelationId);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.DELETE_QA_KNOWLEDGE_CHUNK, request, getHeaders());
}
@Override
public void updateKnowledgeChunkDoc(String knowledgeId, String chunkRelationId, Long structId, String content) {
Assert.notBlank(knowledgeId);
Assert.notBlank(chunkRelationId);
UpsertChunkInfoRequest request = new UpsertChunkInfoRequest();
request.setKnowledgeId(knowledgeId);
request.setChunkRelationId(chunkRelationId);
request.setStructId(structId);
request.setChunkContent(content);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.UPDATE_QA_KNOWLEDGE_CHUNK, request, getHeaders());
}
@Override
public void addKnowledgeChunk(String knowledgeId, List<ChunkInfo> chunkInfos, Integer sort) {
Assert.notBlank(knowledgeId);
Assert.notEmpty(chunkInfos);
Assert.notNull(sort);
Assert.isTrue(sort >= 0);
UpsertChunkInfoRequest request = new UpsertChunkInfoRequest();
request.setKnowledgeId(knowledgeId);
request.setChunkInfos(chunkInfos);
request.setChunkSort(sort);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.ADD_QA_KNOWLEDGE_CHUNK, request, getHeaders());
}
@Override
public void updateKnowledgeChunkSort(String knowledgeId, String chunkRelationId, Integer sort) {
Assert.notBlank(knowledgeId);
Assert.notBlank(chunkRelationId);
Assert.notNull(sort);
Assert.isTrue(sort >= 0);
UpsertChunkInfoRequest request = new UpsertChunkInfoRequest();
request.setKnowledgeId(knowledgeId);
request.setChunkRelationId(chunkRelationId);
request.setChunkSort(sort);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.SORT_QA_KNOWLEDGE_CHUNK, request, getHeaders());
}
@Override
public void updateKnowledgeStruct(String knowledgeId, Long structId, String structName, String isIndex) {
Assert.notBlank(knowledgeId);
Assert.notNull(structId);
UpdateQAKnowledgeStructRequest request = new UpdateQAKnowledgeStructRequest();
request.setKnowledgeId(knowledgeId);
request.setStructId(structId);
request.setStructName(structName);
request.setIsIndex(isIndex);
dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.UPDATE_QA_KNOWLEDGE_STRUCT, request, getHeaders());
}
@Override
public List<QAKnowledgeConfig> getKnowledgeStruct(String knowledgeId) {
Assert.notBlank(knowledgeId);
QAKnowledgeConfigRequest request = new QAKnowledgeConfigRequest();
request.setKnowledgeId(knowledgeId);
QAKnowledgeConfigResult qaKnowledgeConfigResult = dgToolsAbstractHttpClient.doRequest(DgtoolsApiRoute.DgtoolsAI.GET_QA_KNOWLEDGE_STRUCT, request, getHeaders());
return qaKnowledgeConfigResult.getQaKnowledgeConfigs();
}
private List<Header> getHeaders() {
List<Header> headers = new ArrayList<>();
headers.add(DgtoolsApiRoute.JSON_HEADER);
headers.add(DgtoolsApiRoute.AI_HEADER);
headers.add(new BasicHeader(DgtoolsApiRoute.HEADER_X_PLATFORM_AUTHORIZATION, demandAuthService.getToken()));
return headers;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.QAKnowledgeConfig;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import java.io.Serializable;
import java.util.List;
public class TrainKnowledgeRequest extends AbstractRequest<TrainKnowledgeResult> implements Serializable {
private String documentUrl;
private String knowledgeType;
private SegmentationConfigRequest segmentationConfig;
private List<QAKnowledgeConfig> qaKnowledgeConfigs;
public SegmentationConfigRequest getSegmentationConfig() {
return segmentationConfig;
}
......@@ -26,6 +32,22 @@ public class TrainKnowledgeRequest extends AbstractRequest<TrainKnowledgeResult>
this.documentUrl = documentUrl;
}
public String getKnowledgeType() {
return knowledgeType;
}
public void setKnowledgeType(String knowledgeType) {
this.knowledgeType = knowledgeType;
}
public List<QAKnowledgeConfig> getQaKnowledgeConfigs() {
return qaKnowledgeConfigs;
}
public void setQaKnowledgeConfigs(List<QAKnowledgeConfig> qaKnowledgeConfigs) {
this.qaKnowledgeConfigs = qaKnowledgeConfigs;
}
@Override
public String getMethod() throws Exception {
return null;
......
package cn.com.poc.thirdparty.resource.demand.ai.entity.knowledge;
import cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge.ChunkInfo;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
import java.io.Serializable;
import java.util.List;
public class UpsertChunkInfoRequest extends AbstractRequest<AbstractResult> implements Serializable {
......@@ -32,6 +34,31 @@ public class UpsertChunkInfoRequest extends AbstractRequest<AbstractResult> impl
*/
private Integer chunkSort;
/**
* 结构ID
*/
private Long structId;
/**
* 问答知识库分片信息
*/
private List<ChunkInfo> chunkInfos;
public Long getStructId() {
return structId;
}
public void setStructId(Long structId) {
this.structId = structId;
}
public List<ChunkInfo> getChunkInfos() {
return chunkInfos;
}
public void setChunkInfos(List<ChunkInfo> chunkInfos) {
this.chunkInfos = chunkInfos;
}
public String getKnowledgeId() {
return knowledgeId;
......
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/25
*/
public class Chunk {
private String chunkRelationId;
private Integer chunkSort;
private List<ChunkInfo> chunkInfo;
public Integer getChunkSort() {
return chunkSort;
}
public void setChunkSort(Integer chunkSort) {
this.chunkSort = chunkSort;
}
public String getChunkRelationId() {
return chunkRelationId;
}
public void setChunkRelationId(String chunkRelationId) {
this.chunkRelationId = chunkRelationId;
}
public List<ChunkInfo> getChunkInfo() {
return chunkInfo;
}
public void setChunkInfo(List<ChunkInfo> chunkInfo) {
this.chunkInfo = chunkInfo;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
/**
* @author alex.yao
* @date 2025/2/25
*/
public class ChunkInfo {
private Long structId;
private String content;
public Long getStructId() {
return structId;
}
public void setStructId(Long structId) {
this.structId = structId;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
/**
* @author alex.yao
* @date 2025/2/25
*/
public class QAChunkKey {
private Long structId;
private String structName;
private String isIndex;
private Integer sort;
public Long getStructId() {
return structId;
}
public void setStructId(Long structId) {
this.structId = structId;
}
public String getStructName() {
return structName;
}
public void setStructName(String structName) {
this.structName = structName;
}
public String getIsIndex() {
return isIndex;
}
public void setIsIndex(String isIndex) {
this.isIndex = isIndex;
}
public Integer getSort() {
return sort;
}
public void setSort(Integer sort) {
this.sort = sort;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/25
*/
public class QAKnowledgeChunkResult extends AbstractResult {
private List<QAChunkKey> key;
private List<Chunk> chunk;
public List<QAChunkKey> getKey() {
return key;
}
public void setKey(List<QAChunkKey> key) {
this.key = key;
}
public List<Chunk> getChunk() {
return chunk;
}
public void setChunk(List<Chunk> chunk) {
this.chunk = chunk;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
/**
* @author alex.yao
* @date 2025/2/20
*/
public class QAKnowledgeConfig {
/**
* 文档列位置
*/
private Integer column;
/**
* 文档列名称
*/
private String keyName;
/**
* 是否索引列
*/
private Boolean index;
public Integer getColumn() {
return column;
}
public void setColumn(Integer column) {
this.column = column;
}
public String getKeyName() {
return keyName;
}
public void setKeyName(String keyName) {
this.keyName = keyName;
}
public Boolean getIndex() {
return index;
}
public void setIndex(Boolean index) {
this.index = index;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import java.io.Serializable;
/**
* @author alex.yao
* @date 2025/2/26
*/
public class QAKnowledgeConfigRequest extends AbstractRequest<QAKnowledgeConfigResult> implements Serializable {
private String knowledgeId;
public String getKnowledgeId() {
return knowledgeId;
}
public void setKnowledgeId(String knowledgeId) {
this.knowledgeId = knowledgeId;
}
@Override
public String getMethod() throws Exception {
return null;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
import java.util.List;
/**
* @author alex.yao
* @date 2025/2/26
*/
public class QAKnowledgeConfigResult extends AbstractResult {
private List<QAKnowledgeConfig> qaKnowledgeConfigs;
public List<QAKnowledgeConfig> getQaKnowledgeConfigs() {
return qaKnowledgeConfigs;
}
public void setQaKnowledgeConfigs(List<QAKnowledgeConfig> qaKnowledgeConfigs) {
this.qaKnowledgeConfigs = qaKnowledgeConfigs;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import java.io.Serializable;
/**
* @author alex.yao
* @date 2025/2/21
*/
public class QAKnowledgeResponse extends AbstractRequest<QAKnowledgeChunkResult> implements Serializable {
private String knowledgeId;
private String query;
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
public String getKnowledgeId() {
return knowledgeId;
}
public void setKnowledgeId(String knowledgeId) {
this.knowledgeId = knowledgeId;
}
@Override
public String getMethod() throws Exception {
return null;
}
}
package cn.com.poc.thirdparty.resource.demand.ai.entity.qaknowledge;
import cn.com.poc.thirdparty.resource.demand.dgTools.request.AbstractRequest;
import cn.com.poc.thirdparty.resource.demand.dgTools.result.AbstractResult;
import java.io.Serializable;
/**
* @author alex.yao
* @date 2025/2/26
*/
public class UpdateQAKnowledgeStructRequest extends AbstractRequest<AbstractResult> implements Serializable {
private String knowledgeId;
private Long structId;
private String structName;
private String isIndex;
public String getKnowledgeId() {
return knowledgeId;
}
public void setKnowledgeId(String knowledgeId) {
this.knowledgeId = knowledgeId;
}
public Long getStructId() {
return structId;
}
public void setStructId(Long structId) {
this.structId = structId;
}
public String getStructName() {
return structName;
}
public void setStructName(String structName) {
this.structName = structName;
}
public String getIsIndex() {
return isIndex;
}
public void setIsIndex(String isIndex) {
this.isIndex = isIndex;
}
@Override
public String getMethod() throws Exception {
return null;
}
}
......@@ -253,6 +253,26 @@ public interface DgtoolsApiRoute {
String UPDATE_KNOWLEDGE_CHUNK_DOC = "/knowLedgeRest/updateKnowledgeChunkDoc.json";
String ADD_KNOWLEDGE_CHUNK = "/knowLedgeRest/addKnowledgeChunk.json";
/**
* 问答知识库
*/
String GET_QA_KNOWLEDGE_CHUNK_INFOS = "qAKnowledgeRest/getKnowledgeChunkInfos.json"; //获取问答知识库信息分片
String ADD_QA_KNOWLEDGE_CHUNK = "qAKnowledgeRest/addKnowledgeChunk.json"; //新增分片
String UPDATE_QA_KNOWLEDGE_CHUNK = "qAKnowledgeRest/updateKnowledgeChunkDoc.json"; //修改分片内容
String DELETE_QA_KNOWLEDGE_CHUNK = "qAKnowledgeRest/deleteKnowledgeChunk.json"; //删除知识库分片
String OPEN_QA_KNOWLEDGE_CHUNK = "qAKnowledgeRest/openKnowledgeChunk.json"; //开关知识库分片信息
String SORT_QA_KNOWLEDGE_CHUNK = "qAKnowledgeRest/updateKnowledgeChunkSort.json"; //更新分片排序
String UPDATE_QA_KNOWLEDGE_STRUCT = "qAKnowledgeRest/updateKnowledgeStructure.json"; //更新问答知识库结构
String GET_QA_KNOWLEDGE_STRUCT = "qAKnowledgeRest/getKnowledgeStructure.json"; //获取问答知识库结构
/**
* 大模型【通用】
*/
......
......@@ -81,3 +81,4 @@ file.content.empty=The file content cannot be empty
payment.package.configuration.not.exist=The equity packet configuration does not exist
no.permission=No permission
create.num.limit=Creating has reached its maximum limit
qa.knowledge.document.struct.not.consistent=Inconsistent question and answer structure
\ No newline at end of file
......@@ -81,3 +81,4 @@ file.content.empty=\u6587\u6863\u5185\u5BB9\u4E0D\u80FD\u4E3A\u7A7A
payment.package.configuration.not.exist=\u6743\u76CA\u5305\u914D\u7F6E\u4E0D\u5B58\u5728
no.permission=\u6682\u65E0\u6743\u9650
create.num.limit=\u521B\u5EFA\u5DF2\u8FBE\u6700\u5927\u4E0A\u9650
qa.knowledge.document.struct.not.consistent=文档结构不一致
\ No newline at end of file
......@@ -81,3 +81,4 @@ file.content.empty=\u6587\u4EF6\u5185\u5BB9\u4E0D\u80FD\u7232\u7A7A
payment.package.configuration.not.exist=\u6B0A\u76CA\u5305\u914D\u7F6E\u4E0D\u5B58\u5728
no.permission=\u66AB\u7121\u6B0A\u9650
create.num.limit=\u5275\u5EFA\u5DF2\u9054\u6700\u5927\u4E0A\u9650
qa.knowledge.document.struct.not.consistent=文檔結構不一致
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment