From 32da85daabbb0e574f12bc7f1e0af6ff5b0cee6a Mon Sep 17 00:00:00 2001 From: zhouweiyi Date: 星期二, 13 五月 2025 10:55:39 +0800 Subject: [PATCH] 提取PDF中的图片并调用大模型,识别图片内容并返回 --- ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/utils/ZipUtils.java | 95 ++++++++++ ruoyi-admin/src/main/resources/application-prod.yml | 5 ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/PdfImageExtractServiceImpl.java | 144 ++++++++++++++++ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java | 41 ++++ ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/PdfFileContentResult.java | 30 +++ ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java | 219 +++++++++++++---------- ruoyi-admin/src/main/resources/application-dev.yml | 5 7 files changed, 441 insertions(+), 98 deletions(-) diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml index 2a4613f..37c944f 100644 --- a/ruoyi-admin/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -94,3 +94,8 @@ # 鑵捐涓撶敤 sdkAppId: +pdf: + extract: + service: + url: http://localhost:8080 + diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml index cd52c0f..f157186 100644 --- a/ruoyi-admin/src/main/resources/application-prod.yml +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -172,3 +172,8 @@ signName: 娴嬭瘯 # 鑵捐涓撶敤 sdkAppId: + +pdf: + extract: + service: + url: http://localhost:8080 \ No newline at end of file diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/PdfFileContentResult.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/PdfFileContentResult.java new file mode 100644 index 0000000..d6594e4 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/domain/PdfFileContentResult.java @@ -0,0 +1,30 @@ +package org.ruoyi.domain; + +/** + * 鏂囦欢鍐呭缁撴灉灏佽绫� + */ +public class PdfFileContentResult { + private String filename; + private String content; + + public PdfFileContentResult(String filename, String content) { + this.filename = filename; + this.content = content; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} \ No newline at end of file diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java new file mode 100644 index 0000000..759b439 --- /dev/null +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/PdfImageExtractService.java @@ -0,0 +1,41 @@ +package org.ruoyi.service; + +import java.io.IOException; +import java.util.List; +import org.ruoyi.domain.PdfFileContentResult; +import org.springframework.web.multipart.MultipartFile; + +/** + * PDF鍥剧墖鎻愬彇鏈嶅姟鎺ュ彛 + */ +public interface PdfImageExtractService { + + /** + * 浠嶱DF鏂囦欢涓彁鍙栧浘鐗� + * + * @param pdfFile PDF鏂囦欢 + * @param imageFormat 杈撳嚭鍥剧墖鏍煎紡 (png, jpeg, gif) + * @param allowDuplicates 鏄惁鍏佽閲嶅鍥剧墖 + * @return 鍖呭惈鎻愬彇鍥剧墖鐨刏IP鏂囦欢鐨勫瓧鑺傛暟缁� + * @throws IOException 濡傛灉鏂囦欢澶勭悊杩囩▼涓彂鐢熼敊璇� + */ + byte[] extractImages(MultipartFile pdfFile, String imageFormat, boolean allowDuplicates) + throws IOException; + + /** + * 澶勭悊鏂囦欢鍐呭 + * + * @param unzip Base64缂栫爜鐨勫浘鐗囨暟缁� + * @return 鏂囦欢鍐呭缁撴灉鍒楄〃 + * @throws IOException 濡傛灉API璋冪敤杩囩▼涓彂鐢熼敊璇� + */ + List<PdfFileContentResult> dealFileContent(String[] unzip) throws IOException; + + /** + * 鎻愬彇PDF涓殑鍥剧墖骞惰皟鐢╣pt-4o-mini,璇嗗埆鍥剧墖鍐呭骞惰繑鍥� + * @param file + * @return + * @throws IOException + */ + List<PdfFileContentResult> extractImages(MultipartFile file) throws IOException; +} \ No newline at end of file diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/PdfImageExtractServiceImpl.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/PdfImageExtractServiceImpl.java new file mode 100644 index 0000000..55ce87e --- /dev/null +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/service/impl/PdfImageExtractServiceImpl.java @@ -0,0 +1,144 @@ +package org.ruoyi.service.impl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; +import okhttp3.MediaType; +import okhttp3.MultipartBody; +import okhttp3.OkHttpClient; +import okhttp3.OkHttpClient.Builder; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.ruoyi.common.core.domain.R; +import org.ruoyi.domain.PdfFileContentResult; +import org.ruoyi.service.PdfImageExtractService; +import org.ruoyi.utils.ZipUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +/** + * PDF鍥剧墖鎻愬彇鏈嶅姟瀹炵幇绫� + */ +@Service +@Slf4j +public class PdfImageExtractServiceImpl implements PdfImageExtractService { + + @Value("${pdf.extract.service.url}") + private String serviceUrl; + @Value("${pdf.extract.ai-api.url}") + private String aiApiUrl; + @Value("${pdf.extract.ai-api.key}") + private String aiApiKey ; + + private final OkHttpClient client = new Builder() + .connectTimeout(100, TimeUnit.SECONDS) + .readTimeout(150, TimeUnit.SECONDS) + .writeTimeout(150, TimeUnit.SECONDS) + .callTimeout(300, TimeUnit.SECONDS) + .build(); + + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + + @Override + public byte[] extractImages(MultipartFile pdfFile, String imageFormat, boolean allowDuplicates) + throws IOException { + // 鏋勫缓multipart璇锋眰 + RequestBody requestBody = new MultipartBody.Builder() + .setType(MultipartBody.FORM) + .addFormDataPart("fileInput", pdfFile.getOriginalFilename(), + RequestBody.create(MediaType.parse("application/pdf"), pdfFile.getBytes())) + .addFormDataPart("format", imageFormat) + .addFormDataPart("allowDuplicates", String.valueOf(allowDuplicates)) + .build(); + + // 鍒涘缓璇锋眰 + Request request = new Request.Builder() + .url(serviceUrl + "/api/v1/misc/extract-images") + .post(requestBody) + .build(); + + // 鎵ц璇锋眰 + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("璇锋眰澶辫触: " + response.code()); + } + return response.body().bytes(); + } + } + + /** + * 澶勭悊鏂囦欢鍐呭 + * + * @param unzip Base64缂栫爜鐨勫浘鐗囨暟缁� + * @return 鏂囦欢鍐呭缁撴灉鍒楄〃 + * @throws IOException 濡傛灉API璋冪敤杩囩▼涓彂鐢熼敊璇� + */ + @Override + public List<PdfFileContentResult> dealFileContent(String[] unzip) throws IOException { + List<PdfFileContentResult> results = new ArrayList<>(); + int i = 0; + for (String base64Image : unzip) { + // 鏋勫缓璇锋眰JSON + String requestJson = String.format("{" + + "\"model\": \"gpt-4o\"," + + "\"stream\": false," + + "\"messages\": [{" + + "\"role\": \"user\"," + + "\"content\": [{" + + "\"type\": \"text\"," + + "\"text\": \"杩欏紶鍥剧墖鏈変粈涔圽"" + + "}, {" + + "\"type\": \"image_url\"," + + "\"image_url\": {" + + "\"url\": \"%s\"" + + "}}" + + "]}]," + + "\"max_tokens\": 400" + + "}", base64Image); + + // 鍒涘缓璇锋眰 + Request request = new Request.Builder() + .url(aiApiUrl) + .addHeader("Authorization", "Bearer " + aiApiKey) + .post(RequestBody.create(JSON, requestJson)) + .build(); + + // 鎵ц璇锋眰 + try { + log.info("=============call=" + ++i); + Response response = client.newCall(request).execute(); + log.info("=============response=" + response); + if (!response.isSuccessful()) { + throw new IOException("API璇锋眰澶辫触: " + response.code() + response.toString()); + } + + String responseBody = response.body().string(); + log.info("=============responseBody=" + responseBody); + // 浣跨敤鏂囦欢鍚嶏紙杩欓噷浣跨敤base64鐨勫墠10涓瓧绗︿綔涓烘爣璇嗭級鍜孉PI杩斿洖鍐呭鍒涘缓缁撴灉瀵硅薄 + String filename = base64Image.substring(0, Math.min(base64Image.length(), 10)); + results.add(new PdfFileContentResult(filename, responseBody)); + } catch (Exception e) { + log.error(e.getMessage()); + throw new RuntimeException(e); + } + } + + return results; + } + + @Override + public List<PdfFileContentResult> extractImages(MultipartFile file) throws IOException { + String format = "png"; + boolean allowDuplicates = true; + // 鑾峰彇ZIP鏁版嵁 + byte[] zipData = this.extractImages(file, format, allowDuplicates); + // 瑙e帇鏂囦欢骞惰瘑鍒浘鐗囧唴瀹瑰苟杩斿洖 + String[] unzip = ZipUtils.unzipForBase64(zipData); + //瑙f瀽鍥剧墖鍐呭 + return this.dealFileContent(unzip); + } +} \ No newline at end of file diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/utils/ZipUtils.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/utils/ZipUtils.java new file mode 100644 index 0000000..7ae1b2b --- /dev/null +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/utils/ZipUtils.java @@ -0,0 +1,95 @@ +package org.ruoyi.utils; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * ZIP鏂囦欢澶勭悊宸ュ叿绫� + */ +public class ZipUtils { + + /** + * 瑙e帇ZIP鏂囦欢鍒版寚瀹氱洰褰� + * + * @param zipData ZIP鏂囦欢鐨勫瓧鑺傛暟缁� + * @param destDir 鐩爣鐩綍 + * @return 瑙e帇鍚庣殑鏂囦欢璺緞鍒楄〃 + * @throws IOException 濡傛灉瑙e帇杩囩▼涓彂鐢熼敊璇� + */ + public static String[] unzip(byte[] zipData, String destDir) throws IOException { + File destDirFile = new File(destDir); + if (!destDirFile.exists()) { + destDirFile.mkdirs(); + } + + List<String> extractedPaths = new ArrayList<>(); + try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); + ZipInputStream zis = new ZipInputStream(bis)) { + + ZipEntry zipEntry; + while ((zipEntry = zis.getNextEntry()) != null) { + String filePath = destDir + File.separator + zipEntry.getName(); + if (!zipEntry.isDirectory()) { + extractFile(zis, filePath); + extractedPaths.add(filePath); + } else { + new File(filePath).mkdirs(); + } + zis.closeEntry(); + } + } + return extractedPaths.toArray(new String[0]); + } + + private static void extractFile(ZipInputStream zis, String filePath) throws IOException { + try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) { + byte[] buffer = new byte[4096]; + int read; + while ((read = zis.read(buffer)) != -1) { + bos.write(buffer, 0, read); + } + } + } + + /** + * 瑙e帇ZIP鏂囦欢骞惰繑鍥炴枃浠跺唴瀹圭殑Base64缂栫爜瀛楃涓叉暟缁� + * + * @param zipData ZIP鏂囦欢鐨勫瓧鑺傛暟缁� + * @return Base64缂栫爜鐨勬枃浠跺唴瀹规暟缁� + * @throws IOException 濡傛灉瑙e帇杩囩▼涓彂鐢熼敊璇� + */ + public static String[] unzipForBase64(byte[] zipData) throws IOException { + List<String> base64Contents = new ArrayList<>(); + try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData); + ZipInputStream zis = new ZipInputStream(bis)) { + + ZipEntry zipEntry; + while ((zipEntry = zis.getNextEntry()) != null) { + if (!zipEntry.isDirectory()) { + // 璇诲彇鏂囦欢鍐呭鍒板唴瀛� + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[4096]; + int read; + while ((read = zis.read(buffer)) != -1) { + baos.write(buffer, 0, read); + } + + // 灏嗘枃浠跺唴瀹硅浆鎹负Base64瀛楃涓� + String base64Content = Base64.getEncoder().encodeToString(baos.toByteArray()); + base64Contents.add(base64Content); + } + zis.closeEntry(); + } + } + return base64Contents.toArray(new String[0]); + } +} \ No newline at end of file diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java index e573c82..d8066e7 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/knowledge/KnowledgeController.java @@ -1,9 +1,12 @@ package org.ruoyi.chat.controller.knowledge; import cn.dev33.satoken.stp.StpUtil; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import java.io.IOException; import lombok.RequiredArgsConstructor; import org.ruoyi.common.core.domain.R; import org.ruoyi.common.core.validate.AddGroup; @@ -14,6 +17,7 @@ import org.ruoyi.common.web.core.BaseController; import org.ruoyi.core.page.PageQuery; import org.ruoyi.core.page.TableDataInfo; +import org.ruoyi.domain.PdfFileContentResult; import org.ruoyi.domain.bo.KnowledgeAttachBo; import org.ruoyi.domain.bo.KnowledgeFragmentBo; import org.ruoyi.domain.bo.KnowledgeInfoBo; @@ -24,6 +28,7 @@ import org.ruoyi.service.IKnowledgeAttachService; import org.ruoyi.service.IKnowledgeFragmentService; import org.ruoyi.service.IKnowledgeInfoService; +import org.ruoyi.service.PdfImageExtractService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @@ -41,117 +46,135 @@ @RequestMapping("/knowledge") public class KnowledgeController extends BaseController { - private final IKnowledgeInfoService knowledgeInfoService; + private final IKnowledgeInfoService knowledgeInfoService; - private final IKnowledgeAttachService attachService; + private final IKnowledgeAttachService attachService; - private final IKnowledgeFragmentService fragmentService; + private final IKnowledgeFragmentService fragmentService; - /** - * 鏍规嵁鐢ㄦ埛淇℃伅鏌ヨ鏈湴鐭ヨ瘑搴� - */ - @GetMapping("/list") - public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) { - if (!StpUtil.isLogin()) { - throw new SecurityException("璇峰厛鍘荤櫥褰�!"); - } - bo.setUid(LoginHelper.getUserId()); - return knowledgeInfoService.queryPageList(bo, pageQuery); + private final PdfImageExtractService pdfImageExtractService; + + /** + * 鏍规嵁鐢ㄦ埛淇℃伅鏌ヨ鏈湴鐭ヨ瘑搴� + */ + @GetMapping("/list") + public TableDataInfo<KnowledgeInfoVo> list(KnowledgeInfoBo bo, PageQuery pageQuery) { + if (!StpUtil.isLogin()) { + throw new SecurityException("璇峰厛鍘荤櫥褰�!"); } + bo.setUid(LoginHelper.getUserId()); + return knowledgeInfoService.queryPageList(bo, pageQuery); + } - /** - * 鏂板鐭ヨ瘑搴� - */ - @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.INSERT) - @PostMapping("/save") - public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) { - knowledgeInfoService.saveOne(bo); - return R.ok(); - } + /** + * 鏂板鐭ヨ瘑搴� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.INSERT) + @PostMapping("/save") + public R<Void> save(@Validated(AddGroup.class) @RequestBody KnowledgeInfoBo bo) { + knowledgeInfoService.saveOne(bo); + return R.ok(); + } - /** - * 鍒犻櫎鐭ヨ瘑搴� - */ - @PostMapping("/remove/{id}") - public R<String> remove(@PathVariable String id) { - knowledgeInfoService.removeKnowledge(id); - return R.ok("鍒犻櫎鐭ヨ瘑搴撴垚鍔�!"); - } + /** + * 鍒犻櫎鐭ヨ瘑搴� + */ + @PostMapping("/remove/{id}") + public R<String> remove(@PathVariable String id) { + knowledgeInfoService.removeKnowledge(id); + return R.ok("鍒犻櫎鐭ヨ瘑搴撴垚鍔�!"); + } - /** - * 淇敼鐭ヨ瘑搴� - */ - @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.UPDATE) - @PostMapping("/edit") - public R<Void> edit(@RequestBody KnowledgeInfoBo bo) { - return toAjax(knowledgeInfoService.updateByBo(bo)); - } + /** + * 淇敼鐭ヨ瘑搴� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + public R<Void> edit(@RequestBody KnowledgeInfoBo bo) { + return toAjax(knowledgeInfoService.updateByBo(bo)); + } - /** - * 瀵煎嚭鐭ヨ瘑搴撳垪琛� - */ - @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(KnowledgeInfoBo bo, HttpServletResponse response) { - List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo); - ExcelUtil.exportExcel(list, "鐭ヨ瘑搴�", KnowledgeInfoVo.class, response); - } + /** + * 瀵煎嚭鐭ヨ瘑搴撳垪琛� + */ + @Log(title = "鐭ヨ瘑搴�", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(KnowledgeInfoBo bo, HttpServletResponse response) { + List<KnowledgeInfoVo> list = knowledgeInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "鐭ヨ瘑搴�", KnowledgeInfoVo.class, response); + } - /** - * 鏌ヨ鐭ヨ瘑闄勪欢淇℃伅 - */ - @GetMapping("/detail/{kid}") - public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery, @PathVariable String kid) { - bo.setKid(kid); - return attachService.queryPageList(bo, pageQuery); - } + /** + * 鏌ヨ鐭ヨ瘑闄勪欢淇℃伅 + */ + @GetMapping("/detail/{kid}") + public TableDataInfo<KnowledgeAttachVo> attach(KnowledgeAttachBo bo, PageQuery pageQuery, + @PathVariable String kid) { + bo.setKid(kid); + return attachService.queryPageList(bo, pageQuery); + } - /** - * 涓婁紶鐭ヨ瘑搴撻檮浠� - */ - @PostMapping(value = "/attach/upload") - public R<String> upload(KnowledgeInfoUploadBo bo) { - knowledgeInfoService.upload(bo); - return R.ok("涓婁紶鐭ヨ瘑搴撻檮浠舵垚鍔�!"); - } + /** + * 涓婁紶鐭ヨ瘑搴撻檮浠� + */ + @PostMapping(value = "/attach/upload") + public R<String> upload(KnowledgeInfoUploadBo bo) { + knowledgeInfoService.upload(bo); + return R.ok("涓婁紶鐭ヨ瘑搴撻檮浠舵垚鍔�!"); + } - /** - * 鑾峰彇鐭ヨ瘑搴撻檮浠惰缁嗕俊鎭� - * - * @param id 涓婚敭 - */ - @GetMapping("attach/info/{id}") - public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖") - @PathVariable Long id) { - return R.ok(attachService.queryById(id)); - } + /** + * 鑾峰彇鐭ヨ瘑搴撻檮浠惰缁嗕俊鎭� + * + * @param id 涓婚敭 + */ + @GetMapping("attach/info/{id}") + public R<KnowledgeAttachVo> getAttachInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖") + @PathVariable Long id) { + return R.ok(attachService.queryById(id)); + } - /** - * 鍒犻櫎鐭ヨ瘑搴撻檮浠� - */ - @PostMapping("attach/remove/{kid}") - public R<Void> removeAttach(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") - @PathVariable String kid) { - attachService.removeKnowledgeAttach(kid); - return R.ok(); - } + /** + * 鍒犻櫎鐭ヨ瘑搴撻檮浠� + */ + @PostMapping("attach/remove/{kid}") + public R<Void> removeAttach(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") + @PathVariable String kid) { + attachService.removeKnowledgeAttach(kid); + return R.ok(); + } - /** - * 鏌ヨ鐭ヨ瘑鐗囨 - */ - @GetMapping("/fragment/list/{docId}") - public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, PageQuery pageQuery, @PathVariable String docId) { - bo.setDocId(docId); - return fragmentService.queryPageList(bo, pageQuery); - } + /** + * 鏌ヨ鐭ヨ瘑鐗囨 + */ + @GetMapping("/fragment/list/{docId}") + public TableDataInfo<KnowledgeFragmentVo> fragmentList(KnowledgeFragmentBo bo, + PageQuery pageQuery, @PathVariable String docId) { + bo.setDocId(docId); + return fragmentService.queryPageList(bo, pageQuery); + } - /** - * 涓婁紶鏂囦欢缈昏瘧 - */ - @PostMapping("/translationByFile") - @ResponseBody - public String translationByFile(@RequestParam("file") MultipartFile file, String targetLanguage) { - return attachService.translationByFile(file, targetLanguage); - } + /** + * 涓婁紶鏂囦欢缈昏瘧 + */ + @PostMapping("/translationByFile") + @ResponseBody + public String translationByFile(@RequestParam("file") MultipartFile file, String targetLanguage) { + return attachService.translationByFile(file, targetLanguage); + } + + /** + * 鎻愬彇PDF涓殑鍥剧墖骞惰皟鐢╣pt-4o-mini,璇嗗埆鍥剧墖鍐呭骞惰繑鍥� + * + * @param file PDF鏂囦欢 + * @return 淇濆瓨鐨勬枃浠惰矾寰勪俊鎭� + */ + @PostMapping("/extract-images") + @Operation(summary = "鎻愬彇PDF涓殑鍥剧墖骞惰皟鐢ㄥぇ妯″瀷,璇嗗埆鍥剧墖鍐呭骞惰繑鍥�", description = "鎻愬彇PDF涓殑鍥剧墖骞惰皟鐢╣pt-4o-mini,璇嗗埆鍥剧墖鍐呭骞惰繑鍥�") + public R<List<PdfFileContentResult>> extractImages( + @RequestPart("file") MultipartFile file + ) throws IOException { + return R.ok(pdfImageExtractService.extractImages(file)); + } } -- Gitblit v1.9.3