有趣的地方

有趣的地方

【Spring实战】动手拥有自己的ai小站!使用Springboot整合Spring Cloud Gateway实现对接open ai并实现令牌记量和限制对话次数

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家一份高质专栏《Spring 狂野之旅:从入门到入魔》 🚀

本专栏带你从Spring入门到入魔!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net/

相信大家已经见过不少 ai的中转站   有没有想过自己搭建一个呢?先看看成品吧

在看这一篇之前  我是建议大家先去了解一下Springcloud Gateway的原理解读 就是我这篇文章《【云原生】Spring Cloud Gateway的底层原理与实践方法探究》

我一直秉持着知识需要成体系的原则去学习的 我希望大家也能在有限的时间里获得最大的收获  而不是仅仅只是搭了个中转站这种事情

本文重点将实践 也就是使用方法 有不懂原理的可以移步上文

那么 开始吧

目录

相信大家已经见过不少 ai的中转站   有没有想过自己搭建一个呢?先看看成品吧

在看这一篇之前  我是建议大家先去了解一下Springcloud Gateway的原理解读 就是我这篇文章《【云原生】Spring Cloud Gateway的底层原理与实践方法探究》

我一直秉持着知识需要成体系的原则去学习的 我希望大家也能在有限的时间里获得最大的收获  而不是仅仅只是搭了个中转站这种事情

本文重点将实践 也就是使用方法 有不懂原理的可以移步上文

那么 开始吧

前端部分

后端部分

准备工作

Spring Cloud Gateway入门

与Open AI对接

使用Spring Boot调用Open AI的API

添加Spring Cloud Gateway依赖

创建并配置OpenAiGatewayConfig类。

创建OpenAiService类。

配置应用程序属性。

启用Spring Cloud Gateway

配置负载均衡

发送请求到Spring Cloud Gateway

在上面的代码中,我们使用RestTemplate来发送请求到Spring Cloud Gateway的路由。Spring Cloud Gateway会将请求转发到OpenAI的API。这样就实现了基本的对话了!

利用Spring Cloud Gateway实现令牌记量和限制对话次数

创建TokenLimiterFilter类

启用TokenLimiterFilter

现在,当请求经过Spring Cloud Gateway时,它将拦截并使用TokenLimiterFilter进行处理。在TokenLimiterFilter中,就可以根据实际需求实现令牌记量和对话次数限制的逻辑!


前端部分

这边建议直接套chatWeb的模板   前端的实现不是这里的重点   当然有兴趣的同学可以去翻一下源码   我把连接放这了哈GitHub - SuSuZeer/chatgpt-web-with-recharge: 使用vue3搭建的chatgpt聊天页面 在此基础上接入后端 使用Spring Cloud Gateway作为网关 增加了token计量检测 可以在此基础上建立一个充值系统

