import type { PluginApi, ChannelAccount, ChannelChat, OutboundResult } from 'openclaw/plugin-sdk/core'; // VoceChat 账号配置类型 interface VoceChatAccount extends ChannelAccount { serverUrl: string; apiKey: string; botName?: string; } /** * 发送文本消息 */ export async function sendText( api: PluginApi, text: string, chat: ChannelChat, account: VoceChatAccount ): Promise { const { serverUrl, apiKey } = account; try { // 根据聊天类型选择 API 端点 const endpoint = chat.type === 'direct' ? `${serverUrl}/api/bot/send_to_user/${chat.id}` : `${serverUrl}/api/bot/send_to_group/${chat.id}`; const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'text/plain', 'x-api-key': apiKey, }, body: text, }); if (!res.ok) { const error = await res.text(); throw new Error(`VoceChat API error: ${res.status} ${error}`); } const data = await res.json(); return { ok: true, messageId: String(data) }; } catch (err) { api.logger.error('VoceChat: Failed to send text', err); return { ok: false, error: String(err) }; } } /** * 发送 Markdown 消息 */ export async function sendMarkdown( api: PluginApi, markdown: string, chat: ChannelChat, account: VoceChatAccount ): Promise { const { serverUrl, apiKey } = account; try { const endpoint = chat.type === 'direct' ? `${serverUrl}/api/bot/send_to_user/${chat.id}` : `${serverUrl}/api/bot/send_to_group/${chat.id}`; const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'text/markdown', 'x-api-key': apiKey, }, body: markdown, }); if (!res.ok) { const error = await res.text(); throw new Error(`VoceChat API error: ${res.status} ${error}`); } const data = await res.json(); return { ok: true, messageId: String(data) }; } catch (err) { api.logger.error('VoceChat: Failed to send markdown', err); return { ok: false, error: String(err) }; } } /** * 发送文件消息 * 注意:需要先上传文件获取 file_path */ export async function sendFile( api: PluginApi, filePath: string, chat: ChannelChat, account: VoceChatAccount ): Promise { const { serverUrl, apiKey } = account; try { const endpoint = chat.type === 'direct' ? `${serverUrl}/api/bot/send_to_user/${chat.id}` : `${serverUrl}/api/bot/send_to_group/${chat.id}`; const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'vocechat/file', 'x-api-key': apiKey, }, body: JSON.stringify({ path: filePath }), }); if (!res.ok) { const error = await res.text(); throw new Error(`VoceChat API error: ${res.status} ${error}`); } const data = await res.json(); return { ok: true, messageId: String(data) }; } catch (err) { api.logger.error('VoceChat: Failed to send file', err); return { ok: false, error: String(err) }; } } /** * 回复特定消息 */ export async function replyToMessage( api: PluginApi, text: string, mid: string, account: VoceChatAccount ): Promise { const { serverUrl, apiKey } = account; try { const endpoint = `${serverUrl}/api/bot/reply/${mid}`; const res = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'text/plain', 'x-api-key': apiKey, }, body: text, }); if (!res.ok) { const error = await res.text(); throw new Error(`VoceChat API error: ${res.status} ${error}`); } const data = await res.json(); return { ok: true, messageId: String(data) }; } catch (err) { api.logger.error('VoceChat: Failed to reply', err); return { ok: false, error: String(err) }; } } /** * 上传文件(用于发送文件消息前的准备) */ export async function uploadFile( api: PluginApi, fileBuffer: Buffer, fileName: string, account: VoceChatAccount ): Promise<{ ok: boolean; filePath?: string; error?: string }> { const { serverUrl, apiKey } = account; try { // 1. 准备上传 const prepareRes = await fetch(`${serverUrl}/api/bot/file/prepare`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, }, body: JSON.stringify({ content_type: 'application/octet-stream', file_name: fileName, }), }); if (!prepareRes.ok) { throw new Error('Failed to prepare file upload'); } const { upload_url, file_path } = await prepareRes.json(); // 2. 上传文件 const uploadRes = await fetch(upload_url, { method: 'PUT', body: fileBuffer, }); if (!uploadRes.ok) { throw new Error('Failed to upload file'); } return { ok: true, filePath: file_path }; } catch (err) { api.logger.error('VoceChat: Failed to upload file', err); return { ok: false, error: String(err) }; } }