Files
Brain/brain-h5/vite.config.ts
MingNian b0fce840a3 首次提交:脑晴测 H5 项目
包含前端源码、预构建产物(dist/)、零依赖 Node.js 服务器(server.mjs)、
Cloudflare Worker 版本(worker/)、部署文档(DEPLOY.md)和交接文档。

技术总监可直接 clone 后运行 node server.mjs 启动,无需安装 React 或 build。
DEEPSEEK_API_KEY 通过环境变量注入,未纳入仓库。
2026-07-28 10:24:47 +08:00

79 lines
3.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { defineConfig, loadEnv, type Plugin } from "vite";
import react from "@vitejs/plugin-react";
const SYSTEM_PROMPT = `你是一名数字脑健康表现报告助手。根据用户完成游戏时产生的结构化数据,生成通俗、克制、非医疗化的中文报告。
必须遵守:
1. 不诊断疾病,不使用确诊、患病、痴呆、障碍等医疗结论;
2. 只描述本次任务表现,明确设备、环境、熟悉程度可能影响结果;禁止使用“提示存在问题或挑战”“异常”“受损”等暗示医学结论的说法;
3. 建议必须低风险、可执行,不推荐药物或医疗处置;
4. 优先使用“本次反应相对偏慢”“注意表现有波动”“容易遗漏部分信息”“仍有提升空间”等表达;
5. 仅输出合法 JSON不要 Markdown。
JSON 结构:{"summary":"80字内总结","strength":"60字内相对优势","opportunity":"60字内提升空间","recommendations":["建议1","建议2","建议3"]}`;
function localDeepSeekApi(apiKey: string): Plugin {
return {
name: "braincheck-deepseek-local-api",
configureServer(server) {
server.middlewares.use("/api/analyze", async (request, response) => {
if (request.method !== "POST") {
response.statusCode = 405;
response.end("Method not allowed");
return;
}
if (!apiKey) {
response.statusCode = 503;
response.setHeader("content-type", "application/json");
response.end(JSON.stringify({ error: "DEEPSEEK_API_KEY is not configured" }));
return;
}
try {
let raw = "";
for await (const chunk of request) raw += chunk;
const assessment = JSON.parse(raw || "{}");
const upstream = await fetch("https://api.deepseek.com/chat/completions", {
method: "POST",
headers: { "content-type": "application/json", authorization: `Bearer ${apiKey}` },
body: JSON.stringify({
model: "deepseek-chat",
temperature: 0.35,
response_format: { type: "json_object" },
messages: [
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: JSON.stringify({ profile: assessment.profile, metrics: assessment.metrics, eventCount: assessment.events?.length ?? 0 }) },
],
}),
signal: AbortSignal.timeout(15000),
});
if (!upstream.ok) throw new Error(`DeepSeek returned ${upstream.status}`);
const payload = await upstream.json();
const content = payload?.choices?.[0]?.message?.content;
if (!content) throw new Error("DeepSeek returned an empty response");
const rawReport = JSON.parse(content.replace(/^```json\s*|\s*```$/g, ""));
const parsed = {
summary: String(rawReport.summary || "本次四项任务已经完成。"),
strength: String(rawReport.strength || "部分任务表现相对稳定。"),
opportunity: String(rawReport.opportunity || "仍有可以通过规律练习提升的空间。"),
recommendations: Array.isArray(rawReport.recommendations) ? rawReport.recommendations.slice(0, 3).map(String) : [],
};
response.statusCode = 200;
response.setHeader("content-type", "application/json; charset=utf-8");
response.end(JSON.stringify(parsed));
} catch (error) {
response.statusCode = 502;
response.setHeader("content-type", "application/json");
response.end(JSON.stringify({ error: error instanceof Error ? error.message : "AI request failed" }));
}
});
},
};
}
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
return {
build: { outDir: "dist/client" },
server: { host: "0.0.0.0", allowedHosts: ["terminal.local"] },
plugins: [react(), localDeepSeekApi(env.DEEPSEEK_API_KEY)],
};
});