后端部分

  1. 准备工作

    • 安装和配置Java开发环境
       
    • 安装和配置Java开发环境
    • 首先,确保你的计算机已经安装了Java开发工具包(JDK)。你可以从官方网站(https://www.oracle.com/java/technologies/javase-jdk15-downloads.html)下载并安装JDK。

      安装完成后,设置环境变量,以便Java开发工具包可以在计算机上被访问。在Windows系统上,可以按照以下步骤进行设置:

    • 打开控制面板并选择"系统和安全"。
    • 点击"系统",然后选择"高级系统设置"。
    • 在"高级"选项卡下,点击"环境变量"按钮。
    • 在"系统变量"部分,点击"新建"按钮。
    • 输入"JAVA_HOME"作为变量名,并将变量值设置为JDK安装目录的路径(例如:C:\Program Files\Java\jdk-15)。
    • 点击"确定"保存设置。
    • 在MacOS或Linux系统上,可以使用命令行设置环境变量。例如,在MacOS上,可以在终端中输入以下命令:

      export JAVA_HOME=/usr/lib/jvm/java-15-openjdk-amd64

    • 创建Spring Boot项目

      接下来,我们将使用Spring Initializr创建一个新的Spring Boot项目。打开你的文本编辑器,创建一个新的Java项目,并按照以下步骤进行设置:

    • 访问Spring Initializr网站(https://start.spring.io/)。
    • 在页面上选择所需的项目配置,包括构建工具(Maven或Gradle)、Spring Boot版本和项目元数据。
    • 在"Dependencies"部分,搜索并添加所需的依赖,如Spring Web、Spring Data JPA等。
    • 点击"Generate"按钮,下载生成的项目压缩文件。
    • 解压缩项目文件后,你就拥有一个基本的Spring Boot项目结构,可以开始进行开发。

    • 导入所需的依赖
      在项目的pom.xml文件中,你可以添加所需的依赖。例如,如果你需要使用Spring Web框架,可以添加以下依赖:
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

    • 注册Open AI账号并获取API密钥 
      这里的话 最近注册比较 难 需要找好一点的魔法还要国外的接平台  
      因为 有的节点 太多人用 他就会崩 
      当然了 相信很多人已经注册了账号了  那就按照官方的指示获取APIKey即可
  2. Spring Cloud Gateway入门

    • 了解API网关的概念和作用
      API网关是一个中间层,用于在后端服务和客户端之间提供统一的访问接口。它扮演着流量控制、安全认证、请求转发和协议转换等角色,简化了微服务架构中的复杂性。API网关可以集中处理共享的功能,如身份验证、授权、请求转发和负载均衡,从而减轻了后端服务的负担。
    • 使用Spring Cloud Gateway进行基本的路由配置
      <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-starter-gateway</artifactId>
      </dependency>

    • 实现请求转发和负载均衡   下文细讲此处
       
  3. 与Open AI对接

使用Spring Boot调用Open AI的API
 

添加Spring Cloud Gateway依赖

在项目的pom.xml文件中添加以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>com.openai</groupId>
    <artifactId>openai-java-sdk</artifactId>
    <version>1.0.0</version>
</dependency>

创建并配置OpenAiGatewayConfig类。

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;

@Configuration
public class OpenAiGatewayConfig {

    private final OpenAiService openAiService;

    public OpenAiGatewayConfig(OpenAiService openAiService) {
        this.openAiService = openAiService;
    }

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("openai_chat", r -> r.path("/openai/chat")
                        .and()
                        .method(HttpMethod.POST)
                        .filters(f -> f.filter((exchange, chain) -> {
                            // 获取请求参数,例如用户输入的对话消息
                            String message = exchange.getRequest().getBody().toString();
                            // 调用OpenAI API的Chat接口进行对话
                            String response = openAiService.chat(message);
                            // 返回OpenAI API的响应给客户端
                            return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(response.getBytes())));
                        }))
                        .uri("http://api.openai.com/v1/chat/completions")
                )
                .build();
    }
}

 创建了一个名为customRouteLocatorRouteLocator Bean,该Bean定义了一个路由规则,将请求路径为/openai/chat且HTTP方法为POST的请求转发到OpenAI API的Chat接口上。

创建OpenAiService类。

创建一个名为OpenAiService的服务类,用于与OpenAI API进行交互。示例代码如下:

import com.openai.OpenAiApi;
import com.openai.model.ChatCompletionRequest;
import com.openai.model.ChatCompletionResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class OpenAiService {

    @Value("${openai.api.key}")
    private String apiKey;

    public String chat(String message) {
        OpenAiApi openAiApi = new OpenAiApi(apiKey);
        ChatCompletionRequest request = new ChatCompletionRequest();
        // 设置Chat接口所需的参数
        // ...
        ChatCompletionResponse response = openAiApi.chatCompletion(request);
        // 处理Chat接口的响应,返回对话结果
        // ...
        return response.getText();
    }
}

使用OpenAI Java SDK来与OpenAI API进行交互。在chat方法中,根据OpenAI API文档中Chat接口的要求,设置请求参数并调用Chat接口,然后处理响应并返回对话结果。

配置应用程序属性。

application.properties(或application.yml)文件中,配置OpenAI API的密钥:openai.api.key=YOUR_OPENAI_API_KEY

启用Spring Cloud Gateway

在Spring Boot应用程序的入口类(例如BlogApplication.java)上添加@EnableGateway注解,以启用Spring Cloud Gateway。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration;

@SpringBootApplication(exclude = {
        GatewayAutoConfiguration.class,
        GatewayClassPathWarningAutoConfiguration.class,
        GatewayReactiveLoadBalancerClientAutoConfiguration.class
})
@EnableGateway
public class BlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class, args);
    }
}

