突破NTQQ消息边界:LLOneBot的JSON卡片与语音消息全解析
【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 项目地址: https://gitcode.com/gh_mirrors/ll/LLOneBot
引言:NTQQ机器人开发的痛点与解决方案
你是否还在为NTQQ环境下无法发送富媒体消息而烦恼?作为QQ机器人开发者,你是否渴望在NTQQ平台上实现如JSON卡片、语音消息等高级交互功能?本文将深入解析LLOneBot项目如何突破NTQQ的消息类型限制,全面支持JSON卡片与语音消息,为你的机器人开发提供一站式解决方案。
读完本文,你将获得:
- 深入理解LLOneBot对JSON卡片消息的完整支持方案
- 掌握语音消息在NTQQ环境下的处理流程与实现细节
- 学会使用CQ码构造和解析复杂消息类型
- 获取在实际项目中应用这些功能的最佳实践与代码示例
LLOneBot项目概述
LLOneBot是一个使NTQQ(New Technology QQ)支持OneBot11协议的开源项目,允许开发者使用熟悉的OneBot标准进行QQ机器人开发。项目基于Electron和TypeScript构建,通过Hook NTQQ的内部API实现对各种消息类型的支持,包括文本、图片、语音和高级的JSON卡片消息。
JSON卡片消息支持解析
JSON卡片消息的结构与优势
JSON卡片(JSON Card)是一种结构化的富媒体消息格式,允许开发者创建包含标题、描述、图片、按钮等元素的交互式消息。相比普通文本消息,JSON卡片具有以下优势:
| 特性 | 普通文本消息 | JSON卡片消息 |
|---|---|---|
| 信息组织 | 线性文本流 | 结构化布局 |
| 视觉呈现 | 纯文本 | 支持图片、按钮、分栏等 |
| 交互能力 | 无 | 支持按钮点击事件 |
| 信息量 | 有限 | 丰富且层次分明 |
| 可读性 | 依赖格式符号 | 自带视觉层次结构 |
LLOneBot中的JSON卡片实现
LLOneBot通过CQ码(CoolQ Code)扩展实现对JSON卡片的支持。在cqcode.ts文件中,我们可以看到LLOneBot如何解析和生成包含JSON卡片的消息:
// 解析CQ码的核心函数
export function decodeCQCode(source: string): OB11MessageData[] {
const elements: any[] = []
let result: ReturnType<typeof from>
while ((result = from(source))) {
const { type, data, capture } = result
if (capture.index) {
elements.push(h('text', { text: unescape(source.slice(0, capture.index)) }))
}
elements.push(h(type, data))
source = source.slice(capture.index + capture[0].length)
}
if (source) elements.push(h('text', { text: unescape(source) }))
return elements
}
JSON卡片消息的构造与发送
要发送JSON卡片消息,开发者需要使用特定的CQ码格式。以下是一个构造和发送JSON卡片消息的示例:
// 构造JSON卡片CQ码
function createJsonCardCQCode(cardData) {
return encodeCQCode({
type: 'json',
data: {
content: JSON.stringify(cardData)
}
})
}
// 发送群消息示例(SendGroupMsg.ts)
class SendGroupMsg extends SendMsg {
actionName = ActionName.SendGroupMsg
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
delete (payload as Partial<OB11PostSendMsg>).user_id
payload.message_type = 'group'
return super.check(payload)
}
}
JSON卡片消息的处理流程
LLOneBot处理JSON卡片消息的完整流程如下:
语音消息支持解析
语音消息在NTQQ中的处理挑战
NTQQ对语音消息有特殊的格式要求,只支持特定编码的语音文件。LLOneBot需要解决以下挑战:
- 语音格式转换(支持多种输入格式转为NTQQ兼容格式)
- 语音时长计算与验证
- 异步发送与状态跟踪
- 语音文件的临时存储与清理
LLOneBot的语音处理模块
在audio.ts文件中,LLOneBot实现了完整的语音处理功能,包括编码转换、时长计算等核心功能:
// 语音编码转换核心函数
export async function encodeSilk(filePath: string) {
try {
const file = await fsPromise.readFile(filePath)
const pttPath = path.join(TEMP_DIR, randomUUID())
if (!isSilk(file)) {
log(`语音文件${filePath}需要转换成silk`)
// 使用FFmpeg进行格式转换
const convert = () => {
return new Promise<Buffer>((resolve, reject) => {
const ffmpegPath = getConfigUtil().getConfig().ffmpeg || process.env.FFMPEG_PATH || 'ffmpeg'
const cp = spawn(ffmpegPath, ['-y', '-i', filePath, '-ar', '24000', '-ac', '1', '-f', 's16le', pcmPath])
// ...转换过程处理
})
}
// ...处理逻辑
} else {
// 已经是Silk格式,直接处理
// ...
}
} catch (error: any) {
log('convert silk failed', error.stack)
return {}
}
}
语音消息的完整处理流程
LLOneBot处理语音消息的完整流程如下:
语音消息的发送实现
LLOneBot通过SendPrivateMsg和SendGroupMsg类支持语音消息的发送,这两个类都继承自SendMsg基类:
// 发送私聊消息实现
class SendPrivateMsg extends SendMsg {
actionName = ActionName.SendPrivateMsg
protected async check(payload: OB11PostSendMsg): Promise<BaseCheckResult> {
payload.message_type = 'private'
return super.check(payload)
}
}
在消息发送过程中,语音文件会经过格式转换、临时存储和清理等步骤,确保符合NTQQ的要求并保持系统清洁。
消息发送的核心流程
消息发送的整体架构
LLOneBot的消息发送系统采用分层架构设计,从OneBot协议解析到底层API调用,形成了完整的调用链:
消息发送的状态管理
LLOneBot实现了完善的消息发送状态管理机制,确保消息可靠发送:
// 消息发送状态管理(msg.ts)
export let sendMessagePool: Record<string, ((sendSuccessMsg: RawMessage) => void) | null> = {} // peerUid: callbackFunc
export let sentMessages: Record<string, RawMessage> = {} // msgId: RawMessage
async function sendWaiter(peer: Peer, waitComplete = true, timeout: number = 10000) {
// 等待上一个相同的peer发送完
const peerUid = peer.peerUid
let checkLastSendUsingTime = 0
const waitLastSend = async () => {
if (checkLastSendUsingTime > timeout) {
throw '发送超时'
}
let lastSending = sendMessagePool[peer.peerUid]
if (lastSending) {
await sleep(500)
checkLastSendUsingTime += 500
return await waitLastSend()
}
}
await waitLastSend()
// ...后续实现
}
实战应用:构建复杂消息示例
示例1:发送带按钮的JSON卡片
// 构造JSON卡片数据
const cardData = {
type: "template",
data: {
title: "LLOneBot功能测试",
content: "这是一个带按钮的JSON卡片示例",
image: "https://example.com/image.png",
buttons: [
{
text: "查看文档",
action: "open_url",
url: "https://github.com/LLOneBot/LLOneBot"
},
{
text: "发送测试消息",
action: "callback",
data: "test_action"
}
]
}
};
// 转换为CQ码
const cqCode = encodeCQCode({
type: "json",
data: { content: JSON.stringify(cardData) }
});
// 发送群消息
sendGroupMsg({
group_id: 123456789,
message: cqCode
});
示例2:发送语音消息并跟踪状态
// 构造语音CQ码
const voiceCqCode = encodeCQCode({
type: "record",
data: {
file: "local:///path/to/audio.mp3",
magic: 1,
cache: 1
}
});
// 发送私聊消息
const result = await sendPrivateMsg({
user_id: 987654321,
message: voiceCqCode
});
// 检查发送状态
if (result.status === "ok") {
console.log(`语音消息发送成功,消息ID: ${result.data.message_id}`);
// 可以继续跟踪消息状态或进行后续操作
setTimeout(async () => {
const msgStatus = await getMessageStatus(result.data.message_id);
console.log(`语音消息状态: ${msgStatus}`);
}, 3000);
} else {
console.error(`语音消息发送失败: ${result.msg}`);
}
最佳实践与性能优化
消息处理性能优化建议
- 批量处理消息:对于大量消息发送需求,使用批处理减少API调用次数
- 合理设置超时:根据消息类型设置合理的超时时间,语音消息通常需要更长时间
- 缓存转换结果:对于重复使用的语音或卡片,缓存转换结果减少资源消耗
- 异步处理:使用异步IO和非阻塞操作处理文件转换和网络请求
错误处理与重试策略
// 消息发送重试逻辑示例
async function sendWithRetry(peer, elements, retries = 3, delay = 1000) {
try {
return await NTQQMsgApi.sendMsg(peer, elements);
} catch (error) {
if (retries > 0) {
log(`消息发送失败,剩余重试次数: ${retries}`, error);
await sleep(delay);
return sendWithRetry(peer, elements, retries - 1, delay * 2); // 指数退避
}
throw error;
}
}
总结与展望
LLOneBot通过创新的技术方案,成功突破了NTQQ对消息类型的限制,为开发者提供了完整的JSON卡片和语音消息支持。本文详细解析了这些功能的实现原理和使用方法,包括:
- JSON卡片消息的结构、构造方法和发送流程
- 语音消息的格式转换、编码处理和状态管理
- 完整的消息发送架构和状态跟踪机制
- 实战示例和最佳实践建议
随着项目的不断发展,LLOneBot将继续完善对更多消息类型的支持,包括视频消息、文件传输等高级功能,为NTQQ机器人开发提供更强大的工具集。
鼓励与互动
如果本文对你的NTQQ机器人开发有所帮助,请点赞、收藏并关注项目仓库获取最新更新。如有任何问题或建议,欢迎在项目GitHub仓库提交issue或PR参与项目贡献。
下一篇我们将探讨"LLOneBot的事件系统与消息推送机制",敬请期待!
【免费下载链接】LLOneBot 使你的NTQQ支持OneBot11协议进行QQ机器人开发 项目地址: https://gitcode.com/gh_mirrors/ll/LLOneBot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



