Commit 7a66a435f936c4c6e2cfc5cd78b94ea0361ee110

Authored by xiaoxin
1 parent bec2aafe

【增加】AI:写作模版构建

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