@dcrays/dcgchat-test 0.2.12 → 0.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/bot.ts +137 -0
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -152,6 +152,116 @@ function createFileExtractor() {
|
|
|
152
152
|
return { getNewFiles }
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* 从文本中提取 /mobook 目录下的文件
|
|
157
|
+
* @param {string} text
|
|
158
|
+
* @returns {string[]}
|
|
159
|
+
*/
|
|
160
|
+
const EXT_LIST = [
|
|
161
|
+
// 文档类
|
|
162
|
+
'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'txt', 'rtf', 'odt',
|
|
163
|
+
|
|
164
|
+
// 数据/开发
|
|
165
|
+
'json', 'xml', 'csv', 'yaml', 'yml',
|
|
166
|
+
|
|
167
|
+
// 前端/文本
|
|
168
|
+
'html', 'htm', 'md', 'markdown', 'css', 'js', 'ts',
|
|
169
|
+
|
|
170
|
+
// 图片
|
|
171
|
+
'png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'svg', 'ico', 'tiff',
|
|
172
|
+
|
|
173
|
+
// 音频
|
|
174
|
+
'mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a',
|
|
175
|
+
|
|
176
|
+
// 视频
|
|
177
|
+
'mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm',
|
|
178
|
+
|
|
179
|
+
// 压缩包
|
|
180
|
+
'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz',
|
|
181
|
+
|
|
182
|
+
// 可执行/程序
|
|
183
|
+
'exe', 'dmg', 'pkg', 'apk', 'ipa',
|
|
184
|
+
|
|
185
|
+
// 其他常见
|
|
186
|
+
'log', 'dat', 'bin'
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
function extractMobookFiles(text = '') {
|
|
190
|
+
if (typeof text !== 'string' || !text.trim()) return [];
|
|
191
|
+
|
|
192
|
+
const result = new Set();
|
|
193
|
+
|
|
194
|
+
// ✅ 支持的文件类型(可扩展)
|
|
195
|
+
const EXT = `(${EXT_LIST.join('|')})`
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
// 1️⃣ 提取 `xxx.xxx`(反引号包裹)
|
|
199
|
+
const backtickMatches = text.match(
|
|
200
|
+
new RegExp(`\`([^\\\`]+?\\.${EXT})\``, 'gi')
|
|
201
|
+
) || [];
|
|
202
|
+
|
|
203
|
+
backtickMatches.forEach(item => {
|
|
204
|
+
const name = item.replace(/`/g, '').trim();
|
|
205
|
+
if (isValidFileName(name)) {
|
|
206
|
+
result.add(`/mobook/${name}`);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// 2️⃣ 提取 "/mobook/xxx.xxx"(完整路径)
|
|
211
|
+
const fullPathMatches = text.match(
|
|
212
|
+
new RegExp(`/mobook/[\\w\\u4e00-\\u9fa5.-]+?\\.${EXT}`, 'gi')
|
|
213
|
+
) || [];
|
|
214
|
+
|
|
215
|
+
fullPathMatches.forEach(p => {
|
|
216
|
+
result.add(normalizePath(p));
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
// 3️⃣ 提取 “mobook下的 xxx.xxx”
|
|
220
|
+
const mobookInlineMatches = text.match(
|
|
221
|
+
new RegExp(`mobook下的\\s*([\\w\\u4e00-\\u9fa5.-]+?\\.${EXT})`, 'gi')
|
|
222
|
+
) || [];
|
|
223
|
+
|
|
224
|
+
mobookInlineMatches.forEach(item => {
|
|
225
|
+
const match = item.match(
|
|
226
|
+
new RegExp(`([\\w\\u4e00-\\u9fa5.-]+?\\.${EXT})`, 'i')
|
|
227
|
+
);
|
|
228
|
+
if (match && isValidFileName(match[1])) {
|
|
229
|
+
result.add(`/mobook/${match[1]}`);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
} catch (e) {
|
|
234
|
+
// 容错:解析异常不影响主流程
|
|
235
|
+
console.warn('extractMobookFiles error:', e);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return [...result];
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* 校验文件名是否合法(避免脏数据)
|
|
243
|
+
*/
|
|
244
|
+
function isValidFileName(name: string) {
|
|
245
|
+
if (!name) return false;
|
|
246
|
+
|
|
247
|
+
// 过滤异常字符
|
|
248
|
+
if (/[\/\\<>:"|?*]/.test(name)) return false;
|
|
249
|
+
|
|
250
|
+
// 长度限制(防止异常长字符串)
|
|
251
|
+
if (name.length > 200) return false;
|
|
252
|
+
|
|
253
|
+
return true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 规范路径(去重用)
|
|
258
|
+
*/
|
|
259
|
+
function normalizePath(path: string) {
|
|
260
|
+
return path
|
|
261
|
+
.replace(/\/+/g, '/') // 多斜杠 → 单斜杠
|
|
262
|
+
.replace(/\/$/, ''); // 去掉结尾 /
|
|
263
|
+
}
|
|
264
|
+
|
|
155
265
|
/**
|
|
156
266
|
* 处理一条用户消息,调用 Agent 并返回回复
|
|
157
267
|
*/
|
|
@@ -369,6 +479,33 @@ export async function handleDcgchatMessage(params: {
|
|
|
369
479
|
}
|
|
370
480
|
log(`dcgchat[${accountId}][deliver]: sent ${completeFiles.length} media file(s) through channel adapter`);
|
|
371
481
|
}
|
|
482
|
+
const mobookFiles = extractMobookFiles(completeText)
|
|
483
|
+
if (mobookFiles.length > 0) {
|
|
484
|
+
for (let i = 0; i < mobookFiles.length; i++) {
|
|
485
|
+
let url = mobookFiles[i] as string
|
|
486
|
+
const key = getMediaKey(url);
|
|
487
|
+
if (sentMediaKeys.has(key)) {
|
|
488
|
+
log(`dcgchat[${accountId}]: mobookFiles already sent, skipping: ${url}`);
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
if (!fs.existsSync(url)) {
|
|
492
|
+
url = path.join(getWorkspaceDir(), url)
|
|
493
|
+
if (!fs.existsSync(url)) {
|
|
494
|
+
log(`dcgchat[${accountId}]: mobookFiles file not found, skipping: ${url}`);
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
sentMediaKeys.add(key);
|
|
499
|
+
await sendDcgchatMedia({
|
|
500
|
+
cfg,
|
|
501
|
+
accountId,
|
|
502
|
+
log,
|
|
503
|
+
mediaUrl: url,
|
|
504
|
+
text: "",
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
log(`dcgchat[${accountId}][deliver]: sent ${mobookFiles.length} media file(s) through channel adapter`);
|
|
508
|
+
}
|
|
372
509
|
log(`dcgchat[${accountId}]: dispatch complete, sending final state`);
|
|
373
510
|
params.onChunk({
|
|
374
511
|
messageType: "openclaw_bot_chat",
|