reactor:移除 ai 的 api 包
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationUpdateMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService;
|
||||
import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 聊天对话")
|
||||
@RestController
|
||||
@RequestMapping("/ai/chat/conversation")
|
||||
@Validated
|
||||
public class AiChatConversationController {
|
||||
|
||||
@Resource
|
||||
private AiChatConversationService chatConversationService;
|
||||
@Resource
|
||||
private AiChatMessageService chatMessageService;
|
||||
|
||||
@PostMapping("/create-my")
|
||||
@Operation(summary = "创建【我的】聊天对话")
|
||||
public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
|
||||
return success(chatConversationService.createChatConversationMy(createReqVO, getLoginUserId()));
|
||||
}
|
||||
|
||||
@PutMapping("/update-my")
|
||||
@Operation(summary = "更新【我的】聊天对话")
|
||||
public CommonResult<Boolean> updateChatConversationMy(@RequestBody @Valid AiChatConversationUpdateMyReqVO updateReqVO) {
|
||||
chatConversationService.updateChatConversationMy(updateReqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/my-list")
|
||||
@Operation(summary = "获得【我的】聊天对话列表")
|
||||
public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() {
|
||||
List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(getLoginUserId());
|
||||
return success(BeanUtils.toBean(list, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获得【我的】聊天对话")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public CommonResult<AiChatConversationRespVO> getChatConversationMy(@RequestParam("id") Long id) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(id);
|
||||
if (conversation != null && ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) {
|
||||
conversation = null;
|
||||
}
|
||||
return success(BeanUtils.toBean(conversation, AiChatConversationRespVO.class));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除聊天对话")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteChatConversationMy(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationMy(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-by-unpinned")
|
||||
@Operation(summary = "删除未置顶的聊天对话")
|
||||
public CommonResult<Boolean> deleteChatConversationMyByUnpinned() {
|
||||
chatConversationService.deleteChatConversationMyByUnpinned(getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 对话管理 ==========
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得对话分页", description = "用于【对话管理】菜单")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')")
|
||||
public CommonResult<PageResult<AiChatConversationRespVO>> getChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
|
||||
PageResult<AiChatConversationDO> pageResult = chatConversationService.getChatConversationPage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
// 拼接关联数据
|
||||
Map<Long, Integer> messageCountMap = chatMessageService.getChatMessageCountMap(
|
||||
convertList(pageResult.getList(), AiChatConversationDO::getId));
|
||||
return success(BeanUtils.toBean(pageResult, AiChatConversationRespVO.class,
|
||||
conversation -> conversation.setMessageCount(messageCountMap.getOrDefault(conversation.getId(), 0))));
|
||||
}
|
||||
|
||||
@Operation(summary = "管理员删除对话")
|
||||
@DeleteMapping("/delete-by-admin")
|
||||
@Parameter(name = "id", required = true, description = "对话编号", example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-conversation:delete')")
|
||||
public CommonResult<Boolean> deleteChatConversationByAdmin(@RequestParam("id") Long id) {
|
||||
chatConversationService.deleteChatConversationByAdmin(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
### 发送消息(段式)
|
||||
POST {{baseUrl}}/ai/chat/message/send
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"conversationId": "1781604279872581724",
|
||||
"content": "你是 OpenAI 么?"
|
||||
}
|
||||
|
||||
### 发送消息(流式)
|
||||
POST {{baseUrl}}/ai/chat/message/send-stream
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"conversationId": "1781604279872581724",
|
||||
"content": "1+1=?"
|
||||
}
|
||||
|
||||
### 获得指定对话的消息列表
|
||||
GET {{baseUrl}}/ai/chat/message/list-by-conversation-id?conversationId=1781604279872581649
|
||||
Authorization: {{token}}
|
||||
|
||||
### 删除消息
|
||||
DELETE {{baseUrl}}/ai/chat/message/delete?id=50
|
||||
Authorization: {{token}}
|
@@ -0,0 +1,157 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
import cn.iocoder.yudao.module.ai.service.chat.AiChatConversationService;
|
||||
import cn.iocoder.yudao.module.ai.service.chat.AiChatMessageService;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeSegmentService;
|
||||
import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - 聊天消息")
|
||||
@RestController
|
||||
@RequestMapping("/ai/chat/message")
|
||||
@Slf4j
|
||||
public class AiChatMessageController {
|
||||
|
||||
@Resource
|
||||
private AiChatMessageService chatMessageService;
|
||||
@Resource
|
||||
private AiChatConversationService chatConversationService;
|
||||
@Resource
|
||||
private AiChatRoleService chatRoleService;
|
||||
@Resource
|
||||
private AiKnowledgeSegmentService knowledgeSegmentService;
|
||||
@Resource
|
||||
private AiKnowledgeDocumentService knowledgeDocumentService;
|
||||
|
||||
@Operation(summary = "发送消息(段式)", description = "一次性返回,响应较慢")
|
||||
@PostMapping("/send")
|
||||
public CommonResult<AiChatMessageSendRespVO> sendMessage(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
|
||||
return success(chatMessageService.sendMessage(sendReqVO, getLoginUserId()));
|
||||
}
|
||||
|
||||
@Operation(summary = "发送消息(流式)", description = "流式返回,响应较快")
|
||||
@PostMapping(value = "/send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
|
||||
return chatMessageService.sendChatMessageStream(sendReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
@Operation(summary = "获得指定对话的消息列表")
|
||||
@GetMapping("/list-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public CommonResult<List<AiChatMessageRespVO>> getChatMessageListByConversationId(
|
||||
@RequestParam("conversationId") Long conversationId) {
|
||||
AiChatConversationDO conversation = chatConversationService.getChatConversation(conversationId);
|
||||
if (conversation == null || ObjUtil.notEqual(conversation.getUserId(), getLoginUserId())) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
// 1. 获取消息列表
|
||||
List<AiChatMessageDO> messageList = chatMessageService.getChatMessageListByConversationId(conversationId);
|
||||
if (CollUtil.isEmpty(messageList)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
|
||||
// 2. 拼接数据,主要是知识库段落信息
|
||||
Map<Long, AiKnowledgeSegmentDO> segmentMap = knowledgeSegmentService.getKnowledgeSegmentMap(convertListByFlatMap(messageList,
|
||||
message -> CollUtil.isEmpty(message.getSegmentIds()) ? null : message.getSegmentIds().stream()));
|
||||
Map<Long, AiKnowledgeDocumentDO> documentMap = knowledgeDocumentService.getKnowledgeDocumentMap(
|
||||
convertList(segmentMap.values(), AiKnowledgeSegmentDO::getDocumentId));
|
||||
List<AiChatMessageRespVO> messageVOList = BeanUtils.toBean(messageList, AiChatMessageRespVO.class);
|
||||
for (int i = 0; i < messageList.size(); i++) {
|
||||
AiChatMessageDO message = messageList.get(i);
|
||||
if (CollUtil.isEmpty(message.getSegmentIds())) {
|
||||
continue;
|
||||
}
|
||||
// 设置知识库段落信息
|
||||
messageVOList.get(i).setSegments(convertList(message.getSegmentIds(), segmentId -> {
|
||||
AiKnowledgeSegmentDO segment = segmentMap.get(segmentId);
|
||||
if (segment == null) {
|
||||
return null;
|
||||
}
|
||||
AiKnowledgeDocumentDO document = documentMap.get(segment.getDocumentId());
|
||||
if (document == null) {
|
||||
return null;
|
||||
}
|
||||
return new AiChatMessageRespVO.KnowledgeSegment().setId(segment.getId()).setContent(segment.getContent())
|
||||
.setDocumentId(segment.getDocumentId()).setDocumentName(document.getName());
|
||||
}));
|
||||
}
|
||||
return success(messageVOList);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除消息")
|
||||
@DeleteMapping("/delete")
|
||||
@Parameter(name = "id", required = true, description = "消息编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteChatMessage(@RequestParam("id") Long id) {
|
||||
chatMessageService.deleteChatMessage(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "删除指定对话的消息")
|
||||
@DeleteMapping("/delete-by-conversation-id")
|
||||
@Parameter(name = "conversationId", required = true, description = "对话编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteChatMessageByConversationId(@RequestParam("conversationId") Long conversationId) {
|
||||
chatMessageService.deleteChatMessageByConversationId(conversationId, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ========== 对话管理 ==========
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得消息分页", description = "用于【对话管理】菜单")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-conversation:query')")
|
||||
public CommonResult<PageResult<AiChatMessageRespVO>> getChatMessagePage(AiChatMessagePageReqVO pageReqVO) {
|
||||
PageResult<AiChatMessageDO> pageResult = chatMessageService.getChatMessagePage(pageReqVO);
|
||||
if (CollUtil.isEmpty(pageResult.getList())) {
|
||||
return success(PageResult.empty());
|
||||
}
|
||||
// 拼接数据
|
||||
Map<Long, AiChatRoleDO> roleMap = chatRoleService.getChatRoleMap(
|
||||
convertSet(pageResult.getList(), AiChatMessageDO::getRoleId));
|
||||
return success(BeanUtils.toBean(pageResult, AiChatMessageRespVO.class,
|
||||
respVO -> MapUtils.findAndThen(roleMap, respVO.getRoleId(),
|
||||
role -> respVO.setRoleName(role.getName()))));
|
||||
}
|
||||
|
||||
@Operation(summary = "管理员删除消息")
|
||||
@DeleteMapping("/delete-by-admin")
|
||||
@Parameter(name = "id", required = true, description = "消息编号", example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-message:delete')")
|
||||
public CommonResult<Boolean> deleteChatMessageByAdmin(@RequestParam("id") Long id) {
|
||||
chatMessageService.deleteChatMessageByAdmin(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话创建【我的】 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationCreateMyReqVO {
|
||||
|
||||
@Schema(description = "聊天角色编号", example = "666")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "知识库编号", example = "1204")
|
||||
private Long knowledgeId;
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话的分页 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "对话标题", example = "你好")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话 Response VO")
|
||||
@Data
|
||||
public class AiChatConversationRespVO implements VO {
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "对话标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "我是一个标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "是否置顶", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "角色编号", example = "1")
|
||||
@Trans(type = TransType.SIMPLE, target = AiChatRoleDO.class, fields = {"name", "avatar"}, refs = {"roleName", "roleAvatar"})
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = "name", ref = "modelName")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "ERNIE-Bot-turbo-0922")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
private String modelName;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer maxContexts;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 关联 role 信息 ==========
|
||||
|
||||
@Schema(description = "角色头像", example = "https://www.iocoder.cn/1.png")
|
||||
private String roleAvatar;
|
||||
|
||||
@Schema(description = "角色名字", example = "小黄")
|
||||
private String roleName;
|
||||
|
||||
// ========== 仅在【对话管理】时加载 ==========
|
||||
|
||||
@Schema(description = "消息数量", example = "20")
|
||||
private Integer messageCount;
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天对话更新【我的】 Request VO")
|
||||
@Data
|
||||
public class AiChatConversationUpdateMyReqVO {
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "对话编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "对话标题", example = "我是一个标题")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "是否置顶", example = "true")
|
||||
private Boolean pinned;
|
||||
|
||||
@Schema(description = "模型编号", example = "1")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "知识库编号", example = "1")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "角色设定", example = "一个快乐的程序员")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "温度参数", example = "0.8")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "10")
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息的分页 Request VO")
|
||||
@Data
|
||||
public class AiChatMessagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "对话编号", example = "2048")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "用户编号", example = "1024")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "消息内容", example = "你好")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息 Response VO")
|
||||
@Data
|
||||
public class AiChatMessageRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "回复消息编号", example = "1024")
|
||||
private Long replyId;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role")
|
||||
private String type; // 参见 MessageType 枚举类
|
||||
|
||||
@Schema(description = "用户编号", example = "4096")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "角色编号", example = "888")
|
||||
private Long roleId;
|
||||
|
||||
@Schema(description = "模型标志", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "123")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "是否携带上下文", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean useContext;
|
||||
|
||||
@Schema(description = "知识库段落编号数组", example = "[1,2,3]")
|
||||
private List<Long> segmentIds;
|
||||
|
||||
@Schema(description = "知识库段落数组")
|
||||
private List<KnowledgeSegment> segments;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-05-12 12:51")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
// ========== 仅在【对话管理】时加载 ==========
|
||||
|
||||
@Schema(description = "角色名字", example = "小黄")
|
||||
private String roleName;
|
||||
|
||||
@Schema(description = "知识库段落", example = "Java 开发手册")
|
||||
@Data
|
||||
public static class KnowledgeSegment {
|
||||
|
||||
@Schema(description = "段落编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long documentId;
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品使用手册")
|
||||
private String documentName;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息发送 Request VO")
|
||||
@Data
|
||||
public class AiChatMessageSendReqVO {
|
||||
|
||||
@Schema(description = "聊天对话编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "聊天对话编号不能为空")
|
||||
private Long conversationId;
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "帮我写个 Java 算法")
|
||||
@NotEmpty(message = "聊天内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "是否携带上下文", example = "true")
|
||||
private Boolean useContext;
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天消息发送 Response VO")
|
||||
@Data
|
||||
public class AiChatMessageSendRespVO {
|
||||
|
||||
@Schema(description = "发送消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Message send;
|
||||
|
||||
@Schema(description = "接收消息", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Message receive;
|
||||
|
||||
@Schema(description = "消息")
|
||||
@Data
|
||||
public static class Message {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "消息类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "role")
|
||||
private String type; // 参见 MessageType 枚举类
|
||||
|
||||
@Schema(description = "聊天内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "你好,你好啊")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "知识库段落编号数组", example = "[1,2,3]")
|
||||
private List<Long> segmentIds;
|
||||
|
||||
@Schema(description = "知识库段落数组")
|
||||
private List<AiChatMessageRespVO.KnowledgeSegment> segments;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
### 生成图片:OpenAI(DALL)
|
||||
POST {{baseUrl}}/ai/image/draw
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "OpenAI",
|
||||
"prompt": "可爱的小喵星人",
|
||||
"model": "dall-e-3",
|
||||
"height": "1024",
|
||||
"width": "1024",
|
||||
"options": {
|
||||
"style": "vivid"
|
||||
}
|
||||
}
|
||||
|
||||
### 生成图片:StableDiffusion
|
||||
POST {{baseUrl}}/ai/image/draw
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "StableDiffusion",
|
||||
"prompt": "中国长城",
|
||||
"model": "stable-diffusion-v1-6",
|
||||
"height": "1024",
|
||||
"width": "1024",
|
||||
"style": "vivid"
|
||||
}
|
||||
|
||||
### 生成图片:生成图片(Midjourney)
|
||||
POST {{baseUrl}}/ai/image/midjourney/imagine
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"prompt": "中国旗袍",
|
||||
"model": "midjourney",
|
||||
"width": "1",
|
||||
"height": "1",
|
||||
"version": "6.0"
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.*;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyActionReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney.AiMidjourneyImagineReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
|
||||
import cn.iocoder.yudao.module.ai.service.image.AiImageService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.annotation.security.PermitAll;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 绘画")
|
||||
@RestController
|
||||
@RequestMapping("/ai/image")
|
||||
@Slf4j
|
||||
public class AiImageController {
|
||||
|
||||
@Resource
|
||||
private AiImageService imageService;
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获取【我的】绘图分页")
|
||||
public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated AiImagePageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/public-page")
|
||||
@Operation(summary = "获取公开的绘图分页")
|
||||
public CommonResult<PageResult<AiImageRespVO>> getImagePagePublic(AiImagePublicPageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePagePublic(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获取【我的】绘图记录")
|
||||
@Parameter(name = "id", required = true, description = "绘画编号", example = "1024")
|
||||
public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) {
|
||||
AiImageDO image = imageService.getImage(id);
|
||||
if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(image, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/my-list-by-ids")
|
||||
@Operation(summary = "获取【我的】绘图记录列表")
|
||||
@Parameter(name = "ids", required = true, description = "绘画编号数组", example = "1024,2048")
|
||||
public CommonResult<List<AiImageRespVO>> getImageListMyByIds(@RequestParam("ids") List<Long> ids) {
|
||||
List<AiImageDO> imageList = imageService.getImageList(ids);
|
||||
imageList.removeIf(item -> !ObjUtil.equal(getLoginUserId(), item.getUserId()));
|
||||
return success(BeanUtils.toBean(imageList, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@Operation(summary = "生成图片")
|
||||
@PostMapping("/draw")
|
||||
public CommonResult<Long> drawImage(@Valid @RequestBody AiImageDrawReqVO drawReqVO) {
|
||||
return success(imageService.drawImage(getLoginUserId(), drawReqVO));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除【我的】绘画记录")
|
||||
@DeleteMapping("/delete-my")
|
||||
@Parameter(name = "id", required = true, description = "绘画编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteImageMy(@RequestParam("id") Long id) {
|
||||
imageService.deleteImageMy(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ================ midjourney 专属 ================
|
||||
|
||||
@Operation(summary = "【Midjourney】生成图片")
|
||||
@PostMapping("/midjourney/imagine")
|
||||
public CommonResult<Long> midjourneyImagine(@Valid @RequestBody AiMidjourneyImagineReqVO reqVO) {
|
||||
Long imageId = imageService.midjourneyImagine(getLoginUserId(), reqVO);
|
||||
return success(imageId);
|
||||
}
|
||||
|
||||
@Operation(summary = "【Midjourney】通知图片进展", description = "由 Midjourney Proxy 回调")
|
||||
@PostMapping("/midjourney/notify") // 必须是 POST 方法,否则会报错
|
||||
@PermitAll
|
||||
@TenantIgnore
|
||||
public CommonResult<Boolean> midjourneyNotify(@Valid @RequestBody MidjourneyApi.Notify notify) {
|
||||
imageService.midjourneyNotify(notify);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Operation(summary = "【Midjourney】Action 操作(二次生成图片)", description = "例如说:放大、缩小、U1、U2 等")
|
||||
@PostMapping("/midjourney/action")
|
||||
public CommonResult<Long> midjourneyAction(@Valid @RequestBody AiMidjourneyActionReqVO reqVO) {
|
||||
Long imageId = imageService.midjourneyAction(getLoginUserId(), reqVO);
|
||||
return success(imageId);
|
||||
}
|
||||
|
||||
// ================ 绘图管理 ================
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得绘画分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:image:query')")
|
||||
public CommonResult<PageResult<AiImageRespVO>> getImagePage(@Valid AiImagePageReqVO pageReqVO) {
|
||||
PageResult<AiImageDO> pageResult = imageService.getImagePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiImageRespVO.class));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新绘画")
|
||||
@PreAuthorize("@ss.hasPermission('ai:image:update')")
|
||||
public CommonResult<Boolean> updateImage(@Valid @RequestBody AiImageUpdateReqVO updateReqVO) {
|
||||
imageService.updateImage(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除绘画")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:image:delete')")
|
||||
public CommonResult<Boolean> deleteImage(@RequestParam("id") Long id) {
|
||||
imageService.deleteImage(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import org.springframework.ai.openai.OpenAiImageOptions;
|
||||
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画 Request VO")
|
||||
@Data
|
||||
public class AiImageDrawReqVO {
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "模型编号不能为空")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "画一个长城")
|
||||
@NotEmpty(message = "提示词不能为空")
|
||||
@Size(max = 1200, message = "提示词最大 1200")
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 1. dall-e-2 模型:256x256、512x512、1024x1024
|
||||
* 2. dall-e-3 模型:1024x1024, 1792x1024, 或 1024x1792
|
||||
*/
|
||||
@Schema(description = "图片高度")
|
||||
@NotNull(message = "图片高度不能为空")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "图片宽度")
|
||||
@NotNull(message = "图片宽度不能为空")
|
||||
private Integer width;
|
||||
|
||||
// ========== 各平台绘画的拓展参数 ==========
|
||||
|
||||
/**
|
||||
* 绘制参数,不同 platform 的不同参数
|
||||
*
|
||||
* 1. {@link OpenAiImageOptions}
|
||||
* 2. {@link StabilityAiImageOptions}
|
||||
*/
|
||||
@Schema(description = "绘制参数")
|
||||
private Map<String, String> options;
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画分页 Request VO")
|
||||
@Data
|
||||
public class AiImagePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "28987")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "提示词", example = "1")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "绘画状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否发布", example = "1")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画公开的分页 Request VO")
|
||||
@Data
|
||||
public class AiImagePublicPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "提示词")
|
||||
private String prompt;
|
||||
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画 Response VO")
|
||||
@Data
|
||||
public class AiImageRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
private String platform; // 参见 AiPlatformEnum 枚举
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "stable-diffusion-v1-6")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "南极的小企鹅")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "绘画状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "public")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "图片地址", example = "https://www.iocoder.cn/1.png")
|
||||
private String picUrl;
|
||||
|
||||
@Schema(description = "绘画错误信息", example = "图片错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "绘制参数")
|
||||
private Map<String, String> options;
|
||||
|
||||
@Schema(description = "mj buttons 按钮")
|
||||
private List<MidjourneyApi.Button> buttons;
|
||||
|
||||
@Schema(description = "完成时间")
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画修改 Request VO")
|
||||
@Data
|
||||
public class AiImageUpdateReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否发布", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘图操作(Midjourney) Request VO")
|
||||
@Data
|
||||
public class AiMidjourneyActionReqVO {
|
||||
|
||||
@Schema(description = "图片编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "操作按钮编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "MJ::JOB::variation::4::06aa3e66-0e97-49cc-8201-e0295d883de4")
|
||||
@NotEmpty(message = "操作按钮编号不能为空")
|
||||
private String customId;
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.image.vo.midjourney;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 绘画生成(Midjourney) Request VO")
|
||||
@Data
|
||||
public class AiMidjourneyImagineReqVO {
|
||||
|
||||
@Schema(description = "提示词", requiredMode = Schema.RequiredMode.REQUIRED, example = "中国神龙")
|
||||
@NotEmpty(message = "提示词不能为空!")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "模型编号不能为空")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "图片宽度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片宽度不能为空")
|
||||
private Integer width;
|
||||
|
||||
@Schema(description = "图片高度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "图片高度不能为空")
|
||||
private Integer height;
|
||||
|
||||
@Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.0")
|
||||
@NotEmpty(message = "版本号不能为空")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "参考图", example = "https://www.iocoder.cn/x.png")
|
||||
private String referImageUrl;
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
### 创建知识库
|
||||
POST {{baseUrl}}/ai/knowledge/create
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"name": "测试标题",
|
||||
"description": "测试描述",
|
||||
"embeddingModelId": 30,
|
||||
"topK": 3,
|
||||
"similarityThreshold": 0.5,
|
||||
"status": 0
|
||||
}
|
||||
|
||||
### 更新知识库
|
||||
PUT {{baseUrl}}/ai/knowledge/update
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"id": 1,
|
||||
"name": "测试标题(更新)",
|
||||
"description": "测试描述",
|
||||
"embeddingModelId": 30,
|
||||
"topK": 5,
|
||||
"similarityThreshold": 0.6,
|
||||
"status": 0
|
||||
}
|
||||
|
||||
### 获取知识库分页
|
||||
GET {{baseUrl}}/ai/knowledge/page?pageNo=1&pageSize=10
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
@@ -0,0 +1,84 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeSaveReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - AI 知识库")
|
||||
@RestController
|
||||
@RequestMapping("/ai/knowledge")
|
||||
@Validated
|
||||
public class AiKnowledgeController {
|
||||
|
||||
@Resource
|
||||
private AiKnowledgeService knowledgeService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获取知识库分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<PageResult<AiKnowledgeRespVO>> getKnowledgePage(@Valid AiKnowledgePageReqVO pageReqVO) {
|
||||
PageResult<AiKnowledgeDO> pageResult = knowledgeService.getKnowledgePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiKnowledgeRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得知识库")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<AiKnowledgeRespVO> getKnowledge(@RequestParam("id") Long id) {
|
||||
AiKnowledgeDO knowledge = knowledgeService.getKnowledge(id);
|
||||
return success(BeanUtils.toBean(knowledge, AiKnowledgeRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建知识库")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:create')")
|
||||
public CommonResult<Long> createKnowledge(@RequestBody @Valid AiKnowledgeSaveReqVO createReqVO) {
|
||||
return success(knowledgeService.createKnowledge(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新知识库")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
||||
public CommonResult<Boolean> updateKnowledge(@RequestBody @Valid AiKnowledgeSaveReqVO updateReqVO) {
|
||||
knowledgeService.updateKnowledge(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除知识库")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:delete')")
|
||||
public CommonResult<Boolean> deleteKnowledge(@RequestParam("id") Long id) {
|
||||
knowledgeService.deleteKnowledge(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得知识库的精简列表")
|
||||
public CommonResult<List<AiKnowledgeRespVO>> getKnowledgeSimpleList() {
|
||||
List<AiKnowledgeDO> list = knowledgeService.getKnowledgeSimpleListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(convertList(list, knowledge -> new AiKnowledgeRespVO()
|
||||
.setId(knowledge.getId()).setName(knowledge.getName())));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
### 创建知识文档
|
||||
POST {{baseUrl}}/ai/knowledge/document/create
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"knowledgeId": 2,
|
||||
"name": "测试文档",
|
||||
"url": "https://static.iocoder.cn/README.md",
|
||||
"segmentMaxTokens": 800
|
||||
}
|
||||
|
||||
### 批量创建知识文档
|
||||
POST {{baseUrl}}/ai/knowledge/document/create-list
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"knowledgeId": 1,
|
||||
"list": [
|
||||
{
|
||||
"name": "测试文档1",
|
||||
"url": "https://static.iocoder.cn/README.md",
|
||||
"segmentMaxTokens": 800
|
||||
},
|
||||
{
|
||||
"name": "测试文档2",
|
||||
"url": "https://static.iocoder.cn/README_yudao.md",
|
||||
"segmentMaxTokens": 400
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -0,0 +1,90 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.*;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge.AiKnowledgeDocumentCreateReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - AI 知识库文档")
|
||||
@RestController
|
||||
@RequestMapping("/ai/knowledge/document")
|
||||
@Validated
|
||||
public class AiKnowledgeDocumentController {
|
||||
|
||||
@Resource
|
||||
private AiKnowledgeDocumentService documentService;
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获取文档分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<PageResult<AiKnowledgeDocumentRespVO>> getKnowledgeDocumentPage(
|
||||
@Valid AiKnowledgeDocumentPageReqVO pageReqVO) {
|
||||
PageResult<AiKnowledgeDocumentDO> pageResult = documentService.getKnowledgeDocumentPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiKnowledgeDocumentRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取文档详情")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<AiKnowledgeDocumentRespVO> getKnowledgeDocument(@RequestParam("id") Long id) {
|
||||
AiKnowledgeDocumentDO document = documentService.getKnowledgeDocument(id);
|
||||
return success(BeanUtils.toBean(document, AiKnowledgeDocumentRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "新建文档(单个)")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:create')")
|
||||
public CommonResult<Long> createKnowledgeDocument(@RequestBody @Valid AiKnowledgeDocumentCreateReqVO reqVO) {
|
||||
Long id = documentService.createKnowledgeDocument(reqVO);
|
||||
return success(id);
|
||||
}
|
||||
|
||||
@PostMapping("/create-list")
|
||||
@Operation(summary = "新建文档(多个)")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:create')")
|
||||
public CommonResult<List<Long>> createKnowledgeDocumentList(
|
||||
@RequestBody @Valid AiKnowledgeDocumentCreateListReqVO reqVO) {
|
||||
List<Long> ids = documentService.createKnowledgeDocumentList(reqVO);
|
||||
return success(ids);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新文档")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
||||
public CommonResult<Boolean> updateKnowledgeDocument(@Valid @RequestBody AiKnowledgeDocumentUpdateReqVO reqVO) {
|
||||
documentService.updateKnowledgeDocument(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "更新文档状态")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
||||
public CommonResult<Boolean> updateKnowledgeDocumentStatus(
|
||||
@Valid @RequestBody AiKnowledgeDocumentUpdateStatusReqVO reqVO) {
|
||||
documentService.updateKnowledgeDocumentStatus(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除文档")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:delete')")
|
||||
public CommonResult<Boolean> deleteKnowledgeDocument(@RequestParam("id") Long id) {
|
||||
documentService.deleteKnowledgeDocument(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
### 切片内容
|
||||
GET {{baseUrl}}/ai/knowledge/segment/split?url=https://static.iocoder.cn/README_yudao.md&segmentMaxTokens=800
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
### 搜索段落内容
|
||||
GET {{baseUrl}}/ai/knowledge/segment/search?knowledgeId=2&content=如何使用这个产品&topK=5&similarityThreshold=0.1
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
### 获取文档处理列表
|
||||
GET {{baseUrl}}/ai/knowledge/segment/get-process-list?documentIds=1,2,3
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
@@ -0,0 +1,130 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment.*;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeSegmentService;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchReqBO;
|
||||
import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.Parameters;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@Tag(name = "管理后台 - AI 知识库段落")
|
||||
@RestController
|
||||
@RequestMapping("/ai/knowledge/segment")
|
||||
@Validated
|
||||
public class AiKnowledgeSegmentController {
|
||||
|
||||
@Resource
|
||||
private AiKnowledgeSegmentService segmentService;
|
||||
@Resource
|
||||
private AiKnowledgeDocumentService documentService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取段落详情")
|
||||
@Parameter(name = "id", description = "段落编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<AiKnowledgeSegmentRespVO> getKnowledgeSegment(@RequestParam("id") Long id) {
|
||||
AiKnowledgeSegmentDO segment = segmentService.getKnowledgeSegment(id);
|
||||
return success(BeanUtils.toBean(segment, AiKnowledgeSegmentRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获取段落分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<PageResult<AiKnowledgeSegmentRespVO>> getKnowledgeSegmentPage(
|
||||
@Valid AiKnowledgeSegmentPageReqVO pageReqVO) {
|
||||
PageResult<AiKnowledgeSegmentDO> pageResult = segmentService.getKnowledgeSegmentPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiKnowledgeSegmentRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建段落")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:create')")
|
||||
public CommonResult<Long> createKnowledgeSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO createReqVO) {
|
||||
return success(segmentService.createKnowledgeSegment(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新段落内容")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
||||
public CommonResult<Boolean> updateKnowledgeSegment(@Valid @RequestBody AiKnowledgeSegmentSaveReqVO reqVO) {
|
||||
segmentService.updateKnowledgeSegment(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update-status")
|
||||
@Operation(summary = "启禁用段落内容")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:update')")
|
||||
public CommonResult<Boolean> updateKnowledgeSegmentStatus(
|
||||
@Valid @RequestBody AiKnowledgeSegmentUpdateStatusReqVO reqVO) {
|
||||
segmentService.updateKnowledgeSegmentStatus(reqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/split")
|
||||
@Operation(summary = "切片内容")
|
||||
@Parameters({
|
||||
@Parameter(name = "url", description = "文档 URL", required = true),
|
||||
@Parameter(name = "segmentMaxTokens", description = "分段的最大 Token 数", required = true)
|
||||
})
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<List<AiKnowledgeSegmentRespVO>> splitContent(
|
||||
@RequestParam("url") @URL String url,
|
||||
@RequestParam(value = "segmentMaxTokens") Integer segmentMaxTokens) {
|
||||
List<AiKnowledgeSegmentDO> segments = segmentService.splitContent(url, segmentMaxTokens);
|
||||
return success(BeanUtils.toBean(segments, AiKnowledgeSegmentRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-process-list")
|
||||
@Operation(summary = "获取文档处理列表")
|
||||
@Parameter(name = "documentIds", description = "文档编号列表", required = true, example = "1,2,3")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<List<AiKnowledgeSegmentProcessRespVO>> getKnowledgeSegmentProcessList(
|
||||
@RequestParam("documentIds") List<Long> documentIds) {
|
||||
List<AiKnowledgeSegmentProcessRespVO> list = segmentService.getKnowledgeSegmentProcessList(documentIds);
|
||||
return success(list);
|
||||
}
|
||||
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "搜索段落内容")
|
||||
@PreAuthorize("@ss.hasPermission('ai:knowledge:query')")
|
||||
public CommonResult<List<AiKnowledgeSegmentSearchRespVO>> searchKnowledgeSegment(
|
||||
@Valid AiKnowledgeSegmentSearchReqVO reqVO) {
|
||||
// 1. 搜索段落
|
||||
List<AiKnowledgeSegmentSearchRespBO> segments = segmentService
|
||||
.searchKnowledgeSegment(BeanUtils.toBean(reqVO, AiKnowledgeSegmentSearchReqBO.class));
|
||||
if (CollUtil.isEmpty(segments)) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
|
||||
// 2. 拼接 VO
|
||||
Map<Long, AiKnowledgeDocumentDO> documentMap = documentService.getKnowledgeDocumentMap(convertSet(
|
||||
segments, AiKnowledgeSegmentSearchRespBO::getDocumentId));
|
||||
return success(BeanUtils.toBean(segments, AiKnowledgeSegmentSearchRespVO.class,
|
||||
segment -> MapUtils.findAndThen(documentMap, segment.getDocumentId(),
|
||||
document -> segment.setDocumentName(document.getName()))));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档批量创建 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentCreateListReqVO {
|
||||
|
||||
@Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1204")
|
||||
@NotNull(message = "知识库编号不能为空")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "分段的最大 Token 数", requiredMode = Schema.RequiredMode.REQUIRED, example = "800")
|
||||
@NotNull(message = "分段的最大 Token 数不能为空")
|
||||
private Integer segmentMaxTokens;
|
||||
|
||||
@Schema(description = "文档列表", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotEmpty(message = "文档列表不能为空")
|
||||
private List<Document> list;
|
||||
|
||||
@Schema(description = "文档")
|
||||
@Data
|
||||
public static class Document {
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "三方登陆")
|
||||
@NotBlank(message = "文档名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文档 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://doc.iocoder.cn")
|
||||
@URL(message = "文档 URL 格式不正确")
|
||||
private String url;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档的分页 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "知识库编号", example = "1")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "文档名称", example = "Java 开发手册")
|
||||
private String name;
|
||||
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档 Response VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentRespVO {
|
||||
|
||||
@Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文档 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://doc.iocoder.cn")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "文档内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 是一门面向对象的语言.....")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "文档内容长度", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
|
||||
private Integer contentLength;
|
||||
|
||||
@Schema(description = "文档 Token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer tokens;
|
||||
|
||||
@Schema(description = "分片最大 Token 数", requiredMode = Schema.RequiredMode.REQUIRED, example = "512")
|
||||
private Integer segmentMaxTokens;
|
||||
|
||||
@Schema(description = "召回次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer retrievalCount;
|
||||
|
||||
@Schema(description = "文档状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档更新 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentUpdateReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "名称", example = "Java 开发手册")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "分片最大 Token 数", example = "1000")
|
||||
private Integer segmentMaxTokens;
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档更新状态 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentUpdateStatusReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档的创建 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeDocumentCreateReqVO {
|
||||
|
||||
@Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1204")
|
||||
@NotNull(message = "知识库编号不能为空")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "三方登陆")
|
||||
@NotBlank(message = "文档名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "文档 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://doc.iocoder.cn")
|
||||
@URL(message = "文档 URL 格式不正确")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "分段的最大 Token 数", requiredMode = Schema.RequiredMode.REQUIRED, example = "800")
|
||||
@NotNull(message = "分段的最大 Token 数不能为空")
|
||||
private Integer segmentMaxTokens;
|
||||
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库的分页 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "知识库名称", example = "芋艿")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "是否启用", example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库 Response VO")
|
||||
@Data
|
||||
public class AiKnowledgeRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "ruoyi-vue-pro 用户指南")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库描述", example = "帮助你快速构建系统")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "向量模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "14")
|
||||
private Long embeddingModelId;
|
||||
|
||||
@Schema(description = "向量模型标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "qwen-72b-chat")
|
||||
private String embeddingModel;
|
||||
|
||||
@Schema(description = "topK", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
|
||||
private Integer topK;
|
||||
|
||||
@Schema(description = "相似度阈值", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.7")
|
||||
private Double similarityThreshold;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeSaveReqVO {
|
||||
|
||||
@Schema(description = "对话编号", example = "1204")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "知识库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "ruoyi-vue-pro 用户指南")
|
||||
@NotBlank(message = "知识库名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "知识库描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "存储 ruoyi-vue-pro 操作文档")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "向量模型编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "向量模型不能为空")
|
||||
private Long embeddingModelId;
|
||||
|
||||
@Schema(description = "topK", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
|
||||
@NotNull(message = "topK 不能为空")
|
||||
private Integer topK;
|
||||
|
||||
@Schema(description = "相似性阈值", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.5")
|
||||
@NotNull(message = "相似性阈值不能为空")
|
||||
private Double similarityThreshold;
|
||||
|
||||
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "是否启用不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库分段的分页 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "文档编号", example = "1")
|
||||
private Integer documentId;
|
||||
|
||||
@Schema(description = "分段内容关键字", example = "Java 开发")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "分段状态", example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库段落向量进度 Response VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentProcessRespVO {
|
||||
|
||||
@Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long documentId;
|
||||
|
||||
@Schema(description = "总段落数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Long count;
|
||||
|
||||
@Schema(description = "已向量化段落数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
|
||||
private Long embeddingCount;
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库文档分片 Response VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "文档编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long documentId;
|
||||
|
||||
@Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "向量库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1858496a-1dde-4edf-a43e-0aed08f37f8c")
|
||||
private String vectorId;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "切片内容长度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer contentLength;
|
||||
|
||||
@Schema(description = "token 数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Integer tokens;
|
||||
|
||||
@Schema(description = "召回次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
|
||||
private Integer retrievalCount;
|
||||
|
||||
@Schema(description = "文档状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private Long createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 新增/修改知识库段落 request VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "知识库文档编号", example = "1024")
|
||||
private Long documentId;
|
||||
|
||||
@Schema(description = "切片内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 开发手册")
|
||||
@NotEmpty(message = "切片内容不能为空")
|
||||
private String content;
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库段落搜索 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentSearchReqVO {
|
||||
|
||||
@Schema(description = "知识库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "知识库编号不能为空")
|
||||
private Long knowledgeId;
|
||||
|
||||
@Schema(description = "内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "如何使用这个产品")
|
||||
@NotEmpty(message = "内容不能为空")
|
||||
private String content;
|
||||
|
||||
@Schema(description = "最大返回数量", example = "5")
|
||||
private Integer topK;
|
||||
|
||||
@Schema(description = "相似度阈值", example = "0.7")
|
||||
private Double similarityThreshold;
|
||||
|
||||
}
|
@@ -0,0 +1,16 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库段落搜索 Response VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentSearchRespVO extends AiKnowledgeSegmentRespVO {
|
||||
|
||||
@Schema(description = "文档名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "产品使用手册")
|
||||
private String documentName;
|
||||
|
||||
@Schema(description = "相似度分数", requiredMode = Schema.RequiredMode.REQUIRED, example = "0.95")
|
||||
private Double score;
|
||||
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.segment;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Schema(description = "管理后台 - AI 知识库段落的更新状态 Request VO")
|
||||
@Data
|
||||
public class AiKnowledgeSegmentUpdateStatusReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "是否启用不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.mindmap;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapGenerateReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo.AiMindMapRespVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.mindmap.AiMindMapDO;
|
||||
import cn.iocoder.yudao.module.ai.service.mindmap.AiMindMapService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 思维导图")
|
||||
@RestController
|
||||
@RequestMapping("/ai/mind-map")
|
||||
public class AiMindMapController {
|
||||
|
||||
@Resource
|
||||
private AiMindMapService mindMapService;
|
||||
|
||||
@PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
@Operation(summary = "导图生成(流式)", description = "流式返回,响应较快")
|
||||
public Flux<CommonResult<String>> generateMindMap(@RequestBody @Valid AiMindMapGenerateReqVO generateReqVO) {
|
||||
return mindMapService.generateMindMap(generateReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
// ================ 导图管理 ================
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除思维导图")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:mind-map:delete')")
|
||||
public CommonResult<Boolean> deleteMindMap(@RequestParam("id") Long id) {
|
||||
mindMapService.deleteMindMap(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得思维导图分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:mind-map:query')")
|
||||
public CommonResult<PageResult<AiMindMapRespVO>> getMindMapPage(@Valid AiMindMapPageReqVO pageReqVO) {
|
||||
PageResult<AiMindMapDO> pageResult = mindMapService.getMindMapPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiMindMapRespVO.class));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 思维导图生成 Request VO")
|
||||
@Data
|
||||
public class AiMindMapGenerateReqVO {
|
||||
|
||||
@Schema(description = "思维导图内容提示", example = "Java 学习路线")
|
||||
@NotBlank(message = "思维导图内容提示不能为空")
|
||||
private String prompt;
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 思维导图分页 Request VO")
|
||||
@Data
|
||||
public class AiMindMapPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "4325")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "生成内容提示", example = "Java 学习路线")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.mindmap.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 思维导图 Response VO")
|
||||
@Data
|
||||
public class AiMindMapRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3373")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4325")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "生成内容提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "Java 学习路线")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "生成的思维导图内容")
|
||||
private String generatedContent;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo-0125")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,83 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeyRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.model.AiModelRespVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiApiKeyDO;
|
||||
import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - AI API 密钥")
|
||||
@RestController
|
||||
@RequestMapping("/ai/api-key")
|
||||
@Validated
|
||||
public class AiApiKeyController {
|
||||
|
||||
@Resource
|
||||
private AiApiKeyService apiKeyService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 API 密钥")
|
||||
@PreAuthorize("@ss.hasPermission('ai:api-key:create')")
|
||||
public CommonResult<Long> createApiKey(@Valid @RequestBody AiApiKeySaveReqVO createReqVO) {
|
||||
return success(apiKeyService.createApiKey(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新 API 密钥")
|
||||
@PreAuthorize("@ss.hasPermission('ai:api-key:update')")
|
||||
public CommonResult<Boolean> updateApiKey(@Valid @RequestBody AiApiKeySaveReqVO updateReqVO) {
|
||||
apiKeyService.updateApiKey(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除 API 密钥")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:api-key:delete')")
|
||||
public CommonResult<Boolean> deleteApiKey(@RequestParam("id") Long id) {
|
||||
apiKeyService.deleteApiKey(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 API 密钥")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:api-key:query')")
|
||||
public CommonResult<AiApiKeyRespVO> getApiKey(@RequestParam("id") Long id) {
|
||||
AiApiKeyDO apiKey = apiKeyService.getApiKey(id);
|
||||
return success(BeanUtils.toBean(apiKey, AiApiKeyRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 API 密钥分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:api-key:query')")
|
||||
public CommonResult<PageResult<AiApiKeyRespVO>> getApiKeyPage(@Valid AiApiKeyPageReqVO pageReqVO) {
|
||||
PageResult<AiApiKeyDO> pageResult = apiKeyService.getApiKeyPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiApiKeyRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得 API 密钥分页列表")
|
||||
public CommonResult<List<AiModelRespVO>> getApiKeySimpleList() {
|
||||
List<AiApiKeyDO> list = apiKeyService.getApiKeyList();
|
||||
return success(convertList(list, key -> new AiModelRespVO().setId(key.getId()).setName(key.getName())));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,124 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRolePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveMyReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole.AiChatRoleSaveReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 聊天角色")
|
||||
@RestController
|
||||
@RequestMapping("/ai/chat-role")
|
||||
@Validated
|
||||
public class AiChatRoleController {
|
||||
|
||||
@Resource
|
||||
private AiChatRoleService chatRoleService;
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获得【我的】聊天角色分页")
|
||||
public CommonResult<PageResult<AiChatRoleRespVO>> getChatRoleMyPage(@Valid AiChatRolePageReqVO pageReqVO) {
|
||||
PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRoleMyPage(pageReqVO, getLoginUserId());
|
||||
return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获得【我的】聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
public CommonResult<AiChatRoleRespVO> getChatRoleMy(@RequestParam("id") Long id) {
|
||||
AiChatRoleDO chatRole = chatRoleService.getChatRole(id);
|
||||
if (ObjUtil.notEqual(chatRole.getUserId(), getLoginUserId())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(chatRole, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/create-my")
|
||||
@Operation(summary = "创建【我的】聊天角色")
|
||||
public CommonResult<Long> createChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO createReqVO) {
|
||||
return success(chatRoleService.createChatRoleMy(createReqVO, getLoginUserId()));
|
||||
}
|
||||
|
||||
@PutMapping("/update-my")
|
||||
@Operation(summary = "更新【我的】聊天角色")
|
||||
public CommonResult<Boolean> updateChatRoleMy(@Valid @RequestBody AiChatRoleSaveMyReqVO updateReqVO) {
|
||||
chatRoleService.updateChatRoleMy(updateReqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete-my")
|
||||
@Operation(summary = "删除【我的】聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
public CommonResult<Boolean> deleteChatRoleMy(@RequestParam("id") Long id) {
|
||||
chatRoleService.deleteChatRoleMy(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/category-list")
|
||||
@Operation(summary = "获得聊天角色的分类列表")
|
||||
public CommonResult<List<String>> getChatRoleCategoryList() {
|
||||
return success(chatRoleService.getChatRoleCategoryList());
|
||||
}
|
||||
|
||||
// ========== 角色管理 ==========
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建聊天角色")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-role:create')")
|
||||
public CommonResult<Long> createChatRole(@Valid @RequestBody AiChatRoleSaveReqVO createReqVO) {
|
||||
return success(chatRoleService.createChatRole(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新聊天角色")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-role:update')")
|
||||
public CommonResult<Boolean> updateChatRole(@Valid @RequestBody AiChatRoleSaveReqVO updateReqVO) {
|
||||
chatRoleService.updateChatRole(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-role:delete')")
|
||||
public CommonResult<Boolean> deleteChatRole(@RequestParam("id") Long id) {
|
||||
chatRoleService.deleteChatRole(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得聊天角色")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-role:query')")
|
||||
public CommonResult<AiChatRoleRespVO> getChatRole(@RequestParam("id") Long id) {
|
||||
AiChatRoleDO chatRole = chatRoleService.getChatRole(id);
|
||||
return success(BeanUtils.toBean(chatRole, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得聊天角色分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:chat-role:query')")
|
||||
public CommonResult<PageResult<AiChatRoleRespVO>> getChatRolePage(@Valid AiChatRolePageReqVO pageReqVO) {
|
||||
PageResult<AiChatRoleDO> pageResult = chatRoleService.getChatRolePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiChatRoleRespVO.class));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.model.AiModelPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.model.AiModelRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.model.AiModelSaveReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import cn.iocoder.yudao.module.ai.service.model.AiModelService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - AI 模型")
|
||||
@RestController
|
||||
@RequestMapping("/ai/model")
|
||||
@Validated
|
||||
public class AiModelController {
|
||||
|
||||
@Resource
|
||||
private AiModelService modelService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建模型")
|
||||
@PreAuthorize("@ss.hasPermission('ai:model:create')")
|
||||
public CommonResult<Long> createModel(@Valid @RequestBody AiModelSaveReqVO createReqVO) {
|
||||
return success(modelService.createModel(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新模型")
|
||||
@PreAuthorize("@ss.hasPermission('ai:model:update')")
|
||||
public CommonResult<Boolean> updateModel(@Valid @RequestBody AiModelSaveReqVO updateReqVO) {
|
||||
modelService.updateModel(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除模型")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:model:delete')")
|
||||
public CommonResult<Boolean> deleteModel(@RequestParam("id") Long id) {
|
||||
modelService.deleteModel(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得模型")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:model:query')")
|
||||
public CommonResult<AiModelRespVO> getModel(@RequestParam("id") Long id) {
|
||||
AiModelDO model = modelService.getModel(id);
|
||||
return success(BeanUtils.toBean(model, AiModelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得模型分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:model:query')")
|
||||
public CommonResult<PageResult<AiModelRespVO>> getModelPage(@Valid AiModelPageReqVO pageReqVO) {
|
||||
PageResult<AiModelDO> pageResult = modelService.getModelPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiModelRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得模型列表")
|
||||
@Parameter(name = "type", description = "类型", required = true, example = "1")
|
||||
@Parameter(name = "platform", description = "平台", example = "midjourney")
|
||||
public CommonResult<List<AiModelRespVO>> getModelSimpleList(
|
||||
@RequestParam("type") Integer type,
|
||||
@RequestParam(value = "platform", required = false) String platform) {
|
||||
List<AiModelDO> list = modelService.getModelListByStatusAndType(
|
||||
CommonStatusEnum.ENABLE.getStatus(), type, platform);
|
||||
return success(convertList(list, model -> new AiModelRespVO().setId(model.getId())
|
||||
.setName(model.getName()).setModel(model.getModel()).setPlatform(model.getPlatform())));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolRespVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
|
||||
import cn.iocoder.yudao.module.ai.service.model.AiToolService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||
|
||||
@Tag(name = "管理后台 - AI 工具")
|
||||
@RestController
|
||||
@RequestMapping("/ai/tool")
|
||||
@Validated
|
||||
public class AiToolController {
|
||||
|
||||
@Resource
|
||||
private AiToolService toolService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建工具")
|
||||
@PreAuthorize("@ss.hasPermission('ai:tool:create')")
|
||||
public CommonResult<Long> createTool(@Valid @RequestBody AiToolSaveReqVO createReqVO) {
|
||||
return success(toolService.createTool(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新工具")
|
||||
@PreAuthorize("@ss.hasPermission('ai:tool:update')")
|
||||
public CommonResult<Boolean> updateTool(@Valid @RequestBody AiToolSaveReqVO updateReqVO) {
|
||||
toolService.updateTool(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除工具")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:tool:delete')")
|
||||
public CommonResult<Boolean> deleteTool(@RequestParam("id") Long id) {
|
||||
toolService.deleteTool(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得工具")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:tool:query')")
|
||||
public CommonResult<AiToolRespVO> getTool(@RequestParam("id") Long id) {
|
||||
AiToolDO tool = toolService.getTool(id);
|
||||
return success(BeanUtils.toBean(tool, AiToolRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得工具分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:tool:query')")
|
||||
public CommonResult<PageResult<AiToolRespVO>> getToolPage(@Valid AiToolPageReqVO pageReqVO) {
|
||||
PageResult<AiToolDO> pageResult = toolService.getToolPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiToolRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/simple-list")
|
||||
@Operation(summary = "获得工具列表")
|
||||
public CommonResult<List<AiToolRespVO>> getToolSimpleList() {
|
||||
List<AiToolDO> list = toolService.getToolListByStatus(CommonStatusEnum.ENABLE.getStatus());
|
||||
return success(convertList(list, tool -> new AiToolRespVO()
|
||||
.setId(tool.getId()).setName(tool.getName())));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI API 密钥分页 Request VO")
|
||||
@Data
|
||||
public class AiApiKeyPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "名称", example = "文心一言")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
@Schema(description = "管理后台 - AI API 密钥 Response VO")
|
||||
@Data
|
||||
public class AiApiKeyRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC")
|
||||
private String apiKey;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import java.util.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
@Schema(description = "管理后台 - AI API 密钥新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiApiKeySaveReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23538")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "文心一言")
|
||||
@NotEmpty(message = "名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "密钥", requiredMode = Schema.RequiredMode.REQUIRED, example = "ABC")
|
||||
@NotEmpty(message = "密钥不能为空")
|
||||
private String apiKey;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
@NotEmpty(message = "平台不能为空")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "自定义 API 地址", example = "https://aip.baidubce.com")
|
||||
private String url;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天角色分页 Request VO")
|
||||
@Data
|
||||
public class AiChatRolePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "角色名称", example = "李四")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "角色类别", example = "创作")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "是否公开", example = "1")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
@@ -0,0 +1,64 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天角色 Response VO")
|
||||
@Data
|
||||
public class AiChatRoleRespVO implements VO {
|
||||
|
||||
@Schema(description = "角色编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "32746")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "9442")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "模型编号", example = "17640")
|
||||
@Trans(type = TransType.SIMPLE, target = AiModelDO.class, fields = { "name", "model" }, refs = { "modelName", "model" })
|
||||
private Long modelId;
|
||||
@Schema(description = "模型名字", example = "张三")
|
||||
private String modelName;
|
||||
@Schema(description = "模型标识", example = "gpt-3.5-turbo-0125")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "角色类别", requiredMode = Schema.RequiredMode.REQUIRED, example = "创作")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "角色排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "引用的知识库编号列表", example = "1,2,3")
|
||||
private List<Long> knowledgeIds;
|
||||
|
||||
@Schema(description = "引用的工具编号列表", example = "1,2,3")
|
||||
private List<Long> toolIds;
|
||||
|
||||
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天角色新增/修改【我的】 Request VO")
|
||||
@Data
|
||||
public class AiChatRoleSaveMyReqVO {
|
||||
|
||||
@Schema(description = "角色编号", example = "32746")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||
@NotEmpty(message = "角色名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
|
||||
@NotEmpty(message = "角色头像不能为空")
|
||||
@URL(message = "角色头像必须是 URL 格式")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
|
||||
@NotEmpty(message = "角色描述不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色设定不能为空")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "引用的知识库编号列表", example = "1,2,3")
|
||||
private List<Long> knowledgeIds;
|
||||
|
||||
@Schema(description = "引用的工具编号列表", example = "1,2,3")
|
||||
private List<Long> toolIds;
|
||||
|
||||
}
|
@@ -0,0 +1,62 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.chatRole;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
import jakarta.validation.constraints.*;
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 聊天角色新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiChatRoleSaveReqVO {
|
||||
|
||||
@Schema(description = "角色编号", example = "32746")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "模型编号", example = "17640")
|
||||
private Long modelId;
|
||||
|
||||
@Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
|
||||
@NotEmpty(message = "角色名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "角色头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
|
||||
@NotEmpty(message = "角色头像不能为空")
|
||||
@URL(message = "角色头像必须是 URL 格式")
|
||||
private String avatar;
|
||||
|
||||
@Schema(description = "角色类别", requiredMode = Schema.RequiredMode.REQUIRED, example = "创作")
|
||||
@NotEmpty(message = "角色类别不能为空")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "角色排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "角色排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
|
||||
@NotEmpty(message = "角色描述不能为空")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "角色设定", requiredMode = Schema.RequiredMode.REQUIRED, example = "现在开始你扮演一位程序员,你是一名优秀的程序员,具有很强的逻辑思维能力,总能高效的解决问题")
|
||||
@NotEmpty(message = "角色设定不能为空")
|
||||
private String systemMessage;
|
||||
|
||||
@Schema(description = "引用的知识库编号列表", example = "1,2,3")
|
||||
private List<Long> knowledgeIds;
|
||||
|
||||
@Schema(description = "引用的工具编号列表", example = "1,2,3")
|
||||
private List<Long> toolIds;
|
||||
|
||||
@Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "是否公开不能为空")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "状态不能为空")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model;
|
||||
|
||||
import lombok.*;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
|
||||
@Schema(description = "管理后台 - API 模型分页 Request VO")
|
||||
@Data
|
||||
public class AiModelPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "模型名字", example = "张三")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模型标识", example = "gpt-3.5-turbo-0125")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 模型 Response VO")
|
||||
@Data
|
||||
public class AiModelRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2630")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 秘钥编号", example = "22042")
|
||||
private Long keyId;
|
||||
|
||||
@Schema(description = "模型名字", example = "张三")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模型标识", example = "gpt-3.5-turbo-0125")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型平台", example = "OpenAI")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型类型", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "排序", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", example = "2")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "温度参数", example = "1")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "8192")
|
||||
private Integer maxContexts;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.model;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiModelTypeEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - API 模型新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiModelSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "2630")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "API 秘钥编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22042")
|
||||
@NotNull(message = "API 秘钥编号不能为空")
|
||||
private Long keyId;
|
||||
|
||||
@Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
|
||||
@NotEmpty(message = "模型名字不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模型标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "gpt-3.5-turbo-0125")
|
||||
@NotEmpty(message = "模型标识不能为空")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "OpenAI")
|
||||
@NotEmpty(message = "模型平台不能为空")
|
||||
@InEnum(AiPlatformEnum.class)
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "模型类型不能为空")
|
||||
@InEnum(AiModelTypeEnum.class)
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "排序不能为空")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "温度参数", example = "1")
|
||||
private Double temperature;
|
||||
|
||||
@Schema(description = "单条回复的最大 Token 数量", example = "4096")
|
||||
private Integer maxTokens;
|
||||
|
||||
@Schema(description = "上下文的最大 Message 数量", example = "8192")
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工具分页 Request VO")
|
||||
@Data
|
||||
public class AiToolPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "工具名称", example = "王五")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "工具描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工具 Response VO")
|
||||
@Data
|
||||
public class AiToolRespVO {
|
||||
|
||||
@Schema(description = "工具编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19661")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工具名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "工具描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工具新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiToolSaveReqVO {
|
||||
|
||||
@Schema(description = "工具编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "19661")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工具名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
|
||||
@NotEmpty(message = "工具名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "工具描述", example = "你猜")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
### 生成音乐:Suno + 歌词模式
|
||||
POST {{baseUrl}}/ai/music/generate
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "Suno",
|
||||
"generateMode": 2,
|
||||
"prompt": "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。",
|
||||
"model": "chirp-v3.5",
|
||||
"tags": ["Happy"],
|
||||
"title": "Happy Song"
|
||||
}
|
||||
|
||||
### 生成音乐:Suno + 描述模式
|
||||
POST {{baseUrl}}/ai/music/generate
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
|
||||
{
|
||||
"platform": "Suno",
|
||||
"generateMode": 1,
|
||||
"model": "chirp-v3.5",
|
||||
"prompt": "happy music",
|
||||
"makeInstrumental": false
|
||||
}
|
@@ -0,0 +1,98 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO;
|
||||
import cn.iocoder.yudao.module.ai.service.music.AiMusicService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 音乐")
|
||||
@RestController
|
||||
@RequestMapping("/ai/music")
|
||||
public class AiMusicController {
|
||||
|
||||
@Resource
|
||||
private AiMusicService musicService;
|
||||
|
||||
@GetMapping("/my-page")
|
||||
@Operation(summary = "获得【我的】音乐分页")
|
||||
public CommonResult<PageResult<AiMusicRespVO>> getMusicMyPage(@Valid AiMusicPageReqVO pageReqVO) {
|
||||
PageResult<AiMusicDO> pageResult = musicService.getMusicMyPage(pageReqVO, getLoginUserId());
|
||||
return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/generate")
|
||||
@Operation(summary = "音乐生成")
|
||||
public CommonResult<List<Long>> generateMusic(@RequestBody @Valid AiSunoGenerateReqVO reqVO) {
|
||||
return success(musicService.generateMusic(getLoginUserId(), reqVO));
|
||||
}
|
||||
|
||||
@Operation(summary = "删除【我的】音乐记录")
|
||||
@DeleteMapping("/delete-my")
|
||||
@Parameter(name = "id", required = true, description = "音乐编号", example = "1024")
|
||||
public CommonResult<Boolean> deleteMusicMy(@RequestParam("id") Long id) {
|
||||
musicService.deleteMusicMy(id, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get-my")
|
||||
@Operation(summary = "获取【我的】音乐")
|
||||
@Parameter(name = "id", required = true, description = "音乐编号", example = "1024")
|
||||
public CommonResult<AiMusicRespVO> getMusicMy(@RequestParam("id") Long id) {
|
||||
AiMusicDO music = musicService.getMusic(id);
|
||||
if (music == null || ObjUtil.notEqual(getLoginUserId(), music.getUserId())) {
|
||||
return success(null);
|
||||
}
|
||||
return success(BeanUtils.toBean(music, AiMusicRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/update-my")
|
||||
@Operation(summary = "修改【我的】音乐 目前只支持修改标题")
|
||||
@Parameter(name = "title", required = true, description = "音乐名称", example = "夜空中最亮的星")
|
||||
public CommonResult<Boolean> updateMy(AiMusicUpdateMyReqVO updateReqVO) {
|
||||
musicService.updateMyMusic(updateReqVO, getLoginUserId());
|
||||
return success(true);
|
||||
}
|
||||
|
||||
// ================ 音乐管理 ================
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得音乐分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:music:query')")
|
||||
public CommonResult<PageResult<AiMusicRespVO>> getMusicPage(@Valid AiMusicPageReqVO pageReqVO) {
|
||||
PageResult<AiMusicDO> pageResult = musicService.getMusicPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class));
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除音乐")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:music:delete')")
|
||||
public CommonResult<Boolean> deleteMusic(@RequestParam("id") Long id) {
|
||||
musicService.deleteMusic(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新音乐")
|
||||
@PreAuthorize("@ss.hasPermission('ai:music:update')")
|
||||
public CommonResult<Boolean> updateMusic(@Valid @RequestBody AiMusicUpdateReqVO updateReqVO) {
|
||||
musicService.updateMusic(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 音乐分页 Request VO")
|
||||
@Data
|
||||
public class AiMusicPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "12212")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "音乐名称", example = "夜空中最亮的星")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "音乐状态", example = "20")
|
||||
@InEnum(AiMusicStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "生成模式", example = "1")
|
||||
@InEnum(AiMusicGenerateModeEnum.class)
|
||||
private Integer generateMode;
|
||||
|
||||
@Schema(description = "是否发布", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 音乐 Response VO")
|
||||
@Data
|
||||
public class AiMusicRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12212")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "音乐名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "夜空中最亮的星")
|
||||
private String title;
|
||||
|
||||
@Schema(description = "歌词", example = "oh~卖糕的")
|
||||
private String lyric;
|
||||
|
||||
@Schema(description = "图片地址", example = "https://www.iocoder.cn")
|
||||
private String imageUrl;
|
||||
|
||||
@Schema(description = "音频地址", example = "https://www.iocoder.cn")
|
||||
private String audioUrl;
|
||||
|
||||
@Schema(description = "视频地址", example = "https://www.iocoder.cn")
|
||||
private String videoUrl;
|
||||
|
||||
@Schema(description = "音乐状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "描述词", example = "一首轻快的歌曲")
|
||||
private String gptDescriptionPrompt;
|
||||
|
||||
@Schema(description = "提示词", example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer generateMode;
|
||||
|
||||
@Schema(description = "音乐风格标签")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "音乐时长", example = "[\"pop\",\"jazz\",\"punk\"]")
|
||||
private Double duration;
|
||||
|
||||
@Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
@Schema(description = "任务编号", example = "11369")
|
||||
private String taskId;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 修改我的音乐 Request VO")
|
||||
@Data
|
||||
public class AiMusicUpdateMyReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "音乐名称", example = "夜空中最亮的星")
|
||||
private String title;
|
||||
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 音乐修改 Request VO")
|
||||
@Data
|
||||
public class AiMusicUpdateReqVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583")
|
||||
@NotNull(message = "编号不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "是否发布", example = "true")
|
||||
private Boolean publicStatus;
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.music.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI 音乐生成 Request VO")
|
||||
@Data
|
||||
public class AiSunoGenerateReqVO {
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno")
|
||||
@NotBlank(message = "平台不能为空")
|
||||
private String platform; // 参见 AiPlatformEnum 枚举
|
||||
|
||||
/**
|
||||
* 1. 描述模式:描述词 + 是否纯音乐 + 模型
|
||||
* 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型
|
||||
*/
|
||||
@Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
|
||||
@NotNull(message = "生成模式不能为空")
|
||||
private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举
|
||||
|
||||
@Schema(description = "用于生成音乐音频的歌词提示",
|
||||
example = """
|
||||
1.描述模式:创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。
|
||||
2.歌词模式:
|
||||
[Verse]
|
||||
阳光下奔跑 多么欢快
|
||||
假期就要来 心都飞起来
|
||||
朋友在一旁 笑声又灿烂
|
||||
无忧无虑的 每一天甜蜜
|
||||
[Chorus]
|
||||
马上放假了 快来庆祝
|
||||
一起去旅行 快去冒险
|
||||
日子太短暂 别再等待
|
||||
马上放假了 梦想起飞
|
||||
""")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "是否纯音乐", example = "true")
|
||||
private Boolean makeInstrumental;
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5")
|
||||
@NotEmpty(message = "模型不能为空")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "音乐风格", example = "[\"pop\",\"jazz\",\"punk\"]")
|
||||
private List<String> tags;
|
||||
|
||||
@Schema(description = "音乐/歌曲名称", example = "夜空中最亮的星")
|
||||
private String title;
|
||||
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
### 测试 AI 工作流
|
||||
POST {{baseUrl}}/ai/workflow/test
|
||||
Content-Type: application/json
|
||||
Authorization: {{token}}
|
||||
tenant-id: {{adminTenantId}}
|
||||
|
||||
{
|
||||
"id": 4,
|
||||
"params": {
|
||||
"message": "1 + 1 = ?"
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.workflow;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.workflow.vo.*;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.workflow.AiWorkflowDO;
|
||||
import cn.iocoder.yudao.module.ai.service.workflow.AiWorkflowService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - AI 工作流")
|
||||
@RestController
|
||||
@RequestMapping("/ai/workflow")
|
||||
@Slf4j
|
||||
public class AiWorkflowController {
|
||||
|
||||
@Resource
|
||||
private AiWorkflowService workflowService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建 AI 工作流")
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:create')")
|
||||
public CommonResult<Long> createWorkflow(@Valid @RequestBody AiWorkflowSaveReqVO createReqVO) {
|
||||
return success(workflowService.createWorkflow(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新 AI 工作流")
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:update')")
|
||||
public CommonResult<Boolean> updateWorkflow(@Valid @RequestBody AiWorkflowSaveReqVO updateReqVO) {
|
||||
workflowService.updateWorkflow(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除 AI 工作流")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:delete')")
|
||||
public CommonResult<Boolean> deleteWorkflow(@RequestParam("id") Long id) {
|
||||
workflowService.deleteWorkflow(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得 AI 工作流")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:query')")
|
||||
public CommonResult<AiWorkflowRespVO> getWorkflow(@RequestParam("id") Long id) {
|
||||
AiWorkflowDO workflow = workflowService.getWorkflow(id);
|
||||
return success(BeanUtils.toBean(workflow, AiWorkflowRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得 AI 工作流分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:query')")
|
||||
public CommonResult<PageResult<AiWorkflowRespVO>> getWorkflowPage(@Valid AiWorkflowPageReqVO pageReqVO) {
|
||||
PageResult<AiWorkflowDO> pageResult = workflowService.getWorkflowPage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiWorkflowRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/test")
|
||||
@Operation(summary = "测试 AI 工作流")
|
||||
@PreAuthorize("@ss.hasPermission('ai:workflow:test')")
|
||||
public CommonResult<Object> testWorkflow(@Valid @RequestBody AiWorkflowTestReqVO testReqVO) {
|
||||
return success(workflowService.testWorkflow(testReqVO));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工作流分页 Request VO")
|
||||
@Data
|
||||
public class AiWorkflowPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "名称", example = "工作流")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "标识", example = "FLOW")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
@InEnum(CommonStatusEnum.class)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工作流 Response VO")
|
||||
@Data
|
||||
public class AiWorkflowRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "工作流模型 JSON", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||
private String graph;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "时间戳格式")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工作流新增/修改 Request VO")
|
||||
@Data
|
||||
public class AiWorkflowSaveReqVO {
|
||||
|
||||
@Schema(description = "编号", example = "1")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工作流标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
|
||||
@NotEmpty(message = "工作流标识不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "工作流名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "工作流")
|
||||
@NotEmpty(message = "工作流名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "备注", example = "FLOW")
|
||||
private String remark;
|
||||
|
||||
@Schema(description = "工作流模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||
@NotEmpty(message = "工作流模型不能为空")
|
||||
private String graph;
|
||||
|
||||
@Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "FLOW")
|
||||
@NotNull(message = "状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.workflow.vo;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Schema(description = "管理后台 - AI 工作流测试 Request VO")
|
||||
@Data
|
||||
public class AiWorkflowTestReqVO {
|
||||
|
||||
@Schema(description = "工作流编号", example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "工作流模型", example = "{}")
|
||||
private String graph;
|
||||
|
||||
@Schema(description = "参数", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
|
||||
private Map<String, Object> params;
|
||||
|
||||
@AssertTrue(message = "工作流或模型,必须传递一个")
|
||||
public boolean isGraphValid() {
|
||||
return id != null || StrUtil.isNotEmpty(graph);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.write;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWritePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteRespVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.write.AiWriteDO;
|
||||
import cn.iocoder.yudao.module.ai.service.write.AiWriteService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
|
||||
@Tag(name = "管理后台 - AI 写作")
|
||||
@RestController
|
||||
@RequestMapping("/ai/write")
|
||||
public class AiWriteController {
|
||||
|
||||
@Resource
|
||||
private AiWriteService writeService;
|
||||
|
||||
@PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
|
||||
@Operation(summary = "写作生成(流式)", description = "流式返回,响应较快")
|
||||
public Flux<CommonResult<String>> generateWriteContent(@RequestBody @Valid AiWriteGenerateReqVO generateReqVO) {
|
||||
return writeService.generateWriteContent(generateReqVO, getLoginUserId());
|
||||
}
|
||||
|
||||
// ================ 写作管理 ================
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除写作")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('ai:write:delete')")
|
||||
public CommonResult<Boolean> deleteWrite(@RequestParam("id") Long id) {
|
||||
writeService.deleteWrite(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得写作分页")
|
||||
@PreAuthorize("@ss.hasPermission('ai:write:query')")
|
||||
public CommonResult<PageResult<AiWriteRespVO>> getWritePage(@Valid AiWritePageReqVO pageReqVO) {
|
||||
PageResult<AiWriteDO> pageResult = writeService.getWritePage(pageReqVO);
|
||||
return success(BeanUtils.toBean(pageResult, AiWriteRespVO.class));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.write.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.validation.InEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Schema(description = "管理后台 - AI 写作生成 Request VO")
|
||||
@Data
|
||||
public class AiWriteGenerateReqVO {
|
||||
|
||||
@Schema(description = "写作类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@InEnum(value = AiWriteTypeEnum.class, message = "写作类型必须是 {value}")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "写作内容提示", example = "1.撰写:田忌赛马;2.回复:不批")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "原文", example = "领导我要辞职")
|
||||
private String originalContent;
|
||||
|
||||
@Schema(description = "长度", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "长度不能为空")
|
||||
private Integer length;
|
||||
|
||||
@Schema(description = "格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "格式不能为空")
|
||||
private Integer format;
|
||||
|
||||
@Schema(description = "语气", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "语气不能为空")
|
||||
private Integer tone;
|
||||
|
||||
@Schema(description = "语言", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "语言不能为空")
|
||||
private Integer language;
|
||||
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.write.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
|
||||
|
||||
@Schema(description = "管理后台 - AI 写作分页 Request VO")
|
||||
@Data
|
||||
public class AiWritePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "用户编号", example = "28404")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "写作类型", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "平台", example = "TongYi")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.ai.controller.admin.write.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - AI 写作 Response VO")
|
||||
@Data
|
||||
public class AiWriteRespVO {
|
||||
|
||||
@Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "5311")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28404")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "写作类型", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "TongYi")
|
||||
private String platform;
|
||||
|
||||
@Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "qwen")
|
||||
private String model;
|
||||
|
||||
@Schema(description = "生成内容提示", requiredMode = Schema.RequiredMode.REQUIRED, example = "撰写:田忌赛马")
|
||||
private String prompt;
|
||||
|
||||
@Schema(description = "生成的内容", example = "你非常不错")
|
||||
private String generatedContent;
|
||||
|
||||
@Schema(description = "原文", example = "真的么?")
|
||||
private String originalContent;
|
||||
|
||||
@Schema(description = "长度提示词", example = "1")
|
||||
private Integer length;
|
||||
|
||||
@Schema(description = "格式提示词", example = "2")
|
||||
private Integer format;
|
||||
|
||||
@Schema(description = "语气提示词", example = "3")
|
||||
private Integer tone;
|
||||
|
||||
@Schema(description = "语言提示词", example = "4")
|
||||
private Integer language;
|
||||
|
||||
@Schema(description = "错误信息")
|
||||
private String errorMessage;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* TODO 芋艿:站位,无特殊作用
|
||||
*/
|
||||
package cn.iocoder.yudao.module.ai.controller.app;
|
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* 提供 RESTful API 给前端:
|
||||
* 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
|
||||
* 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
|
||||
*/
|
||||
package cn.iocoder.yudao.module.ai.controller;
|
@@ -0,0 +1,100 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.chat;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* AI Chat 对话 DO
|
||||
*
|
||||
* 用户每次发起 Chat 聊天时,会创建一个 {@link AiChatConversationDO} 对象,将它的消息关联在一起
|
||||
*
|
||||
* @author fansili
|
||||
* @since 2024/4/14 17:35
|
||||
*/
|
||||
@TableName("ai_chat_conversation")
|
||||
@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiChatConversationDO extends BaseDO {
|
||||
|
||||
public static final String TITLE_DEFAULT = "新对话";
|
||||
|
||||
/**
|
||||
* ID 编号,自增
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 对话标题
|
||||
*
|
||||
* 默认由系统自动生成,可用户手动修改
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 是否置顶
|
||||
*/
|
||||
private Boolean pinned;
|
||||
/**
|
||||
* 置顶时间
|
||||
*/
|
||||
private LocalDateTime pinnedTime;
|
||||
|
||||
/**
|
||||
* 角色编号
|
||||
*
|
||||
* 关联 {@link AiChatRoleDO#getId()}
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()} 字段
|
||||
*/
|
||||
private Long modelId;
|
||||
/**
|
||||
* 模型标志
|
||||
*
|
||||
* 冗余 {@link AiModelDO#getModel()} 字段
|
||||
*/
|
||||
private String model;
|
||||
|
||||
// ========== 对话配置 ==========
|
||||
|
||||
/**
|
||||
* 角色设定
|
||||
*/
|
||||
private String systemMessage;
|
||||
/**
|
||||
* 温度参数
|
||||
*
|
||||
* 用于调整生成回复的随机性和多样性程度:较低的温度值会使输出更收敛于高频词汇,较高的则增加多样性
|
||||
*/
|
||||
private Double temperature;
|
||||
/**
|
||||
* 单条回复的最大 Token 数量
|
||||
*/
|
||||
private Integer maxTokens;
|
||||
/**
|
||||
* 上下文的最大 Message 数量
|
||||
*/
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.chat;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeSegmentDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
import org.springframework.ai.chat.messages.MessageType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI Chat 消息 DO
|
||||
*
|
||||
* @since 2024/4/14 17:35
|
||||
* @since 2024/4/14 17:35
|
||||
*/
|
||||
@TableName(value = "ai_chat_message", autoResultMap = true)
|
||||
@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiChatMessageDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号,作为每条聊天记录的唯一标识符
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 对话编号
|
||||
*
|
||||
* 关联 {@link AiChatConversationDO#getId()} 字段
|
||||
*/
|
||||
private Long conversationId;
|
||||
/**
|
||||
* 回复消息编号
|
||||
*
|
||||
* 关联 {@link #id} 字段
|
||||
*
|
||||
* 大模型回复的消息编号,用于“问答”的关联
|
||||
*/
|
||||
private Long replyId;
|
||||
|
||||
/**
|
||||
* 消息类型
|
||||
*
|
||||
* 也等价于 OpenAPI 的 role 字段
|
||||
*
|
||||
* 枚举 {@link MessageType}
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
/**
|
||||
* 角色编号
|
||||
*
|
||||
* 关联 {@link AiChatRoleDO#getId()} 字段
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 模型标志
|
||||
*
|
||||
* 冗余 {@link AiModelDO#getModel()}
|
||||
*/
|
||||
private String model;
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()} 字段
|
||||
*/
|
||||
private Long modelId;
|
||||
|
||||
/**
|
||||
* 聊天内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 是否携带上下文
|
||||
*/
|
||||
private Boolean useContext;
|
||||
|
||||
/**
|
||||
* 知识库段落编号数组
|
||||
*
|
||||
* 关联 {@link AiKnowledgeSegmentDO#getId()} 字段
|
||||
*/
|
||||
@TableField(typeHandler = LongListTypeHandler.class)
|
||||
private List<Long> segmentIds;
|
||||
|
||||
}
|
@@ -0,0 +1,127 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.image;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.module.ai.framework.ai.core.model.midjourney.api.MidjourneyApi;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import cn.iocoder.yudao.module.ai.enums.image.AiImageStatusEnum;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
import org.springframework.ai.openai.OpenAiImageOptions;
|
||||
import org.springframework.ai.stabilityai.api.StabilityAiImageOptions;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AI 绘画 DO
|
||||
*
|
||||
* @author fansili
|
||||
*/
|
||||
@TableName(value = "ai_image", autoResultMap = true)
|
||||
@KeySequence("ai_image_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiImageDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 {@link AdminUserRespDTO#getId()}
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 提示词
|
||||
*/
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 平台
|
||||
*
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()}
|
||||
*/
|
||||
private Long modelId;
|
||||
/**
|
||||
* 模型标识
|
||||
*
|
||||
* 冗余 {@link AiModelDO#getModel()}
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 图片宽度
|
||||
*/
|
||||
private Integer width;
|
||||
/**
|
||||
* 图片高度
|
||||
*/
|
||||
private Integer height;
|
||||
|
||||
/**
|
||||
* 生成状态
|
||||
*
|
||||
* 枚举 {@link AiImageStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 完成时间
|
||||
*/
|
||||
private LocalDateTime finishTime;
|
||||
|
||||
/**
|
||||
* 绘画错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 图片地址
|
||||
*/
|
||||
private String picUrl;
|
||||
/**
|
||||
* 是否公开
|
||||
*/
|
||||
private Boolean publicStatus;
|
||||
|
||||
/**
|
||||
* 绘制参数,不同 platform 的不同参数
|
||||
*
|
||||
* 1. {@link OpenAiImageOptions}
|
||||
* 2. {@link StabilityAiImageOptions}
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private Map<String, Object> options;
|
||||
|
||||
/**
|
||||
* mj buttons 按钮
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<MidjourneyApi.Button> buttons;
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*
|
||||
* 1. midjourney proxy:关联的 task id
|
||||
*/
|
||||
private String taskId;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,64 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 知识库 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName(value = "ai_knowledge", autoResultMap = true)
|
||||
@KeySequence("ai_knowledge_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiKnowledgeDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 知识库名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 知识库描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 向量模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()}
|
||||
*/
|
||||
private Long embeddingModelId;
|
||||
/**
|
||||
* 模型标识
|
||||
*
|
||||
* 冗余 {@link AiModelDO#getModel()}
|
||||
*/
|
||||
private String embeddingModel;
|
||||
|
||||
/**
|
||||
* topK
|
||||
*/
|
||||
private Integer topK;
|
||||
/**
|
||||
* 相似度阈值
|
||||
*/
|
||||
private Double similarityThreshold;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* <p>
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 知识库-文档 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName(value = "ai_knowledge_document")
|
||||
@KeySequence("ai_knowledge_document_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiKnowledgeDocumentDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 知识库编号
|
||||
* <p>
|
||||
* 关联 {@link AiKnowledgeDO#getId()}
|
||||
*/
|
||||
private Long knowledgeId;
|
||||
/**
|
||||
* 文档名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 文件 URL
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 内容
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 文档长度
|
||||
*/
|
||||
private Integer contentLength;
|
||||
|
||||
/**
|
||||
* 文档 token 数量
|
||||
*/
|
||||
private Integer tokens;
|
||||
/**
|
||||
* 分片最大 Token 数
|
||||
*/
|
||||
private Integer segmentMaxTokens;
|
||||
|
||||
/**
|
||||
* 召回次数
|
||||
*/
|
||||
private Integer retrievalCount;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* <p>
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 知识库-文档分段 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName(value = "ai_knowledge_segment")
|
||||
@KeySequence("ai_knowledge_segment_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiKnowledgeSegmentDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 向量库的编号 - 空值
|
||||
*/
|
||||
public static final String VECTOR_ID_EMPTY = "";
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 知识库编号
|
||||
* <p>
|
||||
* 关联 {@link AiKnowledgeDO#getId()}
|
||||
*/
|
||||
private Long knowledgeId;
|
||||
/**
|
||||
* 文档编号
|
||||
* <p>
|
||||
* 关联 {@link AiKnowledgeDocumentDO#getId()}
|
||||
*/
|
||||
private Long documentId;
|
||||
/**
|
||||
* 切片内容
|
||||
*/
|
||||
private String content;
|
||||
/**
|
||||
* 切片内容长度
|
||||
*/
|
||||
private Integer contentLength;
|
||||
|
||||
/**
|
||||
* 向量库的编号
|
||||
*/
|
||||
private String vectorId;
|
||||
/**
|
||||
* token 数量
|
||||
*/
|
||||
private Integer tokens;
|
||||
|
||||
/**
|
||||
* 召回次数
|
||||
*/
|
||||
private Integer retrievalCount;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* <p>
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.mindmap;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 思维导图 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName(value = "ai_mind_map")
|
||||
@KeySequence("ai_mind_map_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiMindMapDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
* <p>
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 平台
|
||||
* <p>
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()}
|
||||
*/
|
||||
private Long modelId;
|
||||
/**
|
||||
* 模型
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 生成内容提示
|
||||
*/
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 生成的内容
|
||||
*/
|
||||
private String generatedContent;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.model;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* AI API 秘钥 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("ai_api_key")
|
||||
@KeySequence("ai_chat_conversation_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiApiKeyDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
private String apiKey;
|
||||
/**
|
||||
* 平台
|
||||
*
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
/**
|
||||
* API 地址
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.model;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.type.LongListTypeHandler;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 聊天角色 DO
|
||||
*
|
||||
* @author fansili
|
||||
* @since 2024/4/24 19:39
|
||||
*/
|
||||
@TableName(value = "ai_chat_role", autoResultMap = true)
|
||||
@KeySequence("ai_chat_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiChatRoleDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 角色头像
|
||||
*/
|
||||
private String avatar;
|
||||
/**
|
||||
* 角色分类
|
||||
*/
|
||||
private String category;
|
||||
/**
|
||||
* 角色描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 角色设定
|
||||
*/
|
||||
private String systemMessage;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()} 字段
|
||||
*/
|
||||
private Long modelId;
|
||||
|
||||
/**
|
||||
* 引用的知识库编号列表
|
||||
*
|
||||
* 关联 {@link AiKnowledgeDO#getId()} 字段
|
||||
*/
|
||||
@TableField(typeHandler = LongListTypeHandler.class)
|
||||
private List<Long> knowledgeIds;
|
||||
/**
|
||||
* 引用的工具编号列表
|
||||
*
|
||||
* 关联 {@link AiToolDO#getId()} 字段
|
||||
*/
|
||||
@TableField(typeHandler = LongListTypeHandler.class)
|
||||
private List<Long> toolIds;
|
||||
|
||||
/**
|
||||
* 是否公开
|
||||
*
|
||||
* 1. true - 公开;由管理员在【角色管理】所创建
|
||||
* 2. false - 私有;由个人在【我的角色】所创建
|
||||
*/
|
||||
private Boolean publicStatus;
|
||||
|
||||
/**
|
||||
* 排序值
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.model;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiModelTypeEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* AI 模型 DO
|
||||
*
|
||||
* 默认模型:{@link #status} 为开启,并且 {@link #sort} 排序第一
|
||||
*
|
||||
* @author fansili
|
||||
* @since 2024/4/24 19:39
|
||||
*/
|
||||
@TableName("ai_model")
|
||||
@KeySequence("ai_model_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiModelDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* API 秘钥编号
|
||||
*
|
||||
* 关联 {@link AiApiKeyDO#getId()}
|
||||
*/
|
||||
private Long keyId;
|
||||
/**
|
||||
* 模型名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 模型标志
|
||||
*/
|
||||
private String model;
|
||||
/**
|
||||
* 平台
|
||||
*
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
/**
|
||||
* 类型
|
||||
*
|
||||
* 枚举 {@link AiModelTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 排序值
|
||||
*/
|
||||
private Integer sort;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== 对话配置 ==========
|
||||
|
||||
/**
|
||||
* 温度参数
|
||||
*
|
||||
* 用于调整生成回复的随机性和多样性程度:较低的温度值会使输出更收敛于高频词汇,较高的则增加多样性
|
||||
*/
|
||||
private Double temperature;
|
||||
/**
|
||||
* 单条回复的最大 Token 数量
|
||||
*/
|
||||
private Integer maxTokens;
|
||||
/**
|
||||
* 上下文的最大 Message 数量
|
||||
*/
|
||||
private Integer maxContexts;
|
||||
|
||||
}
|
@@ -0,0 +1,48 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.model;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.service.model.tool.DirectoryListToolFunction;
|
||||
import cn.iocoder.yudao.module.ai.service.model.tool.WeatherQueryToolFunction;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* AI 工具 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("ai_tool")
|
||||
@KeySequence("ai_tool_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiToolDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 工具编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 工具名称
|
||||
*
|
||||
* 对应 Bean 的名字,例如说:
|
||||
* 1. {@link DirectoryListToolFunction} 的 Bean 名字是 directory_list
|
||||
* 2. {@link WeatherQueryToolFunction} 的 Bean 名字是 weather_query
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 工具描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.music;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum;
|
||||
import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 音乐 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName(value = "ai_music", autoResultMap = true)
|
||||
@KeySequence("ai_music_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiMusicDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
* <p>
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 音乐名称
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 歌词
|
||||
*/
|
||||
private String lyric;
|
||||
|
||||
/**
|
||||
* 图片地址
|
||||
*/
|
||||
private String imageUrl;
|
||||
/**
|
||||
* 音频地址
|
||||
*/
|
||||
private String audioUrl;
|
||||
/**
|
||||
* 视频地址
|
||||
*/
|
||||
private String videoUrl;
|
||||
|
||||
/**
|
||||
* 音乐状态
|
||||
* <p>
|
||||
* 枚举 {@link AiMusicStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 生成模式
|
||||
* <p>
|
||||
* 枚举 {@link AiMusicGenerateModeEnum}
|
||||
*/
|
||||
private Integer generateMode;
|
||||
|
||||
/**
|
||||
* 描述词
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 平台
|
||||
* <p>
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
// TODO @芋艿:modelId?
|
||||
/**
|
||||
* 模型
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 音乐风格标签
|
||||
*/
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<String> tags;
|
||||
|
||||
/**
|
||||
* 音乐时长
|
||||
*/
|
||||
private Double duration;
|
||||
|
||||
/**
|
||||
* 是否公开
|
||||
*/
|
||||
private Boolean publicStatus;
|
||||
|
||||
/**
|
||||
* 任务编号
|
||||
*/
|
||||
private String taskId;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
}
|
@@ -0,0 +1,51 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.workflow;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 工作流 DO
|
||||
*
|
||||
* @author lesan
|
||||
*/
|
||||
@TableName(value = "ai_workflow", autoResultMap = true)
|
||||
@KeySequence("ai_workflow") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiWorkflowDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 工作流名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 工作流标识
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 工作流模型 JSON 数据
|
||||
*/
|
||||
private String graph;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*
|
||||
* 枚举 {@link CommonStatusEnum}
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.dataobject.write;
|
||||
|
||||
import cn.iocoder.yudao.module.ai.enums.model.AiPlatformEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
|
||||
import cn.iocoder.yudao.module.ai.enums.DictTypeConstants;
|
||||
import cn.iocoder.yudao.module.ai.enums.write.AiWriteTypeEnum;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* AI 写作 DO
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@TableName("ai_write")
|
||||
@KeySequence("ai_write_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
public class AiWriteDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 用户编号
|
||||
*
|
||||
* 关联 AdminUserDO 的 userId 字段
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 写作类型
|
||||
* <p>
|
||||
* 枚举 {@link AiWriteTypeEnum}
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 平台
|
||||
*
|
||||
* 枚举 {@link AiPlatformEnum}
|
||||
*/
|
||||
private String platform;
|
||||
/**
|
||||
* 模型编号
|
||||
*
|
||||
* 关联 {@link AiModelDO#getId()}
|
||||
*/
|
||||
private Long modelId;
|
||||
/**
|
||||
* 模型
|
||||
*/
|
||||
private String model;
|
||||
|
||||
/**
|
||||
* 生成内容提示
|
||||
*/
|
||||
private String prompt;
|
||||
|
||||
/**
|
||||
* 生成的内容
|
||||
*/
|
||||
private String generatedContent;
|
||||
/**
|
||||
* 原文
|
||||
*/
|
||||
private String originalContent;
|
||||
|
||||
/**
|
||||
* 长度提示词
|
||||
*
|
||||
* 字典:{@link DictTypeConstants#AI_WRITE_LENGTH}
|
||||
*/
|
||||
private Integer length;
|
||||
/**
|
||||
* 格式提示词
|
||||
*
|
||||
* 字典:{@link DictTypeConstants#AI_WRITE_FORMAT}
|
||||
*/
|
||||
private Integer format;
|
||||
/**
|
||||
* 语气提示词
|
||||
*
|
||||
* 字典:{@link DictTypeConstants#AI_WRITE_TONE}
|
||||
*/
|
||||
private Integer tone;
|
||||
/**
|
||||
* 语言提示词
|
||||
*
|
||||
* 字典:{@link DictTypeConstants#AI_WRITE_LANGUAGE}
|
||||
*/
|
||||
private Integer language;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.mysql.chat;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 聊天对话 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiChatConversationMapper extends BaseMapperX<AiChatConversationDO> {
|
||||
|
||||
default List<AiChatConversationDO> selectListByUserId(Long userId) {
|
||||
return selectList(AiChatConversationDO::getUserId, userId);
|
||||
}
|
||||
|
||||
default List<AiChatConversationDO> selectListByUserIdAndPinned(Long userId, boolean pinned) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatConversationDO>()
|
||||
.eq(AiChatConversationDO::getUserId, userId)
|
||||
.eq(AiChatConversationDO::getPinned, pinned));
|
||||
}
|
||||
|
||||
default PageResult<AiChatConversationDO> selectChatConversationPage(AiChatConversationPageReqVO pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatConversationDO>()
|
||||
.eqIfPresent(AiChatConversationDO::getUserId, pageReqVO.getUserId())
|
||||
.likeIfPresent(AiChatConversationDO::getTitle, pageReqVO.getTitle())
|
||||
.betweenIfPresent(AiChatConversationDO::getCreateTime, pageReqVO.getCreateTime())
|
||||
.orderByDesc(AiChatConversationDO::getId));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,59 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.mysql.chat;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.conversation.AiChatConversationPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatConversationDO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* AI 聊天对话 Mapper
|
||||
*
|
||||
* @author fansili
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiChatMessageMapper extends BaseMapperX<AiChatMessageDO> {
|
||||
|
||||
default List<AiChatMessageDO> selectListByConversationId(Long conversationId) {
|
||||
return selectList(new LambdaQueryWrapperX<AiChatMessageDO>()
|
||||
.eq(AiChatMessageDO::getConversationId, conversationId)
|
||||
.orderByAsc(AiChatMessageDO::getId));
|
||||
}
|
||||
|
||||
default Map<Long, Integer> selectCountMapByConversationId(Collection<Long> conversationIds) {
|
||||
// SQL count 查询
|
||||
List<Map<String, Object>> result = selectMaps(new QueryWrapper<AiChatMessageDO>()
|
||||
.select("COUNT(id) AS count, conversation_id AS conversationId")
|
||||
.in("conversation_id", conversationIds)
|
||||
.groupBy("conversation_id"));
|
||||
if (CollUtil.isEmpty(result)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
// 转换数据
|
||||
return CollectionUtils.convertMap(result,
|
||||
record -> MapUtil.getLong(record, "conversationId"),
|
||||
record -> MapUtil.getInt(record, "count" ));
|
||||
}
|
||||
|
||||
default PageResult<AiChatMessageDO> selectPage(AiChatMessagePageReqVO pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiChatMessageDO>()
|
||||
.eqIfPresent(AiChatMessageDO::getConversationId, pageReqVO.getConversationId())
|
||||
.eqIfPresent(AiChatMessageDO::getUserId, pageReqVO.getUserId())
|
||||
.likeIfPresent(AiChatMessageDO::getContent, pageReqVO.getContent())
|
||||
.betweenIfPresent(AiChatMessageDO::getCreateTime, pageReqVO.getCreateTime())
|
||||
.orderByDesc(AiChatMessageDO::getId));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.mysql.image;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.image.vo.AiImagePublicPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.image.AiImageDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 绘图 Mapper
|
||||
*
|
||||
* @author fansili
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiImageMapper extends BaseMapperX<AiImageDO> {
|
||||
|
||||
default AiImageDO selectByTaskId(String taskId) {
|
||||
return selectOne(AiImageDO::getTaskId, taskId);
|
||||
}
|
||||
|
||||
default PageResult<AiImageDO> selectPage(AiImagePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiImageDO>()
|
||||
.eqIfPresent(AiImageDO::getUserId, reqVO.getUserId())
|
||||
.eqIfPresent(AiImageDO::getPlatform, reqVO.getPlatform())
|
||||
.eqIfPresent(AiImageDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(AiImageDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
.betweenIfPresent(AiImageDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(AiImageDO::getId));
|
||||
}
|
||||
|
||||
default PageResult<AiImageDO> selectPageMy(Long userId, AiImagePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiImageDO>()
|
||||
.likeIfPresent(AiImageDO::getPrompt, reqVO.getPrompt())
|
||||
// 情况一:公开
|
||||
.eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiImageDO::getPublicStatus, reqVO.getPublicStatus())
|
||||
// 情况二:私有
|
||||
.eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiImageDO::getUserId, userId)
|
||||
.orderByDesc(AiImageDO::getId));
|
||||
}
|
||||
|
||||
default PageResult<AiImageDO> selectPage(AiImagePublicPageReqVO pageReqVO) {
|
||||
return selectPage(pageReqVO, new LambdaQueryWrapperX<AiImageDO>()
|
||||
.eqIfPresent(AiImageDO::getPublicStatus, Boolean.TRUE)
|
||||
.likeIfPresent(AiImageDO::getPrompt, pageReqVO.getPrompt())
|
||||
.orderByDesc(AiImageDO::getId));
|
||||
}
|
||||
|
||||
default List<AiImageDO> selectListByStatusAndPlatform(Integer status, String platform) {
|
||||
return selectList(AiImageDO::getStatus, status,
|
||||
AiImageDO::getPlatform, platform);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
package cn.iocoder.yudao.module.ai.dal.mysql.knowledge;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.module.ai.controller.admin.knowledge.vo.document.AiKnowledgeDocumentPageReqVO;
|
||||
import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AI 知识库文档 Mapper
|
||||
*
|
||||
* @author xiaoxin
|
||||
*/
|
||||
@Mapper
|
||||
public interface AiKnowledgeDocumentMapper extends BaseMapperX<AiKnowledgeDocumentDO> {
|
||||
|
||||
default PageResult<AiKnowledgeDocumentDO> selectPage(AiKnowledgeDocumentPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<AiKnowledgeDocumentDO>()
|
||||
.eqIfPresent(AiKnowledgeDocumentDO::getKnowledgeId, reqVO.getKnowledgeId())
|
||||
.likeIfPresent(AiKnowledgeDocumentDO::getName, reqVO.getName())
|
||||
.orderByDesc(AiKnowledgeDocumentDO::getId));
|
||||
}
|
||||
|
||||
default void updateRetrievalCountIncr(Collection<Long> ids) {
|
||||
update(new LambdaUpdateWrapper<AiKnowledgeDocumentDO>()
|
||||
.setSql(" retrieval_count = retrieval_count + 1")
|
||||
.in(AiKnowledgeDocumentDO::getId, ids));
|
||||
}
|
||||
|
||||
default List<AiKnowledgeDocumentDO> selectListByStatus(Integer status) {
|
||||
return selectList(AiKnowledgeDocumentDO::getStatus, status);
|
||||
}
|
||||
|
||||
default List<AiKnowledgeDocumentDO> selectListByKnowledgeId(Long knowledgeId) {
|
||||
return selectList(AiKnowledgeDocumentDO::getKnowledgeId, knowledgeId);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user