From 6792b3703ff2b38332d7cd42a8911cc09cd533f3 Mon Sep 17 00:00:00 2001 From: zhaoyingbo Date: Mon, 25 Nov 2024 11:08:54 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9F=BA=E7=A1=80=E5=BB=BA=E8=AE=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .devcontainer/devcontainer.json | 3 +- .env.dev | 4 -- .env.prod | 4 -- .../workflows/{miflow.yml => miflow.yml.bak} | 0 .gitignore | 2 + .gitlab-ci.yml | 38 ++++++++++ .vscode/settings.json | 1 + bun.lockb | Bin 152322 -> 158630 bytes cache.ts | 3 + Dockerfile => docker/deploy/Dockerfile | 0 eslint.config.js | 13 ++++ package.json | 35 ++++----- routes/message/index.ts | 37 +++++----- routes/microApp/index.ts | 46 ++++++++++-- routes/sheet/index.ts | 27 +++++-- routes/sheet/insert.ts | 10 +-- schedule/accessToken.ts | 20 +++--- schedule/index.ts | 12 ++-- services/index.ts | 3 +- test/archive/copyFile.ts | 8 ++- test/archive/createFile.ts | 10 ++- test/archive/getInnerList.ts | 7 -- test/archive/sheet.record.get.test.ts | 13 ---- types/context.ts | 11 ++- utils/genContext.ts | 20 +++++- utils/llm/base.ts | 38 ++++++++++ utils/{llm.ts => llm/index.ts} | 68 +----------------- 27 files changed, 257 insertions(+), 176 deletions(-) delete mode 100644 .env.dev delete mode 100644 .env.prod rename .gitea/workflows/{miflow.yml => miflow.yml.bak} (100%) create mode 100644 .gitlab-ci.yml create mode 100644 cache.ts rename Dockerfile => docker/deploy/Dockerfile (100%) delete mode 100644 test/archive/getInnerList.ts delete mode 100644 test/archive/sheet.record.get.test.ts create mode 100644 utils/llm/base.ts rename utils/{llm.ts => llm/index.ts} (61%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 33f42ec..daa8c66 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -30,7 +30,8 @@ "Prisma.prisma", "humao.rest-client", "GitHub.copilot", - "GitHub.copilot-chat" + "GitHub.copilot-chat", + "oven.bun-vscode" ] } }, diff --git a/.env.dev b/.env.dev deleted file mode 100644 index dcd53a1..0000000 --- a/.env.dev +++ /dev/null @@ -1,4 +0,0 @@ -NODE_ENV=dev -http_proxy=http://proxy.pt.xiaomi.com:80 -https_proxy=http://proxy.pt.xiaomi.com:80 -no_proxy=localhost,.xiaomiwh.cn,.mioffice.cn,.xiaomi.com,.imoaix.cn,.deepseek.com,.gpt.ge,.xiaomi.srv \ No newline at end of file diff --git a/.env.prod b/.env.prod deleted file mode 100644 index 58c0f39..0000000 --- a/.env.prod +++ /dev/null @@ -1,4 +0,0 @@ -NODE_ENV=production -http_proxy=http://proxy.pt.xiaomi.com:80 -https_proxy=http://proxy.pt.xiaomi.com:80 -no_proxy=localhost,.xiaomiwh.cn,.mioffice.cn,.xiaomi.com,.imoaix.cn,.deepseek.com,.gpt.ge,.xiaomi.srv \ No newline at end of file diff --git a/.gitea/workflows/miflow.yml b/.gitea/workflows/miflow.yml.bak similarity index 100% rename from .gitea/workflows/miflow.yml rename to .gitea/workflows/miflow.yml.bak diff --git a/.gitignore b/.gitignore index 96c022e..38ad061 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ profile-* profile* *clinic* *flamegraph* + +.env \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000..7fe72a1 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,38 @@ +variables: + REGISTRY: micr.cloud.mioffice.cn + IMAGE_NAME: micr.cloud.mioffice.cn/egg/egg_server + MATRIX_PROJECT: 462609 + MATRIX_SPACE: egg-server-prev + MATRIX_AK: CAKBCYGR0BI2BGMVUF8 + +stages: + - build + - deploy + +default: + tags: + - fe-bj + +build: + stage: build + only: + - master + image: docker:latest + services: + - docker:dind + script: + - cp $ENV .env + - docker login -u $MATRIX_AK -p $MATRIX_SK $REGISTRY + - docker build -t $IMAGE_NAME:$CI_COMMIT_SHA -f ./docker/deploy/Dockerfile . + - docker push $IMAGE_NAME:$CI_COMMIT_SHA + - docker logout $REGISTRY + - docker rmi $IMAGE_NAME:$CI_COMMIT_SHA + +deploy: + stage: deploy + only: + - master + image: cr.d.xiaomi.net/bigdata-fe/matrix-cli + script: + - matrix-cli config set --access-key $MATRIX_AK --secret-key $MATRIX_SK + - matrix-cli deploy --project $MATRIX_PROJECT --deploy-space $MATRIX_SPACE --reason "$CI_COMMIT_MESSAGE" --deploy-percentage 1 --tag $CI_COMMIT_SHA diff --git a/.vscode/settings.json b/.vscode/settings.json index 7b56f55..565a391 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,6 +25,7 @@ "mindnote", "openai", "openchat", + "oxlint", "pocketbase", "PWTHWP", "qwen", diff --git a/bun.lockb b/bun.lockb index 027941dd766f35057292ab3df58b0fd3676efcc7..c83e5dd74acb46319f9ca1f928eb950a2e6dc517 100755 GIT binary patch delta 37768 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 z⩔ZYtduSj8+;9joyqSQ2xv3xhm}TRrpGy^Y{w>*foT}z~-~BqXp%FGduo4kBC>V z($E4vg`$s)}|C_tuFIK5H;t?X@?^4s$LVG4?zm<>Uy1G$ z_^^*0`!^e*b{OaHJNnHw1nWXM#p~R|;T~btx?RKVg~Bm93Sfb7Rq_i(e-vXVOp*v(rrd%P{M%15BUM@P9f)$cp*S6APGiZr9ptqRlJ5rH^Ck^N z`D3B|?bu7SW&I1a4=Fq3Zee|y!*?P5gvz0HV-lrQ6 z-K$~QU%Z{8hzjre4{zsW-Q~A)e!qA-NAGCS`Y+zj$+~+xv)~7~Mf)7(DzozsI0Ikh zSie6{&BtPTog0w-$tZ7;J6VAdp^z7**)3(C$OwMP&{bM&OhO{{A$1HFTFp;esl3t)Ch}aJD>h~-w9VD zwGPIxjW1C0P7JG0^ZPMI+UTeze>}9Z(Km!LWdfw$y{wh95clQG`F_7)m!2p=cSN*h z9n1Do8_Ma4i!baWtJN>Vd*U|hc5@vu$L5Pb+oLwhR*E^ZmJWSX1AR-MqX~JZpq#hpw6W{Hc6*+jCq<>N1yholbrHH(j)q(~9{S;}pdh)MH`g6Po??p{oKrl;j3bTJjK9DMv@awqd+=lyRbgPta`^sUJBZo(Y z)-8HLZ}RAi3Di|IR!*B7d$M-W!O{`_C?T(3<=o2G#@E^9fw|PL9Cc&*vEAsGPwL06 zzCz&J-j6xG=4v~&OqV=PIngpVra;q5fAuibl)n*DLZ&iJ%U)xeB*v?}@+-Hwci8vW zTxh8DvFJe6`|1(v4R`eCUsRU@s{e&u^=@0$+ff3ZKF>{PGIiV}7oCOw&S#--I1fwf z7SbJiRDkbkZlF;qwhq`Yh{L9%OJ-(X46l~Vx_v5=VPu_t|`_7eT3-x&ud^T@l&)c)}`n*OL-%9u}I|F`; zF}_)K$3fk$nW?EsuAXjzEW#MI_NjUO0&6v2qR;9W@csp>&G=QkO-6dGJC1`@lyOVU z=#!A?Dyzm!OnB?o|I*jpRVj?N5%WFVGW!g|xwYC@^oYZOabj{>LTqYsbY^UP3eJgk z6;BtBNl0-Q6Kq2--j;>9@J6g*81G~#e(Z@hMataVdFRtla<%-L)maB$JS_gTYPHc;K)0&A`Ne?gZ(Y@w1qYC8HNoD zaObUa^+L-8+KCZAsa&$@@Gj-vovd*>mS!{V2Z?1z| zkJLh)w{=LrT5on$P5nijt3(a zc8^U+i`S+rSrW(cd-2xhN>!-Y;xC+|xP7%Mvv$X8(- zE%{&;U5|HT{Q`K0I&xm0^k|F|M_XrRxJIWXxMtC@=_%2fS?QQZ*gY*eUCVk}@s{jh zAYY9g3E*28`6AqiUmA$_R8~Hak1E@hIU5m(S^r_l2XWpk$cnGSo_g?xY?2i}i7l?l zn=*fEeoE!kw9JH5^pu*OsT~NXkB(vY%-{|<6dvWX?7Dr!2fDZ&;A;!Z+4o72Mziue`7>u3GVxn2#$Tf%QGc zm2bwXQ#1(iglLv3WvfcO!?7k_Q7unaoyiLI=H~u!qYWnfM%s7Cr z%`SOkNY`ufmDzZ2tPm6|Zl0CiqNZEL9B-7xdJS@SdQ~!!~OUg%)K=X`MNa> za;G&PXXGs|s?6*(ZHD`R4A$@+7g#X94R6G;hn;xSf;DaVJf4zO3i`C?gH6OFTayS+ bJs5| => { - const { body: rawBody, genResp, larkService } = ctx + const { body: rawBody, genResp, appMap, requestId } = ctx const body = rawBody as MsgProxy.Body // 校验参数 @@ -87,6 +88,20 @@ export const manageMessageReq = async ( return genResp.notFound(error) } + // 获取 app info + const appInfo = appMap[appName] + if (!appInfo) { + const error = "app not found" + db.log.create(LOG_COLLECTION, { ...baseLog, error }) + return genResp.notFound(error) + } + + const larkService = new LarkService({ + appId: appInfo.app_id, + appSecret: appInfo.app_secret, + requestId, + }) + // 如果有 group_id,则发送给所有 group_id 中的人 if (body.group_id) { // 获取所有接收者 @@ -103,14 +118,8 @@ export const manageMessageReq = async ( const makeSendFunc = (receive_id_type: LarkServer.ReceiveIDType) => { return (receive_id: string) => { sendList.push( - larkService - .child(appName) - .message.send( - receive_id_type, - receive_id, - body.msg_type, - finalContent - ) + larkService.message + .send(receive_id_type, receive_id, body.msg_type, finalContent) .then((res) => { sendRes[receive_id_type][receive_id] = res }) @@ -130,14 +139,8 @@ export const manageMessageReq = async ( if (body.receive_id && body.receive_id_type) { body.receive_id.split(",").forEach((receive_id) => { sendList.push( - larkService - .child(appName) - .message.send( - body.receive_id_type, - receive_id, - body.msg_type, - finalContent - ) + larkService.message + .send(body.receive_id_type, receive_id, body.msg_type, finalContent) .then((res) => { sendRes[body.receive_id_type][receive_id] = res }) diff --git a/routes/microApp/index.ts b/routes/microApp/index.ts index 81a81f9..2d8d25a 100644 --- a/routes/microApp/index.ts +++ b/routes/microApp/index.ts @@ -1,3 +1,5 @@ +import { LarkService } from "@egg/net-tool" + import { Context } from "../../types" /** @@ -6,19 +8,34 @@ import { Context } from "../../types" * @returns */ const manageLogin = async (ctx: Context.Data) => { - const { req, larkService, genResp, logger } = ctx + const { req, genResp, logger, appMap, requestId } = ctx logger.info("micro app login") const url = new URL(req.url) const code = url.searchParams.get("code") - const appName = url.searchParams.get("app_name") || undefined + const appName = url.searchParams.get("app_name") if (!code) { return genResp.badRequest("code not found") } + if (!appName) { + return genResp.badRequest("app_name not found") + } + // 获取 app info + const appInfo = appMap[appName] + if (!appInfo) { + return genResp.badRequest("app not found") + } + + const larkService = new LarkService({ + appId: appInfo.app_id, + appSecret: appInfo.app_secret, + requestId, + }) + const { code: resCode, data, message, - } = await larkService.child(appName).user.code2Login(code) + } = await larkService.user.code2Login(code) logger.debug(`get user session: ${JSON.stringify(data)}`) @@ -35,7 +52,7 @@ const manageLogin = async (ctx: Context.Data) => { * @returns */ const manageBatchUser = async (ctx: Context.Data) => { - const { body, genResp, larkService, logger } = ctx + const { body, genResp, logger, appMap, requestId } = ctx logger.info("batch get user info") if (!body) return genResp.badRequest("req body is empty") const { user_ids, user_id_type, app_name } = body @@ -45,10 +62,25 @@ const manageBatchUser = async (ctx: Context.Data) => { if (!user_id_type) { return genResp.badRequest("user_id_type not found") } + if (!app_name) { + return genResp.badRequest("app_name not found") + } + // 获取 app info + const appInfo = appMap[app_name] + if (!appInfo) { + return genResp.badRequest("app not found") + } - const { code, data, message } = await larkService - .child(app_name) - .user.batchGet(user_ids, user_id_type) + const larkService = new LarkService({ + appId: appInfo.app_id, + appSecret: appInfo.app_secret, + requestId, + }) + + const { code, data, message } = await larkService.user.batchGet( + user_ids, + user_id_type + ) logger.debug(`batch get user info: ${JSON.stringify(data)}`) diff --git a/routes/sheet/index.ts b/routes/sheet/index.ts index cd97898..f118aab 100644 --- a/routes/sheet/index.ts +++ b/routes/sheet/index.ts @@ -1,3 +1,4 @@ +import { LarkService } from "@egg/net-tool" import Joi from "joi" import db from "../../db" @@ -10,11 +11,10 @@ import insertSheet from "./insert" * @param {Context.Data} ctx - 上下文数据,包含请求体和响应生成器 * @returns {Promise} 如果校验失败,返回响应对象;否则返回 false */ -const validateSheetReq = async ( - ctx: Context.Data -): Promise => { - const { body, genResp } = ctx - +const validateSheetReq = async ({ + body, + genResp, +}: Context.Data): Promise => { // 定义基础的Schema let schema = Joi.object({ api_key: Joi.string() @@ -64,7 +64,7 @@ const validateSheetReq = async ( * @returns {Promise} 返回响应对象 */ export const manageSheetReq = async (ctx: Context.Data): Promise => { - const { body: rawBody, genResp } = ctx + const { body: rawBody, genResp, appMap, requestId } = ctx const body = rawBody as SheetProxy.InsertData // 校验参数 @@ -83,8 +83,21 @@ export const manageSheetReq = async (ctx: Context.Data): Promise => { return genResp.notFound("app name not found") } + // 获取APP信息 + const appInfo = appMap[appName] + if (!appInfo) { + return genResp.notFound("app not found") + } + + // 组织新的LarkService + ctx.larkService = new LarkService({ + appId: appInfo.app_id, + appSecret: appInfo.app_secret, + requestId, + }) + // 根据请求类型处理 - if (body.type === "insert") return await insertSheet(ctx, appName) + if (body.type === "insert") return await insertSheet(ctx) // 默认返回成功响应 return genResp.ok() diff --git a/routes/sheet/insert.ts b/routes/sheet/insert.ts index 981299d..426876a 100644 --- a/routes/sheet/insert.ts +++ b/routes/sheet/insert.ts @@ -7,13 +7,15 @@ import { SheetProxy } from "../../types/sheetProxy" * @param {string} appName - 应用名称 * @returns {Promise} 返回响应对象 */ -const insertSheet = async (ctx: Context.Data, appName: string) => { +const insertSheet = async (ctx: Context.Data) => { const { genResp, larkService } = ctx const body = ctx.body as SheetProxy.InsertData - const insertRes = await larkService - .child(appName) - .sheet.insertRows(body.sheet_token, body.range, body.values) + const insertRes = await larkService.sheet.insertRows( + body.sheet_token, + body.range, + body.values + ) if (insertRes?.code !== 0) { return genResp.serverError(insertRes?.message) diff --git a/schedule/accessToken.ts b/schedule/accessToken.ts index 25d2891..d311ab7 100644 --- a/schedule/accessToken.ts +++ b/schedule/accessToken.ts @@ -1,24 +1,24 @@ import logger from "@egg/logger" +import { LarkService } from "@egg/net-tool" import pLimit from "p-limit" import db from "../db" -import { LarkService } from "../services" export const resetAccessToken = async () => { try { const appList = await db.appInfo.getFullList() const limit = pLimit(3) - const service = new LarkService("", "schedule") const promiseList = appList.map((app) => limit(() => - service.auth.getAk(app.app_id, app.app_secret).then((res) => { - if (res.code !== 0) return - return db.tenantAccessToken.update( - app.id, - app.name, - res.tenant_access_token - ) - }) + new LarkService({ + appId: app.app_id, + appSecret: app.app_secret, + requestId: "schedule", + }).auth + .getAppAuth() + .then((res) => { + return db.tenantAccessToken.update(app.id, app.name, res) + }) ) ) await Promise.allSettled(promiseList) diff --git a/schedule/index.ts b/schedule/index.ts index 4cce843..88520d4 100644 --- a/schedule/index.ts +++ b/schedule/index.ts @@ -1,10 +1,6 @@ -import schedule from "node-schedule" - -import { resetAccessToken } from "./accessToken" - export const initSchedule = async () => { - // 定时任务,每15分钟刷新一次token - schedule.scheduleJob("*/15 * * * *", resetAccessToken) - // 立即执行一次 - resetAccessToken() + // // 定时任务,每15分钟刷新一次token + // schedule.scheduleJob("*/15 * * * *", resetAccessToken) + // // 立即执行一次 + // resetAccessToken() } diff --git a/services/index.ts b/services/index.ts index 0b646ab..24024cc 100644 --- a/services/index.ts +++ b/services/index.ts @@ -1,4 +1,3 @@ import AttachService from "./attach" -import LarkService from "./lark" -export { AttachService, LarkService } +export { AttachService } diff --git a/test/archive/copyFile.ts b/test/archive/copyFile.ts index c015629..df8b38a 100644 --- a/test/archive/copyFile.ts +++ b/test/archive/copyFile.ts @@ -1,6 +1,10 @@ -import { LarkService } from "../../services" +import { LarkService } from "@egg/net-tool" -const service = new LarkService("egg", "") +const service = new LarkService({ + appId: "cli_9f4b3b1b1b", + appSecret: "bask4IvKT61xCvTUxIkcMaWoiYf", + requestId: "123", +}) const { data: { diff --git a/test/archive/createFile.ts b/test/archive/createFile.ts index 5a307ef..4cc91e5 100644 --- a/test/archive/createFile.ts +++ b/test/archive/createFile.ts @@ -1,8 +1,12 @@ -import LarkDriveService from "../../services/lark/drive" +import { LarkService } from "@egg/net-tool" -const service = new LarkDriveService("egg", "") +const service = new LarkService({ + appId: "cli_9f1e6b4e", + appSecret: "7b2f2f3a9b2c8e8a2f1a2b2b2b2b2b2b", + requestId: "schedule", +}) -const res = await service.createFile( +const res = await service.drive.createFile( "D6ETfzaU9lN08adVDz3kjLey4Bx", "xxx 项目 KV管理器", "bitable" diff --git a/test/archive/getInnerList.ts b/test/archive/getInnerList.ts deleted file mode 100644 index 7b011ba..0000000 --- a/test/archive/getInnerList.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { LarkService } from "../../services" - -const service = new LarkService("egg", "") - -const res = await service.chat.getInnerList() - -console.log(JSON.stringify(res, null, 2)) diff --git a/test/archive/sheet.record.get.test.ts b/test/archive/sheet.record.get.test.ts deleted file mode 100644 index 46b13d3..0000000 --- a/test/archive/sheet.record.get.test.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { test } from "bun:test" - -import LarkSheetService from "../../services/lark/sheet" - -const service = new LarkSheetService("egg", "") - -test("getRecords", async () => { - const res = await service.getRecords( - "bask4BA989TBbnu5R7Onmdh1csb", - "tblabYZk3AYtGLSe" - ) - console.log(res) -}) diff --git a/types/context.ts b/types/context.ts index c6ecaed..a823225 100644 --- a/types/context.ts +++ b/types/context.ts @@ -1,14 +1,19 @@ import { LarkBody, LarkCard } from "@egg/lark-msg-tool" -import { NetTool } from "@egg/net-tool" +import { LarkService, 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" +import { AttachService } from "../services" export namespace Context { + export interface APP_INFO { + app_id: string + app_secret: string + app_name: string + } export interface Data { req: Request requestId: string @@ -23,5 +28,7 @@ export namespace Context { path: PathCheckTool searchParams: URLSearchParams app: "michat" | "egg" | string + appInfo: APP_INFO + appMap: Record } } diff --git a/utils/genContext.ts b/utils/genContext.ts index 4a068fd..4f9adbd 100644 --- a/utils/genContext.ts +++ b/utils/genContext.ts @@ -1,15 +1,22 @@ +import { parseJsonString } from "@egg/hooks" import { LarkBody, LarkCard } from "@egg/lark-msg-tool" import loggerIns from "@egg/logger" -import { NetTool } from "@egg/net-tool" +import { LarkService, 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 { AttachService } from "../services" import { Context } from "../types" +// 获取所有应用信息 +const appMap = parseJsonString(process.env.LARK_APP_MAP, {}) as Record< + string, + Context.APP_INFO +> + /** * 获取之前的requestId。 * @@ -41,10 +48,15 @@ const genContext = async (req: Request) => { const larkBody = new LarkBody(body) const searchParams = new URL(req.url).searchParams const app = searchParams.get("app") || "egg" + const appInfo = appMap[app] const requestId = getPreRequestId(larkBody) || uuid() const logger = loggerIns.child({ requestId }) const genResp = new NetTool({ requestId }) - const larkService = new LarkService(app, requestId) + const larkService = new LarkService({ + appId: appInfo.app_id, + appSecret: appInfo.app_secret, + requestId, + }) const attachService = new AttachService({ requestId }) const path = new PathCheckTool(req.url) const larkCard = new LarkCard( @@ -70,6 +82,8 @@ const genContext = async (req: Request) => { attachService, searchParams, app, + appInfo, + appMap, } as Context.Data } diff --git a/utils/llm/base.ts b/utils/llm/base.ts new file mode 100644 index 0000000..d64de5f --- /dev/null +++ b/utils/llm/base.ts @@ -0,0 +1,38 @@ +import { ChatOpenAI } from "@langchain/openai" +import CallbackHandler, { Langfuse } from "langfuse-langchain" + +/** + * 获取模型 + * @param temperature 温度 + * @returns + */ +export const getModel = (temperature = 0) => { + return new ChatOpenAI( + { + temperature, + model: Bun.env.LLM_MODEL, + apiKey: Bun.env.LLM_API_KEY, + }, + { + baseURL: Bun.env.LLM_BASE_URL, + } + ) +} + +/** + * 获取Langfuse + * @returns + */ +export const getLangfuse = async (name: string, requestId: string) => { + const langfuseParams = { + publicKey: Bun.env.LANGFUSE_PK, + secretKey: Bun.env.LANGFUSE_SK, + baseUrl: Bun.env.LANGFUSE_BASE_URL, + sessionId: requestId, + name, + } + return { + langfuseHandler: new CallbackHandler(langfuseParams), + langfuse: new Langfuse(langfuseParams), + } +} diff --git a/utils/llm.ts b/utils/llm/index.ts similarity index 61% rename from utils/llm.ts rename to utils/llm/index.ts index be9a62d..86441c0 100644 --- a/utils/llm.ts +++ b/utils/llm/index.ts @@ -1,66 +1,7 @@ import { PromptTemplate } from "@langchain/core/prompts" -import { ChatOpenAI } from "@langchain/openai" -import { CallbackHandler, Langfuse } from "langfuse-langchain" import { z } from "zod" -import db from "../db" - -/** - * 获取Langfuse - * @returns - */ -const getLangfuse = async (name: string, requestId: string) => { - const langfuseParams = { - publicKey: await db.appConfig.getLangfusePk(), - secretKey: await db.appConfig.getLangfuseSk(), - baseUrl: "http://langfuse.c5-cloudml.xiaomi.srv", - sessionId: requestId, - name, - } - return { - langfuseHandler: new CallbackHandler(langfuseParams), - langfuse: new Langfuse(langfuseParams), - } -} - -const modelMap = { - "deepseek-chat": { - model: "deepseek-chat", - apiKey: "xx", - baseURL: "http://10.38.214.162:8003/v1", - }, - "qwen2-72b-instruct-int4": { - model: "qwen2-72b-instruct-int4", - apiKey: "xx", - baseURL: "http://10.38.214.206:8000/v1", - }, - "gpt-4o": { - model: "gpt-4o", - apiKey: "sk-EhbBTR0QjhH22iLr9aCb04D2B0F44f88A07c2924Eb54CfA4", - baseURL: "https://api.gpt.ge/v1", - }, - "qwen-72b-instruct-int4/v1": { - model: "qwen-72b-instruct-int4/v1", - apiKey: "xx", - baseURL: - "http://ms-13871-qwen-model-128k-9-1012195754.kscn-tj5-prod2-cloudml.xiaomi.srv/v1", - }, -} - -/** - * 获取模型 - * @param modelName 模型名称 - * @param temperature 温度 - */ -const getModel = async (modelName: keyof typeof modelMap, temperature = 0) => { - const { model, apiKey, baseURL } = modelMap[modelName] - return new ChatOpenAI( - { temperature, model, apiKey }, - { - baseURL, - } - ) -} +import { getLangfuse, getModel } from "./base" const groupAgentConfig = z.object({ chatId: z.string().describe("群聊ID"), @@ -89,7 +30,7 @@ const parseGroupAgentQuery = async ( "parseGroupAgentQuery", requestId ) - const model = await getModel("qwen-72b-instruct-int4/v1") + const model = await getModel() const structuredLlm = model.withStructuredOutput(groupAgentConfig, { name: "groupAgent", }) @@ -140,7 +81,6 @@ const invoke = async ( ) => { const { langfuse, langfuseHandler } = await getLangfuse("invoke", requestId) const prompt = await langfuse.getPrompt(promptName) - const config = prompt.config as { modelName: keyof typeof modelMap } const langchainTextPrompt = PromptTemplate.fromTemplate( prompt.getLangchainPrompt() @@ -148,9 +88,7 @@ const invoke = async ( metadata: { langfusePrompt: prompt }, }) - const chain = langchainTextPrompt.pipe( - await getModel(config.modelName, temperature) - ) + const chain = langchainTextPrompt.pipe(await getModel(temperature)) const { content } = await chain.invoke(variables, { callbacks: [langfuseHandler],