Commit ef701167b76fd2757da5e0d23b08b02a1b7af057
1 parent
7024c5ab
1、增加 chat service
2、可动态传入 modal,选择模型
Showing
6 changed files
with
154 additions
and
9 deletions
yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/AiClientNameEnum.java
| @@ -25,4 +25,13 @@ public enum AiClientNameEnum { | @@ -25,4 +25,13 @@ public enum AiClientNameEnum { | ||
| 25 | private String name; | 25 | private String name; |
| 26 | 26 | ||
| 27 | private String message; | 27 | private String message; |
| 28 | + | ||
| 29 | + public static AiClientNameEnum valueOfName(String name) { | ||
| 30 | + for (AiClientNameEnum nameEnum : AiClientNameEnum.values()) { | ||
| 31 | + if (nameEnum.getName().equals(name)) { | ||
| 32 | + return nameEnum; | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + throw new IllegalArgumentException("Invalid MessageType value: " + name); | ||
| 36 | + } | ||
| 28 | } | 37 | } |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/ChatController.java
| @@ -2,20 +2,20 @@ package cn.iocoder.yudao.module.ai.controller; | @@ -2,20 +2,20 @@ package cn.iocoder.yudao.module.ai.controller; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.exceptions.ExceptionUtil; | 3 | import cn.hutool.core.exceptions.ExceptionUtil; |
| 4 | import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | 4 | import cn.iocoder.yudao.framework.ai.chat.ChatResponse; |
| 5 | -import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 6 | import cn.iocoder.yudao.framework.ai.config.AiClient; | 5 | import cn.iocoder.yudao.framework.ai.config.AiClient; |
| 7 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 6 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 8 | -import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; | ||
| 9 | import cn.iocoder.yudao.module.ai.service.ChatService; | 7 | import cn.iocoder.yudao.module.ai.service.ChatService; |
| 8 | +import cn.iocoder.yudao.module.ai.vo.ChatReq; | ||
| 10 | import io.swagger.v3.oas.annotations.Operation; | 9 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | import io.swagger.v3.oas.annotations.tags.Tag; | 10 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 12 | import lombok.AllArgsConstructor; | 11 | import lombok.AllArgsConstructor; |
| 13 | import lombok.extern.slf4j.Slf4j; | 12 | import lombok.extern.slf4j.Slf4j; |
| 14 | import org.springframework.beans.factory.annotation.Autowired; | 13 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | import org.springframework.http.MediaType; | 14 | import org.springframework.http.MediaType; |
| 15 | +import org.springframework.validation.annotation.Validated; | ||
| 16 | import org.springframework.web.bind.annotation.GetMapping; | 16 | import org.springframework.web.bind.annotation.GetMapping; |
| 17 | +import org.springframework.web.bind.annotation.ModelAttribute; | ||
| 17 | import org.springframework.web.bind.annotation.RequestMapping; | 18 | import org.springframework.web.bind.annotation.RequestMapping; |
| 18 | -import org.springframework.web.bind.annotation.RequestParam; | ||
| 19 | import org.springframework.web.bind.annotation.RestController; | 19 | import org.springframework.web.bind.annotation.RestController; |
| 20 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | 20 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; |
| 21 | import reactor.core.publisher.Flux; | 21 | import reactor.core.publisher.Flux; |
| @@ -43,17 +43,16 @@ public class ChatController { | @@ -43,17 +43,16 @@ public class ChatController { | ||
| 43 | 43 | ||
| 44 | @Operation(summary = "聊天-chat", description = "这个一般等待时间比较久,需要全部完成才会返回!") | 44 | @Operation(summary = "聊天-chat", description = "这个一般等待时间比较久,需要全部完成才会返回!") |
| 45 | @GetMapping("/chat") | 45 | @GetMapping("/chat") |
| 46 | - public CommonResult<String> chat(@RequestParam("prompt") String prompt) { | ||
| 47 | - ChatResponse callRes = aiClient.call(new Prompt(prompt), AiClientNameEnum.QIAN_WEN.getName()); | ||
| 48 | - return CommonResult.success(callRes.getResult().getOutput().getContent()); | 46 | + public CommonResult<String> chat(@Validated @ModelAttribute ChatReq req) { |
| 47 | + return CommonResult.success(chatService.chat(req)); | ||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | // TODO @芋艿:调用这个方法异常,Unable to handle the Spring Security Exception because the response is already committed. | 50 | // TODO @芋艿:调用这个方法异常,Unable to handle the Spring Security Exception because the response is already committed. |
| 52 | @Operation(summary = "聊天-stream", description = "这里跟通义千问一样采用的是 Server-Sent Events (SSE) 通讯模式") | 51 | @Operation(summary = "聊天-stream", description = "这里跟通义千问一样采用的是 Server-Sent Events (SSE) 通讯模式") |
| 53 | @GetMapping(value = "/chatStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | 52 | @GetMapping(value = "/chatStream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) |
| 54 | - public SseEmitter chatStream(@RequestParam("prompt") String prompt) { | 53 | + public SseEmitter chatStream(@Validated @ModelAttribute ChatReq req) { |
| 55 | Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); | 54 | Utf8SseEmitter sseEmitter = new Utf8SseEmitter(); |
| 56 | - Flux<ChatResponse> streamResponse = aiClient.stream(new Prompt(prompt), AiClientNameEnum.QIAN_WEN.getName()); | 55 | + Flux<ChatResponse> streamResponse = chatService.chatStream(req); |
| 57 | streamResponse.subscribe( | 56 | streamResponse.subscribe( |
| 58 | new Consumer<ChatResponse>() { | 57 | new Consumer<ChatResponse>() { |
| 59 | @Override | 58 | @Override |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/AiChatRoleController.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/ChatRoleController.java
| @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; | @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; | ||
| 17 | @RestController | 17 | @RestController |
| 18 | @RequestMapping("/chat-role") | 18 | @RequestMapping("/chat-role") |
| 19 | @AllArgsConstructor | 19 | @AllArgsConstructor |
| 20 | -public class AiChatRoleController { | 20 | +public class ChatRoleController { |
| 21 | 21 | ||
| 22 | private final ChatRoleService chatRoleService; | 22 | private final ChatRoleService chatRoleService; |
| 23 | 23 |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/ChatService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | ||
| 4 | +import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; | ||
| 5 | +import cn.iocoder.yudao.module.ai.vo.ChatReq; | ||
| 6 | +import reactor.core.publisher.Flux; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 聊天 chat | ||
| 10 | + * | ||
| 11 | + * @author fansili | ||
| 12 | + * @time 2024/4/14 15:55 | ||
| 13 | + * @since 1.0 | ||
| 14 | + */ | ||
| 15 | +public interface ChatService { | ||
| 16 | + | ||
| 17 | + /** | ||
| 18 | + * chat | ||
| 19 | + * | ||
| 20 | + * @param req | ||
| 21 | + * @return | ||
| 22 | + */ | ||
| 23 | + String chat(ChatReq req); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * chat stream | ||
| 27 | + * | ||
| 28 | + * @param req | ||
| 29 | + * @param clientNameEnum | ||
| 30 | + * @return | ||
| 31 | + */ | ||
| 32 | + Flux<ChatResponse> chatStream(ChatReq req); | ||
| 33 | +} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/impl/ChatServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.framework.ai.chat.ChatResponse; | ||
| 4 | +import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt; | ||
| 5 | +import cn.iocoder.yudao.framework.ai.config.AiClient; | ||
| 6 | +import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; | ||
| 7 | +import cn.iocoder.yudao.module.ai.service.ChatService; | ||
| 8 | +import cn.iocoder.yudao.module.ai.vo.ChatReq; | ||
| 9 | +import lombok.AllArgsConstructor; | ||
| 10 | +import lombok.extern.slf4j.Slf4j; | ||
| 11 | +import org.springframework.stereotype.Service; | ||
| 12 | +import reactor.core.publisher.Flux; | ||
| 13 | + | ||
| 14 | +/** | ||
| 15 | + * 聊天 service | ||
| 16 | + * | ||
| 17 | + * @author fansili | ||
| 18 | + * @time 2024/4/14 15:55 | ||
| 19 | + * @since 1.0 | ||
| 20 | + */ | ||
| 21 | +@Slf4j | ||
| 22 | +@Service | ||
| 23 | +@AllArgsConstructor | ||
| 24 | +public class ChatServiceImpl implements ChatService { | ||
| 25 | + | ||
| 26 | + private final AiClient aiClient; | ||
| 27 | + | ||
| 28 | + /** | ||
| 29 | + * chat | ||
| 30 | + * | ||
| 31 | + * @param req | ||
| 32 | + * @return | ||
| 33 | + */ | ||
| 34 | + public String chat(ChatReq req) { | ||
| 35 | + AiClientNameEnum clientNameEnum = AiClientNameEnum.valueOfName(req.getModal()); | ||
| 36 | + // 创建 chat 需要的 Prompt | ||
| 37 | + Prompt prompt = new Prompt(req.getPrompt()); | ||
| 38 | + req.setTopK(req.getTopK()); | ||
| 39 | + req.setTopP(req.getTopP()); | ||
| 40 | + req.setTemperature(req.getTemperature()); | ||
| 41 | + // 发送 call 调用 | ||
| 42 | + ChatResponse call = aiClient.call(prompt, clientNameEnum.getName()); | ||
| 43 | + return call.getResult().getOutput().getContent(); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * chat stream | ||
| 48 | + * | ||
| 49 | + * @param req | ||
| 50 | + * @return | ||
| 51 | + */ | ||
| 52 | + @Override | ||
| 53 | + public Flux<ChatResponse> chatStream(ChatReq req) { | ||
| 54 | + AiClientNameEnum clientNameEnum = AiClientNameEnum.valueOfName(req.getModal()); | ||
| 55 | + // 创建 chat 需要的 Prompt | ||
| 56 | + Prompt prompt = new Prompt(req.getPrompt()); | ||
| 57 | + req.setTopK(req.getTopK()); | ||
| 58 | + req.setTopP(req.getTopP()); | ||
| 59 | + req.setTemperature(req.getTemperature()); | ||
| 60 | + return aiClient.stream(prompt, clientNameEnum.getName()); | ||
| 61 | + } | ||
| 62 | +} |
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/vo/ChatReq.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.ai.vo; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum; | ||
| 4 | +import io.swagger.v3.oas.annotations.media.Schema; | ||
| 5 | +import jakarta.validation.constraints.NotNull; | ||
| 6 | +import jakarta.validation.constraints.Size; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.experimental.Accessors; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * chat req | ||
| 12 | + * | ||
| 13 | + * @author fansili | ||
| 14 | + * @time 2024/4/14 16:12 | ||
| 15 | + * @since 1.0 | ||
| 16 | + */ | ||
| 17 | +@Data | ||
| 18 | +@Accessors(chain = true) | ||
| 19 | +public class ChatReq { | ||
| 20 | + | ||
| 21 | + | ||
| 22 | + @NotNull(message = "提示词不能为空!") | ||
| 23 | + @Size(max = 3000, message = "提示词最大3000个字符!") | ||
| 24 | + @Schema(description = "填入固定值,1 issues, 2 pr") | ||
| 25 | + private String prompt; | ||
| 26 | + | ||
| 27 | + @Schema(description = "用于控制随机性和多样性的温度参数") | ||
| 28 | + private Float temperature; | ||
| 29 | + | ||
| 30 | + @Schema(description = "生成时,核采样方法的概率阈值。例如,取值为0.8时,仅保留累计概率之和大于等于0.8的概率分布中的token,\n" + | ||
| 31 | + " * 作为随机采样的候选集。取值范围为(0,1.0),取值越大,生成的随机性越高;取值越低,生成的随机性越低。\n" + | ||
| 32 | + " * 默认值为0.8。注意,取值不要大于等于1\n") | ||
| 33 | + private Float topP; | ||
| 34 | + | ||
| 35 | + @Schema(description = "在生成消息时采用的Top-K采样大小,表示模型生成回复时考虑的候选项集合的大小") | ||
| 36 | + private Integer topK; | ||
| 37 | + | ||
| 38 | + @Schema(description = "ai模型(查看 AiClientNameEnum)") | ||
| 39 | + @NotNull(message = "模型不能为空!") | ||
| 40 | + @Size(max = 30, message = "模型字符最大30个字符!") | ||
| 41 | + private String modal; | ||
| 42 | +} |