Commit ef701167b76fd2757da5e0d23b08b02a1b7af057

Authored by cherishsince
1 parent 7024c5ab

1、增加 chat service

2、可动态传入 modal,选择模型
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 25 private String name;
26 26  
27 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 2  
3 3 import cn.hutool.core.exceptions.ExceptionUtil;
4 4 import cn.iocoder.yudao.framework.ai.chat.ChatResponse;
5   -import cn.iocoder.yudao.framework.ai.chat.prompt.Prompt;
6 5 import cn.iocoder.yudao.framework.ai.config.AiClient;
7 6 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
8   -import cn.iocoder.yudao.module.ai.enums.AiClientNameEnum;
9 7 import cn.iocoder.yudao.module.ai.service.ChatService;
  8 +import cn.iocoder.yudao.module.ai.vo.ChatReq;
10 9 import io.swagger.v3.oas.annotations.Operation;
11 10 import io.swagger.v3.oas.annotations.tags.Tag;
12 11 import lombok.AllArgsConstructor;
13 12 import lombok.extern.slf4j.Slf4j;
14 13 import org.springframework.beans.factory.annotation.Autowired;
15 14 import org.springframework.http.MediaType;
  15 +import org.springframework.validation.annotation.Validated;
16 16 import org.springframework.web.bind.annotation.GetMapping;
  17 +import org.springframework.web.bind.annotation.ModelAttribute;
17 18 import org.springframework.web.bind.annotation.RequestMapping;
18   -import org.springframework.web.bind.annotation.RequestParam;
19 19 import org.springframework.web.bind.annotation.RestController;
20 20 import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
21 21 import reactor.core.publisher.Flux;
... ... @@ -43,17 +43,16 @@ public class ChatController {
43 43  
44 44 @Operation(summary = "聊天-chat", description = "这个一般等待时间比较久,需要全部完成才会返回!")
45 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 50 // TODO @芋艿:调用这个方法异常,Unable to handle the Spring Security Exception because the response is already committed.
52 51 @Operation(summary = "聊天-stream", description = "这里跟通义千问一样采用的是 Server-Sent Events (SSE) 通讯模式")
53 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 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 56 streamResponse.subscribe(
58 57 new Consumer<ChatResponse>() {
59 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 17 @RestController
18 18 @RequestMapping("/chat-role")
19 19 @AllArgsConstructor
20   -public class AiChatRoleController {
  20 +public class ChatRoleController {
21 21  
22 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 +}
... ...