配置负载均衡

如果你希望实现负载均衡,可以在application.properties文件中添加以下配置:

spring.cloud.gateway.discovery.locator.enabled=true

这将启用Spring Cloud Gateway与服务发现组件(如Eureka、Consul等)集成,以实现负载均衡。

发送请求到Spring Cloud Gateway

现在,你可以将请求发送到Spring Cloud Gateway的路由上,然后它会将请求转发到OpenAI的API。

准备一个Spring Boot控制器,用于处理与OpenAI相关的请求:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class OpenAIController {

    @Autowired
    private RestTemplate restTemplate;

    @PostMapping("/api/openai")
    public ResponseEntity<String> invokeOpenAI(@RequestBody String requestBody) {
        HttpHeaders headers = new HttpHeaders();
        headers.set(HttpHeaders.CONTENT_TYPE, "application/json");

        HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);

        return restTemplate.exchange("http://localhost:8080/api/openai", HttpMethod.POST, requestEntity, String.class);
    }
}

在上面的代码中,我们使用RestTemplate来发送请求到Spring Cloud Gateway的路由。Spring Cloud Gateway会将请求转发到OpenAI的API。这样就实现了基本的对话了!



利用Spring Cloud Gateway实现令牌记量和限制对话次数

创建TokenLimiterFilter类

首先,创建一个名为TokenLimiterFilter.java的类,它将实现全局过滤器接口GlobalFilterOrdered接口。

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class TokenLimiterFilter implements GlobalFilter, Ordered {

    private static final String API_KEY_HEADER = "X-API-Key";
    private static final int MAX_REQUESTS_PER_MINUTE = 100;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String apiKey = request.getHeaders().getFirst(API_KEY_HEADER);

        // 检查 API Key 是否有效
        if (isValidApiKey(apiKey)) {
            // 检查对话次数是否超过限制
            if (isWithinRateLimit(apiKey)) {
                // 更新对话次数计数器
                updateRequestCount(apiKey);
                return chain.filter(exchange);
            } else {
                // 对话次数超过限制,返回错误响应
                exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                return exchange.getResponse().setComplete();
            }
        } else {
            // 无效的 API Key,返回错误响应
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
    }

    private boolean isValidApiKey(String apiKey) {
        // 根据实际逻辑检查 API Key 的有效性
        // 返回 true 表示 API Key 有效,返回 false 表示无效
        return /* 根据实际逻辑进行判断 */;
    }

    private boolean isWithinRateLimit(String apiKey) {
        // 根据实际逻辑检查对话次数是否超过限制
        // 返回 true 表示对话次数未超过限制,返回 false 表示超过限制
        int requestCount = /* 根据实际逻辑获取对话次数 */;
        return requestCount < MAX_REQUESTS_PER_MINUTE;
    }

    private void updateRequestCount(String apiKey) {
        // 根据实际逻辑更新对话次数计数器
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}

在上面的代码中,我们实现了filter方法,在该方法中执行了以下操作:

  • 获取请求中的API Key。
  • 检查API Key是否有效。
  • 检查对话次数是否超过限制。
  • 根据结果返回相应的响应给客户端。

启用TokenLimiterFilter

在Spring Boot应用程序的入口类(例如BlogApplication.java)上添加@EnableGateway注解,以启用Spring Cloud Gateway,并通过@ComponentScan注解扫描并启用TokenLimiterFilter

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayReactiveLoadBalancerClientAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication(exclude = {
        GatewayAutoConfiguration.class,
        GatewayClassPathWarningAutoConfiguration.class,
        GatewayReactiveLoadBalancerClientAutoConfiguration.class
})
@EnableGateway
@ComponentScan(basePackages = "com.example.gateway")
@RestController
public class BlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class, args);
    }
}

现在,当请求经过Spring Cloud Gateway时,它将拦截并使用TokenLimiterFilter进行处理。在TokenLimiterFilter中,就可以根据实际需求实现令牌记量和对话次数限制的逻辑!

发表评论:

Powered By Z-BlogPHP 1.7.3

© 2018-2020 有趣的地方 粤ICP备18140861号-1 网站地图