| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import { defineConfig } from "vite";
- // import { darkTheme } from "./src/theme.js";
- import vue from "@vitejs/plugin-vue";
- import Components from "unplugin-vue-components/vite";
- import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
- import svgLoader from "vite-svg-loader";
- import path from "path";
- import basicSsl from "@vitejs/plugin-basic-ssl";
- // DMS token 的读取口径收在 harness/tools/dms-token.mjs(与本仓库的 DMS 脚本共用一份):
- // **显式参数 → 环境变量 → 本机文件 `.dms-token`**。
- // 关键是「每个请求现读」而不是启动时读一次 —— token 约 24 小时过期,以前换一次就要重启 dev server。
- import { DMS_TOKEN_FILE, readDmsToken, parseJwtPayload, describeDmsToken } from "./harness/tools/dms-token.mjs";
- // [已移除] dev 期自己签 NLS token 的中间件(`/nls-token/`)。
- // 2026-09-24 起 token 改由**后端网关**提供:`GET http://121.43.55.7:10011/proxy/verify/getALYToken`
- // → `{code:200, content:"<token>"}`,前端走同源 `/api/` 代理拿(2026-09-29 前叫 `/aly-api/`)。
- // 于是前端侧**不再需要 AccessKeySecret**,vite 也不必持凭据。
- // AK/SK 自签的能力仍留在 harness/tools/nls-token.mjs(工具侧退路,仅在没有网关时用)。
- /** 同一个状态只提醒一次,避免每个请求都刷屏 */
- let dmsTokenWarnedFor = "";
- /**
- * token 有问题时给出**明确**提示 —— 以前 token 过期是**静默失败**(DMS 写入不生效、
- * 只有一条埋在别处控制台里的 warn),排查「为什么数据没存上」要花很久。
- */
- const warnDmsTokenIfNeeded = (token: string): void => {
- if (!token) {
- if (dmsTokenWarnedFor === "missing") return;
- dmsTokenWarnedFor = "missing";
- console.warn(
- `\n[dms] ⚠️ 没有 DMS token,DMS 读写(会话/问答记录/反馈)会失败,聊天本身不受影响。\n` +
- `[dms] 最省事:在浏览器里复制 token,然后跑 \`npm run dms:token\`(从剪贴板读)。\n` +
- `[dms] 文件位置:${DMS_TOKEN_FILE}\n`
- );
- return;
- }
- const exp = Number(parseJwtPayload(token)?.exp);
- if (!Number.isFinite(exp)) return;
- const leftMs = exp * 1000 - Date.now();
- const at = new Date(exp * 1000).toLocaleString("zh-CN");
- if (leftMs <= 0) {
- if (dmsTokenWarnedFor === `expired:${exp}`) return;
- dmsTokenWarnedFor = `expired:${exp}`;
- console.warn(
- `\n[dms] ⚠️ DMS token 已于 ${at} 过期(DMS 读写会失败)。复制新 token 后跑 \`npm run dms:token\`。\n`
- );
- return;
- }
- if (leftMs < 2 * 3600 * 1000) {
- const key = `soon:${exp}`;
- if (dmsTokenWarnedFor === key) return;
- dmsTokenWarnedFor = key;
- console.warn(`\n[dms] ⏳ DMS token 将于 ${at} 过期(还剩 ${(leftMs / 3600000).toFixed(1)} 小时)。\n`);
- }
- };
- // https://vitejs.dev/config/
- export default defineConfig(() => {
- return {
- plugins: [
- vue(),
- Components({
- resolvers: [AntDesignVueResolver()],
- }),
- svgLoader(),
- basicSsl(),
- ],
- server: {
- proxy: {
- // ── 代理总原则(2026-09-29 用户指定)────────────────────────────────
- // 前缀**尽量与服务真实路径一致**,只有服务端本身不带前缀时才剥:
- // /oauth/** → 121.43.55.7:10086,**直通**(真实路径就带 /oauth)
- // /dms/** → 121.43.55.7:10081,**直通**(真实路径就带 /dms)
- // /api/** → 121.43.55.7:10011,**剥掉 /api**(网关真实路径是 /proxy/verify/…,
- // 实测直连 /api/proxy/… 是 404)
- // /chat-api/** → 聊天后端,剥前缀(后端真实路径是 /api/chat,与前端前缀不同名)
- // 三台后端都只有 HTTP,而 dev server 是 HTTPS ⇒ 直连会被浏览器按混合内容拦掉,
- // 必须由服务端这一跳(dev 是 vite 代理,生产是 nginx)代劳。
- // 2026-09-29 之前是 /dms-api(补 /dms) + /ip-api + /aly-api(两条打同一台) —— 现在合并。
- //
- // ⚠️ **target 直接写在这里,不从环境变量读**(用户 2026-09-29 明确要求
- // 「vite.config.ts 里面不要加环境变量」)—— 所以本文件不再 `loadEnv`。
- // 换地址就改这四处;`.env.*` 只管**产物里**用到的值(VITE_DMS_API 等同源前缀)。
- // 后端网关 121.43.55.7:10011:语音识别 token(/proxy/verify/getALYToken)
- // 与取本机 IP(/proxy/verify/getIPByBrowser)**在同一台**,所以共用这一条。
- "/api/": {
- target: "http://121.43.55.7:10011",
- changeOrigin: true,
- rewrite: (path) => path.replace(/^\/api/, ""),
- },
- // DMS 登录服务 121.43.55.7:10086(真实路径带 /oauth,所以直通、不改写)。
- // 前端目前不直接调它(token 是 node 侧换的);留着是为了本地能自测登录接口。
- "/oauth/": {
- target: "http://121.43.55.7:10086",
- changeOrigin: true,
- },
- // DMS 数据管理服务(会话/问答记录/反馈)——真实路由都在 /dms/ 下,前缀同名,直通。
- // token(DMS 的鉴权头名就叫 token,不是 Authorization):
- // ① **前端自己带**:未登录访客用服务账号现换一个(`src/network/api/dms/service-token.ts`,
- // 2026-09-29 用户要求改成这套)—— 这种请求**代理不覆盖**它的 token;
- // ② 请求没带时才由代理兜底注入:读仓库根 `.dms-token`(gitignored)或进程环境变量
- // DMS_TOKEN(`readDmsToken()` 自己会读,见 harness/tools/dms-token.mjs)
- // —— 命令行走代理排查(curl / verify-dms-*.mjs)靠的就是这条。
- // 现读而非静态 headers:换 token 不用重启 dev server。
- "/dms/": {
- target: "http://121.43.55.7:10081",
- changeOrigin: true,
- configure: (proxy) => {
- proxy.on("proxyReq", (proxyReq) => {
- // 前端已经带了 token 就别覆盖(否则前端的刷新逻辑白做)
- const fromClient =
- typeof proxyReq.getHeader === "function" ? proxyReq.getHeader("token") : undefined;
- if (fromClient) return;
- const token = readDmsToken();
- if (token) {
- proxyReq.setHeader("token", token);
- }
- warnDmsTokenIfNeeded(token);
- });
- },
- },
- // 新版聊天后端(POST /api/chat,SSE):后端真实路径是 /api/chat,与前端前缀不同名 ⇒ 剥前缀。
- // 对应 .env.development 中 VITE_CHAT_API="/chat-api"。
- "/chat-api/": {
- target: "http://192.168.2.23:8000",
- changeOrigin: true,
- rewrite: (path) => path.replace(/^\/chat-api/, ""),
- },
- // [已移除] "/stream/" 代理(数字人视频流):src/index.html 里没有任何代码往它发请求,
- // 相关 env(VITE_STREAM_SERVER / VITE_STREAM_TOKEN / VITE_HUMAN_IDLE_MP4_URL)也已删除。
- // [已移除] "/asr/" 代理(https://human-screen-v3.metamaker.cn):旧厂商 ASR 的退路,
- // 2026-09-24 按用户要求把旧实现连同 env(VITE_ASR / VITE_XF_ASR)一起删除;
- // 现在的语音识别走阿里云 NLS(见 harness/docs/reference/asr-nls.md)。
- },
- },
- build: {
- rollupOptions: {
- input: {
- main: path.resolve(__dirname, "index.html"),
- redirect: path.resolve(__dirname, "redirect.html"),
- },
- output: {
- manualChunks: (id) => {
- console.log(id);
- if (id.includes("node_modules/three")) {
- return "three";
- } else if (id.includes("node_modules")) {
- return "vendor";
- }
- },
- },
- },
- assetsInlineLimit: 20480,
- },
- resolve: {
- alias: {
- "@": path.resolve("./src/"),
- three$: path.resolve(__dirname, "./node_modules/three/build/three.cjs"),
- },
- },
- base: "./",
- css: {
- preprocessorOptions: {
- scss: {
- api: "modern-compiler",
- },
- },
- },
- };
- });
|