From 848257759bd4c2a63dbcf52dd2260a0150621462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E4=BA=9A=E6=98=95?= <1549469775@qq.com> Date: Wed, 15 Oct 2025 14:27:55 +0800 Subject: [PATCH] feat: Update build scripts and enhance environment configuration - Refactored build scripts in package.json for better clarity and functionality. - Added new environment variables and paths for production and development setups. - Improved chat component with dynamic message handling and error management. - Updated dependencies in package.json for enhanced performance and compatibility. --- bun.lockb | Bin 204000 -> 226837 bytes internal/helper/src/env.ts | 4 +- internal/helper/src/path.ts | 25 +++--- package.json | 9 +- packages/client/src/components/ChatBox/index.vue | 98 ++++++++++++++-------- packages/client/src/components/ChatBox/prompt.txt | 4 +- packages/client/src/composables/useChat/index.ts | 11 +-- packages/client/src/vue.d.ts | 6 +- packages/client/vite.config.ts | 2 +- packages/core/src/SsrMiddleWare.ts | 15 ++-- packages/server/package.json | 4 +- packages/server/src/jobs/index.ts | 14 ++-- packages/server/src/logger.ts | 10 +-- packages/server/src/middleware/install.ts | 6 +- scripts/build.js | 65 ++++++++++++++ tsup.config.ts | 20 +++++ tsup.jobs.config.ts | 18 ++++ tsup.modules.config.ts | 18 ++++ 18 files changed, 236 insertions(+), 93 deletions(-) create mode 100644 scripts/build.js create mode 100644 tsup.config.ts create mode 100644 tsup.jobs.config.ts create mode 100644 tsup.modules.config.ts diff --git a/bun.lockb b/bun.lockb index 50c00799f69bac8213516077a3d7b032ef7ae897..7d0a184bc69a2ccd1e07437f89d923a4df8de471 100644 GIT binary patch delta 52275 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 ZFPZz0ecK$rX^oeZ|M5{oubUuS_&>3uLD&EQ delta 38539 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[ +interface IMsg { + role: "user" | "assistant" | "system", + content: T extends "user" ? any : string, + reasoning_content?: string, + isHidden?: boolean +} +const msgList = ref([ { role: "system", content: PromptText @@ -26,7 +31,21 @@ enum STATUS { } const status = ref(STATUS.WAITING); -const { sendStream, getConfig, updateConfig } = useChat(); +const { sendStream, getConfig, updateConfig } = useChat(Chat.ModelProvider.OpenAI, { + // DeepSeek + // model: "deepseek-chat", + // apiKey: process.env.AI_APIKEY, + // baseUrl: "https://api.deepseek.com", + // temperature: 0.8, + + // siliconflow + model: "Qwen/Qwen3-8B", // 免费文本模型,可tools + // model: "deepseek-ai/deepseek-vl2", + apiKey: process.env.AI_APIKEY, + baseUrl: "https://api.siliconflow.cn/v1", + temperature: 0.8, +}); + const openaiConfig = reactive({ model: getConfig().model, apiKey: getConfig().apiKey, @@ -39,22 +58,15 @@ watch(openaiConfig, () => { }, { deep: true }) const inputEl = useTemplateRef("inputEl") -onMounted(() => { - inputMsg.value = "列举你能的事情,标记顺序,简洁回答,并提供友好的问候。" - handleSubmit() - inputEl.value?.focus() -}) -function handleSubmit() { - if(status.value === STATUS.SENDING) return +async function sendMsg(msg: any, isHidden?: boolean) { + const newMsg = `检查回答是否符合要求!!! + --- + ${msg}` msgList.value.push({ role: "user", - content: inputMsg.value, - }); - inputMsg.value = ""; - nextTick(() => { - scrollToBottom(); + content: newMsg, + isHidden: isHidden, }); - status.value = STATUS.SENDING; let contents = JSON.parse(JSON.stringify(unref(msgList))).map((v: any) => { return { @@ -67,23 +79,35 @@ function handleSubmit() { content: "", reasoning_content: "", }); - sendStream(contents as any, (msg: any) => { - msgList.value[msgList.value.length - 1].reasoning_content = msg.reasoning_content; - msgList.value[msgList.value.length - 1].content = msg.content; - if (msg.isComplete) { - status.value = STATUS.WAITING; + try { + await sendStream(contents as any, (msg: any) => { + msgList.value[msgList.value.length - 1].reasoning_content = msg.reasoning_content; + msgList.value[msgList.value.length - 1].content = msg.content; + if (msg.isComplete) { + status.value = STATUS.WAITING; + } + }); + } catch (error: any) { + try { + const text = await error.response.text() + msgList.value[msgList.value.length - 1].content = text; + } catch (err) { + msgList.value[msgList.value.length - 1].content = error.message; } + status.value = STATUS.WAITING; + } +} +onMounted(() => { + sendMsg("列举你能的事情,标记顺序,简洁回答。", true) + inputEl.value?.focus() +}) +function handleSubmit() { + if (status.value === STATUS.SENDING) return + sendMsg(inputMsg.value) + inputMsg.value = ""; + nextTick(() => { + scrollToBottom(); }); - - // let cursor = 0 - // const interval = setInterval(() => { - // msgList.value[msgList.value.length - 1].msg += sseDataModule[cursor].answer; - // cursor++; - // if (cursor >= sseDataModule.length) { - // clearInterval(interval); - // status.value = STATUS.WAITING; - // } - // }, 300); } function handleDelete(item: { role: string, content: string, reasoning_content?: string }, index: number) { @@ -110,17 +134,20 @@ function handleDelete(item: { role: string, content: string, reasoning_content?:
diff --git a/packages/client/src/components/ChatBox/prompt.txt b/packages/client/src/components/ChatBox/prompt.txt index e5fea4d..70e9ed1 100644 --- a/packages/client/src/components/ChatBox/prompt.txt +++ b/packages/client/src/components/ChatBox/prompt.txt @@ -1,6 +1,8 @@ +每次回答前必须遵循以下规则!!! + 知识库截断: 2024-06 -你是AI代理人, 由DeepSeek提供技术支持. 你为你的主人服务,为USER提供信息与服务。 +重要信息:你是AI代理人, 由Qwen/Qwen3-8B大模型提供技术支持. 你为你的主人服务,为USER提供信息与服务。 你可以帮主人代为处理一些任务。每次USER发送一条信息,你应该主动带入你的身份。 diff --git a/packages/client/src/composables/useChat/index.ts b/packages/client/src/composables/useChat/index.ts index 86f552f..545ca76 100644 --- a/packages/client/src/composables/useChat/index.ts +++ b/packages/client/src/composables/useChat/index.ts @@ -1,7 +1,7 @@ import { Chat } from "./Chat"; import { OpenAIModelConfig } from "./provider/Openai"; -export function useChat() { +export function useChat(provider: any, config: any) { if (import.meta.env.SSR) { return { sendStream: () => {}, @@ -18,14 +18,9 @@ export function useChat() { } const chat = new Chat(); let curProvider: ReturnType; - curProvider = chat.setProvider(Chat.ModelProvider.OpenAI, { - model: "deepseek-chat", - apiKey: __DEEPSEAK_APIKEY__, - baseUrl: "https://api.deepseek.com", - temperature: 0.8, - }); + curProvider = chat.setProvider(provider, config) function getConfig() { - return curProvider.getConfig(); + return curProvider!.getConfig(); } function updateConfig(config: OpenAIModelConfig) { chat.updateConfig({ diff --git a/packages/client/src/vue.d.ts b/packages/client/src/vue.d.ts index 6f344e0..d45375c 100644 --- a/packages/client/src/vue.d.ts +++ b/packages/client/src/vue.d.ts @@ -19,5 +19,9 @@ declare module '@vue/runtime-core' { } } declare global { - const __DEEPSEAK_APIKEY__: string + const process: { + env: { + AI_APIKEY: string + } + } } diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts index ee243fa..42692d4 100644 --- a/packages/client/vite.config.ts +++ b/packages/client/vite.config.ts @@ -25,7 +25,7 @@ export default defineConfig({ }, }, define: { - __DEEPSEAK_APIKEY__: `"${process.env.DEEPSEAK_APIKEY}"`, + "process.env.AI_APIKEY": `"${process.env.AI_APIKEY}"`, }, build: { emptyOutDir: true, diff --git a/packages/core/src/SsrMiddleWare.ts b/packages/core/src/SsrMiddleWare.ts index 4be0786..8582769 100644 --- a/packages/core/src/SsrMiddleWare.ts +++ b/packages/core/src/SsrMiddleWare.ts @@ -1,5 +1,5 @@ import fs from 'node:fs/promises' -import { getPathByRoot } from "helper/path" +import { isProduction, TemplateHtml, getPathByRoot, clientRoot, ssrManifest, entryServer } from "helper/path" import { parseCookieHeader } from "helper/cookie" import { Env } from "helper/env" import { ViteDevServer } from 'vite' @@ -8,13 +8,8 @@ import type Koa from 'koa' import c2k from 'koa-connect' import { transformHtmlTemplate } from "unhead/server"; -const isProduction = Env.isProduction const base = Env.base -const templateHtml = isProduction - ? await fs.readFile(getPathByRoot('dist', 'client/index.html'), 'utf-8') - : '' - export async function SsrMiddleWare(app: Koa, options?: { onDevViteClose?: Function }) { let vite: ViteDevServer if (!isProduction) { @@ -36,7 +31,7 @@ export async function SsrMiddleWare(app: Koa, options?: { onDevViteClose?: Funct // Production mode: serve pre-built static assets. app.use(async (ctx, next) => { try { - await Send(ctx, ctx.path, { root: getPathByRoot('dist/client'), index: false }); + await Send(ctx, ctx.path, { root: clientRoot, index: false }); if (ctx.status === 404) { await next() } @@ -66,10 +61,10 @@ export async function SsrMiddleWare(app: Koa, options?: { onDevViteClose?: Funct manifest = {} render = (await vite.ssrLoadModule(getPathByRoot('packages', 'client/src/entry-server.ts'))).render } else { - manifest = await fs.readFile(getPathByRoot('dist', 'client/.vite/ssr-manifest.json'), 'utf-8') - template = templateHtml + manifest = await fs.readFile(ssrManifest, 'utf-8') + template = TemplateHtml // @ts-ignore - render = (await import(getPathByRoot('dist', 'server/entry-server.js'))).render + render = (await import(entryServer)).render } const cookies = parseCookieHeader(ctx.request.headers['cookie'] as string) diff --git a/packages/server/package.json b/packages/server/package.json index 6da9a5e..e996d54 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -13,12 +13,12 @@ "@types/koa": "^3.0.0", "@types/koa-bodyparser": "^4.3.12", "@types/koa-send": "^4.1.6", - "@types/path-is-absolute": "^1.0.2", - "jsonwebtoken": "^9.0.2" + "@types/path-is-absolute": "^1.0.2" }, "dependencies": { "@types/jsonwebtoken": "^9.0.10", "formidable": "^3.5.4", + "jsonwebtoken": "^9.0.2", "koa": "^3.0.1", "koa-bodyparser": "^4.4.1", "koa-connect": "^2.1.0", diff --git a/packages/server/src/jobs/index.ts b/packages/server/src/jobs/index.ts index 19c1c19..c4d3a2d 100644 --- a/packages/server/src/jobs/index.ts +++ b/packages/server/src/jobs/index.ts @@ -2,6 +2,8 @@ import fs from 'fs'; import path from 'path'; import scheduler from './scheduler'; import { TaskOptions } from 'node-cron'; +import { isProduction, jobsDir } from 'helper/path'; +import { logger } from '@/logger'; interface OneJob { id: string @@ -16,12 +18,12 @@ export function defineJob(job: OneJob) { return job; } -const jobsDir = path.join(__dirname, 'jobs'); +const _jobsDir = isProduction ? jobsDir : path.join(__dirname, 'jobs'); const jobModules: Record = {}; -fs.readdirSync(jobsDir).forEach(file => { - if (!file.endsWith('Job.ts')) return; - const jobModule = require(path.join(jobsDir, file)); +fs.readdirSync(_jobsDir).forEach(async file => { + if (!file.endsWith(isProduction ? 'Job.js' : 'Job.ts')) return; + const jobModule = await import(path.join(_jobsDir, file)); const job = jobModule.default || jobModule; if (job && job.id && job.cronTime && typeof job.task === 'function') { jobModules[job.id] = job; @@ -30,13 +32,15 @@ fs.readdirSync(jobsDir).forEach(file => { } }); +logger.info(`[Jobs] 加载了 ${Object.keys(jobModules).length} 个任务`); + function callHook(id: string, hookName: string) { const job = jobModules[id]; if (job && typeof job[hookName] === 'function') { try { job[hookName](); } catch (e) { - console.error(`[Job:${id}] ${hookName} 执行异常:`, e); + logger.error(`[Job:${id}] ${hookName} 执行异常:`, e); } } } diff --git a/packages/server/src/logger.ts b/packages/server/src/logger.ts index 6d7daea..d60b889 100644 --- a/packages/server/src/logger.ts +++ b/packages/server/src/logger.ts @@ -1,14 +1,12 @@ import log4js from "log4js"; -import { Env } from 'helper/env'; - -const { LOG_DIR } = Env; +import { logDir } from 'helper/path'; log4js.configure({ appenders: { all: { type: "file", - filename: `${LOG_DIR}/all.log`, + filename: `${logDir}/all.log`, maxLogSize: 102400, pattern: "-yyyy-MM-dd.log", alwaysIncludePattern: true, @@ -20,7 +18,7 @@ log4js.configure({ }, error: { type: "file", - filename: `${LOG_DIR}/error.log`, + filename: `${logDir}/error.log`, maxLogSize: 102400, pattern: "-yyyy-MM-dd.log", alwaysIncludePattern: true, @@ -32,7 +30,7 @@ log4js.configure({ }, jobs: { type: "file", - filename: `${LOG_DIR}/jobs.log`, + filename: `${logDir}/jobs.log`, maxLogSize: 102400, pattern: "-yyyy-MM-dd.log", alwaysIncludePattern: true, diff --git a/packages/server/src/middleware/install.ts b/packages/server/src/middleware/install.ts index 20d21a2..3c519b5 100644 --- a/packages/server/src/middleware/install.ts +++ b/packages/server/src/middleware/install.ts @@ -12,7 +12,7 @@ import { DefaultContext, Next, ParameterizedContext } from "koa" import { AuthMiddleware } from "./Auth" import Session from "./Session" import Send from "./Send" -import { getPathByRoot } from "helper/path" +import { getPathByRoot, isProduction, serverModules, serverPublic } from "helper/path" type App = typeof app @@ -31,7 +31,7 @@ export default async (app: App) => { }) - const publicPath = getPathByRoot("public") + const publicPath = isProduction ? serverPublic : getPathByRoot("public") app.use(async (ctx, next) => { if (!ctx.path.startsWith("/public")) return await next() if (ctx.method.toLowerCase() === "get") { @@ -65,7 +65,7 @@ export default async (app: App) => { app.use(bodyParser()) app.use( await Controller({ - root: path.resolve(__dirname, "../modules"), + root: isProduction ? serverModules : path.resolve(__dirname, "../modules"), handleBeforeEachRequest: (options: any) => { const { auth = true } = options || {} return async (ctx: ParameterizedContext, next: Next) => { diff --git a/scripts/build.js b/scripts/build.js new file mode 100644 index 0000000..7ddeeb8 --- /dev/null +++ b/scripts/build.js @@ -0,0 +1,65 @@ +#!/usr/bin/env node +import { readFileSync, writeFileSync } from 'fs'; +import { join, dirname } from 'path'; +import { fileURLToPath } from 'url'; + +// 获取当前文件目录 +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +const projectRoot = join(__dirname, '..'); + +console.log('🚀 开始构建项目...'); + +try { + // 1. 读取package.json文件 + console.log('📋 读取package.json文件...'); + const rootPackageJson = JSON.parse(readFileSync(join(projectRoot, 'package.json'), 'utf8')); + const serverPackageJson = JSON.parse(readFileSync(join(projectRoot, 'packages/server/package.json'), 'utf8')); + + // 2. 合并依赖 + console.log('🔗 合并依赖...'); + const mergedDependencies = { + ...rootPackageJson.dependencies, + ...serverPackageJson.dependencies + }; + + // 3. 创建生产环境的package.json + const productionPackageJson = { + name: rootPackageJson.name, + type: 'module', + version: rootPackageJson.version || '1.0.0', + description: 'Koa SSR 生产环境应用', + main: 'booststap.js', + scripts: { + start: 'bun run booststap.js' + }, + dependencies: mergedDependencies, + engines: { + bun: '>=1.0.0' + }, + keywords: ['koa', 'ssr', 'vue', 'bun'], + author: '', + license: 'MIT' + }; + + // 4. 写入新的package.json到dist目录 + console.log('💾 生成生产环境package.json...'); + const distPackageJsonPath = join(projectRoot, 'dist', 'package.json'); + writeFileSync(distPackageJsonPath, JSON.stringify(productionPackageJson, null, 2)); + console.log('✅ package.json 已生成到 dist/package.json'); + + // 5. 显示合并后的依赖信息 + console.log('\n📊 依赖合并结果:'); + console.log(`- 根目录依赖: ${Object.keys(rootPackageJson.dependencies || {}).length} 个`); + console.log(`- Server依赖: ${Object.keys(serverPackageJson.dependencies || {}).length} 个`); + console.log(`- 合并后总依赖: ${Object.keys(mergedDependencies).length} 个`); + + console.log('\n🎉 构建脚本执行完成!'); + console.log('📁 生产环境文件已生成到 dist/ 目录'); + console.log('💡 可以使用以下命令启动生产环境:'); + console.log(' cd dist && bun install && bun run start'); + +} catch (error) { + console.error('❌ 构建过程中发生错误:', error.message); + process.exit(1); +} diff --git a/tsup.config.ts b/tsup.config.ts new file mode 100644 index 0000000..9e57ea1 --- /dev/null +++ b/tsup.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from "tsup"; +import pkg from "./package.json"; +import spkg from "./packages/server/package.json"; +import fg from "fast-glob" + +const jobsEntries = await fg(["packages/server/src/jobs/**/*.ts"], { }); +const modulesEntries = await fg(["packages/server/src/modules/**/*.ts"], { }); + + +export default defineConfig({ + entry: ["packages/server/src/booststap.ts", ...jobsEntries, ...modulesEntries], + format: "esm", + sourcemap: false, + clean: false, + cjsInterop: true, + external: [ + ...Object.keys(pkg.dependencies), + ...Object.keys(spkg.dependencies), + ] +}); diff --git a/tsup.jobs.config.ts b/tsup.jobs.config.ts new file mode 100644 index 0000000..8a1a0e0 --- /dev/null +++ b/tsup.jobs.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'tsup' +import pkg from "./package.json"; +import spkg from "./packages/server/package.json"; +import fg from "fast-glob" + +const entries = await fg(["packages/server/src/jobs/**/*.ts"], { }); + +export default defineConfig({ + entry: entries, + format: 'esm', + sourcemap: false, + clean: false, + outDir: "dist/jobs", + external: [ + ...Object.keys(pkg.dependencies), + ...Object.keys(spkg.dependencies), + ] +}) \ No newline at end of file diff --git a/tsup.modules.config.ts b/tsup.modules.config.ts new file mode 100644 index 0000000..76c6978 --- /dev/null +++ b/tsup.modules.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'tsup' +import pkg from "./package.json"; +import spkg from "./packages/server/package.json"; +import fg from "fast-glob" + +const entries = await fg(["packages/server/src/modules/**/*.ts"], { }); + +export default defineConfig({ + entry: entries, + format: 'esm', + sourcemap: false, + clean: false, + outDir: "dist/modules", + external: [ + ...Object.keys(pkg.dependencies), + ...Object.keys(spkg.dependencies), + ] +}) \ No newline at end of file