فهرست منبع

1、新增前端ai接口
2、模型角色加入2d模型上传

liyanbo 10 ماه پیش
والد
کامیت
5313ebeebc

+ 5 - 2
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/controller/admin/chat/vo/conversation/AiChatConversationRespVO.java

@@ -40,8 +40,11 @@ public class AiChatConversationRespVO implements VO {
     @Schema(description = "模型名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三")
     private String modelName;
 
-    @Schema(description = "模型路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "**.glb")
-    private String modelPath;
+    @Schema(description = "2d模型路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "**.glb")
+    private String model2dPath;
+
+    @Schema(description = "3d模型路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "**.glb")
+    private String model3dPath;
 
     @Schema(description = "角色设定", example = "一个快乐的程序员")
     private String systemMessage;

+ 4 - 2
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java

@@ -27,8 +27,10 @@ public class AiChatRoleRespVO implements VO {
     private String modelName;
     @Schema(description = "模型标识", example = "gpt-3.5-turbo-0125")
     private String model;
-    @Schema(description = "模型", example = "**.glb")
-    private String modelPath;
+    @Schema(description = "模型2d路径", example = "**.glb")
+    private String model2dPath;
+    @Schema(description = "模型3d路径", example = "**.glb")
+    private String model3dPath;
 
     @Schema(description = "角色名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
     private String name;

+ 5 - 4
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java

@@ -23,10 +23,11 @@ public class AiChatRoleSaveMyReqVO {
     @URL(message = "角色头像必须是 URL 格式")
     private String avatar;
 
-    @Schema(description = "角色模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
-    @NotEmpty(message = "角色模型不能为空")
-//    @URL(message = "角色模型必须是 URL 格式")
-    private String modelPath;
+    @Schema(description = "模型2d路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+    private String model2dPath;
+
+    @Schema(description = "模型3d路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+    private String model3dPath;
 
     @Schema(description = "角色描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
     @NotEmpty(message = "角色描述不能为空")

+ 5 - 4
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java

@@ -32,10 +32,11 @@ public class AiChatRoleSaveReqVO {
     @NotEmpty(message = "角色类别不能为空")
     private String category;
 
-    @Schema(description = "角色模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
-//    @NotEmpty(message = "角色模型不能为空")
-//    @URL(message = "角色模型必须是 URL 格式")
-    private String modelPath;
+    @Schema(description = "模型2d路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+    private String model2dPath;
+
+    @Schema(description = "模型3d路径", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+    private String model3dPath;
 
     @Schema(description = "角色排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "角色排序不能为空")

+ 8 - 2
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/dal/dataobject/chat/AiChatConversationDO.java

@@ -70,7 +70,7 @@ public class AiChatConversationDO extends BaseDO {
      */
     private Long modelId;
     /**
-     * 模型标志
+     * 2d模型标志
      *
      * 冗余 {@link AiModelDO#getModel()} 字段
      */
@@ -80,7 +80,13 @@ public class AiChatConversationDO extends BaseDO {
      *
      * 冗余 {@link AiModelDO#getModel()} 字段
      */
-    private String modelPath;
+    private String model2dPath;
+    /**
+     * 3d模型路径
+     *
+     * 冗余 {@link AiModelDO#getModel()} 字段
+     */
+    private String model3dPath;
 
     // ========== 对话配置 ==========
 

+ 9 - 2
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/dal/dataobject/model/AiChatRoleDO.java

@@ -8,6 +8,7 @@ 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 io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 
 import java.util.List;
@@ -47,10 +48,16 @@ public class AiChatRoleDO extends BaseDO {
      * 角色描述
      */
     private String description;
+
+    /**
+     * 角色2d模型
+     */
+    private String model2dPath;
+
     /**
-     * 角色模型
+     * 角色3d模型
      */
-    private String modelPath;
+    private String model3dPath;
     /**
      * 角色设定
      */

+ 1 - 1
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/service/chat/AiChatConversationServiceImpl.java

@@ -68,7 +68,7 @@ public class AiChatConversationServiceImpl implements AiChatConversationService
 
         // 2. 创建 AiChatConversationDO 聊天对话
         AiChatConversationDO conversation = new AiChatConversationDO().setUserId(userId).setPinned(false)
-                .setModelId(model.getId()).setModel(model.getModel()).setModelPath(role != null ? role.getModelPath() : null)
+                .setModelId(model.getId()).setModel(model.getModel()).setModel2dPath(role != null ? role.getModel2dPath() : null).setModel3dPath(role != null ? role.getModel3dPath() : null)
                 .setTemperature(model.getTemperature()).setMaxTokens(model.getMaxTokens()).setMaxContexts(model.getMaxContexts());
         if (role != null) {
             conversation.setTitle(role.getName()).setRoleId(role.getId()).setSystemMessage(role.getSystemMessage());

+ 12 - 9
byzs-module-ai/src/main/java/cn/iocoder/byzs/module/ai/service/image/AiImageServiceImpl.java

@@ -130,27 +130,30 @@ public class AiImageServiceImpl implements AiImageService {
             String filePath = "";
 
             //调用文生图
-            if (model.getPlatform().equals(AiPlatformEnum.DOU_BAO.getPlatform())){
-
+            if (model.getPlatform().equals(AiPlatformEnum.DOU_BAO.getPlatform())) {
+                // 验证模型和API密钥
                 AiModelDO model2 = aiModelService.validateModel(model.getId());
                 AiApiKeyDO apiKey = apiKeyService.validateApiKey(model2.getKeyId());
-                AiPlatformEnum platform = AiPlatformEnum.validatePlatform(apiKey.getPlatform());
-
-
+                // 创建ArkService实例(豆包API客户端)
                 ConnectionPool connectionPool = new ConnectionPool(5, 1, TimeUnit.SECONDS);
                 Dispatcher dispatcher = new Dispatcher();
-                ArkService service = ArkService.builder().dispatcher(dispatcher).connectionPool(connectionPool).apiKey(apiKey.getApiKey()).build();
-
+                ArkService service = ArkService.builder()
+                        .dispatcher(dispatcher)
+                        .connectionPool(connectionPool)
+                        .apiKey(apiKey.getApiKey())
+                        .build();
+                // 构建生成请求
                 GenerateImagesRequest generateRequest = GenerateImagesRequest.builder()
                         .model(model.getModel())
                         .prompt(reqVO.getPrompt())
                         .size(reqVO.getWidth() + "x" + reqVO.getHeight())
                         .build();
-
-
+                // 调用豆包API生成图片
                 ImagesResponse imagesResponse = service.generateImages(generateRequest);
+                // 下载图片并上传到文件服务
                 byte[] fileContent = HttpUtil.downloadBytes(imagesResponse.getData().get(0).getUrl());
                 filePath = fileApi.createFile(fileContent);
+                // 关闭服务执行器
                 service.shutdownExecutor();
             }else {
                 // 1.2 执行请求

+ 5 - 0
byzs-web/pom.xml

@@ -23,6 +23,11 @@
             <artifactId>byzs-course</artifactId>
             <version>${revision}</version>
         </dependency>
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>byzs-module-ai</artifactId>
+            <version>${revision}</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 63 - 27
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/ai/WebAiController.java

@@ -1,7 +1,20 @@
 package cn.iocoder.byzs.module.web.controller.admin.ai;
 
+import cn.hutool.core.util.ObjUtil;
 import cn.iocoder.byzs.framework.common.pojo.CommonResult;
 import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
+import cn.iocoder.byzs.framework.tenant.core.aop.TenantIgnore;
+import cn.iocoder.byzs.module.ai.controller.admin.chat.vo.conversation.AiChatConversationCreateMyReqVO;
+import cn.iocoder.byzs.module.ai.controller.admin.chat.vo.conversation.AiChatConversationRespVO;
+import cn.iocoder.byzs.module.ai.controller.admin.chat.vo.message.AiChatMessageSendReqVO;
+import cn.iocoder.byzs.module.ai.controller.admin.chat.vo.message.AiChatMessageSendRespVO;
+import cn.iocoder.byzs.module.ai.controller.admin.image.vo.AiImageDrawReqVO;
+import cn.iocoder.byzs.module.ai.controller.admin.image.vo.AiImageRespVO;
+import cn.iocoder.byzs.module.ai.dal.dataobject.chat.AiChatConversationDO;
+import cn.iocoder.byzs.module.ai.dal.dataobject.image.AiImageDO;
+import cn.iocoder.byzs.module.ai.service.chat.AiChatConversationService;
+import cn.iocoder.byzs.module.ai.service.chat.AiChatMessageService;
+import cn.iocoder.byzs.module.ai.service.image.AiImageService;
 import cn.iocoder.byzs.module.bjdx.controller.admin.course.vo.CoursePageReqVO;
 import cn.iocoder.byzs.module.bjdx.controller.admin.coursetype.vo.CourseTypeListReqVO;
 import cn.iocoder.byzs.module.bjdx.controller.admin.coursetype.vo.CourseTypeRespVO;
@@ -13,54 +26,77 @@ 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 org.springframework.http.MediaType;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
 
 import java.util.List;
 
 import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.byzs.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 @Tag(name = "Web-前端接口")
 @RestController
 @RequestMapping("/bjdxWeb/ai")
 @Validated
+@PermitAll
+@TenantIgnore
 public class WebAiController {
 
     @Resource
-    private CourseService courseService;
+    private AiChatConversationService chatConversationService;
     @Resource
-    private CourseTypeService courseTypeService;
+    private AiChatMessageService chatMessageService;
+    @Resource
+    private AiImageService imageService;
+    
+    private Long userId = 1L;
+
 
+    // ================ 智能问答 ================
 
     @PermitAll
-    @GetMapping("/getCourseByTypeId")
-    @Operation(summary = "根据类型获得课程列表")
-    @Parameter(name = "id", description = "编号", required = true, example = "1024")
-    public CommonResult<List<CoursePageReqVO>> getCourseByTypeId(@RequestParam("typeId") String typeId) {
-        List<CoursePageReqVO> courseList = courseService.getCourseList(new CoursePageReqVO().setCourseType(typeId));
-        return success(courseList);
+    @TenantIgnore
+    @Operation(summary = "创建智能问答")
+    @PostMapping("/create-dialogue")
+    public CommonResult<Long> createChatConversationMy(@RequestBody @Valid AiChatConversationCreateMyReqVO createReqVO) {
+        return success(chatConversationService.createChatConversationMy(createReqVO, userId));
     }
 
+//    @PermitAll
+//    @TenantIgnore
+//    @Operation(summary = "智能问答-获得智能问答列表")
+//    @GetMapping("/dialogue-list")
+//    public CommonResult<List<AiChatConversationRespVO>> getChatConversationMyList() {
+//        List<AiChatConversationDO> list = chatConversationService.getChatConversationListByUserId(getLoginUserId());
+//        return success(BeanUtils.toBean(list, AiChatConversationRespVO.class));
+//    }
+
     @PermitAll
-    @GetMapping("/getTypeGrade")
-    @Operation(summary = "获得课程-年级")
-    public CommonResult<List<CourseTypeRespVO>> getTypeGrade() {
-        CourseTypeListReqVO listReqVO = new CourseTypeListReqVO().setCtTypeNode("0");
-        List<CourseTypeDO> list = courseTypeService.getCourseTypeList(listReqVO);
-        List<CourseTypeRespVO> listVo = BeanUtils.toBean(list, CourseTypeRespVO.class);
-        return success(listVo);
+    @TenantIgnore
+    @Operation(summary = "智能问答-发送消息(流式)", description = "流式返回,响应较快")
+    @PostMapping(value = "/dialogue-send-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(@Valid @RequestBody AiChatMessageSendReqVO sendReqVO) {
+        return chatMessageService.sendChatMessageStream(sendReqVO, userId);
     }
 
-    @PermitAll
-    @GetMapping("/getTypeByGradeId")
-    @Operation(summary = "获得课程-年级大纲")
-    public CommonResult<List<CourseTypeRespVO>> getTypeByGradeId(@RequestParam("id") Integer id) {
-        CourseTypeListReqVO listReqVO = new CourseTypeListReqVO().setCtParentId(id).setCtTypeNode("1");
-        List<CourseTypeDO> list = courseTypeService.getCourseTypeList(listReqVO);
-        List<CourseTypeRespVO> listVo = BeanUtils.toBean(list, CourseTypeRespVO.class);
-        return success(listVo);
+    // ================ 绘图管理 ================
+
+    @Operation(summary = "生成图片")
+    @PostMapping("/create-painting")
+    public CommonResult<Long> drawImage(@Valid @RequestBody AiImageDrawReqVO drawReqVO) {
+        return success(imageService.drawImage(userId, drawReqVO));
+    }
+
+    @GetMapping("/painting-get-my")
+    @Operation(summary = "绘画-获取绘图记录")
+    public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) {
+        AiImageDO image = imageService.getImage(id);
+        if (image == null || ObjUtil.notEqual(userId, image.getUserId())) {
+            return success(null);
+        }
+        return success(BeanUtils.toBean(image, AiImageRespVO.class));
     }
 }