@huo15/dingtalk-connector-pro 1.0.5 → 1.0.7
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/README.en.md +106 -384
- package/README.md +14 -18
- package/dist/index.js +17 -0
- package/dist/openclaw.plugin.json +498 -0
- package/dist/package.json +91 -0
- package/dist/src/channel.js +415 -0
- package/dist/src/config/accounts.js +182 -0
- package/dist/src/config/schema.js +135 -0
- package/dist/src/core/connection.js +561 -0
- package/dist/src/core/message-handler.js +1422 -0
- package/dist/src/core/provider.js +59 -0
- package/dist/src/core/state.js +49 -0
- package/dist/src/directory.js +53 -0
- package/dist/src/docs.js +209 -0
- package/dist/src/gateway-methods.js +360 -0
- package/dist/src/onboarding.js +337 -0
- package/dist/src/policy.js +15 -0
- package/dist/src/probe.js +144 -0
- package/dist/src/reply-dispatcher.js +435 -0
- package/dist/src/runtime.js +26 -0
- package/dist/src/sdk/helpers.js +237 -0
- package/dist/src/sdk/types.js +13 -0
- package/dist/src/secret-input.js +13 -0
- package/dist/src/services/media/audio.js +40 -0
- package/dist/src/services/media/chunk-upload.js +211 -0
- package/dist/src/services/media/common.js +120 -0
- package/dist/src/services/media/file.js +54 -0
- package/dist/src/services/media/image.js +59 -0
- package/dist/src/services/media/index.js +9 -0
- package/dist/src/services/media/video.js +133 -0
- package/dist/src/services/media.js +889 -0
- package/dist/src/services/messaging/card.js +234 -0
- package/dist/src/services/messaging/index.js +8 -0
- package/dist/src/services/messaging/send.js +85 -0
- package/dist/src/services/messaging.js +680 -0
- package/dist/src/targets.js +38 -0
- package/dist/src/types/index.js +1 -0
- package/dist/src/utils/agent.js +55 -0
- package/dist/src/utils/async.js +40 -0
- package/dist/src/utils/constants.js +24 -0
- package/dist/src/utils/http-client.js +33 -0
- package/dist/src/utils/index.js +7 -0
- package/dist/src/utils/logger.js +76 -0
- package/dist/src/utils/session.js +95 -0
- package/dist/src/utils/token.js +71 -0
- package/dist/src/utils/utils-legacy.js +393 -0
- package/index.ts +3 -3
- package/openclaw.plugin.json +1 -1
- package/package.json +16 -5
- package/src/channel.js +415 -0
- package/src/channel.ts +12 -12
- package/src/config/accounts.js +182 -0
- package/src/config/accounts.ts +2 -2
- package/src/config/schema.js +135 -0
- package/src/config/schema.ts +2 -2
- package/src/core/connection.js +561 -0
- package/src/core/connection.ts +2 -2
- package/src/core/message-handler.js +1422 -0
- package/src/core/message-handler.ts +12 -12
- package/src/core/provider.js +59 -0
- package/src/core/provider.ts +4 -4
- package/src/core/state.js +49 -0
- package/src/directory.js +53 -0
- package/src/directory.ts +2 -2
- package/src/docs.js +209 -0
- package/src/docs.ts +3 -3
- package/src/gateway-methods.js +360 -0
- package/src/gateway-methods.ts +5 -5
- package/src/onboarding.js +337 -0
- package/src/onboarding.ts +4 -4
- package/src/policy.js +15 -0
- package/src/policy.ts +1 -1
- package/src/probe.js +144 -0
- package/src/probe.ts +2 -2
- package/src/reply-dispatcher.js +435 -0
- package/src/reply-dispatcher.ts +9 -9
- package/src/runtime.js +26 -0
- package/src/sdk/helpers.js +237 -0
- package/src/sdk/helpers.ts +1 -1
- package/src/sdk/types.js +13 -0
- package/src/secret-input.js +13 -0
- package/src/secret-input.ts +1 -1
- package/src/services/media/audio.js +40 -0
- package/src/services/media/audio.ts +2 -2
- package/src/services/media/chunk-upload.js +211 -0
- package/src/services/media/chunk-upload.ts +2 -2
- package/src/services/media/common.js +120 -0
- package/src/services/media/common.ts +3 -3
- package/src/services/media/file.js +54 -0
- package/src/services/media/file.ts +2 -2
- package/src/services/media/image.js +59 -0
- package/src/services/media/image.ts +2 -2
- package/src/services/media/index.js +9 -0
- package/src/services/media/index.ts +6 -6
- package/src/services/media/video.js +133 -0
- package/src/services/media/video.ts +2 -2
- package/src/services/media.js +889 -0
- package/src/services/media.ts +12 -12
- package/src/services/messaging/card.js +234 -0
- package/src/services/messaging/card.ts +3 -3
- package/src/services/messaging/index.js +8 -0
- package/src/services/messaging/index.ts +3 -3
- package/src/services/messaging/send.js +85 -0
- package/src/services/messaging/send.ts +3 -3
- package/src/services/messaging.js +680 -0
- package/src/services/messaging.ts +8 -8
- package/src/targets.js +38 -0
- package/src/targets.ts +1 -1
- package/src/types/index.js +1 -0
- package/src/types/index.ts +1 -1
- package/src/utils/agent.js +55 -0
- package/src/utils/async.js +40 -0
- package/src/utils/constants.js +24 -0
- package/src/utils/http-client.js +33 -0
- package/src/utils/http-client.ts +1 -1
- package/src/utils/index.js +7 -0
- package/src/utils/index.ts +4 -4
- package/src/utils/logger.js +76 -0
- package/src/utils/session.js +95 -0
- package/src/utils/session.ts +1 -1
- package/src/utils/token.js +71 -0
- package/src/utils/token.ts +2 -2
- package/src/utils/utils-legacy.js +393 -0
- package/src/utils/utils-legacy.ts +8 -8
- package/CHANGELOG.md +0 -485
- package/SKILL.md +0 -40
- package/_meta.json +0 -4
- package/docs/AGENT_ROUTING.md +0 -335
- package/docs/DEAP_AGENT_GUIDE.en.md +0 -115
- package/docs/DEAP_AGENT_GUIDE.md +0 -115
- package/docs/images/dingtalk.svg +0 -1
- package/docs/images/image-1.png +0 -0
- package/docs/images/image-2.png +0 -0
- package/docs/images/image-3.png +0 -0
- package/docs/images/image-4.png +0 -0
- package/docs/images/image-5.png +0 -0
- package/docs/images/image-6.png +0 -0
- package/docs/images/image-7.png +0 -0
- package/install-beta.sh +0 -438
- package/install-npm.sh +0 -167
- package/tsconfig.json +0 -20
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片处理模块
|
|
3
|
+
* 支持图片上传、本地路径处理
|
|
4
|
+
*/
|
|
5
|
+
import { LOCAL_IMAGE_RE, } from './common.js';
|
|
6
|
+
import { uploadMediaToDingTalk } from '../media.js';
|
|
7
|
+
/**
|
|
8
|
+
* 扫描内容中的本地图片路径,上传到钉钉并替换为标准 Markdown 图片语法
|
|
9
|
+
*
|
|
10
|
+
* 上传本地文件到钉钉媒体服务,获取 mediaId 后,
|
|
11
|
+
* 使用  格式替换原始本地路径。
|
|
12
|
+
*/
|
|
13
|
+
export async function processLocalImages(content, oapiToken, log) {
|
|
14
|
+
if (!oapiToken) {
|
|
15
|
+
log?.warn?.(`[DingTalk][Media] 无 oapiToken,跳过图片后处理`);
|
|
16
|
+
return content;
|
|
17
|
+
}
|
|
18
|
+
let result = content;
|
|
19
|
+
// 第一步:匹配 markdown 图片语法 
|
|
20
|
+
const mdMatches = [...content.matchAll(LOCAL_IMAGE_RE)];
|
|
21
|
+
if (mdMatches.length > 0) {
|
|
22
|
+
log?.info?.(`[DingTalk][Media] 检测到 ${mdMatches.length} 个 markdown 图片,开始上传...`);
|
|
23
|
+
for (const match of mdMatches) {
|
|
24
|
+
const [fullMatch, alt, rawPath] = match;
|
|
25
|
+
const cleanPath = rawPath.replace(/\\ /g, ' ');
|
|
26
|
+
const { mediaId } = await uploadMediaToDingTalk(cleanPath, 'image', oapiToken, 20 * 1024 * 1024, log);
|
|
27
|
+
if (mediaId) {
|
|
28
|
+
// 使用标准 Markdown 图片语法:
|
|
29
|
+
const replacement = ``;
|
|
30
|
+
result = result.replace(fullMatch, replacement);
|
|
31
|
+
log?.info?.(`[DingTalk][Media] 图片已替换为 Markdown 格式: ${replacement}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// 本地图片路径 不应该被强制转换为 图片地址,会直接影响用户展示,比如用户只是想知道某个图片具体的路径
|
|
36
|
+
// 第二步:匹配纯文本中的本地图片路径
|
|
37
|
+
// const bareMatches = [...result.matchAll(BARE_IMAGE_PATH_RE)];
|
|
38
|
+
// const newBareMatches = bareMatches.filter((m) => {
|
|
39
|
+
// if (m.index === undefined) return false;
|
|
40
|
+
// const idx = m.index;
|
|
41
|
+
// const before = result.slice(Math.max(0, idx - 10), idx);
|
|
42
|
+
// return !before.includes('](');
|
|
43
|
+
// });
|
|
44
|
+
// if (newBareMatches.length > 0) {
|
|
45
|
+
// log?.info?.(`[DingTalk][Media] 检测到 ${newBareMatches.length} 个纯文本图片路径,开始上传...`);
|
|
46
|
+
// for (const match of newBareMatches.reverse()) {
|
|
47
|
+
// const [fullMatch, rawPath] = match;
|
|
48
|
+
// log?.info?.(`[DingTalk][Media] 纯文本图片:"${fullMatch}" -> path="${rawPath}"`);
|
|
49
|
+
// const {mediaId} = await uploadMediaToDingTalk(rawPath, 'image', oapiToken, 20 * 1024 * 1024, log);
|
|
50
|
+
// if (mediaId) {
|
|
51
|
+
// // 使用标准 Markdown 图片语法:
|
|
52
|
+
// const replacement = ``;
|
|
53
|
+
// result = result.slice(0, match.index!) + result.slice(match.index!).replace(fullMatch, replacement);
|
|
54
|
+
// log?.info?.(`[DingTalk][Media] 替换纯文本路径为图片:${replacement}`);
|
|
55
|
+
// }
|
|
56
|
+
// }
|
|
57
|
+
// }
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 视频处理模块
|
|
3
|
+
* 支持视频元数据提取、封面生成、视频消息发送
|
|
4
|
+
*/
|
|
5
|
+
import { VIDEO_MARKER_PATTERN, toLocalPath, uploadMediaToDingTalk } from './common.js';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
/**
|
|
8
|
+
* 提取视频元数据(时长、分辨率)
|
|
9
|
+
*/
|
|
10
|
+
export async function extractVideoMetadata(filePath, log) {
|
|
11
|
+
try {
|
|
12
|
+
const ffmpeg = require('fluent-ffmpeg');
|
|
13
|
+
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
|
|
14
|
+
const ffprobePath = require('@ffprobe-installer/ffprobe').path;
|
|
15
|
+
ffmpeg.setFfmpegPath(ffmpegPath);
|
|
16
|
+
ffmpeg.setFfprobePath(ffprobePath);
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
ffmpeg.ffprobe(filePath, (err, metadata) => {
|
|
19
|
+
if (err) {
|
|
20
|
+
log?.warn?.(`[DingTalk][Video] ffprobe 执行失败:${err.message}`);
|
|
21
|
+
resolve(null);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const duration = metadata.format?.duration ? Math.floor(parseFloat(metadata.format.duration)) : 0;
|
|
26
|
+
const videoStream = metadata.streams?.find((s) => s.codec_type === 'video');
|
|
27
|
+
const width = videoStream?.width || 0;
|
|
28
|
+
const height = videoStream?.height || 0;
|
|
29
|
+
resolve({ duration, width, height });
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
log?.warn?.(`[DingTalk][Video] 解析 ffprobe 输出失败`);
|
|
33
|
+
resolve(null);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
log?.warn?.(`[DingTalk][Video] 提取视频元数据失败:${err.message}`);
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 生成视频封面图(第 1 秒截图)
|
|
45
|
+
*/
|
|
46
|
+
export async function extractVideoThumbnail(videoPath, outputPath, log) {
|
|
47
|
+
try {
|
|
48
|
+
const ffmpeg = require('fluent-ffmpeg');
|
|
49
|
+
const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path;
|
|
50
|
+
const path = await import('path');
|
|
51
|
+
ffmpeg.setFfmpegPath(ffmpegPath);
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
ffmpeg(videoPath)
|
|
54
|
+
.screenshots({
|
|
55
|
+
count: 1,
|
|
56
|
+
folder: path.dirname(outputPath),
|
|
57
|
+
filename: path.basename(outputPath),
|
|
58
|
+
timemarks: ['1'],
|
|
59
|
+
size: '?x360',
|
|
60
|
+
})
|
|
61
|
+
.on('end', () => {
|
|
62
|
+
log?.info?.(`[DingTalk][Video] 封面生成成功:${outputPath}`);
|
|
63
|
+
resolve(outputPath);
|
|
64
|
+
})
|
|
65
|
+
.on('error', (err) => {
|
|
66
|
+
log?.error?.(`[DingTalk][Video] 封面生成失败:${err.message}`);
|
|
67
|
+
resolve(null);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
log?.error?.(`[DingTalk][Video] ffmpeg 失败:${err.message}`);
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 提取视频标记并发送视频消息
|
|
78
|
+
*/
|
|
79
|
+
export async function processVideoMarkers(content, sessionWebhook, config, oapiToken, log, useProactiveApi = false, target) {
|
|
80
|
+
const logPrefix = useProactiveApi ? '[DingTalk][Video][Proactive]' : '[DingTalk][Video]';
|
|
81
|
+
if (!oapiToken) {
|
|
82
|
+
log?.warn?.(`${logPrefix} 无 oapiToken,跳过视频处理`);
|
|
83
|
+
return content;
|
|
84
|
+
}
|
|
85
|
+
const matches = [...content.matchAll(VIDEO_MARKER_PATTERN)];
|
|
86
|
+
if (matches.length === 0) {
|
|
87
|
+
log?.info?.(`${logPrefix} 未检测到视频标记,跳过处理`);
|
|
88
|
+
return content;
|
|
89
|
+
}
|
|
90
|
+
const videoInfos = [];
|
|
91
|
+
const invalidVideos = [];
|
|
92
|
+
for (const match of matches) {
|
|
93
|
+
try {
|
|
94
|
+
const videoData = JSON.parse(match[1]);
|
|
95
|
+
const rawPath = videoData.path;
|
|
96
|
+
const absPath = toLocalPath(rawPath);
|
|
97
|
+
videoInfos.push({ path: absPath });
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
log?.warn?.(`${logPrefix} 解析视频标记失败:${match[1]}`);
|
|
101
|
+
invalidVideos.push(match[1]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (videoInfos.length === 0) {
|
|
105
|
+
// 只有无效标记时,也要移除标记避免原样输出
|
|
106
|
+
if (invalidVideos.length > 0) {
|
|
107
|
+
log?.warn?.(`${logPrefix} 检测到无效视频标记,已忽略并移除`);
|
|
108
|
+
return content.replaceAll(VIDEO_MARKER_PATTERN, '').trim();
|
|
109
|
+
}
|
|
110
|
+
return content;
|
|
111
|
+
}
|
|
112
|
+
log?.info?.(`${logPrefix} 检测到 ${videoInfos.length} 个视频,开始上传...`);
|
|
113
|
+
let result = content;
|
|
114
|
+
for (const match of matches) {
|
|
115
|
+
const full = match[0];
|
|
116
|
+
try {
|
|
117
|
+
const videoData = JSON.parse(match[1]);
|
|
118
|
+
const absPath = toLocalPath(videoData.path);
|
|
119
|
+
if (!fs.existsSync(absPath)) {
|
|
120
|
+
log?.warn?.(`${logPrefix} 视频文件不存在:${absPath}`);
|
|
121
|
+
result = result.replace(full, '⚠️ 视频文件不存在');
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const mediaId = await uploadMediaToDingTalk(absPath, 'video', oapiToken, 20 * 1024 * 1024, log);
|
|
125
|
+
result = result.replace(full, mediaId ? `[视频已上传:${mediaId}]` : '⚠️ 视频上传失败');
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
log?.warn?.(`${logPrefix} 解析视频标记失败:${match[1]}`);
|
|
129
|
+
result = result.replace(full, '');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|