feat: 优化飞书消息处理

This commit is contained in:
zhaoyingbo 2024-10-12 07:14:53 +00:00
parent b44f66f6be
commit 9dcd406280
18 changed files with 241 additions and 722 deletions

@ -27,6 +27,9 @@
"tseslint",
"userid",
"wlpbbgiky",
"Xauthor",
"Xicon",
"Xname",
"Yoav",
"zhaoyingbo"
]

BIN
bun.lockb

Binary file not shown.

@ -1,4 +1,4 @@
import { commonNote, pendingHeader, successHeader } from "./common"
import { cardComponent } from "@egg/lark-msg-tool"
const functionSelector = {
elements: [
@ -27,9 +27,9 @@ const functionSelector = {
{
tag: "hr",
},
commonNote,
cardComponent.commonNote,
],
pendingHeader,
header: cardComponent.pendingHeader,
}
const timeScopeSelector = {
@ -98,9 +98,9 @@ const timeScopeSelector = {
{
tag: "hr",
},
commonNote,
cardComponent.commonNote,
],
pendingHeader,
header: cardComponent.pendingHeader,
}
const resultReport = {
@ -120,15 +120,15 @@ const resultReport = {
{
tag: "hr",
},
commonNote,
cardComponent.commonNote,
],
successHeader,
header: cardComponent.pendingHeader,
}
const groupAgentCard = {
const cardMap = {
functionSelector,
timeScopeSelector,
resultReport,
}
export default groupAgentCard
export default cardMap

19
constant/function.ts Normal file

@ -0,0 +1,19 @@
const functionMap = {
egg: {
Xname: "小煎蛋",
Xauthor: "zhaoyingbo",
Xicon: "🍳",
},
groupAgent: {
Xname: "Group Agent",
Xauthor: "AI创新应用组",
Xicon: "🔥",
},
sheetDB: {
Xname: "小煎蛋 Sheet DB",
Xauthor: "zhaoyingbo",
Xicon: "🍪",
},
}
export default functionMap

22
constant/template.ts Normal file

@ -0,0 +1,22 @@
export enum CardTemplate {
groupSelector = "ctp_AA0LgXOkJpIn",
functionSelector = "ctp_AA0xqIITeUex",
timeScopeSelector = "ctp_AA00oqPWT1Hq",
resultReport = "ctp_AA00oqPWTHWP",
successMsg = "ctp_AA0LgXOkEOPK",
errorMsg = "ctp_AA0LgXOkEuqi",
}
const tempMap = {
groupSelector: "ctp_AA0LgXOkJpIn",
functionSelector: "ctp_AA0xqIITeUex",
timeScopeSelector: "ctp_AA00oqPWT1Hq",
resultReport: "ctp_AA00oqPWTHWP",
successMsg: "ctp_AA0LgXOkEOPK",
errorMsg: "ctp_AA0LgXOkEuqi",
chatId: "ctp_AAi3NnHb6zgK",
guide: "ctp_AAyVx5R39xU9",
createKVSuccess: "ctp_AA00oqPWPXtG",
}
export default tempMap

@ -19,36 +19,36 @@
"devDependencies": {
"@commitlint/cli": "^19.5.0",
"@commitlint/config-conventional": "^19.5.0",
"@eslint/js": "^9.11.1",
"@eslint/js": "^9.12.0",
"@types/node-schedule": "^2.1.7",
"@types/uuid": "^10.0.0",
"bun-types": "^1.1.29",
"eslint": "^9.11.1",
"bun-types": "^1.1.30",
"eslint": "^9.12.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"husky": "^9.1.6",
"lint-staged": "^15.2.10",
"prettier": "^3.3.3",
"typescript-eslint": "^8.7.0"
"typescript-eslint": "^8.8.1"
},
"peerDependencies": {
"typescript": "^5.5.4"
},
"dependencies": {
"@dotenvx/dotenvx": "^1.14.2",
"@dotenvx/dotenvx": "^1.19.0",
"@egg/hooks": "^1.2.0",
"@egg/lark-msg-tool": "^1.5.0",
"@egg/lark-msg-tool": "^1.7.1",
"@egg/logger": "^1.4.3",
"@egg/net-tool": "^1.9.1",
"@egg/path-tool": "^1.4.1",
"@langchain/core": "^0.3.4",
"@langchain/openai": "^0.3.2",
"@langchain/core": "^0.3.10",
"@langchain/openai": "^0.3.7",
"joi": "^17.13.3",
"langfuse-langchain": "^3.26.0",
"langfuse-langchain": "^3.27.0",
"node-schedule": "^2.1.1",
"p-limit": "^6.1.0",
"pocketbase": "^0.21.5",
"uuid": "^10.0.0",
"winston": "^3.14.2",
"winston": "^3.15.0",
"winston-daily-rotate-file": "^5.0.0"
}
}

@ -1,5 +1,3 @@
import { getActionType } from "@egg/lark-msg-tool"
import { Context } from "../../types"
import groupAgent from "./groupAgent"
@ -30,8 +28,10 @@ const manageAction = async (ctx: Context.Data) => {
* @param {Context.Data} ctx -
*/
export const manageActionMsg = async (ctx: Context.Data) => {
const actionType = getActionType(ctx.body)
if (["button", "select_static"].includes(actionType)) return ctx.genResp.ok()
const {
larkBody: { actionType },
} = ctx
if (["button", "select_static"].includes(actionType!)) return ctx.genResp.ok()
const card = await manageAction(ctx)
if (card) return ctx.genResp.custom(card)
return ctx.genResp.ok()

@ -1,29 +1,21 @@
import type { LarkEvent } from "@egg/lark-msg-tool"
import {
getChatId,
getChatType,
getMentions,
getMsgText,
getMsgType,
} from "@egg/lark-msg-tool"
import { type LarkBody } from "@egg/lark-msg-tool"
import db from "../../db"
import { LarkService } from "../../services"
import { Context } from "../../types"
import createKVTemp from "../sheet/createKVTemp"
import groupAgent from "./groupAgent"
/**
* P2P或者群聊并且艾特了机器人
* @param {LarkEvent.Data} body
* @param larkBody
*/
const getIsP2pOrGroupAtBot = async (body: LarkEvent.Data): Promise<boolean> => {
const getIsP2pOrGroupAtBot = async (larkBody: LarkBody): Promise<boolean> => {
const appList = (await db.appInfo.getFullList())
.map((v) => v.app_name)
.filter((v) => v)
const isP2p = getChatType(body) === "p2p"
const isAtBot = getMentions(body)?.some?.((mention) =>
const isP2p = larkBody.chatType === "p2p"
const isAtBot = larkBody.mentions?.some?.((mention) =>
appList.includes(mention.name)
)
return Boolean(isP2p || isAtBot)
@ -38,24 +30,24 @@ const filterIllegalMsg = async ({
body,
logger,
larkService,
larkBody,
}: Context.Data): Promise<boolean> => {
const { chatId, msgType, msgText } = larkBody
// 没有chatId的消息不处理
const chatId = getChatId(body)
logger.info(`bot req chatId: ${chatId}`)
if (!chatId) return true
// 非私聊和群聊中艾特机器人的消息不处理
if (!(await getIsP2pOrGroupAtBot(body))) {
if (!(await getIsP2pOrGroupAtBot(larkBody))) {
return true
}
// 获取msgType
const msgType = getMsgType(body)
logger.info(`bot req msgType: ${msgType}`)
// 放行纯文本消息
if (msgType === "text") {
// 过滤艾特全体成员的消息
if (getMsgText(body).includes("@_all")) {
if (msgText.includes("@_all")) {
return true
}
// 放行
@ -84,54 +76,67 @@ const filterIllegalMsg = async ({
/**
* ID消息
* @param {string} chatId - chatId
* @param {LarkService} service - Lark服务实例
* @param {Context.Data} ctx -
*/
const manageIdMsg = (chatId: string, service: LarkService): void => {
service.message.sendTemp("chat_id", chatId, "ctp_AAi3NnHb6zgK", {
chat_id: chatId,
})
const manageIdMsg = ({
larkBody: { chatId },
larkCard,
larkService,
}: Context.Data): void => {
larkService.message.sendCard2Chat(
chatId,
larkCard.genTempCard("chatId", { chat_id: chatId }) as string
)
}
/**
*
* @param {Context.Data} ctx - body, larkService和logger
* @param {Context.Data} ctx -
*/
const manageHelpMsg = (chatId: string, service: LarkService): void => {
service.message.sendTemp("chat_id", chatId, "ctp_AAyVx5R39xU9", {
chat_id: chatId,
})
const manageHelpMsg = ({
larkBody: { chatId },
larkCard,
larkService,
}: Context.Data): void => {
larkService.message.sendCard2Chat(
chatId,
larkCard.genTempCard("guide", { chat_id: chatId }) as string
)
}
/**
*
* @param {Context.Data} ctx - body, logger, larkService和attachService
* @param {Context.Data} ctx -
*/
const manageCMDMsg = (ctx: Context.Data) => {
const { body, logger, larkService, attachService } = ctx
const text = getMsgText(body)
logger.info(`bot req text: ${text}`)
const chatId = getChatId(body)
const {
body,
logger,
larkService,
attachService,
larkBody: { msgText, chatId },
} = ctx
logger.info(`bot req text: ${msgText}`)
// 处理命令消息
if (text.trim() === "/id") {
if (msgText.trim() === "/id") {
logger.info(`bot command is /id, chatId: ${chatId}`)
manageIdMsg(chatId, larkService)
manageIdMsg(ctx)
return
}
// 帮助
if (text.trim() === "/help") {
if (msgText.trim() === "/help") {
logger.info(`bot command is /help, chatId: ${chatId}`)
manageHelpMsg(chatId, larkService)
manageHelpMsg(ctx)
return
}
// CI监控
if (text.trim() === "/ci") {
if (msgText.trim() === "/ci") {
logger.info(`bot command is /ci, chatId: ${chatId}`)
attachService.ciMonitor(chatId)
return
}
// 简报
if (text.includes("share") && text.includes("简报")) {
if (msgText.includes("share") && msgText.includes("简报")) {
logger.info(`bot command is share report, chatId: ${chatId}`)
// 这个用时比较久,先发一条提醒用户收到了请求
// TODO: 迁移到简报服务中
@ -145,13 +150,13 @@ const manageCMDMsg = (ctx: Context.Data) => {
return
}
// 创建Sheet DB
if (text.trim() === "/gen db") {
if (msgText.trim() === "/gen db") {
logger.info(`bot command is /gen db, chatId: ${chatId}`)
createKVTemp.createFromEvent(ctx)
return
}
// 选择群组信息
if (text.trim() === "/groupchat") {
if (msgText.trim() === "/groupchat") {
logger.info(`bot command is /groupchat, chatId: ${chatId}`)
groupAgent.sendGroupSelector(ctx)
return

@ -1,232 +0,0 @@
const functionSelectorCard = {
elements: [
{
tag: "markdown",
content: "已经选中的群聊:**${chatName}**\n",
},
{
tag: "action",
actions: [
{
tag: "select_static",
placeholder: {
tag: "plain_text",
content: "请选择功能",
},
value: {
chatId: "${chatId}",
chatName: "${chatName}",
action: "sendTimeScopeSelector",
},
options: "${functions}",
},
],
},
{
tag: "hr",
},
{
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由AI创新应用组提供支持Rid${requestId}",
},
],
},
],
header: {
template: "purple",
title: {
content: "🧑‍💻 感谢使用 Group Agent",
tag: "plain_text",
},
},
}
const timeScopeSelectorCard = {
elements: [
{
tag: "markdown",
content:
"已经选中群聊:**${chatName}**\n\n已经选择功能**${functionName}**\n\n请选择时间范围",
},
{
tag: "action",
actions: [
{
tag: "button",
text: {
tag: "plain_text",
content: "过去一天",
},
type: "default",
value: {
chatId: "${chatId}",
chatName: "${chatName}",
functionId: "${functionId}",
functionName: "${functionName}",
timeScope: "1",
requestId: "${requestId}",
action: "manageGroupMsg",
},
},
{
tag: "button",
text: {
tag: "plain_text",
content: "过去三天",
},
type: "default",
value: {
chatId: "${chatId}",
chatName: "${chatName}",
functionId: "${functionId}",
functionName: "${functionName}",
timeScope: "3",
requestId: "${requestId}",
action: "manageGroupMsg",
},
},
{
tag: "button",
text: {
tag: "plain_text",
content: "过去七天",
},
type: "default",
value: {
chatId: "${chatId}",
chatName: "${chatName}",
functionId: "${functionId}",
functionName: "${functionName}",
timeScope: "7",
requestId: "${requestId}",
action: "manageGroupMsg",
},
},
],
},
{
tag: "hr",
},
{
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由AI创新应用组提供支持Rid${requestId}",
},
],
},
],
header: {
template: "purple",
title: {
content: "🧑‍💻 感谢使用 Group Agent",
tag: "plain_text",
},
},
}
const resultReportCard = {
elements: [
{
tag: "markdown",
content:
"群聊:**${chatName}**,功能:**${functionName}**,总结天数:**${timeScope}**\n\n以下内容由AI模型生成耗时**${processingTime}s**",
},
{
tag: "hr",
},
{
tag: "markdown",
content: "${llmRes}",
},
{
tag: "hr",
},
{
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由AI创新应用组提供支持Rid${requestId}",
},
],
},
],
header: {
template: "green",
title: {
content: "🧑‍💻 感谢使用 Group Agent",
tag: "plain_text",
},
},
}
const successMsgCard = {
elements: [
{
tag: "markdown",
content: "${content}",
},
{
tag: "hr",
},
{
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由${author}提供支持Rid${requestId}",
},
],
},
],
header: {
template: "green",
title: {
content: "🔥 感谢使用 ${app}",
tag: "plain_text",
},
},
}
const errorMsgCard = {
elements: [
{
tag: "markdown",
content: "${content}",
},
{
tag: "hr",
},
{
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由${author}提供支持Rid${requestId}",
},
],
},
],
header: {
template: "red",
title: {
content: "⛔ ${app} 错误提示",
tag: "plain_text",
},
},
}
const cardTemplateMap = {
functionSelector: functionSelectorCard,
timeScopeSelector: timeScopeSelectorCard,
resultReport: resultReportCard,
successMsg: successMsgCard,
errorMsg: errorMsgCard,
}
export default cardTemplateMap

@ -1,24 +1,5 @@
import {
genCardMsg,
getActionOption,
getActionValue,
getChatId,
getMessageId,
LarkAction,
} from "@egg/lark-msg-tool"
import { Context } from "../../../types"
import llm from "../../../utils/llm"
import cardTemplateMap from "./cards"
enum CardTemplate {
groupSelector = "ctp_AA0LgXOkJpIn",
functionSelector = "ctp_AA0xqIITeUex",
timeScopeSelector = "ctp_AA00oqPWT1Hq",
resultReport = "ctp_AA00oqPWTHWP",
successMsg = "ctp_AA0LgXOkEOPK",
errorMsg = "ctp_AA0LgXOkEuqi",
}
/**
*
@ -26,10 +7,11 @@ enum CardTemplate {
*/
const sendGroupSelector = async ({
larkService,
body,
logger,
requestId,
larkCard,
larkBody: { chatId },
}: Context.Data) => {
const cardGender = larkCard.child("groupAgent")
const { data: innerList } = await larkService.chat.getInnerList()
logger.info(`Inner list: ${JSON.stringify(innerList)}`)
// 组织群组数据
@ -37,14 +19,9 @@ const sendGroupSelector = async ({
text: v.name,
value: `${v.chat_id}|${v.name}`,
}))
larkService.message.sendTemp(
"chat_id",
getChatId(body),
CardTemplate.groupSelector,
{
groups,
requestId,
}
larkService.message.sendCard2Chat(
chatId,
cardGender.genTempCard("groupSelector", { groups }) as string
)
}
@ -52,24 +29,19 @@ const sendGroupSelector = async ({
*
* @param ctx -
*/
const sendFunctionSelector = async (ctx: Context.Data) => {
const { logger, requestId } = ctx
const body = ctx.body as LarkAction.Data
const option = getActionOption(body)
logger.debug(`Action option: ${JSON.stringify(option)}`)
const [chatId, chatName] = option.split("|")
const sendFunctionSelector = async ({
logger,
larkCard,
larkBody: { actionOption },
}: Context.Data) => {
const cardGender = larkCard.child("groupAgent", false)
logger.debug(`Action option: ${JSON.stringify(actionOption)}`)
const [chatId, chatName] = (actionOption ?? "").split("|")
if (!chatId || !chatName) {
logger.error(
`Invalid targetChatId or targetChatName: ${JSON.stringify(option)}`
)
return genCardMsg(
cardTemplateMap.errorMsg,
{
content: "Invalid targetChatId or targetChatName",
requestId,
},
false
`Invalid targetChatId or targetChatName: ${JSON.stringify(actionOption)}`
)
return cardGender.genErrorCard("Invalid targetChatId or targetChatName")
}
// 组织功能数据
const functions = [
@ -78,71 +50,54 @@ const sendFunctionSelector = async (ctx: Context.Data) => {
value: "summary-gpt-4o|总结消息",
},
]
return genCardMsg(
cardTemplateMap.functionSelector,
{
functions,
chatId,
chatName,
requestId,
},
false
)
return cardGender.genCard("functionSelector", {
functions,
chatId,
chatName,
})
}
/**
*
* @param ctx - body和larkService
*/
const sendTimeScopeSelector = async (ctx: Context.Data) => {
const { logger, requestId } = ctx
const body = ctx.body as LarkAction.Data
const option = getActionOption(body)
logger.debug(`Action option: ${JSON.stringify(option)}`)
const [functionId, functionName] = option.split("|")
const sendTimeScopeSelector = async ({
logger,
larkCard,
larkBody: { actionOption, actionValue },
}: Context.Data) => {
const cardGender = larkCard.child("groupAgent", false)
logger.debug(`Action option: ${JSON.stringify(actionOption)}`)
const [functionId, functionName] = (actionOption ?? "").split("|")
if (!functionId || !functionName) {
logger.error(`Invalid functionId or functionName: ${option}`)
return genCardMsg(
cardTemplateMap.errorMsg,
{
content: "Invalid functionId or functionName",
requestId,
},
false
logger.error(
`Invalid functionId or functionName: ${JSON.stringify(actionOption)}`
)
return cardGender.genErrorCard("Invalid functionId or functionName")
}
const value = getActionValue(body)
logger.debug(`Action value: ${JSON.stringify(value)}`)
const { chatId, chatName } = value
logger.debug(`Action value: ${JSON.stringify(actionValue)}`)
const { chatId, chatName } = actionValue
if (!chatName || !chatId) {
logger.error(`Invalid chatName or chatId: ${JSON.stringify(value)}`)
return genCardMsg(
cardTemplateMap.errorMsg,
{
content: "Invalid chatName or chatId",
requestId,
},
false
)
logger.error(`Invalid chatName or chatId: ${JSON.stringify(actionValue)}`)
return cardGender.genErrorCard("Invalid chatName or chatId")
}
return genCardMsg(
cardTemplateMap.timeScopeSelector,
{
chatId,
chatName,
functionId,
functionName,
requestId,
},
false
)
return cardGender.genCard("timeScopeSelector", {
chatId,
chatName,
functionId,
functionName,
})
}
const sendGroupReport = async (ctx: Context.Data) => {
const { larkService, logger, requestId } = ctx
const body = ctx.body as LarkAction.Data
const { chatId, chatName, functionId, functionName, timeScope } =
getActionValue(body)
const sendGroupReport = async ({
larkService,
logger,
requestId,
larkCard,
larkBody: { actionValue, messageId },
}: Context.Data) => {
const cardGender = larkCard.child("groupAgent")
const { chatId, chatName, functionId, functionName, timeScope } = actionValue
// 记录发送loading消息后的时间戳
const startTime = Date.now()
@ -166,17 +121,14 @@ const sendGroupReport = async (ctx: Context.Data) => {
// 如果没有历史记录则返回错误消息
if (chatHistory.length === 0) {
logger.error("Chat history is empty")
await larkService.message.updateTemp(
getMessageId(body),
CardTemplate.errorMsg,
{
content: "未找到聊天记录",
requestId,
}
await larkService.message.update(
messageId,
cardGender.genErrorCard("未找到聊天记录")
)
return
}
logger.debug(`Chat history: ${JSON.stringify(chatHistory)}`)
try {
const llmRes = await llm.invoke(functionId, {
chatHistory: JSON.stringify(chatHistory),
@ -187,27 +139,23 @@ const sendGroupReport = async (ctx: Context.Data) => {
// 计算时间差并存储在processingTime变量中以秒为单位
const processingTime = ((endTime - startTime) / 1000).toFixed(2)
logger.info(`LLM takes time: ${processingTime}s, result: ${llmRes}`)
await larkService.message.updateTemp(
getMessageId(body),
CardTemplate.resultReport,
{
// 更新消息卡片
await larkService.message.update(
messageId,
cardGender.genCard("resultReport", {
chatName,
functionName,
llmRes,
timeScope,
requestId,
processingTime,
}
})
)
} catch (error: any) {
logger.error(`LLM error: ${error.message}`)
await larkService.message.updateTemp(
getMessageId(body),
CardTemplate.errorMsg,
{
content: "LLM调用失败: " + error.message,
requestId,
}
await larkService.message.update(
messageId,
cardGender.genErrorCard("LLM调用失败: " + error.message)
)
}
}
@ -217,33 +165,26 @@ const sendGroupReport = async (ctx: Context.Data) => {
* @param ctx - body和larkService
*/
const manageGroupMsg = async (ctx: Context.Data) => {
const { logger, requestId } = ctx
const body = ctx.body as LarkAction.Data
const value = getActionValue(body)
logger.debug(`Action value: ${JSON.stringify(value)}`)
const { chatId, chatName, functionId, functionName, timeScope } = value
const {
logger,
larkCard,
larkBody: { actionValue },
} = ctx
const cardGender = larkCard.child("groupAgent", false)
logger.debug(`Action value: ${JSON.stringify(actionValue)}`)
const { chatId, chatName, functionId, functionName, timeScope } = actionValue
if (!chatId || !chatName || !functionId || !functionName || !timeScope) {
logger.error(`Invalid value: ${JSON.stringify(value)}`)
return genCardMsg(
cardTemplateMap.errorMsg,
{
content: "Invalid value",
requestId,
},
false
)
logger.error(`Invalid value: ${JSON.stringify(actionValue)}`)
return cardGender.genErrorCard("Invalid value")
}
// 处理群组消息
sendGroupReport(ctx)
// 发送一个loading的消息
return genCardMsg(
cardTemplateMap.successMsg,
{
content: "Group Agent 正在爬楼中,请稍等...",
requestId,
},
false
)
return cardGender.genSuccessCard("正在爬楼中,请稍等...")
}
const groupAgent = {

@ -1,5 +1,3 @@
import { getIsActionMsg, getIsEventMsg } from "@egg/lark-msg-tool"
import { Context } from "../../types"
import { manageActionMsg } from "./actionMsg"
import { manageEventMsg } from "./eventMsg"
@ -10,7 +8,7 @@ import { manageEventMsg } from "./eventMsg"
* @returns {Promise<Response>}
*/
export const manageBotReq = async (ctx: Context.Data): Promise<Response> => {
const { body } = ctx
const { body, larkBody } = ctx
// 检查请求体是否为空
if (!body) {
@ -24,9 +22,9 @@ export const manageBotReq = async (ctx: Context.Data): Promise<Response> => {
}
// 处理Event消息
if (getIsEventMsg(body)) manageEventMsg(ctx)
if (larkBody.isEventMsg) manageEventMsg(ctx)
// 处理Action消息
if (getIsActionMsg(body)) return await manageActionMsg(ctx)
if (larkBody.isActionMsg) return await manageActionMsg(ctx)
// 返回成功响应
return ctx.genResp.custom("{}")

@ -1,7 +1,4 @@
import { getChatId, getChatType, getUserId } from "@egg/lark-msg-tool"
import { Context, LarkServer } from "../../types"
import { genSheetDbErrorMsg } from "../../utils/larkMsg"
/**
*
@ -55,35 +52,35 @@ const create = async ({
* @param ctx - Context
*/
const createFromEvent = async (ctx: Context.Data) => {
const chatId = getChatId(ctx.body)
const {
larkBody: { chatId, chatType, userId },
larkService,
larkCard,
logger,
} = ctx
if (!chatId) return
// 先发一条消息告诉用户正在创建
ctx.larkService.message.send(
"chat_id",
chatId,
"text",
"正在为您创建多维表格,请稍等片刻~"
)
larkService.message.sendText2Chat(chatId, "正在为您创建多维表格,请稍等片刻~")
const cardGender = larkCard.child("groupAgent")
try {
const createRes = await create(ctx)
// 错误处理,发送错误消息
if (createRes.code !== 0) throw new Error(createRes.message)
// 创建成功,根据消息类型添加协作者
if (getChatType(ctx.body) === "p2p") {
const addRes = await ctx.larkService.drive.addCollaborator(
if (chatType === "p2p") {
const addRes = await larkService.drive.addCollaborator(
createRes.data.fileToken,
"bitable",
"userid",
getUserId(ctx.body)!,
userId!,
"full_access"
)
if (addRes.code !== 0) throw new Error(addRes.message)
}
// 为群组添加协作者
else {
const addRes = await ctx.larkService.drive.addCollaborator(
const addRes = await larkService.drive.addCollaborator(
createRes.data.fileToken,
"bitable",
"openchat",
@ -93,16 +90,16 @@ const createFromEvent = async (ctx: Context.Data) => {
if (addRes.code !== 0) throw new Error(addRes.message)
}
// 全部成功,发送成功消息
ctx.larkService.message.sendTemp(
"chat_id",
larkService.message.sendCard2Chat(
chatId,
"ctp_AA00oqPWPXtG",
createRes.data
cardGender.genTempCard("createKVSuccess", createRes.data) as string
)
} catch (e: any) {
ctx.logger.error(`create KV bitable failed: ${e.message}`)
const errorMsg = genSheetDbErrorMsg(e.message) as string
ctx.larkService.message.send("chat_id", chatId, "interactive", errorMsg)
logger.error(`create KV bitable failed: ${e.message}`)
larkService.message.sendCard2Chat(
chatId,
cardGender.genErrorCard(`创建失败:${e.message}`) as string
)
}
}

@ -1,5 +1,4 @@
import { LarkServer } from "../../types/larkServer"
import { genTempMsg } from "../../utils/larkMsg"
import LarkBaseService from "./base"
class LarkMessageService extends LarkBaseService {
@ -28,32 +27,11 @@ class LarkMessageService extends LarkBaseService {
}
/**
*
* @param receiveIdType id类型 open_id/user_id/union_id/email/chat_id
* @param receiveId IDID类型应与查询参数receiveIdType
* @param templateId ID
* @param variable
*/
async sendTemp(
receiveIdType: LarkServer.ReceiveIDType,
receiveId: string,
templateId: string,
variable: any
) {
return this.send(
receiveIdType,
receiveId,
"interactive",
genTempMsg(templateId, variable)
)
}
/**
*
*
* @param receiveId IDID类型应与查询参数receiveIdType
* @param content
*/
async sendInteractive2Chat(receiveId: string, content: string) {
async sendCard2Chat(receiveId: string, content: string) {
return this.send("chat_id", receiveId, "interactive", content)
}
@ -76,16 +54,6 @@ class LarkMessageService extends LarkBaseService {
return this.patch<LarkServer.BaseRes>(path, { content })
}
/**
*
* @param messageId id
* @param templateId ID
* @param variable
*/
async updateTemp(messageId: string, templateId: string, variable: any) {
return this.update(messageId, genTempMsg(templateId, variable))
}
/**
*
* @param chatId ID

@ -1,7 +1,11 @@
import { LarkBody, LarkCard } from "@egg/lark-msg-tool"
import { NetTool } from "@egg/net-tool"
import { PathCheckTool } from "@egg/path-tool"
import { Logger } from "winston"
import cardMap from "../constant/card"
import functionMap from "../constant/function"
import tempMap from "../constant/template"
import { AttachService, LarkService } from "../services"
export namespace Context {
@ -13,6 +17,8 @@ export namespace Context {
body: any
text: string
larkService: LarkService
larkBody: LarkBody
larkCard: LarkCard<typeof cardMap, typeof tempMap, typeof functionMap>
attachService: AttachService
path: PathCheckTool
searchParams: URLSearchParams

@ -1,61 +0,0 @@
export const commonNote = {
tag: "note",
elements: [
{
tag: "plain_text",
content: "🍳 功能由${xAuthor}提供支持Rid${requestId}",
},
],
}
export const successHeader = {
template: "green",
title: {
content: "🔥 感谢使用 ${xName}",
tag: "plain_text",
},
}
export const errorHeader = {
template: "red",
title: {
content: "⛔ ${xName} 错误提示",
tag: "plain_text",
},
}
export const pendingHeader = {
template: "purple",
title: {
content: "🔥 感谢使用 ${xName}",
tag: "plain_text",
},
}
export const baseSuccessCard = {
elements: [
{
tag: "markdown",
content: "${content}",
},
{
tag: "hr",
},
commonNote,
],
successHeader,
}
export const baseErrorCard = {
elements: [
{
tag: "markdown",
content: "${content}",
},
{
tag: "hr",
},
commonNote,
],
errorHeader,
}

@ -1,32 +0,0 @@
class LarkCard {
private requestId: string
private xName: string
private xAuthor: string
private functionMap = {
egg: {
name: "小煎蛋",
author: "zhaoyingbo",
},
groupAgent: {
name: "Group Agent",
author: "AI创新应用组",
},
sheetDB: {
name: "小煎蛋 Sheet DB",
author: "zhaoyingbo",
},
}
constructor(func: keyof typeof this.functionMap, requestId: string) {
this.requestId = requestId
this.xName = this.functionMap[func].name
this.xAuthor = this.functionMap[func].author
}
child(func: keyof typeof this.functionMap) {
return new LarkCard(func, this.requestId)
}
}
export default LarkCard

@ -1,21 +1,24 @@
import { getActionValue } from "@egg/lark-msg-tool"
import { LarkBody, LarkCard } from "@egg/lark-msg-tool"
import loggerIns from "@egg/logger"
import { NetTool } from "@egg/net-tool"
import { PathCheckTool } from "@egg/path-tool"
import { v4 as uuid } from "uuid"
import cardMap from "../constant/card"
import functionMap from "../constant/function"
import tempMap from "../constant/template"
import { AttachService, LarkService } from "../services"
import { Context } from "../types"
/**
* requestId
*
* @param {any} body -
* @returns {string} requestId
* @param larkBody -
* @returns requestId
*/
const getPreRequestId = (body: any) => {
const getPreRequestId = (larkBody: LarkBody) => {
// 在Action请求中会带上之前的requestId
const value = getActionValue(body)
const value = larkBody.actionValue
if (!value || !value.requestId) return ""
return value.requestId
}
@ -35,14 +38,23 @@ const genContext = async (req: Request) => {
} catch {
/* empty */
}
const larkBody = new LarkBody(body)
const searchParams = new URL(req.url).searchParams
const app = searchParams.get("app") || "egg"
const requestId = getPreRequestId(body) || uuid()
const requestId = getPreRequestId(larkBody) || uuid()
const logger = loggerIns.child({ requestId })
const genResp = new NetTool({ requestId })
const larkService = new LarkService(app, requestId)
const attachService = new AttachService({ requestId })
const path = new PathCheckTool(req.url)
const larkCard = new LarkCard(
"egg",
true,
requestId,
cardMap,
tempMap,
functionMap
)
return {
req,
@ -53,6 +65,8 @@ const genContext = async (req: Request) => {
body,
text,
larkService,
larkBody,
larkCard,
attachService,
searchParams,
app,

@ -1,129 +0,0 @@
/**
* JSON
* @param {string} title -
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
const genErrorMsg = (
title: string,
content: string,
stringify: boolean = true
) => {
const msg = {
elements: [
{
tag: "markdown",
content,
},
],
header: {
title: {
content: title,
tag: "plain_text",
},
template: "red",
},
}
return stringify ? JSON.stringify(msg) : msg
}
/**
* JSON
* @param {string} title -
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
const genSuccessMsg = (
title: string,
content: string,
stringify: boolean = true
) => {
const msg = {
elements: [
{
tag: "markdown",
content,
},
],
header: {
title: {
content: title,
tag: "plain_text",
},
template: "green",
},
}
return stringify ? JSON.stringify(msg) : msg
}
/**
* JSON
* @param {string} id - ID
* @param {any} variable -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
export const genTempMsg = (
id: string,
variable: any,
stringify: boolean = true
) => {
const msg = {
type: "template",
data: {
config: {
update_multi: true,
enable_forward: false,
},
template_id: id,
template_variable: variable,
},
}
return stringify ? JSON.stringify(msg) : msg
}
/**
* Sheet DB JSON
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
export const genSheetDbErrorMsg = (
content: string,
stringify: boolean = true
) => genErrorMsg("🍪 小煎蛋 Sheet DB 错误提醒", content, stringify)
/**
* Sheet DB JSON
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
export const genSheetDbSuccessMsg = (
content: string,
stringify: boolean = true
) => genSuccessMsg("🍪 感谢使用小煎蛋 Sheet DB", content, stringify)
/**
* Group Agent JSON
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
export const genGroupAgentErrorMsg = (
content: string,
stringify: boolean = true
) => genErrorMsg("🧑‍💻 Group Agent 错误提醒", content, stringify)
/**
* Group Agent JSON
* @param {string} content -
* @param {boolean} [stringify=true] - JSON
* @returns {string | object} JSON
*/
export const genGroupAgentSuccessMsg = (
content: string,
stringify: boolean = true
) => genSuccessMsg("🧑‍💻 感谢使用 Group Agent", content, stringify)