AI工作流优化

This commit is contained in:
zhang
2026-02-13 18:14:39 +08:00
parent afa3c78180
commit 885d46a4aa
59 changed files with 863 additions and 287 deletions

View File

@@ -81,6 +81,20 @@ public class SysOssController extends BaseController {
return R.ok(uploadVo);
}
/**
* 上传文件(千问百炼版)
*
* @param file 文件
*/
@Log(title = "上传文件(千问百炼版)", businessType = BusinessType.INSERT)
@PostMapping(value = "/fileUpload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<SysOssUploadVo> fileUpload(@RequestPart("file") MultipartFile file) {
if (ObjectUtil.isNull(file)) {
return R.fail("上传文件不能为空");
}
return R.ok(ossService.fileUpload(file));
}
/**
* 下载OSS对象
*

View File

@@ -3,6 +3,7 @@ package org.ruoyi.system.service;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.system.domain.bo.SysOssBo;
import org.ruoyi.system.domain.vo.SysOssUploadVo;
import org.ruoyi.system.domain.vo.SysOssVo;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
@@ -60,6 +61,14 @@ public interface ISysOssService {
*/
SysOssVo upload(File file);
/**
* 上传文件到千问平台(千问百炼版本)
*
* @param file 要上传的 MultipartFile 对象
* @return 上传成功后的 SysOssVo 对象,包含文件信息
*/
SysOssUploadVo fileUpload(MultipartFile file);
/**
* 文件下载方法,支持一次性下载完整文件
*

View File

@@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.constant.CacheNames;
import org.ruoyi.common.core.domain.dto.OssDTO;
import org.ruoyi.common.core.exception.ServiceException;
import org.ruoyi.common.core.service.ConfigService;
import org.ruoyi.common.core.service.OssService;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.SpringUtils;
@@ -20,6 +21,7 @@ import org.ruoyi.common.core.utils.file.FileUtils;
import org.ruoyi.common.json.utils.JsonUtils;
import org.ruoyi.common.mybatis.core.page.PageQuery;
import org.ruoyi.common.mybatis.core.page.TableDataInfo;
import org.ruoyi.common.oss.constant.OssConstant;
import org.ruoyi.common.oss.core.OssClient;
import org.ruoyi.common.oss.entity.UploadResult;
import org.ruoyi.common.oss.enums.AccessPolicyType;
@@ -27,10 +29,14 @@ import org.ruoyi.common.oss.factory.OssFactory;
import org.ruoyi.system.domain.SysOss;
import org.ruoyi.system.domain.SysOssExt;
import org.ruoyi.system.domain.bo.SysOssBo;
import org.ruoyi.system.domain.vo.SysOssUploadVo;
import org.ruoyi.system.domain.vo.SysOssVo;
import org.ruoyi.system.mapper.SysOssMapper;
import org.ruoyi.system.service.ISysOssService;
import org.jetbrains.annotations.NotNull;
import org.ruoyi.system.utils.QwenFileUploadUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
@@ -38,6 +44,9 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
@@ -55,6 +64,18 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
private final SysOssMapper baseMapper;
private final ConfigService configService;
// 默认密钥
private static String API_KEY;
// 默认api路径地址
private static String API_HOST;
// 上传文件服务器地址
@Value("${sys.upload.path}")
private String UPLOAD_PATH;
/**
* 查询OSS对象存储列表
*
@@ -220,6 +241,73 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
return BeanUtil.toBean(sysOssVo, OssDTO.class);
}
/**
* 上传文件至千问百炼平台
* @param file 要上传的 MultipartFile 对象
* @return 上传成功后的 SysOssVo 对象,包含文件信息
*/
@Override
public SysOssUploadVo fileUpload(MultipartFile file) {
String originalName = file.getOriginalFilename();
if (StringUtils.isEmpty(originalName)){
throw new ServiceException("文件名不能为空");
}
int lastDotIndex = originalName != null ? originalName.lastIndexOf(".") : -1;
String prefix = lastDotIndex > 0 ? originalName.substring(0, lastDotIndex) : "";
String suffix = lastDotIndex > 0 ? originalName.substring(lastDotIndex) : "";
try {
// 确保上传目录存在
Path uploadDir = Paths.get(UPLOAD_PATH);
if (!Files.exists(uploadDir)) {
Files.createDirectories(uploadDir);
}
// 生成上传文件名
Path targetPath = uploadDir.resolve(originalName);
// 直接保存文件
File pathFile = targetPath.toFile();
file.transferTo(pathFile);
// 获取配置
initConfig();
// 使用工具类上传文件到阿里云
String fileId = QwenFileUploadUtils.uploadFile(pathFile, API_HOST, API_KEY);
if (StringUtils.isEmpty(fileId)) {
throw new ServiceException("文件上传失败未获取到fileId");
}
// 拿到上传地址的路径地址
String filePath = targetPath.toAbsolutePath().toString();
// 保存文件信息到数据库
return buildEntity(filePath, fileId, suffix, prefix, originalName);
} catch (IOException e) {
throw new ServiceException("文件上传失败: " + e.getMessage());
}
}
/**
* 保存数据到数据库中
* @param filePath 上传文件地址
* @param fileId 百炼平台返回fileID
* @param suffix 文件后缀
* @param prefix 文件前缀
* @param originalName 文件名称
* @return SysOssUploadVo 上传返回VO对象
*/
@NotNull
private SysOssUploadVo buildEntity(String filePath, String fileId, String suffix, String prefix, String originalName) {
String url = OssConstant.FILE_ID_PREFIX + fileId;
SysOss oss = new SysOss();
oss.setUrl(url);
oss.setExt1(filePath);
oss.setFileSuffix(suffix);
oss.setFileName(prefix);
oss.setOriginalName(originalName);
oss.setService(OssConstant.DASH_SCOPE);
baseMapper.insert(oss);
SysOssUploadVo uploadVo = new SysOssUploadVo();
BeanUtils.copyProperties(oss, uploadVo);
uploadVo.setFileName(originalName);
return uploadVo;
}
/**
* 上传文件到对象存储服务,并保存文件信息到数据库
*
@@ -286,4 +374,20 @@ public class SysOssServiceImpl implements ISysOssService, OssService {
}
return oss;
}
/**
* 初始化配置并返回API密钥和主机
*/
private void initConfig() {
String apiKey = configService.getConfigValue(OssConstant.CONFIG_NAME_KEY);
if (StringUtils.isEmpty(apiKey)) {
throw new ServiceException("请先配置Qwen上传文件相关API_KEY");
}
API_KEY = apiKey;
String apiHost = configService.getConfigValue(OssConstant.CONFIG_NAME_URL);
if (StringUtils.isEmpty(apiHost)) {
throw new ServiceException("请先配置Qwen上传文件相关API_HOST");
}
API_HOST = apiHost;
}
}

