mirror of
https://github.com/201206030/novel.git
synced 2025-07-17 01:36:37 +00:00
feat: 集成 Spring AI 框架,实现基础的 AI 写作功能
This commit is contained in:
@ -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";
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
|
||||
}
|
||||
|
@ -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:
|
||||
|
Reference in New Issue
Block a user