尝试兼容napcat,修复伪人发送表情乱码 以及一些兼容性修改

This commit is contained in:
chenyuxin221 2025-04-03 15:38:23 +08:00
parent c82c137596
commit b4032881da
4 changed files with 134 additions and 28 deletions

View file

@ -465,6 +465,17 @@ export const faceMapReverse = {
} }
export async function convertFaces (msg, handleAt = false, e) { export async function convertFaces (msg, handleAt = false, e) {
if (!msg) return []
// 处理HTML实体编码和多余右括号
if (typeof msg === 'string') {
msg = msg.replace(/[/g, '[')
.replace(/]/g, ']')
.replace(/&/g, '&')
.replace(/\\/g, '') // 移除多余的反斜杠
.replace(/\]+/g, ']') // 将多个连续的右括号替换为单个右括号
}
handleAt = e?.isGroup && handleAt handleAt = e?.isGroup && handleAt
let groupMembers let groupMembers
let groupCardQQMap = {} let groupCardQQMap = {}
@ -486,6 +497,7 @@ export async function convertFaces (msg, handleAt = false, e) {
} }
} }
} }
let tmpMsg = '' let tmpMsg = ''
let tmpFace = '' let tmpFace = ''
let tmpAt = '' let tmpAt = ''
@ -493,13 +505,20 @@ export async function convertFaces (msg, handleAt = false, e) {
let foundAt = false let foundAt = false
let msgs = [] let msgs = []
for (let i = 0; i < msg.length; i++) { for (let i = 0; i < msg.length; i++) {
// console.log(msg[i]) const char = msg[i]
if (msg[i] === '[') { const nextChar = msg[i + 1]
if (char === '[') {
foundFace = true foundFace = true
if (tmpMsg) {
msgs.push(tmpMsg)
tmpMsg = ''
}
continue continue
} }
if (!foundFace) { if (!foundFace) {
if (handleAt && msg[i] === '@') { if (handleAt && char === '@') {
foundAt = true foundAt = true
if (tmpMsg) { if (tmpMsg) {
msgs.push(tmpMsg) msgs.push(tmpMsg)
@ -508,7 +527,7 @@ export async function convertFaces (msg, handleAt = false, e) {
continue continue
} }
if (handleAt && foundAt) { if (handleAt && foundAt) {
tmpAt += msg[i] tmpAt += char
if (groupCardQQMap[tmpAt]) { if (groupCardQQMap[tmpAt]) {
foundAt = false foundAt = false
msgs.push(segment.at(groupCardQQMap[tmpAt], groupMembers.get(groupCardQQMap[tmpAt]).card, false)) msgs.push(segment.at(groupCardQQMap[tmpAt], groupMembers.get(groupCardQQMap[tmpAt]).card, false))
@ -516,36 +535,53 @@ export async function convertFaces (msg, handleAt = false, e) {
continue continue
} }
} else { } else {
tmpMsg += msg[i] tmpMsg += char
} }
} else { } else {
if (msg[i] !== ']') { if (char !== ']') {
tmpFace += msg[i] tmpFace += char
} else { } else {
foundFace = false foundFace = false
if (faceMapReverse[tmpFace] || faceMapReverse['/' + tmpFace] || faceMapReverse[_.trimStart(tmpFace, '/')]) { // 处理CQ码格式
if (tmpMsg) { if (tmpFace.startsWith('CQ:face,id=')) {
msgs.push(tmpMsg) const faceId = parseInt(tmpFace.split('=')[1].split(',')[0])
} msgs.push(segment.face(faceId))
msgs.push(segment.face(parseInt(faceMapReverse[tmpFace] || faceMapReverse['/' + tmpFace] || faceMapReverse[_.trimStart(tmpFace, '/')]))) tmpFace = ''
tmpMsg = '' }
} else { // 处理表情名称格式
tmpMsg += `[${tmpFace}]` else if (faceMapReverse[tmpFace] || faceMapReverse['/' + tmpFace] || faceMapReverse[_.trimStart(tmpFace, '/')]) {
msgs.push(segment.face(parseInt(faceMapReverse[tmpFace] || faceMapReverse['/' + tmpFace] || faceMapReverse[_.trimStart(tmpFace, '/')])))
tmpFace = ''
} else {
// 如果找不到对应的表情,将整个内容作为普通文本处理
tmpMsg += `[${tmpFace}]`
tmpFace = ''
} }
tmpFace = ''
} }
} }
} }
// 处理剩余内容
if (tmpMsg) { if (tmpMsg) {
msgs.push(tmpMsg) msgs.push(tmpMsg)
tmpMsg = '' // 清空临时消息
} }
// 处理未闭合的表情标记
if (tmpFace) { if (tmpFace) {
msgs.push(`[${tmpFace}`) if (tmpFace.endsWith(']')) {
msgs.push(`[${tmpFace.slice(0, -1)}]`) // 如果有多余的右括号,去掉它
} else {
msgs.push(`[${tmpFace}]`) // 正常添加右括号
}
} }
if (handleAt && tmpAt) { if (handleAt && tmpAt) {
msgs.push(`@${tmpAt}`) msgs.push(`@${tmpAt}`)
} }
return msgs
// 确保返回数组
return Array.isArray(msgs) ? msgs : [msgs].filter(Boolean)
} }
export function testConvertFaces () { export function testConvertFaces () {

View file

@ -23,15 +23,85 @@ export class SerpImageTool extends AbstractTool {
func = async function (opts) { func = async function (opts) {
let { q, limit = 2, source = 'bing' } = opts let { q, limit = 2, source = 'bing' } = opts
let serpRes = await fetch(`https://serp.ikechan8370.com/image/${source}?q=${encodeURIComponent(q)}&limit=${limit}`, {
headers: {
'X-From-Library': 'ikechan8370'
}
})
serpRes = await serpRes.json()
let res = serpRes.data // 验证参数
return `images search results in json format:\n${JSON.stringify(res)}. the murl field is actual picture url. You should use sendPicture to send them` if (!q || typeof q !== 'string') {
return {
error: 'Invalid search query',
data: []
}
}
// 验证搜索源
if (!['bing', 'yandex'].includes(source)) {
return {
error: 'Invalid search source. Must be either "bing" or "yandex"',
data: []
}
}
try {
// 构建 URL
const url = `https://serp.ikechan8370.com/image/${source}?q=${encodeURIComponent(q)}&limit=${limit}`
console.log('Searching images with URL:', url)
let serpRes = await fetch(url, {
headers: {
'X-From-Library': 'ikechan8370',
'Accept': 'application/json'
}
})
// 检查响应状态
if (!serpRes.ok) {
const errorText = await serpRes.text()
console.error('API error response:', errorText)
throw new Error(`HTTP error! status: ${serpRes.status}, response: ${errorText}`)
}
// 获取响应文本并解析 JSON
const serpData = await serpRes.json()
console.log('API response:', JSON.stringify(serpData, null, 2))
// 验证响应格式
if (!serpData || serpData.code !== 200 || !Array.isArray(serpData.data)) {
console.error('Invalid response format:', serpData)
throw new Error('Invalid response format from server')
}
// 确保返回的数据是数组
const res = Array.isArray(serpData.data) ? serpData.data : []
if (res.length === 0) {
return {
error: 'No images found',
data: []
}
}
// 验证每个图片 URL
const validImages = res.filter(img => {
if (!img || typeof img !== 'object') return false
if (!img.murl || typeof img.murl !== 'string') return false
if (!img.murl.startsWith('http')) return false
return true
})
if (validImages.length === 0) {
return {
error: 'No valid image URLs found',
data: []
}
}
return `images search results in json format:\n${JSON.stringify(validImages)}. the murl field is actual picture url. You should use sendPicture to send them`
} catch (error) {
console.error('Search image error:', error)
return {
error: `Failed to search images: ${error.message}`,
data: []
}
}
} }
description = 'Useful when you want to search images from the Internet.' description = 'Useful when you want to search images from the Internet.'