8 天以前 2f80b7085c4eabce06d3491306b75eecc275275f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package com.ruoyi.ai.service;
 
import com.ruoyi.common.utils.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
 
@Component
public class AiFileTextExtractor {
 
    private static final long MAX_FILE_SIZE = 10L * 1024 * 1024;
 
    public String extractText(MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IllegalArgumentException("文件过大,请控制在10MB以内");
        }
 
        String filename = file.getOriginalFilename();
        String ext = getExtension(filename);
        byte[] bytes = file.getBytes();
 
        if (isPlainText(ext)) {
            return decodeText(bytes);
        }
        if ("docx".equals(ext)) {
            return extractDocx(bytes);
        }
        if ("xlsx".equals(ext)) {
            return extractXlsx(bytes);
        }
        if ("xls".equals(ext)) {
            return extractXls(bytes);
        }
        if (isImage(ext)) {
            return "图片文件:" + filename + ",已上传,请结合图片内容识别采购单据、表格和产品明细。";
        }
        throw new IllegalArgumentException("暂不支持该文件类型: " + ext);
    }
 
    public boolean isImageFile(MultipartFile file) {
        if (file == null) {
            return false;
        }
        return isImage(getExtension(file.getOriginalFilename()));
    }
 
    private String extractDocx(byte[] bytes) throws IOException {
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
             XWPFDocument document = new XWPFDocument(inputStream);
             XWPFWordExtractor extractor = new XWPFWordExtractor(document)) {
            return extractor.getText();
        }
    }
 
    private String extractXlsx(byte[] bytes) throws IOException {
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
             XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) {
            return extractWorkbook(workbook);
        }
    }
 
    private String extractXls(byte[] bytes) throws IOException {
        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
             HSSFWorkbook workbook = new HSSFWorkbook(inputStream)) {
            return extractWorkbook(workbook);
        }
    }
 
    private String extractWorkbook(org.apache.poi.ss.usermodel.Workbook workbook) {
        StringBuilder text = new StringBuilder();
        DataFormatter formatter = new DataFormatter();
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            Sheet sheet = workbook.getSheetAt(i);
            text.append("Sheet: ").append(sheet.getSheetName()).append("\n");
            for (Row row : sheet) {
                short lastCellNum = row.getLastCellNum();
                if (lastCellNum <= 0) {
                    text.append("\n");
                    continue;
                }
                for (int c = 0; c < lastCellNum; c++) {
                    String cellText = formatter.formatCellValue(row.getCell(c));
                    text.append(cellText);
                    if (c < lastCellNum - 1) {
                        text.append('\t');
                    }
                }
                text.append('\n');
            }
        }
        return text.toString();
    }
 
    private String decodeText(byte[] bytes) {
        String utf8 = new String(bytes, StandardCharsets.UTF_8);
        if (utf8.contains("�")) {
            return new String(bytes, java.nio.charset.Charset.forName("GBK"));
        }
        return utf8;
    }
 
    private String getExtension(String filename) {
        if (!StringUtils.hasText(filename) || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
    }
 
    private boolean isPlainText(String ext) {
        return StringUtils.inStringIgnoreCase(ext,
                "txt", "md", "markdown", "json", "xml", "yaml", "yml", "csv", "log", "properties",
                "java", "js", "ts", "vue", "html", "css", "sql", "py", "go", "sh", "bat");
    }
 
    private boolean isImage(String ext) {
        return StringUtils.inStringIgnoreCase(ext, "png", "jpg", "jpeg", "webp", "bmp");
    }
}