首次提交:脑晴测 H5 项目

包含前端源码、预构建产物(dist/)、零依赖 Node.js 服务器(server.mjs)、
Cloudflare Worker 版本(worker/)、部署文档(DEPLOY.md)和交接文档。

技术总监可直接 clone 后运行 node server.mjs 启动,无需安装 React 或 build。
DEEPSEEK_API_KEY 通过环境变量注入,未纳入仓库。
This commit is contained in:
MingNian
2026-07-28 10:24:47 +08:00
commit b0fce840a3
152 changed files with 8536 additions and 0 deletions

52
brain-h5/worker/index.js Normal file
View File

@@ -0,0 +1,52 @@
const SYSTEM_PROMPT = `你是一名数字脑健康表现报告助手。根据用户完成游戏时产生的结构化数据,生成通俗、克制、非医疗化的中文报告。不得诊断疾病,不得推荐药物或医疗处置,不得使用“异常、受损、提示存在问题或挑战”等暗示医学结论的说法。只描述本次表现,优先使用“反应相对偏慢、注意表现有波动、容易遗漏、仍有提升空间”。只输出合法 JSON{"summary":"80字内总结","strength":"60字内相对优势","opportunity":"60字内提升空间","recommendations":["建议1","建议2","建议3"]}`;
async function analyze(request, env) {
if (!env.DEEPSEEK_API_KEY) return Response.json({ error: "AI service is not configured" }, { status: 503 });
try {
const assessment = await request.json();
const upstream = await fetch("https://api.deepseek.com/chat/completions", {
method: "POST",
headers: { "content-type": "application/json", authorization: `Bearer ${env.DEEPSEEK_API_KEY}` },
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) return Response.json({ error: "AI service request failed" }, { status: 502 });
const payload = await upstream.json();
const content = payload?.choices?.[0]?.message?.content;
const rawReport = JSON.parse(String(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) : [],
};
return Response.json(parsed, { headers: { "cache-control": "no-store" } });
} catch {
return Response.json({ error: "AI report could not be generated" }, { status: 502 });
}
}
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (url.pathname === "/api/analyze") {
if (request.method !== "POST") return new Response("Method not allowed", { status: 405 });
return analyze(request, env);
}
const response = await env.ASSETS.fetch(request);
const acceptsHtml = request.headers.get("accept")?.includes("text/html");
if (response.status !== 404 || !acceptsHtml || !["GET", "HEAD"].includes(request.method)) return response;
const indexUrl = new URL(request.url);
indexUrl.pathname = "/index.html";
indexUrl.search = "";
return env.ASSETS.fetch(new Request(indexUrl, request));
},
};