فهرست منبع

springai添加可访问数据库智能体,只能提无法从外部获取参数,只能从聊天框获取

Taohongrun 5 ماه پیش
والد
کامیت
c52c338531

+ 2 - 2
front-end/scripts/generate-api.js

@@ -6,8 +6,8 @@ import { v4 as uuidv4 } from 'uuid'
 import os from 'os'
 import path from 'path'
 import AdmZip from 'adm-zip'
-const sourceUrl = 'http://58.87.69.234:9902/ts.zip'
-//const sourceUrl = 'http://localhost:9902/ts.zip'
+//const sourceUrl = 'http://58.87.69.234:9902/ts.zip'
+const sourceUrl = 'http://localhost:9902/ts.zip'
 const tmpFilePath = os.tmpdir() + '/' + uuidv4() + '.zip'
 const generatePath = 'src/apis/__generated'
 

BIN
front-end/src/assets/logo.jpg


+ 2 - 2
front-end/vite.config.ts

@@ -17,8 +17,8 @@ export default defineConfig({
     port: 5177,
     proxy: {
       '/api': {
-        //target: 'http://localhost:9902',
-        target: 'http://58.87.69.234:9902',
+        target: 'http://localhost:9902',
+        //target: 'http://58.87.69.234:9902',
         changeOrigin: true,
         rewrite: (path) => path.replace(/^\/api/, '')
       }

+ 23 - 0
pom.xml

@@ -25,6 +25,7 @@
         <jimmer.version>0.8.134</jimmer.version>
         <hutool.version>5.8.25</hutool.version>
         <sa-token.version>1.37.0</sa-token.version>
+        <mybatis-plus-boot-starter.version>3.5.7</mybatis-plus-boot-starter.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     </properties>
@@ -143,6 +144,28 @@
             <artifactId>sa-token-spring-boot3-starter</artifactId>
             <version>${sa-token.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
+            <version>${mybatis-plus-boot-starter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>${mybatis-plus-boot-starter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-annotation</artifactId>
+            <version>${mybatis-plus-boot-starter.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
     </dependencies>
     <dependencyManagement>
         <dependencies>

+ 2 - 0
src/main/java/io/github/qifan777/knowledge/ServerApplication.java

@@ -3,6 +3,7 @@ package io.github.qifan777.knowledge;
 
 import io.github.qifan777.knowledge.infrastructure.code.CodeAssistantProperties;
 import org.babyfish.jimmer.client.EnableImplicitApi;
+import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -10,6 +11,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
 @SpringBootApplication
 @EnableImplicitApi
 @EnableConfigurationProperties(CodeAssistantProperties.class)
+@MapperScan("io.github.qifan777.knowledge.mapper")
 public class ServerApplication {
     public static void main(String[] args) {
         SpringApplication.run(ServerApplication.class, args);

+ 40 - 0
src/main/java/io/github/qifan777/knowledge/ai/agent/userAgent/UserInfo.java

@@ -0,0 +1,40 @@
+package io.github.qifan777.knowledge.ai.agent.userAgent;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+import io.github.qifan777.knowledge.ai.agent.AbstractAgent;
+import io.github.qifan777.knowledge.ai.agent.Agent;
+import lombok.AllArgsConstructor;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.context.annotation.Description;
+
+import java.util.function.Function;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2025/3/14
+ */
+@Agent
+@Description("获取当前系统用户相关提问于回答")
+@AllArgsConstructor
+public class UserInfo extends AbstractAgent implements Function<UserInfo.Request, String> {
+    private final ChatModel chatModel;
+    @Override
+    public String apply(Request request) {
+        return ChatClient.create(chatModel)
+                .prompt()
+                .functions(getFunctions(UserNameFunction.class))
+                .user(request.query())
+                .call()
+                .content();
+    }
+
+    public record Request(
+            @JsonProperty(required = true) @JsonPropertyDescription(value = "用户原始的提问") String query) {
+    }
+}

+ 44 - 0
src/main/java/io/github/qifan777/knowledge/ai/agent/userAgent/UserNameFunction.java

@@ -0,0 +1,44 @@
+package io.github.qifan777.knowledge.ai.agent.userAgent;
+
+import cn.dev33.satoken.stp.StpUtil;
+import com.baomidou.mybatisplus.extension.toolkit.Db;
+
+import io.github.qifan777.knowledge.context.UserContext;
+import io.github.qifan777.knowledge.domain.po.User;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Description;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 获取用户sql
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2025/3/13
+ */
+@Component
+@Description("获取系统用户名称")
+@Slf4j
+public  class UserNameFunction implements Function<UserNameFunction.Request, String> {
+
+    @Autowired
+    RedisTemplate redisTemplate;
+
+    @Override
+    public String apply(Request request) {
+        System.out.println(UserContext.getThreadUserId());
+        List<String> userNameList = Db.lambdaQuery(User.class).list().stream().map(User::getNickname).collect(Collectors.toList());
+        System.out.println(".................xxxxxxxxxxxxxx:{}xxxxxxx"+userNameList);
+        return userNameList.toString();
+    }
+
+    public record Request() {
+    }
+}

+ 2 - 0
src/main/java/io/github/qifan777/knowledge/ai/message/AiMessageController.java

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import io.github.qifan777.knowledge.ai.agent.Agent;
 import io.github.qifan777.knowledge.ai.message.dto.AiMessageInput;
 import io.github.qifan777.knowledge.ai.message.dto.AiMessageWrapper;
+import io.github.qifan777.knowledge.context.UserContext;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import lombok.extern.slf4j.Slf4j;
@@ -78,6 +79,7 @@ public class AiMessageController {
     @SneakyThrows
     @PostMapping(value = "chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
     public Flux<ServerSentEvent<String>> chat(@RequestPart String input, @RequestPart(required = false) MultipartFile file) {
+        System.out.println(UserContext.getThreadUserId());
         AiMessageWrapper aiMessageWrapper = objectMapper.readValue(input, AiMessageWrapper.class);
         String[] functionBeanNames = new String[0];
         // 如果启用Agent则获取Agent的bean

+ 42 - 0
src/main/java/io/github/qifan777/knowledge/config/MVCConfig.java

@@ -0,0 +1,42 @@
+package io.github.qifan777.knowledge.config;
+
+
+import io.github.qifan777.knowledge.interceptor.LoginInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2024/12/4
+ */
+@Configuration
+public class MVCConfig implements WebMvcConfigurer {
+
+
+
+    @Autowired
+    RedisTemplate<String,String> redisTemplate;
+
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        ValueOperations<String,String> valueOperations = redisTemplate.opsForValue();
+
+        registry.addInterceptor(new LoginInterceptor(valueOperations))
+                .addPathPatterns("/**")
+                .excludePathPatterns("/user/login")
+                .order(2);
+//        registry.addInterceptor(new RefreshInterceptor(hashOperations,redisTemplate))
+//                .addPathPatterns("/**")
+//                .order(1);
+    }
+}

+ 23 - 0
src/main/java/io/github/qifan777/knowledge/config/RedisConfiguration.java

@@ -0,0 +1,23 @@
+package io.github.qifan777.knowledge.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+@Slf4j
+public class RedisConfiguration {
+
+    @Bean
+    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
+        log.info("Redis模板对象开始创建");
+        RedisTemplate redisTemplate =new RedisTemplate();
+        redisTemplate.setConnectionFactory(redisConnectionFactory);
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        log.info("redis模板对象创建成功");
+        return redisTemplate;
+    }
+}

+ 40 - 0
src/main/java/io/github/qifan777/knowledge/context/UserContext.java

@@ -0,0 +1,40 @@
+package io.github.qifan777.knowledge.context;
+
+
+public class UserContext {
+
+    private static final ThreadLocal<String> idThreadLocal = new ThreadLocal<>();
+    private static final ThreadLocal<String> nameThreadLocal = new ThreadLocal<>();
+    private static final ThreadLocal<Integer> roleIdThreadLocal = new ThreadLocal<>();
+
+    public static String getThreadUserId(){
+        return idThreadLocal.get();
+    }
+
+    public static void setThreadUserId(String id){
+        idThreadLocal.set(id);
+    }
+
+
+    public static Integer getThreadUserRoleId(){
+        return roleIdThreadLocal.get();
+    }
+
+    public static void setThreadUserRoleId(Integer id){
+        roleIdThreadLocal.set(id);
+    }
+
+    public static String getThreadUserName(){
+        return nameThreadLocal.get();
+    }
+
+    public static void setThreadUserName(String name){
+        nameThreadLocal.set(name);
+    }
+
+    public static void clear(){
+        idThreadLocal.remove();
+        nameThreadLocal.remove();
+        roleIdThreadLocal.remove();
+    }
+}

+ 25 - 0
src/main/java/io/github/qifan777/knowledge/domain/po/User.java

@@ -0,0 +1,25 @@
+package io.github.qifan777.knowledge.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2025/3/13
+ */
+@Data
+@TableName("user")
+public class User {
+    @TableId(type = IdType.ASSIGN_ID)
+    private String id;
+    private String phone;
+    private String nickname;
+}

+ 41 - 0
src/main/java/io/github/qifan777/knowledge/interceptor/LoginInterceptor.java

@@ -0,0 +1,41 @@
+package io.github.qifan777.knowledge.interceptor;
+
+import io.github.qifan777.knowledge.context.UserContext;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2024/12/4
+ */
+public class LoginInterceptor implements HandlerInterceptor {
+   private ValueOperations<String,String> valueOperations;
+
+    public LoginInterceptor(ValueOperations valueOperations) {
+        this.valueOperations = valueOperations;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+        UserContext.clear();
+    }
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        //获取redis用户信息
+        //cookie格式为token=xxxxx
+        //获取token
+        String token = request.getHeader("Cookie").split("=")[1];
+
+        String userId = valueOperations.get(token);
+        if(userId.isEmpty()) return false;
+        UserContext.setThreadUserId(userId);
+        return true;
+    }
+}

+ 22 - 0
src/main/java/io/github/qifan777/knowledge/mapper/UserMapper.java

@@ -0,0 +1,22 @@
+package io.github.qifan777.knowledge.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import io.github.qifan777.knowledge.domain.po.User;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author itcast
+ */
+public interface UserMapper extends BaseMapper<User> {
+
+
+
+}

+ 9 - 0
src/main/java/io/github/qifan777/knowledge/service/UserService.java

@@ -0,0 +1,9 @@
+package io.github.qifan777.knowledge.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import io.github.qifan777.knowledge.domain.po.User;
+
+public interface UserService extends IService<User> {
+
+}

+ 31 - 0
src/main/java/io/github/qifan777/knowledge/service/impl/UserServiceImpl.java

@@ -0,0 +1,31 @@
+package io.github.qifan777.knowledge.service.impl;
+
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import io.github.qifan777.knowledge.domain.po.User;
+import io.github.qifan777.knowledge.mapper.UserMapper;
+import io.github.qifan777.knowledge.service.UserService;
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2024/11/21
+ */
+@Service
+@Slf4j
+@Validated
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+
+
+
+
+
+}

+ 52 - 0
src/main/java/io/github/qifan777/knowledge/test.java

@@ -0,0 +1,52 @@
+package io.github.qifan777.knowledge;
+
+import com.alibaba.dashscope.aigc.generation.Generation;
+import com.alibaba.dashscope.aigc.generation.GenerationParam;
+import com.alibaba.dashscope.aigc.generation.GenerationResult;
+import com.alibaba.dashscope.common.Message;
+import com.alibaba.dashscope.common.Role;
+import com.alibaba.dashscope.exception.ApiException;
+import com.alibaba.dashscope.exception.InputRequiredException;
+import com.alibaba.dashscope.exception.NoApiKeyException;
+
+import java.util.Arrays;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author taohongrun
+ * @since 2025/3/13
+ */
+public class test {
+    public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
+        Generation gen = new Generation();
+        Message userMsg = Message.builder()
+                .role(Role.USER.getValue())
+                .content("你是谁?")
+                .build();
+        GenerationParam param = GenerationParam.builder()
+
+                .apiKey("sk-375aa80dcb56402db68857b31846b1bb")
+                .model("deepseek-v3")
+                .messages(Arrays.asList(userMsg))
+                // 不可以设置为"text"
+                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
+                .build();
+        return gen.call(param);
+    }
+    public static void main(String[] args) {
+        try {
+            GenerationResult result = callWithMessage();
+            System.out.println("思考过程:");
+            System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
+            System.out.println("回复内容:");
+            System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
+        } catch (ApiException | NoApiKeyException | InputRequiredException e) {
+            // 使用日志框架记录异常信息
+            System.err.println("An error occurred while calling the generation service: " + e.getMessage());
+        }
+        System.exit(0);
+    }
+}

+ 3 - 0
src/main/java/io/github/qifan777/knowledge/user/UserController.java

@@ -9,6 +9,7 @@ import io.qifan.infrastructure.common.exception.BusinessException;
 import lombok.AllArgsConstructor;
 import org.babyfish.jimmer.client.FetchBy;
 import org.babyfish.jimmer.sql.EnableDtoGeneration;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 
 import java.util.Optional;
@@ -19,6 +20,7 @@ import java.util.Optional;
 @AllArgsConstructor
 public class UserController {
     private final UserRepository userRepository;
+    private final RedisTemplate<String,String> redisTemplate;
 
     @GetMapping
     public @FetchBy(value = "FETCHER", ownerType = UserRepository.class) User userInfo() {
@@ -34,6 +36,7 @@ public class UserController {
             throw new BusinessException("用户名/密码错误");
         }
         StpUtil.login(databaseUser.id());
+        redisTemplate.opsForValue().set(StpUtil.getTokenInfo().tokenValue, databaseUser.id());
         return StpUtil.getTokenInfo();
     }
 

+ 3 - 3
src/main/resources/application.yml

@@ -10,7 +10,7 @@ spring:
     redis:
       database: 0
       timeout: 10s
-      password: 123456
+      password: Taohongrun0
       repositories:
         enabled: false
       lettuce:
@@ -34,12 +34,12 @@ spring:
   ai:
     # 阿里灵积
     dash-scope:
-      api-key: sk-08bb815887e3480d932b6dcc6a6e60d7
+      api-key: sk-375aa80dcb56402db68857b31846b1bb
       chat:
         options:
           model: qwen-max
           # 多模态图片理解需要开启
-#          multi-model: true
+         # multi-model: true
       embedding:
         options:
           model: text-embedding-v2