diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 30c2168..3fea719 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -30,8 +30,7 @@ "humao.rest-client", "GitHub.copilot", "GitHub.copilot-chat", - "oven.bun-vscode", - "Prisma.prisma" + "oven.bun-vscode" ] } }, diff --git a/.env.example b/.env.example index a3b324d..7eea887 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,6 @@ # Node Environment: dev, production NODE_ENV=dev -DATABASE_URL= - # PocketBase Auth PB_USER= PB_PASS= diff --git a/bun.lockb b/bun.lockb index 33acc9c..6ab4a8e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/constant/config.ts b/constant/config.ts index 1e8e393..a7bc496 100644 --- a/constant/config.ts +++ b/constant/config.ts @@ -3,41 +3,37 @@ import { RecordModel } from "pocketbase" import pbClient from "../db/pbClient" -interface Config extends RecordModel { +interface ConfigModel extends RecordModel { key: string value: string desc: string } -export interface AppInfo extends RecordModel { +export interface AppInfoModel extends RecordModel { name: string - app_id: string - app_secret: string - app_name: string + appId: string + appSecret: string + appName: string } export const APP_CONFIG: Record = {} -export const APP_MAP: Record> = {} +export const APP_MAP: Record = {} /** * 初始化应用配置 */ const initAppConfig = async () => { // 获取所有环境变量 - const envList = await pbClient.collection("env").getFullList() + const envList = await pbClient.collection("env").getFullList() for (const env of envList) { APP_CONFIG[env.key] = env.value } logger.info(`Get env list: ${JSON.stringify(APP_CONFIG)}`) // 获取所有应用信息 - const appList = await pbClient.collection("app").getFullList() + const appList = await pbClient.collection("app").getFullList() for (const app of appList) { - APP_MAP[app.name] = { - app_id: app.app_id, - app_secret: app.app_secret, - app_name: app.app_name, - } + APP_MAP[app.name] = app } logger.info(`Get app list: ${JSON.stringify(APP_MAP)}`) } diff --git a/constant/message.ts b/constant/message.ts index 39d3ec6..5c0ee27 100644 --- a/constant/message.ts +++ b/constant/message.ts @@ -1,5 +1,10 @@ export enum RespMessage { - hasRegistered = "本群已订阅日报,周报", - registerSuccess = "周报、日报订阅成功", - cancelSuccess = "周报、日报订阅取消成功", + hasRegisteredDaily = "本群已订阅日报", + hasRegisteredWeekly = "本群已订阅周报", + registerDailySuccess = "日报订阅成功", + registerWeeklySuccess = "周报订阅成功", + cancelDailySuccess = "日报订阅取消成功", + cancelWeeklySuccess = "周报订阅取消成功", + registerFailed = "订阅失败", + cancelFailed = "取消订阅失败", } diff --git a/controller/groupAgent/agent.ts b/controller/groupAgent/agent.ts index addba25..17883da 100644 --- a/controller/groupAgent/agent.ts +++ b/controller/groupAgent/agent.ts @@ -2,7 +2,7 @@ import { Context } from "../../types" import llm from "../../utils/llm" import getChatHistory from "./chatHistory" -const agent = async (ctx: Context.Data) => { +const agent = async (ctx: Context) => { const { logger, requestId, @@ -26,7 +26,7 @@ const agent = async (ctx: Context.Data) => { const { startTime, endTime } = await llm.timeParser(msgText, requestId) logger.info(`Parsed time: startTime: ${startTime}, endTime: ${endTime}`) // 更新卡片 - updateCard(cardGender.genPendingCard("正在爬楼中,请稍等...")) + await updateCard(cardGender.genPendingCard("正在爬楼中,请稍等...")) // 获取聊天记录 const { messages: chatHistory, mentions: historyMentions } = await getChatHistory(ctx, { @@ -36,7 +36,7 @@ const agent = async (ctx: Context.Data) => { mentions, senderOpenId: openId, excludedMessageIds: [message_id, messageId], - excludeMentions: [appInfo.app_name], + excludeMentions: [appInfo.appName], }) // 如果没有聊天记录,返回错误信息 if (chatHistory.length === 0) { @@ -48,7 +48,7 @@ const agent = async (ctx: Context.Data) => { // 根据Mention,拼装原始消息 let userInput = rawMsgText.trim() for (const mention of mentions ?? []) { - if (mention.name !== appInfo.app_name) { + if (mention.name !== appInfo.appName) { userInput = userInput.replace(mention.key, `@${mention.name}`) } else { userInput = userInput.replace(mention.key, "") diff --git a/controller/groupAgent/chatHistory.ts b/controller/groupAgent/chatHistory.ts index 036c8c9..a1c3e9b 100644 --- a/controller/groupAgent/chatHistory.ts +++ b/controller/groupAgent/chatHistory.ts @@ -43,7 +43,7 @@ const extractTextFromJson = (data: any): string => { * @returns 聊天消息数组 */ const getChatHistory = async ( - { larkService, logger }: Context.Data, + { larkService, logger }: Context, { chatId, startTime, @@ -86,7 +86,7 @@ const getChatHistory = async ( String(endTimeTimestamp) ) - if (chatHistory.length === 0) + if (!chatHistory?.length) return { messages: [], mentions: new Map(), @@ -169,12 +169,17 @@ const getChatHistory = async ( // 从接口获取用户名 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) + try { + 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) + } + } catch (error) { + // 报错了可以不处理,只是没有名字而已 + logger.error(`Failed to get user info: ${error}`) } } diff --git a/controller/groupAgent/report.ts b/controller/groupAgent/report.ts index 6ba644d..37a7ff9 100644 --- a/controller/groupAgent/report.ts +++ b/controller/groupAgent/report.ts @@ -2,7 +2,8 @@ import { LarkService } from "@egg/net-tool" import { APP_MAP } from "../../constant/config" import { RespMessage } from "../../constant/message" -import prisma from "../../prisma" +import db from "../../db" +import { GrpSumSubWithApp } from "../../db/grpSumSub" import { Context } from "../../types" import genContext from "../../utils/genContext" import llm from "../../utils/llm" @@ -11,35 +12,29 @@ import getChatHistory from "./chatHistory" /** * 总结指定聊天记录 - * @param {Context.Data} ctx - 请求上下文 + * @param {Context} ctx - 请求上下文 * @param {string} timeScope - 时间范围 * @param {any} subscription - 订阅信息 * @returns {Promise} */ const genReport = async ( - ctx: Context.Data, + ctx: Context, timeScope: "daily" | "weekly", - subscription: { - id: bigint - chat_id: string - robot_id: string - initiator: string - } + subscription: GrpSumSubWithApp ) => { const { logger, requestId, larkCard } = ctx const cardGender = larkCard.child("groupAgent") try { - const { chat_id: chatId, robot_id: robotId } = subscription - // 获取接口信息 - const appInfo = APP_MAP[robotId] - if (!appInfo) { - logger.error(`Failed to get app info for ${robotId}`) - return - } + const { + chatId, + expand: { + app: { appId, appSecret, appName }, + }, + } = subscription // 组织接口 const larkService = new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, + appId, + appSecret, requestId, }) // 获取时间范围 @@ -50,12 +45,12 @@ const genReport = async ( // 获取聊天记录 const { messages: chatHistory } = await getChatHistory( - { larkService, logger } as Context.Data, + { larkService, logger } as Context, { chatId, startTime, endTime, - excludeMentions: [appInfo.app_name], + excludeMentions: [appName], } ) if (chatHistory.length === 0) { @@ -80,21 +75,18 @@ const genReport = async ( logger.info( `LLM takes time: ${processingTime}s, see detail: http://langfuse.ai.srv/project/cm1j2tkj9001gukrgdvc1swuw/sessions/${requestId}` ) + // 生成卡片内容 + const cardContent = cardGender.genCard("autoReport", { + llmRes, + timeScope: timeScope === "daily" ? "今日日报" : "本周周报", + }) // 发送卡片消息 - await larkService.message.sendCard2Chat( - chatId, - cardGender.genCard("autoReport", { - llmRes, - timeScope: timeScope === "daily" ? "今日日报" : "本周周报", - }) - ) - // 记录发送的卡片 - await prisma.chat_agent_message_log.create({ - data: { - subscription_id: subscription.id, - initiator: subscription.initiator, - langfuse_link: `http://langfuse.ai.srv/project/cm1j2tkj9001gukrgdvc1swuw/sessions/${requestId}`, - }, + await larkService.message.sendCard2Chat(chatId, cardContent) + // 记录总结日志 + await db.grpSumLog.create({ + subscription: subscription.id, + content: JSON.stringify(cardContent), + langfuseLink: `http://langfuse.ai.srv/project/cm1j2tkj9001gukrgdvc1swuw/sessions/${requestId}`, }) } catch (error: any) { logger.error( @@ -113,21 +105,34 @@ const genAllReport = async (timeScope: "daily" | "weekly" = "daily") => { try { // 获取全部需要自动总结的群组 - const subscriptionList = - await prisma.chat_agent_summary_subscription.findMany({ - where: { - terminator: "", - }, - }) + let subList = await db.grpSumSub.getAll( + `terminator = ""${timeScope === "daily" ? ' && timeScope = "daily"' : ""}` + ) - if (subscriptionList.length === 0) { + // 没有需要总结的群组 + if (!subList || subList.length === 0) { logger.info("No group needs to be summarized") return } + // 如果是周五,获取了需要日报和周报的订阅,根据chatId,过滤掉需要周报的日报订阅 + if (timeScope === "weekly") { + const dailySubList = subList.filter((sub) => sub.timeScope === "daily") + const weeklySubList = subList.filter((sub) => sub.timeScope === "weekly") + // 过滤掉需要周报的日报订阅 + subList = dailySubList + .filter( + (dailySub) => + !weeklySubList.find( + (weeklySub) => weeklySub.chatId === dailySub.chatId + ) + ) + .concat(weeklySubList) + } + // 一个一个群组的总结,避免触发频率限制 - for (const subscription of subscriptionList) { - await genReport(ctx, timeScope, subscription) + for (const sub of subList) { + await genReport(ctx, sub.timeScope, sub) } } catch (e: any) { logger.error(`Auto summary error: ${e.message}`) @@ -136,10 +141,10 @@ const genAllReport = async (timeScope: "daily" | "weekly" = "daily") => { /** * 立即生成日报或周报(测试用) - * @param {Context.Data} ctx - 请求上下文 + * @param {Context} ctx - 请求上下文 * @returns {Promise} */ -const gen4Test = async (ctx: Context.Data, timeScope: "daily" | "weekly") => { +const gen4Test = async (ctx: Context, timeScope: "daily" | "weekly") => { const { logger, larkCard, @@ -153,26 +158,24 @@ const gen4Test = async (ctx: Context.Data, timeScope: "daily" | "weekly") => { logger.error("Invalid request body") return } + // 获取订阅信息 - const subscription = await prisma.chat_agent_summary_subscription.findFirst( - { - where: { - chat_id: chatId, - terminator: "", - }, - } + const sub = await db.grpSumSub.getByFilter( + `terminator = "" && chatId = "${chatId}" && timeScope = "${timeScope}"` ) // 没有订阅信息 - if (!subscription) { + if (!sub) { logger.error(`No subscription found for chat ${chatId}`) await larkService.message.sendCard2Chat( chatId, - larkCard.genErrorCard("本群未订阅日报、周报") + larkCard.genErrorCard( + `本群未订阅${timeScope === "daily" ? "日报" : "周报"}` + ) ) return } // 总结 - await genReport(ctx, timeScope, subscription) + await genReport(ctx, timeScope, sub) } catch (error: any) { logger.error(`Failed to summarize chat ${chatId}: ${error.message}`) } @@ -182,54 +185,77 @@ const gen4Test = async (ctx: Context.Data, timeScope: "daily" | "weekly") => { * 注册消息总结的订阅 * @returns */ -const subscribe = async ({ - app, - larkService, - logger, - larkBody, - larkCard, -}: Context.Data) => { +const subscribe = async ( + { app, larkService, logger, larkBody, larkCard }: Context, + timeScope: "daily" | "weekly" +) => { + const cardGender = larkCard.child("groupAgent") + const sendErrorMsg = () => + larkService.message.sendCard2Chat( + larkBody.chatId, + cardGender.genErrorCard(RespMessage.registerFailed) + ) try { - const cardGender = larkCard.child("groupAgent") // 判断是否有 chatId 和 userId if (!larkBody.chatId || !larkBody.userId) { logger.error(`chatId or userId is empty`) return } + + // 获取用户信息 + const user = await db.user.getByCtx({ larkBody, larkService } as Context) + if (!user) { + logger.error(`Failed to get user info`) + await sendErrorMsg() + return + } // 先查询是否已经存在订阅 - const subscription = await prisma.chat_agent_summary_subscription.findFirst( - { - where: { - chat_id: larkBody.chatId, - terminator: "", - }, - } + const sub = await db.grpSumSub.getByFilter( + `terminator = "" && chatId = "${larkBody.chatId} && timeScope = "${timeScope}"` ) - // 如果已经存在订阅,则返回已经注册过了 - if (subscription) { - logger.info(`chatId: ${larkBody.chatId} has been registered`) - // 发送已经注册过的消息 + if (sub) { + logger.info( + `chatId: ${larkBody.chatId} has been registered, timeScope: ${timeScope}` + ) + // 发送已经注册过了的消息 await larkService.message.sendCard2Chat( larkBody.chatId, - cardGender.genSuccessCard(RespMessage.hasRegistered) + cardGender.genSuccessCard( + timeScope === "daily" + ? RespMessage.hasRegisteredDaily + : RespMessage.hasRegisteredWeekly + ) ) return } // 注册订阅 - await prisma.chat_agent_summary_subscription.create({ - data: { - chat_id: larkBody.chatId, - robot_id: app, - initiator: larkBody.userId, - }, + const createRes = await db.grpSumSub.create({ + app: APP_MAP[app].id, + initiator: user.id, + terminator: "", + chatId: larkBody.chatId, + timeScope, }) + + if (!createRes) { + logger.error( + `Failed to register chatId: ${larkBody.chatId}, timeScope: ${timeScope}` + ) + await sendErrorMsg() + return + } // 发送成功消息 await larkService.message.sendCard2Chat( larkBody.chatId, - cardGender.genSuccessCard(RespMessage.registerSuccess) + cardGender.genSuccessCard( + timeScope === "daily" + ? RespMessage.registerDailySuccess + : RespMessage.registerWeeklySuccess + ) ) } catch (e: any) { logger.error(`Subscribe error: ${e.message}`) + await sendErrorMsg() } } @@ -237,54 +263,75 @@ const subscribe = async ({ * 取消消息总结的订阅 * @returns */ -const unsubscribe = async ({ - logger, - larkBody, - larkService, - larkCard, -}: Context.Data) => { +const unsubscribe = async ( + { logger, larkBody, larkService, larkCard }: Context, + timeScope: "daily" | "weekly" +) => { + const cardGender = larkCard.child("groupAgent") + const sendErrorMsg = () => + larkService.message.sendCard2Chat( + larkBody.chatId, + cardGender.genErrorCard(RespMessage.cancelFailed) + ) try { - const cardGender = larkCard.child("groupAgent") // 判断是否有 chatId 和 userId if (!larkBody.chatId || !larkBody.userId) { logger.error(`chatId or userId is empty`) return } - // 查找现有的订阅 - const subscription = await prisma.chat_agent_summary_subscription.findFirst( - { - where: { - chat_id: larkBody.chatId, - terminator: "", - }, - } + + // 获取用户信息 + const user = await db.user.getByCtx({ larkBody, larkService } as Context) + if (!user) { + logger.error(`Failed to get user info`) + await sendErrorMsg() + return + } + // 先查询是否已经存在订阅 + const sub = await db.grpSumSub.getByFilter( + `terminator = "" && chatId = "${larkBody.chatId} && timeScope = "${timeScope}"` ) - // 如果没有找到订阅,则返回错误 - if (!subscription) { - logger.info(`chatId: ${larkBody.chatId} has not been registered`) - // 发送已经取消订阅的消息 + + if (!sub) { + logger.info( + `chatId: ${larkBody.chatId} has not been registered, timeScope: ${timeScope}` + ) + // 发送未注册的消息 await larkService.message.sendCard2Chat( larkBody.chatId, - cardGender.genSuccessCard(RespMessage.cancelSuccess) + cardGender.genSuccessCard( + timeScope === "daily" + ? RespMessage.cancelDailySuccess + : RespMessage.cancelWeeklySuccess + ) ) return } - // 更新订阅,设置终止者和终止时间 - await prisma.chat_agent_summary_subscription.update({ - where: { - id: subscription.id, - }, - data: { - terminator: larkBody.userId, - }, + // 更新订阅 + const updateRes = await db.grpSumSub.update(sub.id, { + terminator: user.id, }) + + if (!updateRes) { + logger.error( + `Failed to cancel chatId: ${larkBody.chatId}, timeScope: ${timeScope}` + ) + await sendErrorMsg() + return + } + // 发送成功消息 await larkService.message.sendCard2Chat( larkBody.chatId, - cardGender.genSuccessCard(RespMessage.cancelSuccess) + cardGender.genSuccessCard( + timeScope === "daily" + ? RespMessage.cancelDailySuccess + : RespMessage.cancelWeeklySuccess + ) ) } catch (e: any) { logger.error(`Unsubscribe error: ${e.message}`) + await sendErrorMsg() } } diff --git a/controller/sheet/createKVTemp.ts b/controller/sheet/createKVTemp.ts index c879acf..614b791 100644 --- a/controller/sheet/createKVTemp.ts +++ b/controller/sheet/createKVTemp.ts @@ -8,7 +8,7 @@ import { Context, LarkServer } from "../../types" const create = async ({ larkService, logger, -}: Context.Data): Promise => { +}: Context): Promise => { const copyRes = await larkService.drive.copyFile( "D6ETfzaU9lN08adVDz3kjLey4Bx", "bask4drDOy7zc3nDVyZb5RYDzOe", @@ -51,7 +51,7 @@ const create = async ({ * 从事件创建键值多维表格 * @param ctx - Context */ -const createFromEvent = async (ctx: Context.Data) => { +const createFromEvent = async (ctx: Context) => { const { larkBody: { chatId, chatType, userId }, larkService, diff --git a/controller/sheet/insert.ts b/controller/sheet/insert.ts index 426876a..ed56a7c 100644 --- a/controller/sheet/insert.ts +++ b/controller/sheet/insert.ts @@ -3,11 +3,11 @@ import { SheetProxy } from "../../types/sheetProxy" /** * 插入表格数据 - * @param {Context.Data} ctx - 上下文数据,包含请求体和响应生成器 + * @param {Context} ctx - 上下文数据,包含请求体和响应生成器 * @param {string} appName - 应用名称 * @returns {Promise} 返回响应对象 */ -const insertSheet = async (ctx: Context.Data) => { +const insertSheet = async (ctx: Context) => { const { genResp, larkService } = ctx const body = ctx.body as SheetProxy.InsertData diff --git a/db/apiKey/index.ts b/db/apiKey/index.ts index c75aec4..ff18155 100644 --- a/db/apiKey/index.ts +++ b/db/apiKey/index.ts @@ -1,10 +1,10 @@ import { RecordModel } from "pocketbase" -import { AppInfo } from "../../constant/config" +import { AppInfoModel } from "../../constant/config" import { managePbError } from "../../utils/pbTools" import pbClient from "../pbClient" -const DB_NAME = "api_key" +const DB_NAME = "apiKey" export interface ApiKey { name: string @@ -16,7 +16,7 @@ export type ApiKeyModel = ApiKey & RecordModel export interface ApiKeyModelWithApp extends ApiKeyModel { expand: { - app: AppInfo + app: AppInfoModel } } diff --git a/db/grpSumLog/index.ts b/db/grpSumLog/index.ts new file mode 100644 index 0000000..e2adf50 --- /dev/null +++ b/db/grpSumLog/index.ts @@ -0,0 +1,28 @@ +import { RecordModel } from "pocketbase" + +import { managePbError } from "../../utils/pbTools" +import pbClient from "../pbClient" + +export interface GroupSummaryLog { + subscription: string + content: string + langfuseLink: string +} + +export type GroupSummaryLogModel = GroupSummaryLog & RecordModel + +/** + * 创建群总结日志 + * @param log + * @returns + */ +const create = async (log: GroupSummaryLog) => + managePbError(() => + pbClient.collection("groupSummaryLog").create(log) + ) + +const grpSumLog = { + create, +} + +export default grpSumLog diff --git a/db/grpSumSub/index.ts b/db/grpSumSub/index.ts new file mode 100644 index 0000000..1845f0c --- /dev/null +++ b/db/grpSumSub/index.ts @@ -0,0 +1,59 @@ +import { RecordModel } from "pocketbase" + +import { AppInfoModel } from "../../constant/config" +import { managePbError } from "../../utils/pbTools" +import pbClient from "../pbClient" + +export interface GroupSummarySubscription { + app: string + initiator: string + terminator: string + chatId: string + timeScope: "daily" | "weekly" +} + +export type GroupSummarySubscriptionModel = GroupSummarySubscription & + RecordModel + +export interface GrpSumSubWithApp extends GroupSummarySubscriptionModel { + expand: { + app: AppInfoModel + } +} + +const create = async (subscription: GroupSummarySubscription) => + managePbError(() => + pbClient.collection("groupSummarySubscription").create(subscription) + ) + +const update = async ( + id: string, + subscription: Partial +) => + managePbError(() => + pbClient.collection("groupSummarySubscription").update(id, subscription) + ) + +const getAll = async (filter: string = "") => + managePbError(() => + pbClient.collection("groupSummarySubscription").getFullList({ + filter, + expand: "app", + }) + ) + +const getByFilter = async (filter: string) => + managePbError(() => + pbClient + .collection("groupSummarySubscription") + .getFirstListItem(filter, { expand: "app" }) + ) + +const grpSumSub = { + create, + update, + getAll, + getByFilter, +} + +export default grpSumSub diff --git a/db/index.ts b/db/index.ts index 6755ace..d0fd63f 100644 --- a/db/index.ts +++ b/db/index.ts @@ -1,11 +1,17 @@ import apiKey from "./apiKey" +import grpSumLog from "./grpSumLog" +import grpSumSub from "./grpSumSub" import log from "./log" import receiveGroup from "./receiveGroup" +import user from "./user" const db = { apiKey, receiveGroup, log, + user, + grpSumLog, + grpSumSub, } export default db diff --git a/db/log/index.ts b/db/log/index.ts index 9d3c0e5..20e611e 100644 --- a/db/log/index.ts +++ b/db/log/index.ts @@ -3,17 +3,17 @@ import { RecordModel } from "pocketbase" import { managePbError } from "../../utils/pbTools" import pbClient from "../pbClient" -const DB_NAME = "message_log" +const DB_NAME = "messageLog" export interface Log { - api_key: string - group_id?: string - receive_id?: string - receive_id_type?: string - msg_type: string + apiKey: string + groupId?: string + receiveId?: string + receiveIdType?: string + msgType: string content: string - final_content?: string - send_result?: any + finalContent?: string + sendResult?: any error?: string } diff --git a/db/pbClient.ts b/db/pbClient.ts index dfb520f..f6a2c9a 100644 --- a/db/pbClient.ts +++ b/db/pbClient.ts @@ -1,11 +1,11 @@ import PocketBase from "pocketbase" -const pbClient = new PocketBase("https://lark-egg-preview.ai.xiaomi.com") +const pbClient = new PocketBase(Bun.env.PB_URL) pbClient.autoCancellation(false) await pbClient .collection("_superusers") - .authWithPassword(Bun.env.PB_USER!, Bun.env.PB_PASS!) + .authWithPassword(Bun.env.PB_USER, Bun.env.PB_PASS) export default pbClient diff --git a/db/receiveGroup/index.ts b/db/receiveGroup/index.ts index 1983442..7b0e638 100644 --- a/db/receiveGroup/index.ts +++ b/db/receiveGroup/index.ts @@ -8,10 +8,10 @@ const DB_NAME = "message_group" export interface ReceiveGroup { name: string email?: string[] - chat_id?: string[] - open_id?: string[] - union_id?: string[] - user_id?: string[] + chatId?: string[] + openId?: string[] + unionId?: string[] + userId?: string[] } export type ReceiveGroupModel = ReceiveGroup & RecordModel diff --git a/db/user/index.ts b/db/user/index.ts new file mode 100644 index 0000000..48106ca --- /dev/null +++ b/db/user/index.ts @@ -0,0 +1,81 @@ +import { RecordModel } from "pocketbase" + +import { Context } from "../../types" +import { managePbError } from "../../utils/pbTools" +import pbClient from "../pbClient" + +// 用户接口定义 +interface User { + email: string + name: string + openId: string + userId: string + avatar: string + password: string + emailVisibility: boolean + verified: boolean +} + +// 用户模型类型 +export type UserModel = User & RecordModel + +/** + * 创建用户 + * @param {User} user - 用户信息 + * @returns {Promise} - 创建的用户模型 + */ +const create = async (user: User) => + managePbError(() => pbClient.collection("user").create(user)) + +/** + * 通过用户ID获取用户 + * @param {string} userId - 用户ID + * @returns {Promise} - 用户模型或null + */ +const getByUserId = async (userId: string) => + managePbError(() => + pbClient.collection("user").getFirstListItem(`user_id = "${userId}"`) + ) + +/** + * 通过上下文获取用户 + * @param {Context} context - 上下文对象 + * @returns {Promise} - 用户模型或null + */ +const getByCtx = async ({ larkBody, larkService }: Context) => { + if (!larkBody.userId) return null + // 先从数据库获取用户信息 + const user = await getByUserId(larkBody.userId) + if (user) return user + // 如果数据库中没有用户信息,从larkService获取用户信息 + const userInfo = await larkService.user.getOne(larkBody.userId, "user_id") + if (userInfo.code !== 0) return null + // 解构用户信息 + const { + user_id, + open_id, + avatar: { avatar_origin }, + email, + name, + } = userInfo.data.user + const newUser = { + userId: user_id, + openId: open_id, + avatar: avatar_origin, + email, + name, + emailVisibility: false, + verified: false, + password: email, + } + // 创建新用户 + const finalUser = await create(newUser) + return finalUser +} + +// 用户对象 +const user = { + getByCtx, +} + +export default user diff --git a/docker/deploy/Dockerfile b/docker/deploy/Dockerfile index 5520a04..74c03e2 100644 --- a/docker/deploy/Dockerfile +++ b/docker/deploy/Dockerfile @@ -12,8 +12,6 @@ RUN bun install COPY . . -RUN bunx prisma generate - EXPOSE 3000 CMD ["bun", "start"] \ No newline at end of file diff --git a/index.ts b/index.ts index 5d1c119..7192885 100644 --- a/index.ts +++ b/index.ts @@ -1,7 +1,6 @@ import logger from "@egg/logger" import initAppConfig from "./constant/config" -import prisma from "./prisma" import { manageBotReq } from "./routes/bot" import { manageMessageReq } from "./routes/message" import { manageMicroAppReq } from "./routes/microApp" @@ -56,9 +55,3 @@ const server = Bun.serve({ }) logger.info(`Listening on ${server.hostname}:${server.port}`) - -// 关闭数据库连接 -process.on("SIGINT", async () => { - await prisma.$disconnect() - process.exit(0) -}) diff --git a/package.json b/package.json index 57766af..4c91a60 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "lint-staged": "^15.2.11", "oxlint": "^0.13.2", "prettier": "^3.4.2", - "prisma": "5.22.0", "typescript-eslint": "^8.18.1" }, "peerDependencies": { @@ -44,7 +43,6 @@ "@egg/path-tool": "^1.4.1", "@langchain/core": "^0.3.24", "@langchain/openai": "^0.3.14", - "@prisma/client": "5.22.0", "joi": "^17.13.3", "langfuse-langchain": "^3.32.0", "node-schedule": "^2.1.1", diff --git a/prisma/index.ts b/prisma/index.ts deleted file mode 100644 index fdc7831..0000000 --- a/prisma/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { PrismaClient } from "@prisma/client" - -const prisma = new PrismaClient() - -export default prisma diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index aea0978..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,31 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? -// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "mysql" - url = env("DATABASE_URL") -} - -model chat_agent_summary_subscription { - id BigInt @id @default(autoincrement()) // 摘要订阅 ID - chat_id String @default("") // 关联的聊天 ID - robot_id String @default("") // 机器人 ID - initiator String @default("") // 发起者 ID - terminator String @default("") // 终止者 ID - created_at DateTime @default(now()) // 创建时间 - updated_at DateTime @updatedAt // 更新时间 -} - -model chat_agent_message_log { - id BigInt @id @default(autoincrement()) // 消息日志 ID - subscription_id BigInt @default(0) // 关联的摘要订阅 ID - initiator String @default("") // 发起者 ID - langfuse_link String @default("") // Langfuse 日志 -} diff --git a/routes/bot/actionMsg.ts b/routes/bot/actionMsg.ts index 497648a..ff5e91c 100644 --- a/routes/bot/actionMsg.ts +++ b/routes/bot/actionMsg.ts @@ -4,9 +4,9 @@ const GROUP_MAP = {} /** * 处理点击事件 - * @param {Context.Data} ctx - 上下文数据,包含body, larkService和logger + * @param {Context} ctx - 上下文数据,包含body, larkService和logger */ -const manageAction = async (ctx: Context.Data) => { +const manageAction = async (ctx: Context) => { const { larkBody: { actionValue }, logger, @@ -16,16 +16,16 @@ const manageAction = async (ctx: Context.Data) => { } logger.info(`Got lark action cardGroup: ${cardGroup}`) if (!cardGroup) return - const func = GROUP_MAP[cardGroup] as (ctx: Context.Data) => Promise + const func = GROUP_MAP[cardGroup] as (ctx: Context) => Promise if (!func) return return func(ctx) } /** * 处理Action消息 - * @param {Context.Data} ctx - 上下文数据 + * @param {Context} ctx - 上下文数据 */ -export const manageActionMsg = async (ctx: Context.Data) => { +export const manageActionMsg = async (ctx: Context) => { const { larkBody: { actionType }, } = ctx diff --git a/routes/bot/eventMsg.ts b/routes/bot/eventMsg.ts index 1f4494c..67607f5 100644 --- a/routes/bot/eventMsg.ts +++ b/routes/bot/eventMsg.ts @@ -5,7 +5,7 @@ import { Context } from "../../types" /** * 过滤出非法消息,如果发表情包就直接发回去 - * @param {Context.Data} ctx - 上下文数据,包含body, logger和larkService + * @param {Context} ctx - 上下文数据,包含body, logger和larkService * @returns {boolean} 是否为非法消息 */ const filterIllegalMsg = async ({ @@ -14,14 +14,14 @@ const filterIllegalMsg = async ({ larkService, larkBody, appInfo, -}: Context.Data): Promise => { +}: Context): Promise => { const { chatId, msgType, msgText } = larkBody // 没有chatId的消息不处理 logger.info(`bot req chatId: ${chatId}`) if (!chatId) return true // 非私聊和群聊中艾特机器人的消息不处理 - if (!larkBody.isP2P && !larkBody.isAtBot(appInfo.app_name)) { + if (!larkBody.isP2P && !larkBody.isAtBot(appInfo.appName)) { return true } @@ -59,40 +59,37 @@ const filterIllegalMsg = async ({ /** * 发送ID消息 - * @param {Context.Data} ctx - 上下文数据 + * @param {Context} ctx - 上下文数据 */ const manageIdMsg = ({ larkBody: { chatId }, larkCard, larkService, -}: Context.Data): void => { +}: Context) => larkService.message.sendCard2Chat( chatId, larkCard.genTempCard("chatId", { chat_id: chatId }) ) -} /** * 回复引导消息 - * @param {Context.Data} ctx - 上下文数据 + * @param {Context} ctx - 上下文数据 */ const manageHelpMsg = ( - { larkBody: { chatId }, larkCard, larkService }: Context.Data, + { larkBody: { chatId }, larkCard, larkService }: Context, tempKey: keyof typeof tempMap -): void => { +) => larkService.message.sendCard2Chat( chatId, larkCard.genTempCard(tempKey, { chat_id: chatId }) as string ) -} /** * 处理命令消息 - * @param {Context.Data} ctx - 上下文数据 + * @param {Context} ctx - 上下文数据 */ -const manageCMDMsg = (ctx: Context.Data) => { +const manageCMDMsg = async (ctx: Context) => { const { - app, body, logger, larkService, @@ -104,66 +101,75 @@ const manageCMDMsg = (ctx: Context.Data) => { // 处理命令消息 if (msgText === "/id") { logger.info(`bot command is /id, chatId: ${chatId}`) - manageIdMsg(ctx) + await manageIdMsg(ctx) return } - // 小煎蛋专属功能 - if (app === "egg") { - // CI监控 - if (msgText === "/ci") { - logger.info(`bot command is /ci, chatId: ${chatId}`) - attachService.ciMonitor(chatId) - return - } - // 简报 - if (msgText.includes("share") && msgText.includes("简报")) { - logger.info(`bot command is share report, chatId: ${chatId}`) - // 这个用时比较久,先发一条提醒用户收到了请求 - // TODO: 迁移到简报服务中 - larkService.message.send( - "chat_id", - chatId, - "text", - "正在为您收集简报,请稍等片刻~" - ) - attachService.reportCollector(body) - return - } - // 创建Sheet DB - if (msgText === "/gen db") { - logger.info(`bot command is /gen db, chatId: ${chatId}`) - createKVTemp.createFromEvent(ctx) - return - } - - // 私聊场景下或者/help命令 - if (msgText === "/help" || isP2P) { - logger.info(`bot command is /help, chatId: ${chatId}`) - manageHelpMsg(ctx, "eggGuide") - return - } + // CI监控 + if (msgText === "/ci") { + logger.info(`bot command is /ci, chatId: ${chatId}`) + await attachService.ciMonitor(chatId) + return + } + // 简报 + if (msgText.includes("share") && msgText.includes("简报")) { + logger.info(`bot command is share report, chatId: ${chatId}`) + // 这个用时比较久,先发一条提醒用户收到了请求 + // TODO: 迁移到简报服务中 + await larkService.message.sendText2Chat( + chatId, + "正在为您收集简报,请稍等片刻~" + ) + await attachService.reportCollector(body) + return + } + // 创建Sheet DB + if (msgText === "/gen db") { + logger.info(`bot command is /gen db, chatId: ${chatId}`) + await createKVTemp.createFromEvent(ctx) + return } - // michat私聊场景下,先回复提示消息 - if (isP2P && app === "michat") { + // 私聊场景下或者/help命令 + if (msgText === "/help" || isP2P) { logger.info(`bot command is /help, chatId: ${chatId}`) - manageHelpMsg(ctx, "miChatGuide") + await manageHelpMsg(ctx, "eggGuide") return } // 仅限群组功能 if (isInGroup) { - // 注册群组 - if (msgText === "开启日报、周报") { - logger.info(`bot command is register, chatId: ${chatId}`) - groupAgent.report.subscribe(ctx) + // 注册群组日报 + if (msgText === "开启日报") { + logger.info( + `bot command is register, chatId: ${chatId}, timeScope: daily` + ) + groupAgent.report.subscribe(ctx, "daily") return } - // 注销群组 - if (msgText === "关闭日报、周报") { - logger.info(`bot command is unregister, chatId: ${chatId}`) - groupAgent.report.unsubscribe(ctx) + // 注册群组周报 + if (msgText === "开启周报") { + logger.info( + `bot command is register, chatId: ${chatId}, timeScope: weekly` + ) + groupAgent.report.subscribe(ctx, "weekly") + return + } + + // 注销群组日报 + if (msgText === "关闭日报") { + logger.info( + `bot command is unregister, chatId: ${chatId}, timeScope: daily` + ) + groupAgent.report.unsubscribe(ctx, "daily") + return + } + // 注销群组周报 + if (msgText === "关闭周报") { + logger.info( + `bot command is unregister, chatId: ${chatId}, timeScope: weekly` + ) + groupAgent.report.unsubscribe(ctx, "weekly") return } // 立即发送日简报 @@ -187,11 +193,11 @@ const manageCMDMsg = (ctx: Context.Data) => { /** * 处理Event消息 - * @param {Context.Data} ctx - 上下文数据 + * @param {Context} ctx - 上下文数据 */ -export const manageEventMsg = async (ctx: Context.Data) => { +export const manageEventMsg = async (ctx: Context) => { // 过滤非法消息 if (await filterIllegalMsg(ctx)) return // 处理命令消息 - manageCMDMsg(ctx) + await manageCMDMsg(ctx) } diff --git a/routes/bot/index.ts b/routes/bot/index.ts index 7f97f48..c7bb959 100644 --- a/routes/bot/index.ts +++ b/routes/bot/index.ts @@ -4,11 +4,11 @@ import { manageEventMsg } from "./eventMsg" /** * 处理机器人请求 - * @param {Context.Data} ctx - 上下文数据,包含请求体、日志记录器和响应生成器 + * @param {Context} ctx - 上下文数据,包含请求体、日志记录器和响应生成器 * @returns {Promise} 返回响应对象 */ -export const manageBotReq = async (ctx: Context.Data): Promise => { - const { body, larkBody, app, attachService } = ctx +export const manageBotReq = async (ctx: Context): Promise => { + const { body, larkBody } = ctx // 检查请求体是否为空 if (!body) { @@ -21,11 +21,6 @@ export const manageBotReq = async (ctx: Context.Data): Promise => { return Response.json({ challenge: body.challenge }) } - // 如果是michat的Event转发给MiChatServer - if (app === "michat" && larkBody.isEvent && !larkBody.isMessageEvent) { - attachService.proxyMiChatEvent(body) - } - // 处理消息事件 if (larkBody.isMessageEvent) manageEventMsg(ctx) // 处理Action消息 diff --git a/routes/message/index.ts b/routes/message/index.ts index 008d671..7c94b50 100644 --- a/routes/message/index.ts +++ b/routes/message/index.ts @@ -1,20 +1,24 @@ import { stringifyJson } from "@egg/hooks" -import { LarkService } from "@egg/net-tool" -import { APP_MAP } from "../../constant/config" import db from "../../db" import { Log } from "../../db/log" import { Context, LarkServer, MsgProxy } from "../../types" +import genLarkService from "../../utils/genLarkService" + +const ID_TYPE_MAP = { + chat_id: "chatId", + open_id: "openId", + union_id: "unionId", + user_id: "userId", + email: "email", +} /** * 校验消息请求的参数 - * @param {Context.Data} ctx - 上下文数据,包含请求体和响应生成器 + * @param {Context} ctx - 上下文数据,包含请求体和响应生成器 * @returns {false | Response} 如果校验失败,返回响应对象;否则返回 false */ -const validateMessageReq = ({ - body, - genResp, -}: Context.Data): false | Response => { +const validateMessageReq = ({ body, genResp }: Context): false | Response => { if (!body.api_key) { return genResp.badRequest("api_key is required") } @@ -35,12 +39,10 @@ const validateMessageReq = ({ /** * 处理消息请求 - * @param {Context.Data} ctx - 上下文数据,包含请求体、日志记录器、响应生成器和 Lark 服务 + * @param {Context} ctx - 上下文数据,包含请求体、日志记录器、响应生成器和 Lark 服务 * @returns {Promise} 返回响应对象 */ -export const manageMessageReq = async ( - ctx: Context.Data -): Promise => { +export const manageMessageReq = async (ctx: Context): Promise => { const { body: rawBody, genResp, requestId } = ctx const body = rawBody as MsgProxy.Body @@ -55,12 +57,12 @@ export const manageMessageReq = async ( : body.content // 初始化发送结果对象 - const sendRes = { - chat_id: {} as Record, - open_id: {} as Record, - union_id: {} as Record, - user_id: {} as Record, - email: {} as Record, + const sendResult: Record> = { + chatId: {}, + openId: {}, + unionId: {}, + userId: {}, + email: {}, } // 发送消息列表 @@ -68,39 +70,25 @@ export const manageMessageReq = async ( // 构造消息记录 const baseLog: Log = { - ...body, - final_content: finalContent, + apiKey: body.api_key, + groupId: body.group_id, + receiveId: body.receive_id, + receiveIdType: body.receive_id_type, + msgType: body.msg_type, + content: body.content, + finalContent, } // 校验 api_key const apiKeyInfo = await db.apiKey.getOne(body.api_key) if (!apiKeyInfo) { const error = "api key not found" - db.log.create({ ...baseLog, error }) + await db.log.create({ ...baseLog, error }) return genResp.notFound(error) } - // 获取 app name - const appName = apiKeyInfo.expand?.app?.name - if (!appName) { - const error = "app name not found" - db.log.create({ ...baseLog, error }) - return genResp.notFound(error) - } - - // 获取 app info - const appInfo = APP_MAP[appName] - if (!appInfo) { - const error = "app not found" - db.log.create({ ...baseLog, error }) - return genResp.notFound(error) - } - - const larkService = new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, - requestId, - }) + // 生成 Lark 服务 + const larkService = genLarkService(apiKeyInfo.expand.app.name, requestId) // 如果有 group_id,则发送给所有 group_id 中的人 if (body.group_id) { @@ -108,11 +96,11 @@ export const manageMessageReq = async ( const group = await db.receiveGroup.getOne(body.group_id!) if (!group) { const error = "message group not found" - db.log.create({ ...baseLog, error }) + await db.log.create({ ...baseLog, error }) return genResp.notFound(error) } - const { chat_id, open_id, union_id, user_id, email } = group + const { chatId, openId, unionId, userId, email } = group // 构造发送消息函数 const makeSendFunc = (receive_id_type: LarkServer.ReceiveIDType) => { @@ -121,17 +109,17 @@ export const manageMessageReq = async ( larkService.message .send(receive_id_type, receive_id, body.msg_type, finalContent) .then((res) => { - sendRes[receive_id_type][receive_id] = res + sendResult[ID_TYPE_MAP[receive_id_type]][receive_id] = res }) ) } } // 创建消息列表 - if (chat_id) chat_id.map(makeSendFunc("chat_id")) - if (open_id) open_id.map(makeSendFunc("open_id")) - if (union_id) union_id.map(makeSendFunc("union_id")) - if (user_id) user_id.map(makeSendFunc("user_id")) + if (chatId) chatId.map(makeSendFunc("chat_id")) + if (openId) openId.map(makeSendFunc("open_id")) + if (unionId) unionId.map(makeSendFunc("union_id")) + if (userId) userId.map(makeSendFunc("user_id")) if (email) email.map(makeSendFunc("email")) } @@ -142,7 +130,7 @@ export const manageMessageReq = async ( larkService.message .send(body.receive_id_type, receive_id, body.msg_type, finalContent) .then((res) => { - sendRes[body.receive_id_type][receive_id] = res + sendResult[ID_TYPE_MAP[body.receive_id_type]][receive_id] = res }) ) }) @@ -152,11 +140,11 @@ export const manageMessageReq = async ( // 发送消息 await Promise.allSettled(sendList) // 保存消息记录 - db.log.create({ ...baseLog, send_result: sendRes }) - return genResp.ok(sendRes) + await db.log.create({ ...baseLog, sendResult }) + return genResp.ok(sendResult) } catch { const error = "send msg failed" - db.log.create({ ...baseLog, error }) - return genResp.serverError(error, sendRes) + await db.log.create({ ...baseLog, error }) + return genResp.serverError(error, sendResult) } } diff --git a/routes/microApp/index.ts b/routes/microApp/index.ts index d5e3217..59dddfc 100644 --- a/routes/microApp/index.ts +++ b/routes/microApp/index.ts @@ -8,7 +8,7 @@ import { Context } from "../../types" * @param req * @returns */ -const manageLogin = async (ctx: Context.Data) => { +const manageLogin = async (ctx: Context) => { const { req, genResp, logger, requestId } = ctx logger.info("micro app login") const url = new URL(req.url) @@ -27,8 +27,8 @@ const manageLogin = async (ctx: Context.Data) => { } const larkService = new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, + appId: appInfo.appId, + appSecret: appInfo.appSecret, requestId, }) @@ -52,7 +52,7 @@ const manageLogin = async (ctx: Context.Data) => { * @param req * @returns */ -const manageBatchUser = async (ctx: Context.Data) => { +const manageBatchUser = async (ctx: Context) => { const { body, genResp, logger, requestId } = ctx logger.info("batch get user info") if (!body) return genResp.badRequest("req body is empty") @@ -73,8 +73,8 @@ const manageBatchUser = async (ctx: Context.Data) => { } const larkService = new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, + appId: appInfo.appId, + appSecret: appInfo.appSecret, requestId, }) @@ -97,7 +97,7 @@ const manageBatchUser = async (ctx: Context.Data) => { * @param req * @returns */ -export const manageMicroAppReq = async (ctx: Context.Data) => { +export const manageMicroAppReq = async (ctx: Context) => { const path = ctx.path.child("/micro_app") // 处理登录请求 if (path.exact("/login")) { diff --git a/routes/sheet/index.ts b/routes/sheet/index.ts index 7184a64..c73026b 100644 --- a/routes/sheet/index.ts +++ b/routes/sheet/index.ts @@ -9,13 +9,13 @@ import { SheetProxy } from "../../types/sheetProxy" /** * 校验表格请求的参数 - * @param {Context.Data} ctx - 上下文数据,包含请求体和响应生成器 + * @param {Context} ctx - 上下文数据,包含请求体和响应生成器 * @returns {Promise} 如果校验失败,返回响应对象;否则返回 false */ const validateSheetReq = async ({ body, genResp, -}: Context.Data): Promise => { +}: Context): Promise => { // 定义基础的Schema let schema = Joi.object({ api_key: Joi.string() @@ -61,10 +61,10 @@ const validateSheetReq = async ({ /** * 处理表格请求 - * @param {Context.Data} ctx - 上下文数据,包含请求体、响应生成器和 Lark 服务 + * @param {Context} ctx - 上下文数据,包含请求体、响应生成器和 Lark 服务 * @returns {Promise} 返回响应对象 */ -export const manageSheetReq = async (ctx: Context.Data): Promise => { +export const manageSheetReq = async (ctx: Context): Promise => { const { body: rawBody, genResp, requestId } = ctx const body = rawBody as SheetProxy.InsertData @@ -92,8 +92,8 @@ export const manageSheetReq = async (ctx: Context.Data): Promise => { // 组织新的LarkService ctx.larkService = new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, + appId: appInfo.appId, + appSecret: appInfo.appSecret, requestId, }) diff --git a/test/archive/llm.ts b/test/archive/llm.ts index 2be6028..60a288b 100644 --- a/test/archive/llm.ts +++ b/test/archive/llm.ts @@ -13,9 +13,13 @@ const chatHistory = [ }, ] -const res = await llm.invoke("summary-qwen-72b-instruct-int4", { - chatHistory: JSON.stringify(chatHistory), - time: new Date().toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" }), -}) +const res = await llm.invoke( + "summary-qwen-72b-instruct-int4", + { + chatHistory: JSON.stringify(chatHistory), + time: new Date().toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" }), + }, + "123456" +) console.log(res) diff --git a/types/context.ts b/types/context.ts index d5efa36..a656131 100644 --- a/types/context.ts +++ b/types/context.ts @@ -3,27 +3,25 @@ import { LarkService, NetTool } from "@egg/net-tool" import { PathCheckTool } from "@egg/path-tool" import { Logger } from "winston" -import { AppInfo } from "../constant/appMap" import cardMap from "../constant/card" +import { AppInfoModel } from "../constant/config" import functionMap from "../constant/function" import tempMap from "../constant/template" import { AttachService } from "../services" -export namespace Context { - export interface Data { - req: Request - requestId: string - logger: Logger - genResp: NetTool - body: any - text: string - larkService: LarkService - larkBody: LarkBody - larkCard: LarkCard - attachService: AttachService - path: PathCheckTool - searchParams: URLSearchParams - app: "michat" | "egg" | string - appInfo: AppInfo - } +export interface Context { + req: Request + requestId: string + logger: Logger + genResp: NetTool + body: any + text: string + larkService: LarkService + larkBody: LarkBody + larkCard: LarkCard + attachService: AttachService + path: PathCheckTool + searchParams: URLSearchParams + app: "michat" | "egg" | string + appInfo: AppInfoModel } diff --git a/types/index.ts b/types/index.ts index 783e846..ef12df5 100644 --- a/types/index.ts +++ b/types/index.ts @@ -3,3 +3,11 @@ import type { LarkServer } from "./larkServer" import type { MsgProxy } from "./msgProxy" export { Context, LarkServer, MsgProxy } + +declare module "bun" { + interface Env { + PB_USER: string + PB_PASS: string + PB_URL: string + } +} diff --git a/utils/genContext.ts b/utils/genContext.ts index 36d1bd4..6104e34 100644 --- a/utils/genContext.ts +++ b/utils/genContext.ts @@ -29,7 +29,7 @@ const getPreRequestId = (larkBody: LarkBody) => { * 生成请求上下文。 * * @param {Request} req - 请求对象。 - * @returns {Promise} 返回包含请求上下文的对象。 + * @returns {Promise} 返回包含请求上下文的对象。 */ const genContext = async (req: Request) => { let body: any = null @@ -74,7 +74,7 @@ const genContext = async (req: Request) => { searchParams, app, appInfo, - } as Context.Data + } as Context } export default genContext diff --git a/utils/genLarkService.ts b/utils/genLarkService.ts index 2de651e..2a15d08 100644 --- a/utils/genLarkService.ts +++ b/utils/genLarkService.ts @@ -5,8 +5,8 @@ import { APP_MAP } from "../constant/config" const genLarkService = (app: string, requestId: string) => { const appInfo = APP_MAP[app] return new LarkService({ - appId: appInfo.app_id, - appSecret: appInfo.app_secret, + appId: appInfo.appId, + appSecret: appInfo.appSecret, requestId, }) }