Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4f5d632
feat: add resource API
lu-yg Sep 5, 2025
df6ba91
fix: modify source API
lu-yg Sep 5, 2025
0fef229
fix: modify source API
lu-yg Sep 5, 2025
ab24c40
fix: modify source API
lu-yg Sep 5, 2025
787d1d1
fix: modify source API
lu-yg Sep 5, 2025
5fed78f
fix: modify source API
lu-yg Sep 5, 2025
d483f04
fix: modify source API
lu-yg Sep 5, 2025
72e9c67
fix: modify source API
lu-yg Sep 5, 2025
1fe61d5
fix: modify source API
lu-yg Sep 5, 2025
fd74ac8
fix: modify source API
lu-yg Sep 5, 2025
398e5c0
feat: add scheduled tasks
lu-yg Sep 9, 2025
0b8105c
fix: modify resource download
lu-yg Sep 9, 2025
6c9c7e4
fix: modify resource group update
lu-yg Sep 9, 2025
6178ed2
fix: modify resource group update
lu-yg Sep 9, 2025
3d723ae
fix: modify resource group update
lu-yg Sep 9, 2025
797045c
Merge branch 'opentiny:develop' into feat/resourceManagement
lu-yg Sep 10, 2025
3e2e616
fix: modify resource download
lu-yg Sep 10, 2025
603f65d
fix: modify block group
lu-yg Sep 15, 2025
f8d37c0
fix: modify AI chat
lu-yg Sep 16, 2025
e7c73d8
Merge branch 'opentiny:develop' into feat/resourceManagement
lu-yg Sep 16, 2025
6c4f3ea
fix: modify AI chat
lu-yg Sep 16, 2025
35a0b45
fix: modify AI chat
lu-yg Sep 16, 2025
4d7848b
fix: modify AI chat
lu-yg Sep 16, 2025
ad807d9
fix: modify AI chat
lu-yg Sep 16, 2025
53313bf
fix: modify AI chat
lu-yg Sep 16, 2025
ca4ff1b
fix: modify AI chat
lu-yg Sep 16, 2025
bff65fe
fix: modify AI chat
lu-yg Sep 16, 2025
f1fe5d0
Merge branch 'opentiny:develop' into feat/resourceManagement
lu-yg Sep 17, 2025
4eaee7a
fix: modify resource upload
lu-yg Sep 17, 2025
d211902
fix: modify resource upload
lu-yg Sep 17, 2025
28bef56
fix: modify resource upload
lu-yg Sep 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.batik.util.XMLResourceDescriptor;
import org.springframework.web.multipart.MultipartFile;
import org.w3c.dom.Document;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -235,6 +238,70 @@ public static String extractContentType(String base64Data) {
throw new IllegalArgumentException("Cannot extract content type from Base64 data");
}

/**
* 图片验证
*/
public static boolean validateByImageIO(MultipartFile file) {
try {
String filename = file.getOriginalFilename();
if (filename == null) {
return false;
}
// 获取文件扩展名
String extension = getFileExtension(filename).toLowerCase();

if ("svg".equals(extension)) {
return isSvgFile(file);
}

BufferedImage image = ImageIO.read(new ByteArrayInputStream(file.getBytes()));
return image != null;
} catch (IOException e) {
return false;
}
}

/**
* SVG文件验证
*/
private static boolean isSvgFile(MultipartFile file) {
try {
byte[] bytes = file.getBytes();
String content = new String(bytes, StandardCharsets.UTF_8);

// 简单检查:包含<svg标签和SVG命名空间
return content.contains("<svg") &&
(content.contains("xmlns=\"http://www.w3.org/2000/svg\"") ||
content.contains("xmlns='http://www.w3.org/2000/svg'"));

} catch (IOException e) {
return false;
}
}
/**
* 获取文件扩展名
*/
private static String getFileExtension(String filename) {
if (filename == null || !filename.contains(".")) {
return "";
}
return filename.substring(filename.lastIndexOf(".") + 1);
}
/**
* 简化版Base64转换
*/
public static String convertToBase64(MultipartFile file) throws IOException {
String mimeType = file.getContentType();
byte[] fileBytes = file.getBytes();
String base64 = Base64.getEncoder().encodeToString(fileBytes);
// 如果是SVG文件,修正MIME类型
String filename = file.getOriginalFilename();
if (filename != null && filename.toLowerCase().endsWith(".svg")) {
mimeType = "image/svg+xml";
}
return "data:" + mimeType + ";base64," + base64;
}

/**
* MIME类型转格式
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ public class AiChatController {
@Parameter(name = "ChatRequest", description = "入参对象")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema())),
content = @Content(mediaType = "application/json", schema = @Schema())),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "AI api")
@SystemControllerLog(description = "AI chat")
@PostMapping("/ai/chat")
public ResponseEntity<?> aiChat(@RequestBody ChatRequest request) {
try {
Expand Down Expand Up @@ -99,12 +99,12 @@ public ResponseEntity<?> aiChat(@RequestBody ChatRequest request) {
@Parameter(name = "ChatRequest", description = "入参对象")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema())),
content = @Content(mediaType = "application/json", schema = @Schema())),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "AI api v1")
@SystemControllerLog(description = "AI completions")
@PostMapping("/chat/completions")
public ResponseEntity<?> chat(@RequestBody ChatRequest request,
public ResponseEntity<?> completions(@RequestBody ChatRequest request,
@RequestHeader("Authorization") String authorization) {
if (authorization != null && authorization.startsWith("Bearer ")) {
String token = authorization.replace("Bearer ", "");
Expand Down Expand Up @@ -133,11 +133,11 @@ public ResponseEntity<?> chat(@RequestBody ChatRequest request,
* @return ai回答信息 result
*/
@Operation(summary = "搜索知识库", description = "搜索知识库",
parameters = {
@Parameter(name = "content", description = "入参对象")
}, responses = {
parameters = {
@Parameter(name = "content", description = "入参对象")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema())),
content = @Content(mediaType = "application/json", schema = @Schema())),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "AI serarch api")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
package com.tinyengine.it.controller;

