@dcrays/dcgchat-test 0.4.28 → 0.4.29
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/channel.ts +8 -8
- package/src/request/oss.ts +92 -9
- package/src/tools/messageTool.ts +1 -1
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -192,6 +192,14 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
|
|
|
192
192
|
return
|
|
193
193
|
}
|
|
194
194
|
const mediaUrl = expanded[0]
|
|
195
|
+
|
|
196
|
+
const { sessionId, agentId } = getInfoBySessionKey(sessionKey)
|
|
197
|
+
if (!msgCtx.sessionId) {
|
|
198
|
+
msgCtx.sessionId = sessionId
|
|
199
|
+
}
|
|
200
|
+
if (!msgCtx.agentId) {
|
|
201
|
+
msgCtx.agentId = agentId
|
|
202
|
+
}
|
|
195
203
|
if (!mediaUrl || !msgCtx.sessionId) {
|
|
196
204
|
dcgLogger(`dcgchat: sendMedia skipped (duplicate in session): ${mediaUrl} sessionId=${msgCtx.sessionId} sessionKey=${sessionKey}`)
|
|
197
205
|
return
|
|
@@ -213,19 +221,11 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
|
|
|
213
221
|
}
|
|
214
222
|
addSentMediaKey(msgCtx.sessionId, mediaUrl)
|
|
215
223
|
}
|
|
216
|
-
|
|
217
|
-
const { sessionId, agentId } = getInfoBySessionKey(sessionKey)
|
|
218
|
-
if (!msgCtx.sessionId) {
|
|
219
|
-
msgCtx.sessionId = sessionId
|
|
220
|
-
}
|
|
221
224
|
const fileName = mediaUrl?.split(/[\\/]/).pop() || ''
|
|
222
225
|
const notMessageId = `${msgCtx?.messageId}`?.length === 13 || !msgCtx?.messageId
|
|
223
226
|
try {
|
|
224
227
|
const botToken = msgCtx.botToken ?? getOpenClawConfig()?.channels?.["dcgchat-test"]?.botToken ?? ''
|
|
225
228
|
const url = mediaUrl ? await ossUpload(mediaUrl, botToken, 1) : ''
|
|
226
|
-
if (!msgCtx.agentId) {
|
|
227
|
-
msgCtx.agentId = agentId
|
|
228
|
-
}
|
|
229
229
|
wsSendRaw(msgCtx, {
|
|
230
230
|
response: opts.text ?? '',
|
|
231
231
|
is_finish: notMessageId ? -1 : 0,
|
package/src/request/oss.ts
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises'
|
|
2
|
+
import { extname } from 'node:path'
|
|
1
3
|
import { fileURLToPath } from 'node:url'
|
|
2
4
|
// @ts-ignore
|
|
3
5
|
import OSS from 'ali-oss'
|
|
4
6
|
import { getStsToken, getUserToken } from './api.js'
|
|
5
7
|
import { dcgLogger } from '../utils/log.js'
|
|
6
8
|
|
|
9
|
+
/** 仅对内存 Buffer 超过此大小使用分片(本地路径一律走 put,避免 multipart 对类型的限制) */
|
|
10
|
+
const MULTIPART_THRESHOLD_BYTES = 1024 * 1024
|
|
11
|
+
|
|
7
12
|
/** 分片大小:OSS 要求每片 ≥100 KB(最后一片可更小) */
|
|
8
13
|
const MULTIPART_PART_SIZE = 1024 * 1024
|
|
9
14
|
|
|
10
15
|
/** ali-oss 默认 timeout 为 60s,大文件单 PUT 或慢网易触发 ResponseTimeoutError */
|
|
11
|
-
const OSS_HTTP_TIMEOUT_MS =
|
|
16
|
+
const OSS_HTTP_TIMEOUT_MS = 15 * 60 * 1000
|
|
12
17
|
|
|
13
18
|
/** 归一化入参,避免 file://、包装对象、TypedArray 等导致 SDK 识别失败 */
|
|
14
19
|
function coerceOssFileInput(input: File | string | Buffer): File | string | Buffer {
|
|
@@ -38,11 +43,83 @@ function coerceOssFileInput(input: File | string | Buffer): File | string | Buff
|
|
|
38
43
|
return input
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
function
|
|
42
|
-
if (
|
|
43
|
-
|
|
46
|
+
async function getUploadByteLength(input: File | string | Buffer): Promise<number> {
|
|
47
|
+
if (Buffer.isBuffer(input)) return input.length
|
|
48
|
+
if (typeof input === 'string') {
|
|
49
|
+
const s = await stat(input)
|
|
50
|
+
return s.size
|
|
51
|
+
}
|
|
52
|
+
return input.size
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 常见可在浏览器内联预览的类型(避免一律 application/octet-stream 触发下载) */
|
|
56
|
+
const PREVIEW_EXT_MIME: Record<string, string> = {
|
|
57
|
+
'.jpg': 'image/jpeg',
|
|
58
|
+
'.jpeg': 'image/jpeg',
|
|
59
|
+
'.png': 'image/png',
|
|
60
|
+
'.gif': 'image/gif',
|
|
61
|
+
'.webp': 'image/webp',
|
|
62
|
+
'.bmp': 'image/bmp',
|
|
63
|
+
'.svg': 'image/svg+xml',
|
|
64
|
+
'.ico': 'image/x-icon',
|
|
65
|
+
'.avif': 'image/avif',
|
|
66
|
+
'.heic': 'image/heic',
|
|
67
|
+
'.heif': 'image/heif',
|
|
68
|
+
'.pdf': 'application/pdf',
|
|
69
|
+
'.mp4': 'video/mp4',
|
|
70
|
+
'.webm': 'video/webm',
|
|
71
|
+
'.mov': 'video/quicktime',
|
|
72
|
+
'.mp3': 'audio/mpeg',
|
|
73
|
+
'.wav': 'audio/wav',
|
|
74
|
+
'.ogg': 'audio/ogg',
|
|
75
|
+
'.opus': 'audio/opus',
|
|
76
|
+
'.m4a': 'audio/mp4',
|
|
77
|
+
'.aac': 'audio/aac',
|
|
78
|
+
'.flac': 'audio/flac',
|
|
79
|
+
'.txt': 'text/plain; charset=utf-8',
|
|
80
|
+
'.log': 'text/plain; charset=utf-8',
|
|
81
|
+
'.csv': 'text/csv; charset=utf-8',
|
|
82
|
+
'.html': 'text/html; charset=utf-8',
|
|
83
|
+
'.htm': 'text/html; charset=utf-8',
|
|
84
|
+
'.css': 'text/css; charset=utf-8',
|
|
85
|
+
'.js': 'text/javascript; charset=utf-8',
|
|
86
|
+
'.mjs': 'text/javascript; charset=utf-8',
|
|
87
|
+
'.json': 'application/json; charset=utf-8',
|
|
88
|
+
'.xml': 'application/xml; charset=utf-8',
|
|
89
|
+
'.md': 'text/markdown; charset=utf-8',
|
|
90
|
+
'.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
91
|
+
'.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
92
|
+
'.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function mimeFromPathOrName(pathOrName: string): string | undefined {
|
|
96
|
+
const base = pathOrName.split(/[/\\]/).pop() ?? pathOrName
|
|
97
|
+
const ext = extname(base).toLowerCase()
|
|
98
|
+
return ext ? PREVIEW_EXT_MIME[ext] : undefined
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** 解析上传 Content-Type,并配合 Content-Disposition: inline 便于直链预览 */
|
|
102
|
+
function resolveMime(input: File | string | Buffer, fileNameHint?: string): string {
|
|
103
|
+
if (typeof input === 'string') {
|
|
104
|
+
return mimeFromPathOrName(input) ?? 'application/octet-stream'
|
|
105
|
+
}
|
|
106
|
+
if (Buffer.isBuffer(input)) {
|
|
107
|
+
if (fileNameHint) {
|
|
108
|
+
const fromName = mimeFromPathOrName(fileNameHint)
|
|
109
|
+
if (fromName) return fromName
|
|
110
|
+
}
|
|
111
|
+
return 'application/octet-stream'
|
|
112
|
+
}
|
|
113
|
+
const declared = input.type?.trim()
|
|
114
|
+
if (declared && declared !== 'application/octet-stream') {
|
|
115
|
+
return declared
|
|
44
116
|
}
|
|
45
|
-
|
|
117
|
+
const name = typeof input.name === 'string' && input.name ? input.name : ''
|
|
118
|
+
if (name) {
|
|
119
|
+
const fromName = mimeFromPathOrName(name)
|
|
120
|
+
if (fromName) return fromName
|
|
121
|
+
}
|
|
122
|
+
return declared || 'application/octet-stream'
|
|
46
123
|
}
|
|
47
124
|
|
|
48
125
|
/**
|
|
@@ -82,7 +159,7 @@ export const ossUpload = async (
|
|
|
82
159
|
const file = coerceOssFileInput(rawFile)
|
|
83
160
|
const { content, fileName } = await toUploadContent(file)
|
|
84
161
|
const data = await getStsToken(fileName, botToken, isPrivate)
|
|
85
|
-
const mime = resolveMime(file)
|
|
162
|
+
const mime = resolveMime(file, fileName)
|
|
86
163
|
const onProgress = uploadOptions?.onProgress
|
|
87
164
|
|
|
88
165
|
const options: OSS.Options = {
|
|
@@ -114,15 +191,21 @@ export const ossUpload = async (
|
|
|
114
191
|
},
|
|
115
192
|
parallel: 4,
|
|
116
193
|
partSize: MULTIPART_PART_SIZE,
|
|
117
|
-
mime
|
|
194
|
+
mime,
|
|
195
|
+
/** 直链打开时优先内联展示,而非附件下载 */
|
|
196
|
+
headers: {
|
|
197
|
+
'Content-Disposition': 'inline'
|
|
198
|
+
}
|
|
118
199
|
}
|
|
119
200
|
objectResult = await client.multipartUpload(name, content, multipartUploadOptions)
|
|
120
201
|
|
|
121
202
|
if (objectResult?.res?.status !== 200) {
|
|
122
203
|
dcgLogger(`OSS 上传失败, ${objectResult?.res?.status}`)
|
|
123
204
|
}
|
|
124
|
-
|
|
125
|
-
|
|
205
|
+
const requestUrls = objectResult?.res?.requestUrls || []
|
|
206
|
+
const url = requestUrls[0] || ''
|
|
207
|
+
dcgLogger(`OSS 上传成功, ${isPrivate === 1 ? objectResult.name || url : url}`)
|
|
208
|
+
return isPrivate === 1 ? objectResult.name || url : url
|
|
126
209
|
} catch (error) {
|
|
127
210
|
dcgLogger(`OSS 上传失败: ${error}`, 'error')
|
|
128
211
|
}
|
package/src/tools/messageTool.ts
CHANGED