egg_server/routes/bot/groupAgent/chatHistory.ts
zhaoyingbo 056d51f5a7
All checks were successful
Egg Server CI/CD / build-image (push) Successful in 46s
Egg Server CI/CD / refresh-image (push) Successful in 14s
Egg Server CI/CD / fast-deploy (push) Successful in 3s
feat(group-agent): 更新卡片 & 过滤机器人消息
2024-10-15 01:33:25 +00:00

166 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { parseJsonString } from "@egg/hooks"
import logger from "@egg/logger"
import { Context, LarkServer } from "../../../types"
interface Message {
user: string
content: string
time: string
}
/**
* 提取 JSON 数据中的文本内容
* @param data - JSON 数据
* @returns 提取的文本内容
*/
const extractTextFromJson = (data: any): string => {
let result = ""
if (Array.isArray(data)) {
// 如果是数组,遍历数组元素
for (const element of data) {
result += extractTextFromJson(element) // 递归调用处理每个元素
}
} else if (typeof data === "object" && data !== null) {
// 如果是对象,遍历对象的键
for (const key in data) {
if (key === "text" && typeof data[key] === "string") {
result += data[key] // 拼接 text 值
} else {
result += extractTextFromJson(data[key]) // 递归调用处理子对象
}
}
}
return result
}
/**
* 获取聊天历史记录
* @param context - 上下文数据
* @returns 聊天消息数组
*/
const getChatHistory = async ({
larkService,
larkBody: {
actionValue: { chatId, timeScope },
},
}: Context.Data): Promise<Message[]> => {
// 获取历史消息timeScope为1、3、7分别代表1天、3天、7天
// 获取服务器的时区偏移量(以分钟为单位)
const serverTimezoneOffset = new Date().getTimezoneOffset()
// 上海时区的偏移量UTC+8以分钟为单位
const shanghaiTimezoneOffset = -8 * 60
// 计算时间戳,调整为上海时区
const endTimeTimestamp =
Math.round(new Date().getTime() / 1000) +
(shanghaiTimezoneOffset - serverTimezoneOffset) * 60
const startTimeTimestamp = endTimeTimestamp - Number(timeScope) * 24 * 60 * 60
// 获取群聊中的历史记录
const { data: chatHistory } = await larkService.message.getHistory(
chatId,
String(startTimeTimestamp),
String(endTimeTimestamp)
)
if (chatHistory.length === 0) return []
// 清洗数据
// 取出所有的被AT的人以及发送者
const mentions: Map<string, string> = new Map()
const senders: Set<string> = new Set()
// 过滤出文本和post消息
const allowedMsgTypes = ["text", "post"]
const filteredMsg: typeof chatHistory = []
// 遍历历史消息
for (const chat of chatHistory) {
if (chat.mentions) {
for (const mention of chat.mentions) {
mentions.set(mention.id, mention.name)
}
}
if (chat.sender && chat.sender.sender_type === "user") {
senders.add(chat.sender.id)
}
if (allowedMsgTypes.includes(chat.msg_type)) {
filteredMsg.push(chat)
}
}
// 取出没有被AT的发送者
const noMentionSenders = new Set(
[...senders].filter((sender) => !mentions.has(sender))
)
logger.debug(`Mentions: ${JSON.stringify(mentions)}`)
logger.debug(`Senders: ${JSON.stringify(senders)}`)
logger.debug(`No mention senders: ${JSON.stringify(noMentionSenders)}`)
// 从接口获取用户名
if (noMentionSenders.size !== 0) {
const {
data: { items },
} = await larkService.user.batchGet([...noMentionSenders])
logger.debug(`Get user info: ${JSON.stringify(items)}`)
for (const item of items) {
mentions.set(item.open_id, item.name)
}
}
const messages: Message[] = []
/**
* 获取文本消息内容
* @param chat - 聊天消息数据
* @returns 文本消息内容
*/
const getText = (chat: LarkServer.MessageData) => {
let { text } = parseJsonString(chat.body.content, { text: "" }) as {
text: string
}
if (!text) return ""
// 替换被AT的人
if (chat.mentions) {
for (const mention of chat.mentions) {
const mentionKey = mention.key
const mentionName = `@${mention.name}`
text = text.replace(mentionKey, mentionName)
}
}
// 去除可能出现的标签
return text.replace(/<[^>]+>/g, "")
}
/**
* 获取 post 消息内容
* @param chat - 聊天消息数据
* @returns post 消息内容
*/
const getPost = (chat: LarkServer.MessageData) => {
const content = parseJsonString(chat.body.content, null)
if (!content) return ""
return extractTextFromJson(content)
}
// 构建消息数组
for (const chat of filteredMsg) {
// 过滤掉机器人消息
const user = mentions.get(chat.sender.id)
if (!user) continue
messages.push({
user: mentions.get(chat.sender.id)!,
content: chat.msg_type === "text" ? getText(chat) : getPost(chat),
time: new Date(Number(chat.create_time)).toLocaleString("zh-CN", {
timeZone: "Asia/Shanghai",
}),
})
}
return messages
}
export default getChatHistory