feat: 集成 Spring AI 框架,实现基础的 AI 写作功能

This commit is contained in:
xiongxiaoyang 2025-02-19 23:44:29 +08:00
parent 295a9096b5
commit 9f71aa4a59
6 changed files with 210 additions and 22 deletions

View File

@ -41,28 +41,29 @@ novel 是一套基于时下**最新** Java 技术栈 Spring Boot 3 + Vue 3 开
## 后端技术选型
| 技术 | 版本 | 说明 | 官网 | 学习 |
|---------------------|:--------------:|---------------------| --------------------------------------- |:-----------------------------------------------------------------------------------------------------------------------------:|
| Spring Boot | 3.0.0 | 容器 + MVC 框架 | [进入](https://spring.io/projects/spring-boot) | [进入](https://docs.spring.io/spring-boot/docs/3.0.0/reference/html) |
| MyBatis | 3.5.9 | ORM 框架 | [进入](http://www.mybatis.org) | [进入](https://mybatis.org/mybatis-3/zh/index.html) |
| MyBatis-Plus | 3.5.3 | MyBatis 增强工具 | [进入](https://baomidou.com/) | [进入](https://baomidou.com/pages/24112f/) |
| JJWT | 0.11.5 | JWT 登录支持 | [进入](https://github.com/jwtk/jjwt) | - |
| Lombok | 1.18.24 | 简化对象封装工具 | [进入](https://github.com/projectlombok/lombok) | [进入](https://projectlombok.org/features/all) |
| Caffeine | 3.1.0 | 本地缓存支持 | [进入](https://github.com/ben-manes/caffeine) | [进入](https://github.com/ben-manes/caffeine/wiki/Home-zh-CN) |
| Redis | 7.0 | 分布式缓存支持 | [进入](https://redis.io) | [进入](https://redis.io/docs) |
| Redisson | 3.17.4 | 分布式锁实现 | [进入](https://github.com/redisson/redisson) | [进入](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) |
| MySQL | 8.0 | 数据库服务 | [进入](https://www.mysql.com) | [进入](https://docs.oracle.com/en-us/iaas/mysql-database/doc/getting-started.html) |
| ShardingSphere-JDBC | 5.1.1 | 数据库分库分表支持 | [进入](https://shardingsphere.apache.org) | [进入](https://shardingsphere.apache.org/document/5.1.1/cn/overview) |
| Elasticsearch | 8.2.0 | 搜索引擎服务 | [进入](https://www.elastic.co) | [进入](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) |
| RabbitMQ | 3.10.2 | 开源消息中间件 | [进入](https://www.rabbitmq.com) | [进入](https://www.rabbitmq.com/tutorials/tutorial-one-java.html) |
| XXL-JOB | 2.3.1 | 分布式任务调度平台 | [进入](https://www.xuxueli.com/xxl-job) | [进入](https://www.xuxueli.com/xxl-job) |
| Sentinel | 1.8.4 | 流量控制组件 | [进入](https://github.com/alibaba/Sentinel) | [进入](https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5) |
| Springdoc-openapi | 2.0.0 | Swagger 3 接口文档自动生成 | [进入](https://github.com/springdoc/springdoc-openapi) | [进入](https://springdoc.org/) |
| Spring Boot Admin | 3.0.0-M1 | 应用管理和监控 | [进入](https://github.com/codecentric/spring-boot-admin) | [进入](https://codecentric.github.io/spring-boot-admin/3.0.0-M1) |
| Undertow | 2.2.17.Final | Java 开发的高性能 Web 服务器 | [进入](https://undertow.io) | [进入](https://undertow.io/documentation.html) |
| Docker | - | 应用容器引擎 | [进入](https://www.docker.com/) | - |
| Jenkins | - | 自动化部署工具 | [进入](https://github.com/jenkinsci/jenkins) | - |
| Sonarqube | - | 代码质量控制 | [进入](https://www.sonarqube.org/) | - |
| 技术 | 版本 | 说明 | 官网 | 学习 |
|---------------------|:------------:|---------------------| ------------------------------------- |:------------------------------------------------------------------------------------------------------------------------:|
| Spring Boot | 3.3.0 | 容器 + MVC 框架 | [进入](https://spring.io/projects/spring-boot) | [进入](https://docs.spring.io/spring-boot/docs/3.0.0/reference/html) |
| Spring AI | 1.0.0-SNAPSHOT | Spring 官方 AI 框架 | [进入](https://spring.io/projects/spring-ai) | [进入](https://docs.spring.io/spring-ai/reference/) |
| MyBatis | 3.5.9 | ORM 框架 | [进入](http://www.mybatis.org) | [进入](https://mybatis.org/mybatis-3/zh/index.html) |
| MyBatis-Plus | 3.5.3 | MyBatis 增强工具 | [进入](https://baomidou.com/) | [进入](https://baomidou.com/pages/24112f/) |
| JJWT | 0.11.5 | JWT 登录支持 | [进入](https://github.com/jwtk/jjwt) | - |
| Lombok | 1.18.24 | 简化对象封装工具 | [进入](https://github.com/projectlombok/lombok) | [进入](https://projectlombok.org/features/all) |
| Caffeine | 3.1.0 | 本地缓存支持 | [进入](https://github.com/ben-manes/caffeine) | [进入](https://github.com/ben-manes/caffeine/wiki/Home-zh-CN) |
| Redis | 7.0 | 分布式缓存支持 | [进入](https://redis.io) | [进入](https://redis.io/docs) |
| Redisson | 3.17.4 | 分布式锁实现 | [进入](https://github.com/redisson/redisson) | [进入](https://github.com/redisson/redisson/wiki/%E7%9B%AE%E5%BD%95) |
| MySQL | 8.0 | 数据库服务 | [进入](https://www.mysql.com) | [进入](https://docs.oracle.com/en-us/iaas/mysql-database/doc/getting-started.html) |
| ShardingSphere-JDBC | 5.1.1 | 数据库分库分表支持 | [进入](https://shardingsphere.apache.org) | [进入](https://shardingsphere.apache.org/document/5.1.1/cn/overview) |
| Elasticsearch | 8.2.0 | 搜索引擎服务 | [进入](https://www.elastic.co) | [进入](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) |
| RabbitMQ | 3.10.2 | 开源消息中间件 | [进入](https://www.rabbitmq.com) | [进入](https://www.rabbitmq.com/tutorials/tutorial-one-java.html) |
| XXL-JOB | 2.3.1 | 分布式任务调度平台 | [进入](https://www.xuxueli.com/xxl-job) | [进入](https://www.xuxueli.com/xxl-job) |
| Sentinel | 1.8.4 | 流量控制组件 | [进入](https://github.com/alibaba/Sentinel) | [进入](https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5) |
| Springdoc-openapi | 2.0.0 | Swagger 3 接口文档自动生成 | [进入](https://github.com/springdoc/springdoc-openapi) | [进入](https://springdoc.org/) |
| Spring Boot Admin | 3.0.0-M1 | 应用管理和监控 | [进入](https://github.com/codecentric/spring-boot-admin) | [进入](https://codecentric.github.io/spring-boot-admin/3.0.0-M1) |
| Undertow | 2.2.17.Final | Java 开发的高性能 Web 服务器 | [进入](https://undertow.io) | [进入](https://undertow.io/documentation.html) |
| Docker | - | 应用容器引擎 | [进入](https://www.docker.com/) | - |
| Jenkins | - | 自动化部署工具 | [进入](https://github.com/jenkinsci/jenkins) | - |
| Sonarqube | - | 代码质量控制 | [进入](https://www.sonarqube.org/) | - |
**注:更多热门新技术待集成。**

34
pom.xml
View File

@ -177,6 +177,12 @@
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<!-- AI -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
@ -212,6 +218,18 @@
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
@ -248,6 +266,22 @@
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>

View File

@ -0,0 +1,83 @@
package io.github.xxyopen.novel.controller.author;
import io.github.xxyopen.novel.core.common.resp.RestResp;
import io.github.xxyopen.novel.core.constant.ApiRouterConsts;
import io.github.xxyopen.novel.core.constant.SystemConfigConsts;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 作家后台-AI模块API控制器
*
* @author xiongxiaoyang
* @date 2025/2/19
*/
@Tag(name = "AiController", description = "作家后台-AI模块")
@SecurityRequirement(name = SystemConfigConsts.HTTP_AUTH_HEADER_NAME)
@RestController
@RequestMapping(ApiRouterConsts.API_AUTHOR_AI_URL_PREFIX)
@RequiredArgsConstructor
public class AuthorAiController {
private final ChatClient chatClient;
/**
* AI扩写
*/
@Operation(summary = "AI扩写接口")
@PostMapping("/expand")
public RestResp<String> expandText(@RequestParam("text") String text, @RequestParam("ratio") Double ratio) {
String prompt = "请将以下文本扩写为原长度的" + ratio/100 + "倍:" + text;
return RestResp.ok(chatClient.prompt()
.user(prompt)
.call()
.content());
}
/**
* AI缩写
*/
@Operation(summary = "AI缩写接口")
@PostMapping("/condense")
public RestResp<String> condenseText(@RequestParam("text") String text, @RequestParam("ratio") Integer ratio) {
String prompt = "请将以下文本缩写为原长度的" + 100/ratio + "分之一:" + text;
return RestResp.ok(chatClient.prompt()
.user(prompt)
.call()
.content());
}
/**
* AI续写
*/
@Operation(summary = "AI续写接口")
@PostMapping("/continue")
public RestResp<String> continueText(@RequestParam("text") String text, @RequestParam("length") Integer length) {
String prompt = "请续写以下文本,续写长度约为" + length + "字:" + text;
return RestResp.ok(chatClient.prompt()
.user(prompt)
.call()
.content());
}
/**
* AI润色
*/
@Operation(summary = "AI润色接口")
@PostMapping("/polish")
public RestResp<String> polishText(@RequestParam("text") String text) {
String prompt = "请润色优化以下文本,保持原意:" + text;
return RestResp.ok(chatClient.prompt()
.user(prompt)
.call()
.content());
}
}

View File

@ -0,0 +1,47 @@
package io.github.xxyopen.novel.core.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestClient;
/**
* Ai 相关配置
*
* @author xiongxiaoyang
* @date 2025/2/19
*/
@Configuration
@Slf4j
public class AiConfig {
/**
* 目的配置自定义的 RestClientBuilder 对象
* <p>
* 原因Spring AI 框架的 ChatClient 内部通过 RestClientSpring Framework 6 Spring Boot 3 中引入 发起 HTTP REST 请求与远程的大模型服务进行通信
* 如果项目中没有配置自定义的 RestClientBuilder 对象 那么在 RestClient 的自动配置类 org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration
* 中配置的 RestClientBuilder 对象会使用 Spring 容器中提供的 HttpMessageConverters 由于本项目中配置了 spring.jackson.generator.write-numbers-as-strings
* = true 所以 Spring 容器中的 HttpMessageConverters RestClient 发起 HTTP REST 请求转换 Java 对象为 JSON 字符串时会自动将 Number 类型的
* Java 对象属性转换为字符串而导致请求参数错误
* <p>
* 示例"temperature": 0.7 ="temperature": "0.7"
* {"code":20015,"message":"The parameter is invalid. Please check again.","data":null}
*/
@Bean
public RestClient.Builder restClientBuilder() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 连接超时时间
factory.setConnectTimeout(5000);
// 读取超时时间
factory.setReadTimeout(60000);
return RestClient.builder().requestFactory(factory);
}
@Bean
public ChatClient chatClient(ChatClient.Builder chatClientBuilder) {
return chatClientBuilder.build();
}
}

View File

@ -62,6 +62,11 @@ public class ApiRouterConsts {
*/
public static final String SEARCH_URL_PREFIX = "/search";
/**
* AI模块请求路径前缀
*/
public static final String AI_URL_PREFIX = "/ai";
/**
* 前台门户首页API请求路径前缀
*/
@ -94,4 +99,10 @@ public class ApiRouterConsts {
public static final String API_FRONT_SEARCH_URL_PREFIX =
API_FRONT_URL_PREFIX + SEARCH_URL_PREFIX;
/**
* 作家后台AI相关API请求路径前缀
*/
public static final String API_AUTHOR_AI_URL_PREFIX = API_AUTHOR_URL_PREFIX + AI_URL_PREFIX;
}

View File

@ -34,6 +34,18 @@ server:
# 端口号
port: 8888
--- #--------------------- Spring AI 配置----------------------
spring:
ai:
openai:
api-key:
base-url: https://api.siliconflow.cn
chat:
options:
model: deepseek-ai/DeepSeek-R1-Distill-Llama-8B
--- #---------------------数据库配置---------------------------
spring:
datasource: