Commit 7a66a435f936c4c6e2cfc5cd78b94ea0361ee110
1 parent
bec2aafe
【增加】AI:写作模版构建
Showing
4 changed files
with
62 additions
and
6 deletions
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/AiWriteController.java
| 1 | package cn.iocoder.yudao.module.ai.controller.admin.write; | 1 | package cn.iocoder.yudao.module.ai.controller.admin.write; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO; | ||
| 4 | import cn.iocoder.yudao.module.ai.service.write.AiWriteService; | 5 | import cn.iocoder.yudao.module.ai.service.write.AiWriteService; |
| 5 | import io.swagger.v3.oas.annotations.Operation; | 6 | import io.swagger.v3.oas.annotations.Operation; |
| 6 | import io.swagger.v3.oas.annotations.tags.Tag; | 7 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 7 | import jakarta.annotation.Resource; | 8 | import jakarta.annotation.Resource; |
| 8 | import jakarta.annotation.security.PermitAll; | 9 | import jakarta.annotation.security.PermitAll; |
| 10 | +import jakarta.validation.Valid; | ||
| 9 | import org.springframework.http.MediaType; | 11 | import org.springframework.http.MediaType; |
| 10 | import org.springframework.web.bind.annotation.PostMapping; | 12 | import org.springframework.web.bind.annotation.PostMapping; |
| 13 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 11 | import org.springframework.web.bind.annotation.RequestMapping; | 14 | import org.springframework.web.bind.annotation.RequestMapping; |
| 12 | import org.springframework.web.bind.annotation.RestController; | 15 | import org.springframework.web.bind.annotation.RestController; |
| 13 | import reactor.core.publisher.Flux; | 16 | import reactor.core.publisher.Flux; |
| @@ -22,8 +25,8 @@ public class AiWriteController { | @@ -22,8 +25,8 @@ public class AiWriteController { | ||
| 22 | 25 | ||
| 23 | @PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | 26 | @PostMapping(value = "/generate-stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) |
| 24 | @PermitAll | 27 | @PermitAll |
| 25 | - @Operation(summary = "作文生产(流式)", description = "流式返回,响应较快") | ||
| 26 | - public Flux<CommonResult<String>> generateComposition() { | ||
| 27 | - return writeService.generateComposition(); | 28 | + @Operation(summary = "写作生成(流式)", description = "流式返回,响应较快") |
| 29 | + public Flux<CommonResult<String>> generateComposition(@RequestBody @Valid AiWriteGenerateReqVO generateReqVO) { | ||
| 30 | + return writeService.generateComposition(generateReqVO); | ||
| 28 | } | 31 | } |
| 29 | } | 32 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/write/vo/AiWriteGenerateReqVO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.controller.admin.write.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | +import jakarta.validation.constraints.NotBlank; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +@Schema(description = "管理后台 - AI 写作生成 Request VO") | ||
| 8 | +@Data | ||
| 9 | +public class AiWriteGenerateReqVO { | ||
| 10 | + | ||
| 11 | + @Schema(description = "写作内容", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "田忌赛马") | ||
| 12 | + private String content; | ||
| 13 | + | ||
| 14 | + @Schema(description = "原文", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "领导我要辞职") | ||
| 15 | + private String originalContent; | ||
| 16 | + | ||
| 17 | + @Schema(description = "回复内容", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "准了") | ||
| 18 | + private String replyContent; | ||
| 19 | + | ||
| 20 | + @Schema(description = "长度", requiredMode = Schema.RequiredMode.REQUIRED, example = "中等") | ||
| 21 | + @NotBlank(message = "长度不能为空") | ||
| 22 | + private String length; | ||
| 23 | + | ||
| 24 | + @Schema(description = "格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "文章") | ||
| 25 | + @NotBlank(message = "格式不能为空") | ||
| 26 | + private String format; | ||
| 27 | + | ||
| 28 | + @Schema(description = "语气", requiredMode = Schema.RequiredMode.REQUIRED, example = "随意") | ||
| 29 | + @NotBlank(message = "语气不能为空") | ||
| 30 | + private String tone; | ||
| 31 | + | ||
| 32 | + @Schema(description = "语言", requiredMode = Schema.RequiredMode.REQUIRED, example = "中文") | ||
| 33 | + @NotBlank(message = "语言不能为空") | ||
| 34 | + private String language; | ||
| 35 | + | ||
| 36 | + | ||
| 37 | + @Schema(description = "写作类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||
| 38 | + private Integer writeType; | ||
| 39 | +} | ||
| 0 | \ No newline at end of file | 40 | \ No newline at end of file |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteService.java
| 1 | package cn.iocoder.yudao.module.ai.service.write; | 1 | package cn.iocoder.yudao.module.ai.service.write; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO; | ||
| 4 | import reactor.core.publisher.Flux; | 5 | import reactor.core.publisher.Flux; |
| 5 | 6 | ||
| 6 | /** | 7 | /** |
| @@ -11,7 +12,7 @@ import reactor.core.publisher.Flux; | @@ -11,7 +12,7 @@ import reactor.core.publisher.Flux; | ||
| 11 | public interface AiWriteService { | 12 | public interface AiWriteService { |
| 12 | 13 | ||
| 13 | 14 | ||
| 14 | - Flux<CommonResult<String>> generateComposition(); | 15 | + Flux<CommonResult<String>> generateComposition(AiWriteGenerateReqVO generateReqVO); |
| 15 | 16 | ||
| 16 | 17 | ||
| 17 | } | 18 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/write/AiWriteServiceImpl.java
| @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoChatModel; | ||
| 7 | import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions; | 7 | import cn.iocoder.yudao.framework.ai.core.model.xinghuo.XingHuoOptions; |
| 8 | import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions; | 8 | import cn.iocoder.yudao.framework.ai.core.model.yiyan.YiYanChatOptions; |
| 9 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 9 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 10 | +import cn.iocoder.yudao.module.ai.controller.admin.write.vo.AiWriteGenerateReqVO; | ||
| 10 | import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; | 11 | import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; |
| 11 | import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; | 12 | import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; |
| 12 | import jakarta.annotation.Resource; | 13 | import jakarta.annotation.Resource; |
| @@ -37,11 +38,11 @@ public class AiWriteServiceImpl implements AiWriteService { | @@ -37,11 +38,11 @@ public class AiWriteServiceImpl implements AiWriteService { | ||
| 37 | 38 | ||
| 38 | 39 | ||
| 39 | @Override | 40 | @Override |
| 40 | - public Flux<CommonResult<String>> generateComposition() { | 41 | + public Flux<CommonResult<String>> generateComposition(AiWriteGenerateReqVO generateReqVO) { |
| 41 | StreamingChatClient chatClient = apiKeyService.getStreamingChatClient(6L); | 42 | StreamingChatClient chatClient = apiKeyService.getStreamingChatClient(6L); |
| 42 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform("QianWen"); | 43 | AiPlatformEnum platform = AiPlatformEnum.validatePlatform("QianWen"); |
| 43 | ChatOptions chatOptions = buildChatOptions(platform, "qwen-72b-chat", 1.0, 1000); | 44 | ChatOptions chatOptions = buildChatOptions(platform, "qwen-72b-chat", 1.0, 1000); |
| 44 | - Prompt prompt = new Prompt("请直接写一篇关于 气候变化 的文章,格式为自动,语气为自动,语言为自动,长度为自动。请确保涵盖主要观点,不需要标题,不需要任何额外的解释或道歉。", chatOptions); | 45 | + Prompt prompt = new Prompt(buildWritingPrompt(generateReqVO), chatOptions); |
| 45 | Flux<ChatResponse> streamResponse = chatClient.stream(prompt); | 46 | Flux<ChatResponse> streamResponse = chatClient.stream(prompt); |
| 46 | // 3.3 流式返回 | 47 | // 3.3 流式返回 |
| 47 | StringBuffer contentBuffer = new StringBuffer(); | 48 | StringBuffer contentBuffer = new StringBuffer(); |
| @@ -54,11 +55,23 @@ public class AiWriteServiceImpl implements AiWriteService { | @@ -54,11 +55,23 @@ public class AiWriteServiceImpl implements AiWriteService { | ||
| 54 | }).doOnComplete(() -> { | 55 | }).doOnComplete(() -> { |
| 55 | log.info("generateComposition complete, content: {}", contentBuffer); | 56 | log.info("generateComposition complete, content: {}", contentBuffer); |
| 56 | }).onErrorResume(error -> { | 57 | }).onErrorResume(error -> { |
| 58 | + log.error("[AI 写作] 发生异常", error); | ||
| 57 | return Flux.just(error(ErrorCodeConstants.AI_CHAT_STREAM_ERROR)); | 59 | return Flux.just(error(ErrorCodeConstants.AI_CHAT_STREAM_ERROR)); |
| 58 | }); | 60 | }); |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | 63 | ||
| 64 | + private String buildWritingPrompt(AiWriteGenerateReqVO generateReqVO) { | ||
| 65 | + String template = "请直接写一篇关于 [{}] 的文章,格式为:{},语气为:{},语言为:{},长度为:{}。请确保涵盖主要内容,不需要任何额外的解释或道歉。"; | ||
| 66 | + String content = generateReqVO.getContent(); | ||
| 67 | + String format = generateReqVO.getFormat(); | ||
| 68 | + String tone = generateReqVO.getTone(); | ||
| 69 | + String language = generateReqVO.getLanguage(); | ||
| 70 | + String length = generateReqVO.getLength(); | ||
| 71 | + return StrUtil.format(template, content, format, tone, language, length); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + // TODO 芋艿:复用 | ||
| 62 | private static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) { | 75 | private static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) { |
| 63 | Float temperatureF = temperature != null ? temperature.floatValue() : null; | 76 | Float temperatureF = temperature != null ? temperature.floatValue() : null; |
| 64 | //noinspection EnhancedSwitchMigration | 77 | //noinspection EnhancedSwitchMigration |