mirror of
https://github.com/201206030/novel.git
synced 2025-04-27 07:30:50 +00:00
feat: 集成 Spring AI 框架,实现基础的 AI 写作功能
This commit is contained in:
parent
295a9096b5
commit
9f71aa4a59
@ -42,8 +42,9 @@ 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) |
|
| 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 | 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/) |
|
| MyBatis-Plus | 3.5.3 | MyBatis 增强工具 | [进入](https://baomidou.com/) | [进入](https://baomidou.com/pages/24112f/) |
|
||||||
| JJWT | 0.11.5 | JWT 登录支持 | [进入](https://github.com/jwtk/jjwt) | - |
|
| JJWT | 0.11.5 | JWT 登录支持 | [进入](https://github.com/jwtk/jjwt) | - |
|
||||||
|
34
pom.xml
34
pom.xml
@ -177,6 +177,12 @@
|
|||||||
<artifactId>spring-boot-starter-mail</artifactId>
|
<artifactId>spring-boot-starter-mail</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- AI -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.mysql</groupId>
|
<groupId>com.mysql</groupId>
|
||||||
<artifactId>mysql-connector-j</artifactId>
|
<artifactId>mysql-connector-j</artifactId>
|
||||||
@ -212,6 +218,18 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</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>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@ -248,6 +266,22 @@
|
|||||||
<enabled>false</enabled>
|
<enabled>false</enabled>
|
||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</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>
|
</repositories>
|
||||||
<pluginRepositories>
|
<pluginRepositories>
|
||||||
<pluginRepository>
|
<pluginRepository>
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 内部通过 RestClient(Spring 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -62,6 +62,11 @@ public class ApiRouterConsts {
|
|||||||
*/
|
*/
|
||||||
public static final String SEARCH_URL_PREFIX = "/search";
|
public static final String SEARCH_URL_PREFIX = "/search";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI模块请求路径前缀
|
||||||
|
*/
|
||||||
|
public static final String AI_URL_PREFIX = "/ai";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前台门户首页API请求路径前缀
|
* 前台门户首页API请求路径前缀
|
||||||
*/
|
*/
|
||||||
@ -94,4 +99,10 @@ public class ApiRouterConsts {
|
|||||||
public static final String API_FRONT_SEARCH_URL_PREFIX =
|
public static final String API_FRONT_SEARCH_URL_PREFIX =
|
||||||
API_FRONT_URL_PREFIX + 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;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,18 @@ server:
|
|||||||
# 端口号
|
# 端口号
|
||||||
port: 8888
|
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:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user