day2
学习git的基本操作:
- git clone url
- cd 文件夹
- git fetch origin dev 拉取分支 git pull
- git switch dev 切换分支
- 提交并推送
新增接口:案件查询删除、报告查询删除、目录查询
CaseController.Java
package com.fj.report.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fj.report.entity.SysCaseFile;
import com.fj.report.entity.SysCaseInfo;
import com.fj.report.service.SysCaseFileService;
import com.fj.report.service.SysCaseInfoService;
import com.fj.report.vo.MaterialGroupVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/case-select")
@Tag(name = "案件管理", description = "案件相关操作API")
public class CaseController {
@Autowired
private SysCaseInfoService sysCaseInfoService;
@Autowired
private SysCaseFileService sysCaseFileService;
/**
* 分页查询案件列表
*/
@GetMapping("/list")
@Operation(summary = "分页查询案件列表")
public ResponseEntity<IPage<SysCaseInfo>> listCases(
@Parameter(description = "当前页") @RequestParam(defaultValue = "1") Long pageNum,
@Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long pageSize,
@Parameter(description = "案件名称") @RequestParam(required = false) String caseName) {
Page<SysCaseInfo> page = new Page<>(pageNum, pageSize);
IPage<SysCaseInfo> result = sysCaseInfoService.lambdaQuery()
.like(caseName != null, SysCaseInfo::getCaseName, caseName)
.eq(SysCaseInfo::getStatus, 1) // 查询有效案件
.orderByDesc(SysCaseInfo::getCreateTime)
.page(page);
return ResponseEntity.ok(result);
}
/**
* 新增案件
*/
@PostMapping
@Operation(summary = "新增案件")
public ResponseEntity<String> addCase(
@RequestBody SysCaseInfo caseInfo) {
// 设置初始值
caseInfo.setStatus(1); // 有效
caseInfo.setProcessStatus(0); // 待处理
caseInfo.setCreateTime(java.time.LocalDateTime.now());
boolean success = sysCaseInfoService.save(caseInfo);
return success ? ResponseEntity.ok("案件添加成功")
: ResponseEntity.status(500).body("案件添加失败");
}
/**
* 删除案件(逻辑删除)
*/
@DeleteMapping("/{caseId}")
@Operation(summary = "删除案件")
public ResponseEntity<String> deleteCase(
@Parameter(description = "案件ID") @PathVariable Long caseId) {
boolean success = sysCaseInfoService.removeById(caseId);
return success ? ResponseEntity.ok("案件删除成功")
: ResponseEntity.status(500).body("案件删除失败");
}
/**
* 获取案件下的材料分组列表
* 对应页面:原始目录、材料目录等分类
*/
@GetMapping("/{caseId}/materials")
@Operation(summary = "获取案件材料分组列表")
public ResponseEntity<List<MaterialGroupVO>> getMaterialGroups(
@Parameter(description = "案件ID") @PathVariable Long caseId) {
List<MaterialGroupVO> groups = sysCaseFileService.getMaterialGroupsByCaseId(caseId);
return ResponseEntity.ok(groups);
}
/**
* 搜索案件内的文件
*/
@GetMapping("/{caseId}/files/search")
@Operation(summary = "搜索案件内的文件")
public ResponseEntity<?> searchFiles(
@Parameter(description = "案件ID") @PathVariable Long caseId,
@Parameter(description = "搜索关键词") @RequestParam String keyword) {
var files = sysCaseFileService.searchFiles(caseId, keyword);
return ResponseEntity.ok(files);
}
/**
* 获取特定材料类型下的所有文件
*/
@GetMapping("/{caseId}/materials/{materialTypeId}/files")
@Operation(summary = "获取指定材料类型的文件列表")
public ResponseEntity<?> getFilesByMaterial(
@Parameter(description = "案件ID") @PathVariable Long caseId,
@Parameter(description = "材料类型ID") @PathVariable Long materialTypeId) {
var files = sysCaseFileService.getFilesByMaterialType(caseId, materialTypeId);
return ResponseEntity.ok(files);
}
}
SysCaseFileService.Java
package com.fj.report.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fj.report.entity.SysCaseFile;
import com.fj.report.vo.MaterialGroupVO;
import java.util.List;
/**
* 案件文件服务接口
*/
public interface SysCaseFileService extends IService<SysCaseFile> {
/**
* 根据案件ID查询分组后的材料及文件
* @param caseId 案件ID
* @return 按材料类型分组的文件列表
*/
List<MaterialGroupVO> getMaterialGroupsByCaseId(Long caseId);
/**
* 根据案件ID和材料类型ID查询文件列表
* @param caseId 案件ID
* @param materialTypeId 材料类型ID
* @return 文件列表
*/
List<SysCaseFile> getFilesByMaterialType(Long caseId, Long materialTypeId);
/**
* 搜索文件(按文件名)
* @param caseId 案件ID
* @param keyword 关键词
* @return 匹配的文件列表
*/
List<SysCaseFile> searchFiles(Long caseId, String keyword);
}
SysCaseFileServiceImpl.Java
package com.fj.report.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fj.report.entity.SysCaseCatalog;
import com.fj.report.entity.SysCaseFile;
import com.fj.report.entity.SysMaterials;
import com.fj.report.mapper.SysCaseFileMapper;
import com.fj.report.mapper.SysMaterialsMapper;
import com.fj.report.service.SysCaseFileService;
import com.fj.report.vo.CaseFileVO;
import com.fj.report.vo.MaterialGroupVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 案件文件服务实现类
*
* @author fj
*/
@Service
public class SysCaseFileServiceImpl extends ServiceImpl<SysCaseFileMapper, SysCaseFile> implements SysCaseFileService {
@Autowired
private SysMaterialsMapper sysMaterialsMapper;
/**
* 根据案件ID查询分组后的材料及文件
*
* @param caseId 案件ID
* @return 按材料类型分组的文件列表
*/
@Override
public List<MaterialGroupVO> getMaterialGroupsByCaseId(Long caseId) {
// 1. 查询该案件下的所有文件
List<SysCaseFile> caseFiles = this.lambdaQuery()
.eq(SysCaseFile::getCaseId, caseId)
.orderByAsc(SysCaseFile::getMaterialTypeId)
.list();
if(caseFiles.isEmpty()){
return new ArrayList<>();
}
// 2. 根据文件的材料类型进行分组
Map<Long, List<SysCaseFile>> groupedFiles = caseFiles.stream()
.collect(Collectors.groupingBy(SysCaseFile::getMaterialTypeId));
// 3. 构建 MaterialGroupVO 列表返回
List<MaterialGroupVO> result = new ArrayList<>();
for(Map.Entry<Long, List<SysCaseFile>> entry : groupedFiles.entrySet()){
Long materialTypeId = entry.getKey();
List<SysCaseFile> files = entry.getValue();
// 获取材料类型信息
SysMaterials material = sysMaterialsMapper.selectById(materialTypeId);
MaterialGroupVO group = new MaterialGroupVO();
group.setMaterialTypeId(materialTypeId);
group.setMaterialTypeName(material != null ? material.getMaterialTypeName() : "未知类型");
group.setFileCount(files.size());
// 转换为VO
List<CaseFileVO> fileVOs = files.stream()
.map(file -> {
CaseFileVO vo = new CaseFileVO();
vo.setCaseFileId(file.getCaseFileId());
vo.setFileName(file.getFileName());
vo.setFileId(file.getFileId());
vo.setCreateTime(file.getCreateTime());
vo.setCreateBy(file.getCreateBy());
return vo;
})
.collect(Collectors.toList());
group.setFiles(fileVOs);
result.add(group);
}
return result;
}
@Override
public List<SysCaseFile> getFilesByMaterialType(Long caseId, Long materialTypeId) {
return this.lambdaQuery()
.eq(SysCaseFile::getCaseId, caseId)
.eq(SysCaseFile::getMaterialTypeId, materialTypeId)
.list();
}
@Override
public List<SysCaseFile> searchFiles(Long caseId, String keyword) {
return this.lambdaQuery()
.eq(SysCaseFile::getCaseId, caseId)
.like(SysCaseFile::getFileName, keyword)
.list();
}
}
CaseFileVO.Java
package com.fj.report.vo;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 案件文件VO
*/
@Data
public class CaseFileVO {
/**
* 案件文件ID
*/
private Long caseFileId;
/**
* 文件名
*/
private String fileName;
/**
* 文件ID
*/
private Long fileId;
/**
* 创建时间
*/
private LocalDateTime createTime;
/**
* 创建人
*/
private Long createBy;
}
材料视图类:
package com.fj.report.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 材料类型及其文件分组VO
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MaterialGroupVO {
/**
* 材料类型ID
*/
private Long materialTypeId;
/**
* 材料类型名称
*/
private String materialTypeName;
/**
* 该类型下的文件列表
*/
private List<CaseFileVO> files;
/**
* 文件数量
*/
private Integer fileCount;
}
报告:
ReportController.Java
package com.fj.report.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fj.report.entity.SysReportInfo;
import com.fj.report.service.SysReportInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/doc-manage")
@Tag(name = "报告管理", description = "报告相关操作API")
public class ReportController {
@Autowired
private SysReportInfoService sysReportInfoService;
/**
* 分页查询报告列表
*/
@GetMapping("/list")
@Operation(summary = "分页查询报告列表")
public ResponseEntity<IPage<SysReportInfo>> listReports(
@Parameter(description = "当前页") @RequestParam(defaultValue = "1") Long pageNum,
@Parameter(description = "每页条数") @RequestParam(defaultValue = "10") Long pageSize,
@Parameter(description = "报告名称") @RequestParam(required = false) String reportName
){
Page<SysReportInfo> page = new Page<>(pageNum, pageSize);
IPage<SysReportInfo> result = sysReportInfoService.lambdaQuery()
.like(reportName != null, SysReportInfo::getReportName, reportName)
.eq(SysReportInfo::getStatus, 1) // 查询有效报告
.orderByDesc(SysReportInfo::getCreateTime)
.page(page);
return ResponseEntity.ok(result);
}
/**
* 删除报告
*/
@DeleteMapping("/{reportId}")
@Operation(summary = "删除报告")
public ResponseEntity<String> deleteReport(
@Parameter(description = "报告ID") @PathVariable Long reportId
){
boolean success = sysReportInfoService.removeById(reportId);
return success ? ResponseEntity.ok("报告删除成功")
: ResponseEntity.status(500).body("报告删除失败");
}
}
新增调用SpringAI实现应答:
添加配置:
spring:
# 数据源配置
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://39.103.56.106:15432/fj_report_test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: Bzfurniture@2025
hikari:
minimum-idle: 5
maximum-pool-size: 30
connection-timeout: 5000
idle-timeout: 600000
max-lifetime: 1200000
leak-detection-threshold: 10000
# Redis配置
data:
redis:
host: 39.103.56.106
port: 16379
password: Ht5#bLk8$nMq4xZ
database: 0
timeout: 3000ms
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: -1ms
# Kafka配置
kafka:
bootstrap-servers: 39.103.56.106:19092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
acks: all
retries: 3
consumer:
group-id: fj-report-server-dev
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
auto-offset-reset: earliest
enable-auto-commit: true
# Spring AI Alibaba配置
ai:
# 阿里云DashScope配置
alibaba:
dashscope:
api-key: "sk-your-aliyun-api-key" # 阿里云API Key
chat:
options:
model: "qwen-max" # 这里不能用DeepSeek-V3,要用阿里云的模型
temperature: 0.1
# OpenAI兼容配置(用于第三方兼容接口)
openai:
api-key: "sk-HmCbA0klDAA9po6o210b9a033cF0420eAf2585B9B87d6740" # 第三方API Key
base-url: "https://one-api.maas.com.cn" # 注意:去掉 /chat/completions
chat:
options:
model: "deepseek-chat" # 模型名称
temperature: 0.1
max-tokens: 2000
# SpringDoc OpenAPI (Swagger) 配置 - 开发环境
springdoc:
swagger-ui:
enabled: true
api-docs:
enabled: true
aliyun:
# 阿里云OSS配置
cloud:
access-key: LTAI5t61NaouEwRGAYFaSnJH
secret-key: sG2D7OXI0sJrnE5HqguNwzT2hBWCpZ
oss:
endpoint: oss-cn-beijing.aliyuncs.com
bucket-name: server-zs
# 可选配置
region: cn-beijing
# 多租户模式下可为每个租户配置目录前缀
tenant-path-prefix: tenant/
# 访问图片URL时对图片进行固定宽度处理为200px
url-style: ${OSS_URL_STYLE:?x-oss-process=image/resize,w_200}
# 角色ARN,用于权限管理 办法sts凭证
# arn: acs:ram::1254456248189381:role/aliyunossrole
# 日志级别
logging:
level:
root: INFO
com.fj.report: DEBUG
org.springframework.jdbc.core: DEBUG
org.apache.ibatis: DEBUG
com.baomidou.mybatisplus: DEBUG
添加依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.1</version>
<relativePath/>
</parent>
<groupId>com.fj.report</groupId>
<artifactId>fj-report-server</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>fj-report-server</name>
<description>Spring Boot服务用于报告生成和管理</description>
<properties>
<java.version>21</java.version>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- 依赖版本管理 -->
<mybatis-plus.version>3.5.7</mybatis-plus.version>
<postgresql.version>42.7.3</postgresql.version>
<spring-ai.version>1.0.0-M4</spring-ai.version>
<lombok.version>1.18.30</lombok.version>
<poi.version>5.2.4</poi.version>
<itext.version>7.2.5</itext.version>
<aliyun.oss.version>3.18.3</aliyun.oss.version>
<aliyun.oss.sts.version>3.1.0</aliyun.oss.sts.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- Spring AI BOM -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>${spring-ai.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- MyBatis Plus (Spring Boot 3.x 专用) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
<!-- PostgreSQL Driver -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql.version}</version>
</dependency>
<!-- Spring Boot Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Spring Kafka -->
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
<!-- Spring AI OpenAI Spring Boot Starter -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<!-- Spring Boot Configuration Processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- SpringDoc OpenAPI (Swagger) -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.1</version>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 阿里云OSS -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>aliyun-java-sdk-sts</artifactId>
<version>${aliyun.oss.sts.version}</version>
</dependency>
<!-- Excel处理 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<!-- PDF处理 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>kernel</artifactId>
<version>${itext.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>layout</artifactId>
<version>${itext.version}</version>
</dependency>
</dependencies>
<build>
<finalName>fj-report-server</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<!-- 阿里云仓库 -->
<repository>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<!-- Spring AI Alibaba 快照仓库 -->
<repository>
<id>sonatype-snapshots</id>
<name>Sonatype Snapshots</name>
<url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<!-- Spring里程碑仓库 -->
<repository>
<id>spring-milestone</id>
<name>Spring Milestone Repository</name>
<url>https://repo.spring.io/milestone</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<!-- Maven 中央仓库 -->
<repository>
<id>central</id>
<name>Maven Central</name>
<url>https://repo1.maven.org/maven2/</url>
</repository>
</repositories>
</project>
创建AI配置类 AiConfig.Java:
package com.fj.report.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* AI配置类 - 使用 Spring AI OpenAI
* Spring Boot 自动配置会根据 application-dev.yml 的配置创建 ChatModel Bean
*
* @author fj
*/
@Slf4j
@Configuration
public class AiConfig {
/**
* 创建 ChatClient Bean
* ChatModel 由 Spring AI OpenAI 自动配置提供
*/
@Bean
public ChatClient chatClient(ChatModel chatModel) {
log.info("初始化 ChatClient");
log.info("ChatModel 实现类: {}", chatModel.getClass().getName());
return ChatClient.builder(chatModel)
.defaultSystem("你是一个专业的文档分析和内容生成助手。" +
"能够根据提供的材料生成专业、准确、结构清晰的报告。" +
"请确保内容完整、逻辑严密、表达准确。")
.build();
}
}
创建Controller:
package com.fj.report.controller;
import com.fj.report.dto.MaterialsPromptsRequest;
import com.fj.report.service.AiService;
import com.fj.report.vo.ArticleVos;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.stream.Collectors;
/**
* 材料 + 提示词生成结果控制器
*
* @author fj
*/
@Slf4j
@RestController
@RequestMapping("materials-prompts")
@Tag(name = "材料 + 提示词生成结果", description = "材料 + 提示词生成结果相关操作API")
public class MaterialsPromptsController {
@Autowired
private AiService aiService;
/**
* 材料 + 提示词生成结果(流式方式)
*/
@Operation(summary = "流式生成分析报告", description = "根据材料和提示词流式生成分析报告")
@PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> generateOutputStream(@RequestBody MaterialsPromptsRequest request) {
log.info("接收到流式材料生成请求,材料数: {}, 提示词: {}",
request.getArticles().size(), request.getSystemPrompt());
return aiService.generateFromArticlesStream(request.getArticles(), request.getSystemPrompt());
}
}
创建AIservice:
package com.fj.report.service;
import com.fj.report.vo.ArticleVos;
import reactor.core.publisher.Flux;
import java.util.List;
/**
* AI 服务接口
*/
public interface AiService {
/**
* 调用大模型生成文本(同步)
*/
String generateText(String prompt);
/**
* 调用大模型(带系统提示词)
*/
String generateWithSystemPrompt(String systemPrompt, String userPrompt);
/**
* 流式响应
*/
Flux<String> generateStream(String prompt);
/**
* 流式响应(带系统提示词)
*/
Flux<String> generateStreamWithSystemPrompt(String systemPrompt, String userPrompt);
/**
* 从材料列表生成内容(同步)
*/
Flux<String> generateFromArticlesStream(List<ArticleVos> articles, String systemPrompt);
}
实现接口:
package com.fj.report.service.impl;
import com.fj.report.service.AiService;
import com.fj.report.vo.ArticleVos;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import java.util.List;
import java.util.stream.Collectors;
@Slf4j
@Service
public class AiServiceImpl implements AiService
{
private final ChatClient chatClient;
@Autowired
public AiServiceImpl(ChatClient chatClient) {
this.chatClient = chatClient;
}
@Override
public String generateText(String prompt) {
log.info("接收到的提示词:{}", prompt);
return chatClient.prompt()
.user(prompt)
.call()
.content();
}
@Override
public String generateWithSystemPrompt(String systemPrompt, String userPrompt) {
return chatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.call()
.content();
}
@Override
public Flux<String> generateStream(String prompt) {
return chatClient.prompt()
.user(prompt)
.stream()
.content()
.doOnError(e -> log.error("流式响应出错:", e))
.doOnComplete(() -> log.info("流式响应完成"));
}
@Override
public Flux<String> generateStreamWithSystemPrompt(String systemPrompt, String userPrompt) {
return chatClient.prompt()
.system(systemPrompt)
.user(userPrompt)
.stream()
.content()
.doOnError(e -> log.error("流式响应出错:", e))
.doOnComplete(() -> log.info("流式响应完成"));
}
@Override
public Flux<String> generateFromArticlesStream(List<ArticleVos> articles, String systemPrompt) {
// 拼接材料内容
String combinedContent = articles.stream()
.map(article ->"文件名:" + article.getFileName() + "\n内容:" + article.getContent())
.collect(Collectors.joining("\n\n"));
log.info("拼接后的内容为:{}", combinedContent);
return generateStreamWithSystemPrompt(systemPrompt, combinedContent)
.doOnError(e -> log.error("流式从文章内容生成文本失败: {}", e.getMessage(), e));}
}
实现视图类:
package com.fj.report.vo;
import lombok.Data;
@Data
public class ArticleVos {
// 文件名
String fileName;
// 解析后的文件内容
String content;
}