Commit edd3398c authored by 陈立彬's avatar 陈立彬

1.AI问答助手增加检索范围字段 2.热门问题人工管理

parent 0df3d041
package cn.breeze.elleai.application.dto.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
@Data
public class HotQaRequestDto implements Serializable {
@Schema(description = "页码")
@JsonProperty("page_no")
private Integer pageNo = 1;
@Schema(description = "分页数量")
@JsonProperty("page_size")
private Integer pageSize = 10;
@Schema(description = "问题名称")
private String name;
@Schema(description = "状态(0禁用 1启用)")
private Integer status;
}
package cn.breeze.elleai.application.dto.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
@Data
public class HotQaSaveDto implements Serializable {
@Schema(description = "ID")
private Integer id;
/**
* 问题
*/
@Schema(description = "问题")
private String question;
/**
* 答案
*/
@Schema(description = "答案")
private String answer;
/**
* 排序优先级
*/
@Schema(description = "排序优先级")
@JsonProperty("sort_index")
private Integer sortIndex;
/**
* 状态(0禁用 1启用)
*/
@Schema(description = "状态")
private Integer status;
}
package cn.breeze.elleai.application.dto.response;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HotQaDto implements Serializable {
private Integer id;
/**
* 问题
*/
@Schema(description = "问题")
private String question;
/**
* 答案
*/
@Schema(description = "答案")
private String answer;
/**
* 排序优先级
*/
@Schema(description = "排序优先级")
@JsonProperty("sort_index")
private Integer sortIndex;
/**
* 状态(0禁用 1启用)
*/
@Schema(description = "状态")
private Integer status;
/**
* 创建时间
*/
@Schema(description = "创建时间")
@JsonProperty("create_time")
private Date createTime;
}
......@@ -6,6 +6,7 @@ import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
public class UserAskResultMobileDto implements Serializable {
......@@ -22,4 +23,8 @@ public class UserAskResultMobileDto implements Serializable {
@Schema(description = "消息ID")
@JsonProperty("message_id")
private Integer messageId;
@Schema(description = "热门推荐问题")
@JsonProperty("hots")
private List<HotQaMobileDto> hots;
}
......@@ -5,10 +5,7 @@ import cn.breeze.elleai.application.dto.inner.AiChatComplateResultDto;
import cn.breeze.elleai.application.dto.request.*;
import cn.breeze.elleai.application.dto.response.*;
import cn.breeze.elleai.domain.sparring.model.request.*;
import cn.breeze.elleai.domain.sparring.model.response.KbTagResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionHistoryResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.*;
import cn.breeze.elleai.domain.sparring.service.ChatCompletionService;
import cn.breeze.elleai.domain.sparring.service.KbService;
import cn.breeze.elleai.domain.sparring.service.KbTagService;
......@@ -18,6 +15,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
......@@ -417,6 +415,30 @@ public class AppChatCompletionService {
// 保存问答详情
Integer userQaRecordId = chatCompletionService.saveUserQaRecord(chatCompletionId, 0, null, request.getContent(), request.getAssistantId());
// 获取随机问题
final List<HotQaMobileDto> hots = Lists.newArrayList();
PageResult<HotQaMobileDto> pageResult = this.hotQaList(new QaAssistantRequestDto());
if(Objects.nonNull(pageResult) && CollectionUtil.isNotEmpty(pageResult.getItems())) {
List<HotQaMobileDto> items = pageResult.getItems();
if(items.size() > 2){
Collections.shuffle(items);
items = items.subList(0, 2);
}
hots.addAll(items);
}
List<HotQaResponseModel> hotQaList = chatCompletionService.hotQaList(new HotQaRequestModel());
if(CollectionUtil.isNotEmpty(hotQaList)) {
Collections.shuffle(hotQaList);
if(hotQaList.size() > 2) {
hotQaList = hotQaList.subList(0, 2);
}
hotQaList.forEach(v -> {
HotQaMobileDto dto = new HotQaMobileDto();
dto.setQuestion(v.getQuestion());
hots.add(dto);
});
}
Map<String, String> inputs = new HashMap<>();
inputs.put("assistant_id", Objects.nonNull(request.getAssistantId()) ? String.valueOf(request.getAssistantId()) : "");
JSONObject param = new JSONObject();
......@@ -444,6 +466,7 @@ public class AppChatCompletionService {
result.setReplyContent(buffer.toString());
result.setChatCompletionId(chatCompletionId);
result.setMessageId(userQaRecordId);
result.setHots(hots);
return result;
}).doOnComplete(
() -> {
......@@ -554,4 +577,69 @@ public class AppChatCompletionService {
}
}
/************************************************** 热门问题 **************************************************/
/**
* 更新热门问题
* @param id
* @param status
*/
public void updateHotQaStatus(Integer id, Integer status) {
chatCompletionService.updateHotQaStatus(id, status);
}
/**
* 删除热门问题
* @param id
*/
public void deleteHotQa(Integer id) {
chatCompletionService.deleteHotQa(id);
}
/**
* 获取热门问题详情
* @param id
* @return
*/
public HotQaDto hotQaDetail(Integer id) {
HotQaResponseModel model = chatCompletionService.hotQaDetail(id);
HotQaDto result = BeanUtil.copyProperties(model, HotQaDto.class);
return result;
}
/**
* 保存热门问题
* @param dto
*/
public void saveHotQa(HotQaSaveDto dto) {
HotQaSaveModel model = BeanUtil.copyProperties(dto, HotQaSaveModel.class);
chatCompletionService.saveHotQa(model);
}
/**
* 热门问题分页查询
* @param request
* @return
*/
public PageResult<HotQaDto> hotQaPaginQuery(HotQaRequestDto request) {
HotQaRequestModel requestModel = BeanUtil.copyProperties(request, HotQaRequestModel.class);
Page<HotQaResponseModel> page = chatCompletionService.hotQaPaginQuery(requestModel);
PageResult<HotQaDto> pageResult = PageResult.of(request.getPageNo(), request.getPageSize(), (int) page.getTotalRow(), null);
if(CollectionUtil.isNotEmpty(page.getRecords())) {
List<HotQaDto> dtoList = page.getRecords().stream().map(v -> {
HotQaDto dto = BeanUtil.copyProperties(v, HotQaDto.class);
return dto;
}).collect(Collectors.toList());
pageResult.setItems(dtoList);
}
return pageResult;
}
}
......@@ -1173,7 +1173,7 @@ public class AppExamineService {
List<ExamineQaResponseModel> examineQaList = examineService.examineQaList(examineId);
if(CollectionUtil.isNotEmpty(examineQaList)) {
OptionalInt indexOpt = IntStream.range(0, examineQaList.size())
.filter(i -> examineQaList.get(i).getId() == currentQuestionId)
.filter(i -> Objects.equals(examineQaList.get(i).getId(), currentQuestionId))
.findFirst();
if (indexOpt.isPresent()) {
int index = indexOpt.getAsInt();
......
......@@ -3,9 +3,8 @@ package cn.breeze.elleai.controller.admin;
import cn.breeze.elleai.application.dto.ApiResponse;
import cn.breeze.elleai.application.dto.PageResult;
import cn.breeze.elleai.application.dto.request.QaAssistantRequestDto;
import cn.breeze.elleai.application.dto.request.QaAssistantSaveDto;
import cn.breeze.elleai.application.dto.request.UserQaRequestDto;
import cn.breeze.elleai.application.dto.request.*;
import cn.breeze.elleai.application.dto.response.HotQaDto;
import cn.breeze.elleai.application.dto.response.QaAssistantDto;
import cn.breeze.elleai.application.dto.response.UserChatCompletionDto;
import cn.breeze.elleai.application.dto.response.UserChatCompletionHistoryDto;
......@@ -80,4 +79,41 @@ public class ChatCompletionController {
PageResult<UserChatCompletionDto> pageResult = chatCompletionService.userQaPaginQuery(request);
return ApiResponse.ok(pageResult);
}
@Operation(summary = "启用/禁用热门问题")
@PostMapping("/hot_qa/update_status/{id}/{status}")
public ApiResponse<String> updateHotQaStatus(@Schema(description = "热门问题ID") @PathVariable("id") Integer id,
@Schema(description = "状态(0禁用 1启用)") @PathVariable("status") Integer status) {
chatCompletionService.updateHotQaStatus(id, status);
return ApiResponse.ok("ok");
}
@Operation(summary = "删除热门问题")
@PostMapping("/hot_qa/delete/{id}")
public ApiResponse<String> deleteHotQa(@Schema(description = "热门问题ID") @PathVariable("id") Integer id) {
chatCompletionService.deleteHotQa(id);
return ApiResponse.ok("ok");
}
@Operation(summary = "热门问题详情")
@GetMapping("/hot_qa/detail/{id}")
public ApiResponse<HotQaDto> hotQaDetail(@Schema(description = "热门问题ID") @PathVariable("id") Integer id) {
HotQaDto detail = chatCompletionService.hotQaDetail(id);
return ApiResponse.ok(detail);
}
@Operation(summary = "保存热门问题")
@PostMapping("/hot_qa/save")
public ApiResponse<String> saveOrUpdateHotQa(@RequestBody HotQaSaveDto dto) {
chatCompletionService.saveHotQa(dto);
return ApiResponse.ok("ok");
}
@Operation(summary = "热门问题列表")
@GetMapping("/hot_qa/list")
public ApiResponse<PageResult<HotQaDto>> hotQaList(@QueryParam HotQaRequestDto request) {
PageResult<HotQaDto> pageResult = chatCompletionService.hotQaPaginQuery(request);
return ApiResponse.ok(pageResult);
}
}
package cn.breeze.elleai.domain.sparring.model.request;
import lombok.Data;
import java.io.Serializable;
@Data
public class HotQaRequestModel implements Serializable {
private Integer pageNo;
private Integer pageSize;
private String name;
private Integer status;
}
package cn.breeze.elleai.domain.sparring.model.request;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class HotQaSaveModel implements Serializable {
private Integer id;
/**
* 问题
*/
private String question;
/**
* 答案
*/
private String answer;
/**
* 排序优先级
*/
private Integer sortIndex;
/**
* 状态(0禁用 1启用)
*/
private Integer status;
/**
* 是否删除(0否 1是)
*/
private Integer deleted;
/**
* 创建时间
*/
private Date createTime;
}
package cn.breeze.elleai.domain.sparring.model.response;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class HotQaResponseModel implements Serializable {
private Integer id;
/**
* 问题
*/
private String question;
/**
* 答案
*/
private String answer;
/**
* 排序优先级
*/
private Integer sortIndex;
/**
* 状态(0禁用 1启用)
*/
private Integer status;
/**
* 是否删除(0否 1是)
*/
private Integer deleted;
/**
* 创建时间
*/
private Date createTime;
}
package cn.breeze.elleai.domain.sparring.service;
import cn.breeze.elleai.application.dto.request.CommonRequestDto;
import cn.breeze.elleai.domain.sparring.model.CommonRequestModel;
import cn.breeze.elleai.domain.sparring.model.request.*;
import cn.breeze.elleai.domain.sparring.model.response.HotQaResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionHistoryResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionResponseModel;
......@@ -43,4 +46,17 @@ public interface ChatCompletionService {
void deleteQaAssistant(Integer id);
void saveQaAssistant(QaAssistantSaveModel dto);
/***************************************** 热门问题 *****************************************/
Page<HotQaResponseModel> hotQaPaginQuery(HotQaRequestModel request);
List<HotQaResponseModel> hotQaList(HotQaRequestModel request);
HotQaResponseModel hotQaDetail(Integer id);
void updateHotQaStatus(Integer id, Integer status);
void deleteHotQa(Integer id);
void saveHotQa(HotQaSaveModel dto);
}
package cn.breeze.elleai.domain.sparring.service;
import cn.breeze.elleai.domain.sparring.model.request.*;
import cn.breeze.elleai.domain.sparring.model.response.HotQaResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.QaAssistantResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionHistoryResponseModel;
import cn.breeze.elleai.domain.sparring.model.response.UserChatCompletionResponseModel;
import cn.breeze.elleai.infra.entity.HotQaEntity;
import cn.breeze.elleai.infra.entity.QaAssistantEntity;
import cn.breeze.elleai.infra.entity.UserChatCompletionEntity;
import cn.breeze.elleai.infra.entity.UserChatCompletionHistoryEntity;
import cn.breeze.elleai.infra.mapper.HotQaMapper;
import cn.breeze.elleai.infra.mapper.QaAssistantMapper;
import cn.breeze.elleai.infra.mapper.UserChatCompletionHistoryMapper;
import cn.breeze.elleai.infra.mapper.UserChatCompletionMapper;
......@@ -27,6 +30,7 @@ import java.util.Objects;
import static cn.breeze.elleai.infra.entity.table.QaAssistantTableDef.QA_ASSISTANT_ENTITY;
import static cn.breeze.elleai.infra.entity.table.UserChatCompletionHistoryTableDef.USER_CHAT_COMPLETION_HISTORY_ENTITY;
import static cn.breeze.elleai.infra.entity.table.UserChatCompletionTableDef.USER_CHAT_COMPLETION_ENTITY;
import static cn.breeze.elleai.infra.entity.table.HotQaTableDef.HOT_QA_ENTITY;
@Service
......@@ -39,6 +43,8 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
private final QaAssistantMapper qaAssistantMapper;
private final HotQaMapper hotQaMapper;
@Override
public Page<UserChatCompletionResponseModel> userQaPaginQuery(UserQaRequestModel request) {
Integer pageNo = ObjectUtil.defaultIfNull(request.getPageNo(), 1);
......@@ -231,4 +237,68 @@ public class ChatCompletionServiceImpl implements ChatCompletionService{
}
qaAssistantMapper.insertOrUpdateSelective(entity);
}
@Override
public Page<HotQaResponseModel> hotQaPaginQuery(HotQaRequestModel request) {
Integer pageNo = ObjectUtil.defaultIfNull(request.getPageNo(), 1);
Integer pageSize = ObjectUtil.defaultIfNull(request.getPageSize(), 10);
QueryWrapper queryWrapper = QueryWrapper.create()
.where(HOT_QA_ENTITY.DELETED.eq(0));
if(StrUtil.isNotEmpty(request.getName())) {
queryWrapper.and(HOT_QA_ENTITY.QUESTION.like("%"+request.getName()+"%"));
}
if(Objects.nonNull(request.getStatus())) {
queryWrapper.and(HOT_QA_ENTITY.STATUS.eq(request.getStatus()));
}
queryWrapper.orderBy(HOT_QA_ENTITY.SORT_INDEX, false);
Page<HotQaResponseModel> page = hotQaMapper.paginateAs(pageNo, pageSize, queryWrapper, HotQaResponseModel.class);
return page;
}
@Override
public List<HotQaResponseModel> hotQaList(HotQaRequestModel request) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(HOT_QA_ENTITY.DELETED.eq(0));
if(StrUtil.isNotEmpty(request.getName())) {
queryWrapper.and(HOT_QA_ENTITY.QUESTION.like("%"+request.getName()+"%"));
}
if(Objects.nonNull(request.getStatus())) {
queryWrapper.and(HOT_QA_ENTITY.STATUS.eq(request.getStatus()));
}
queryWrapper.orderBy(HOT_QA_ENTITY.SORT_INDEX, false);
return hotQaMapper.selectListByQueryAs(queryWrapper, HotQaResponseModel.class);
}
@Override
public HotQaResponseModel hotQaDetail(Integer id) {
QueryWrapper queryWrapper = QueryWrapper.create()
.where(HOT_QA_ENTITY.ID.eq(id).and(HOT_QA_ENTITY.DELETED.eq(0)));
return hotQaMapper.selectOneByQueryAs(queryWrapper, HotQaResponseModel.class);
}
@Override
public void updateHotQaStatus(Integer id, Integer status) {
UpdateChain.of(HotQaEntity.class)
.set(HOT_QA_ENTITY.STATUS, status)
.where(HOT_QA_ENTITY.ID.eq(id))
.update();
}
@Override
public void deleteHotQa(Integer id) {
UpdateChain.of(HotQaEntity.class)
.set(HOT_QA_ENTITY.DELETED, 1)
.where(HOT_QA_ENTITY.ID.eq(id))
.update();
}
@Override
public void saveHotQa(HotQaSaveModel dto) {
HotQaEntity entity = BeanUtil.toBean(dto, HotQaEntity.class);
hotQaMapper.insertOrUpdateSelective(entity);
}
}
package cn.breeze.elleai.infra.entity;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 实体类。
*
* @author breeze
* @since 2024-11-04
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("ai_hot_qa")
public class HotQaEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Integer id;
/**
* 问题
*/
private String question;
/**
* 答案
*/
private String answer;
/**
* 排序优先级
*/
private Integer sortIndex;
/**
* 状态(0禁用 1启用)
*/
private Integer status;
/**
* 是否删除(0否 1是)
*/
private Integer deleted;
/**
* 创建时间
*/
private Date createTime;
}
......@@ -62,6 +62,11 @@ public class QaAssistantEntity implements Serializable {
*/
private Integer status;
/**
* 检索范围(0内部知识库 1全网)
*/
private Integer searchScope;
/**
* 是否删除(0否 1是)
*/
......
package cn.breeze.elleai.infra.entity.table;
import com.mybatisflex.core.query.QueryColumn;
import com.mybatisflex.core.table.TableDef;
import java.io.Serial;
/**
* 表定义层。
*
* @author breeze
* @since 2024-11-04
*/
public class HotQaTableDef extends TableDef {
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
public static final HotQaTableDef HOT_QA_ENTITY = new HotQaTableDef();
public final QueryColumn ID = new QueryColumn(this, "id");
/**
* 问题
*/
public final QueryColumn QUESTION = new QueryColumn(this, "question");
/**
* 答案
*/
public final QueryColumn ANSWER = new QueryColumn(this, "answer");
/**
* 排序优先级
*/
public final QueryColumn SORT_INDEX = new QueryColumn(this, "sort_index");
/**
* 状态(0禁用 1启用)
*/
public final QueryColumn STATUS = new QueryColumn(this, "status");
/**
* 是否删除(0否 1是)
*/
public final QueryColumn DELETED = new QueryColumn(this, "deleted");
/**
* 创建时间
*/
public final QueryColumn CREATE_TIME = new QueryColumn(this, "create_time");
/**
* 所有字段。
*/
public final QueryColumn ALL_COLUMNS = new QueryColumn(this, "*");
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, QUESTION, ANSWER, SORT_INDEX, STATUS, DELETED, CREATE_TIME};
public HotQaTableDef() {
super("", "ai_hot_qa");
}
private HotQaTableDef(String schema, String name, String alisa) {
super(schema, name, alisa);
}
public HotQaTableDef as(String alias) {
String key = getNameWithSchema() + "." + alias;
return getCache(key, k -> new HotQaTableDef("", "ai_hot_qa", alias));
}
}
......@@ -69,6 +69,11 @@ public class QaAssistantTableDef extends TableDef {
*/
public final QueryColumn VISIBLE_ROLE_IDS = new QueryColumn(this, "visible_role_ids");
/**
* 检索范围(0内部知识库 1全网)
*/
public final QueryColumn SEARCH_SCOPE = new QueryColumn(this, "search_scope");
/**
* 所有字段。
*/
......@@ -77,7 +82,7 @@ public class QaAssistantTableDef extends TableDef {
/**
* 默认字段,不包含逻辑删除或者 large 等字段。
*/
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, NAME, DESCRIPTION, ICON_URL, CATEGORY_IDS, VISIBLE_ROLE_IDS, STATUS, DELETED, CREATE_TIME, UPDATE_TIME};
public final QueryColumn[] DEFAULT_COLUMNS = new QueryColumn[]{ID, NAME, DESCRIPTION, ICON_URL, CATEGORY_IDS, VISIBLE_ROLE_IDS, SEARCH_SCOPE, STATUS, DELETED, CREATE_TIME, UPDATE_TIME};
public QaAssistantTableDef() {
super("", "ai_qa_assistant");
......
package cn.breeze.elleai.infra.mapper;
import cn.breeze.elleai.infra.entity.HotQaEntity;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 映射层。
*
* @author breeze
* @since 2024-11-04
*/
@Mapper
public interface HotQaMapper extends BaseMapper<HotQaEntity> {
}
......@@ -54,11 +54,8 @@ public class SingleJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
log.info("定时轮询AI点评异常任务开始.");
List<ExamineEvaluateJobResponseModel> jobList = commonService.pendingEvaluateJobList();
log.info("定时轮询AI点评异常任务,jobList size = {}", jobList.size());
if(CollectionUtil.isNotEmpty(jobList)) {
jobList.forEach(v -> {
try {
......@@ -68,8 +65,6 @@ public class SingleJob extends QuartzJobBean {
}
});
}
log.info("定时轮询AI点评异常任务结束.");
}
@Async
......
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