feat: 添加项目配置和依赖更新

配置更新:
1. 前端配置
   - 添加 hook-fetch 依赖用于 HTTP 请求
   - 更新 vite.config.mts 配置
   - 添加 .npmrc 配置文件

2. 后端配置
   - 更新 application.yml 和 application-dev.yml 配置
   - 更新 docker-compose.yml 配置

3. 代码优化
   - OSS 客户端优化
   - SSE 管理器优化
   - 聊天服务和向量存储策略优化

4. 项目文档
   - 添加 CLAUDE.md 项目指南

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
大壮
2026-04-02 09:44:56 +00:00
parent ac8e6ca088
commit 2f25a943b8
14 changed files with 584 additions and 98 deletions

View File

@@ -15,6 +15,7 @@ import org.hzhub.common.oss.properties.OssProperties;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.async.*;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
@@ -94,7 +95,14 @@ public class OssClient {
.region(of())
.forcePathStyle(isStyle)
.httpClient(NettyNioAsyncHttpClient.builder()
.connectionTimeout(Duration.ofSeconds(60)).build())
.connectionTimeout(Duration.ofMinutes(5))
.readTimeout(Duration.ofMinutes(5))
.writeTimeout(Duration.ofMinutes(5))
.build())
.overrideConfiguration(ClientOverrideConfiguration.builder()
.apiCallTimeout(Duration.ofMinutes(10))
.apiCallAttemptTimeout(Duration.ofMinutes(5))
.build())
.build();
//AWS基于 CRT 的 S3 AsyncClient 实例用作 S3 传输管理器的底层客户端
@@ -172,36 +180,22 @@ public class OssClient {
* @throws OssException 如果上传失败,抛出自定义异常
*/
public UploadResult upload(InputStream inputStream, String key, Long length, String contentType) {
// 如果输入流不是 ByteArrayInputStream则将其读取为字节数组再创建 ByteArrayInputStream
if (!(inputStream instanceof ByteArrayInputStream)) {
inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream));
}
// 输入流转换为字节数组,使用异步字节数组上传方式
try {
// 创建异步请求体length如果为空会报错
BlockingInputStreamAsyncRequestBody body = BlockingInputStreamAsyncRequestBody.builder()
.contentLength(length)
.subscribeTimeout(Duration.ofSeconds(120))
.build();
byte[] bytes = IoUtil.readBytes(inputStream);
// 使用 transferManager 进行上传
Upload upload = transferManager.upload(
x -> x.requestBody(body).addTransferListener(LoggingTransferListener.create())
.putObjectRequest(
y -> y.bucket(properties.getBucketName())
.key(key)
.contentType(contentType)
// 用于设置对象的访问控制列表ACL。不同云厂商对ACL的支持和实现方式有所不同
// 因此根据具体的云服务提供商你可能需要进行不同的配置自行开启阿里云有acl权限配置腾讯云没有acl权限配置
//.acl(getAccessPolicy().getObjectCannedACL())
.build())
.build());
// 使用异步方式上传字节数组
software.amazon.awssdk.services.s3.model.PutObjectResponse response = client.putObject(
software.amazon.awssdk.services.s3.model.PutObjectRequest.builder()
.bucket(properties.getBucketName())
.key(key)
.contentType(contentType)
.contentLength((long) bytes.length)
.build(),
software.amazon.awssdk.core.async.AsyncRequestBody.fromBytes(bytes)
).join();
// 将输入流写入请求体
body.writeInputStream(inputStream);
// 等待文件上传操作完成
CompletedUpload uploadResult = upload.completionFuture().join();
String eTag = uploadResult.response().eTag();
String eTag = response.eTag();
// 提取上传结果中的 ETag并构建一个自定义的 UploadResult 对象
return UploadResult.builder().url(getUrl() + StringUtils.SLASH + key).filename(key).eTag(eTag).build();