View File

@@ -0,0 +1,50 @@
package org.ruoyi.system.utils;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.ruoyi.common.core.utils.StringUtils;
import java.io.File;
import java.io.IOException;
import java.rmi.ServerException;
/***
* 千问上传文件工具类
*/
public class QwenFileUploadUtils {
// 上传本地文件
public static String uploadFile(File file, String apiHost, String apiKey) throws IOException {
OkHttpClient client = new OkHttpClient();
// 构建 multipart/form-data 请求体(千问要求的格式)
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", file.getName(), // 参数名必须为 file
RequestBody.create(MediaType.parse("application/octet-stream"), file))
.addFormDataPart("purpose", "file-extract") // 必须为 file-extract文档解析专用
.build();
// 构建请求(必须为 POST 方法)
Request request = new Request.Builder()
.url(apiHost)
.post(requestBody)
.addHeader("Authorization", apiKey) // 认证头格式正确
.build();
// 发送请求并解析 fileId
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new ServerException("上传失败:" + response.code() + " " + response.message());
}
// 解析响应体,获取 fileId
String responseBody = response.body().string();
if (StringUtils.isEmpty(responseBody)){
throw new ServerException("上传失败:响应体为空");
}
JSONObject jsonObject = JSONObject.parseObject(responseBody);
// 千问返回的 fileId
return jsonObject.getString("id");
}
}
}