file-parser.js
4.01 KB
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
/**
* File Parser Service
*
* 解析上传文件内容,支持文本、PDF、DOCX 等格式。
* 返回 { text, mimeType, truncated }
*/
const fs = require('fs');
const path = require('path');
const MAX_TEXT_LENGTH = 50000; // 最大解析字符数
// 文本类扩展名
const TEXT_EXTENSIONS = new Set([
'.txt', '.md', '.log', '.csv', '.json', '.yaml', '.yml',
'.js', '.ts', '.jsx', '.tsx', '.py', '.java', '.go', '.rs',
'.html', '.css', '.scss', '.xml', '.sql', '.sh', '.bat',
'.env', '.ini', '.toml', '.conf',
]);
// 图片类扩展名
const IMAGE_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp', '.svg']);
/**
* 解析文件内容
* @param {string} filePath - 文件绝对路径
* @returns {Promise<{text: string, mimeType: string, truncated: boolean}>}
*/
async function parseFileContent(filePath) {
const ext = path.extname(filePath).toLowerCase();
const fileName = path.basename(filePath);
// 1. 文本类文件
if (TEXT_EXTENSIONS.has(ext)) {
const raw = fs.readFileSync(filePath, 'utf-8');
const truncated = raw.length > MAX_TEXT_LENGTH;
const text = truncated ? raw.substring(0, MAX_TEXT_LENGTH) + '\n\n... [文件内容过长,已截断]' : raw;
return { text, mimeType: getMimeType(ext), truncated };
}
// 2. PDF
if (ext === '.pdf') {
try {
const pdfParse = require('pdf-parse');
const buffer = fs.readFileSync(filePath);
const data = await pdfParse(buffer);
const raw = data.text || '';
const truncated = raw.length > MAX_TEXT_LENGTH;
const text = truncated ? raw.substring(0, MAX_TEXT_LENGTH) + '\n\n... [PDF 内容过长,已截断]' : raw;
return { text, mimeType: 'application/pdf', truncated };
} catch (err) {
return { text: `[PDF 解析失败: ${err.message}]`, mimeType: 'application/pdf', truncated: false };
}
}
// 3. DOCX
if (ext === '.docx') {
try {
const mammoth = require('mammoth');
const result = await mammoth.extractRawText({ path: filePath });
const raw = result.value || '';
const truncated = raw.length > MAX_TEXT_LENGTH;
const text = truncated ? raw.substring(0, MAX_TEXT_LENGTH) + '\n\n... [DOCX 内容过长,已截断]' : raw;
return { text, mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', truncated };
} catch (err) {
return { text: `[DOCX 解析失败: ${err.message}]`, mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', truncated: false };
}
}
// 4. 图片
if (IMAGE_EXTENSIONS.has(ext)) {
return {
text: `[用户上传了图片: ${fileName}]`,
mimeType: getMimeType(ext),
truncated: false,
};
}
// 5. 其他:尝试当文本读取
try {
const raw = fs.readFileSync(filePath, 'utf-8');
const truncated = raw.length > MAX_TEXT_LENGTH;
const text = truncated ? raw.substring(0, MAX_TEXT_LENGTH) + '\n\n... [文件内容过长,已截断]' : raw;
return { text, mimeType: 'application/octet-stream', truncated };
} catch {
return { text: `[不支持的文件格式: ${ext}]`, mimeType: 'application/octet-stream', truncated: false };
}
}
function getMimeType(ext) {
const map = {
'.txt': 'text/plain', '.md': 'text/markdown', '.log': 'text/plain',
'.csv': 'text/csv', '.json': 'application/json',
'.js': 'text/javascript', '.ts': 'text/typescript',
'.py': 'text/x-python', '.html': 'text/html', '.css': 'text/css',
'.xml': 'text/xml', '.yaml': 'text/yaml', '.yml': 'text/yaml',
'.pdf': 'application/pdf',
'.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',
'.gif': 'image/gif', '.webp': 'image/webp', '.svg': 'image/svg+xml',
};
return map[ext] || 'application/octet-stream';
}
module.exports = { parseFileContent };