import com.tinyengine.it.common.base.Result;
import com.tinyengine.it.common.context.LoginUserContext;
import com.tinyengine.it.common.exception.ExceptionEnum;
import com.tinyengine.it.common.log.SystemControllerLog;
import com.tinyengine.it.common.utils.ImageThumbnailGenerator;
import com.tinyengine.it.common.utils.Utils;
Expand All @@ -28,6 +30,7 @@
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -38,6 +41,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.OutputStream;
import java.net.URLEncoder;
Expand All @@ -61,6 +65,9 @@ public class ResourceController {
@Autowired
private ResourceService resourceService;

@Autowired
private LoginUserContext loginUserContext;

/**
* 查询表Resource信息
*
Expand All @@ -69,7 +76,7 @@ public class ResourceController {
@Operation(summary = "查询表Resource信息", description = "查询表Resource信息",
responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "查询表Resource信息")
Expand All @@ -90,7 +97,7 @@ public Result<List<Resource>> getAllResource() {
@Parameter(name = "id", description = "Resource主键id")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "根据id查询表Resource信息")
Expand All @@ -110,7 +117,7 @@ public Result<Resource> getResourceById(@PathVariable Integer id) {
@Parameter(name = "resourceGroupId", description = "ResourceGroup主键id")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "根据分组id和创建人查询表t_resource信息")
Expand All @@ -132,7 +139,7 @@ public Result<List<Resource>> getResourceByResourceGroupId(@PathVariable Integer
@Parameter(name = "des", description = "描述")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "模糊查询表Resource信息列表")
Expand All @@ -154,7 +161,7 @@ public Result<List<Resource>> getResourceById(@RequestParam String name, @Reques
@Parameter(name = "resource", description = "Resource入参对象")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "创建resource")
Expand All @@ -167,20 +174,36 @@ public Result<Resource> createResource(@Valid @RequestBody Resource resource) th
/**
* 上传图片
*
* @param resource the resource
* @param file the file
* @return Resource信息 result
*/
@Operation(summary = "上传图片", description = "上传图片",
parameters = {
@Parameter(name = "resource", description = "Resource入参对象")
}, responses = {
parameters = {
@Parameter(name = "file", description = "图片")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "上传图片")
@PostMapping("/resource/uoload")
public Result<Resource> resourceUoload(@Valid @RequestBody Resource resource) throws Exception {
@PostMapping("/resource/upload")
public Result<Resource> resourceUpload(@RequestParam MultipartFile file) throws Exception {
// 获取文件的原始名称
String fileName = StringUtils.cleanPath(java.util.Optional.ofNullable(file.getOriginalFilename()).orElse("image"));

if(!ImageThumbnailGenerator.validateByImageIO(file)){
return Result.failed(ExceptionEnum.CM325);
}
if(fileName.contains("..")) {
return Result.failed(ExceptionEnum.CM325);
}
// 将文件转为 Base64
String base64 = ImageThumbnailGenerator.convertToBase64(file);
Resource resource = new Resource();
resource.setName(fileName);
resource.setResourceData(base64);
resource.setAppId(loginUserContext.getAppId());
resource.setCategory("image");
Resource result = resourceService.resourceUpload(resource);
return Result.success(result);
}
Expand All @@ -196,7 +219,7 @@ public Result<Resource> resourceUoload(@Valid @RequestBody Resource resource) th
@Parameter(name = "resources", description = "Resource入参对象")
}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "批量创建Resource")
Expand All @@ -218,7 +241,7 @@ public Result<List<Resource>> createResource(@Valid @RequestBody List<Resource>
@Parameter(name = "id", description = "id"),
@Parameter(name = "Resource", description = "入参对象")}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "修改单个Resource信息")
Expand Down Expand Up @@ -258,7 +281,7 @@ public Result<Resource> deleteResource(@PathVariable Integer id) {
parameters = {
@Parameter(name = "id", description = "id")}, responses = {
@ApiResponse(responseCode = "200", description = "返回信息",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "获取resource信息详情")
Expand All @@ -277,7 +300,7 @@ public Result<Resource> detail(@PathVariable Integer id) {
parameters = {
@Parameter(name = "data", description = "base64编码数据")}, responses = {
@ApiResponse(responseCode = "200", description = "图片流数据",
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
content = @Content(mediaType = "application/json", schema = @Schema(implementation = Resource.class))),
@ApiResponse(responseCode = "400", description = "请求失败")
})
@SystemControllerLog(description = "获取资源")
Expand Down
Loading