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

View file

@ -23,15 +23,85 @@ export class SerpImageTool extends AbstractTool {
func = async function (opts) {
let { q, limit = 2, source = 'bing' } = opts
let serpRes = await fetch(`https://serp.ikechan8370.com/image/${source}?q=${encodeURIComponent(q)}&limit=${limit}`, {
// 验证参数
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'
'X-From-Library': 'ikechan8370',
'Accept': 'application/json'
}
})
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 (!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.'