Trae Assistant
init
4797b80
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>冷链闭环智能体 · ColdChain Optimizer</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<style>
:root {
--bg: #f4f7fb;
--card: #ffffff;
--primary: #0f3d5e;
--accent: #14b8a6;
--text: #1f2937;
--muted: #6b7280;
--shadow: 0 12px 30px rgba(15, 61, 94, 0.12);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif;
background: var(--bg);
color: var(--text);
}
.app-shell {
max-width: 1200px;
margin: 0 auto;
padding: 24px 20px 48px;
}
header {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 16px;
margin-bottom: 20px;
}
.brand {
display: flex;
align-items: center;
gap: 16px;
}
.brand-mark {
width: 52px;
height: 52px;
border-radius: 16px;
background: linear-gradient(135deg, #0f3d5e, #14b8a6);
color: #fff;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
letter-spacing: 2px;
}
.brand-title {
font-size: 22px;
font-weight: 700;
}
.brand-subtitle {
color: var(--muted);
margin-top: 4px;
}
.chips {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.chip {
background: rgba(20, 184, 166, 0.12);
color: #0f766e;
padding: 6px 12px;
border-radius: 999px;
font-size: 12px;
font-weight: 600;
}
.overview {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.overview-card {
background: var(--card);
border-radius: 16px;
padding: 18px;
box-shadow: var(--shadow);
}
.overview-title {
font-size: 13px;
color: var(--muted);
}
.overview-value {
font-size: 26px;
font-weight: 700;
margin-top: 8px;
}
.layout {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
gap: 20px;
}
.panel {
background: var(--card);
border-radius: 18px;
padding: 20px;
box-shadow: var(--shadow);
}
.panel-title {
font-size: 16px;
font-weight: 700;
margin-bottom: 12px;
}
.panel-subtitle {
color: var(--muted);
margin-bottom: 16px;
font-size: 13px;
}
.form-grid {
display: grid;
gap: 12px;
}
label {
font-size: 13px;
color: var(--muted);
}
input,
textarea {
width: 100%;
border-radius: 12px;
border: 1px solid #e5e7eb;
padding: 10px 12px;
font-size: 14px;
background: #f9fafb;
}
textarea {
min-height: 110px;
resize: vertical;
}
.btn-row {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
button {
border: none;
border-radius: 12px;
padding: 10px 16px;
font-weight: 600;
cursor: pointer;
}
.btn-primary {
background: var(--primary);
color: #fff;
}
.btn-ghost {
background: rgba(15, 61, 94, 0.08);
color: var(--primary);
}
.status-card {
background: #0f3d5e;
color: #fff;
border-radius: 16px;
padding: 16px;
margin-top: 16px;
}
.timeline {
display: grid;
gap: 16px;
}
.timeline-item {
border: 1px solid #e5e7eb;
border-radius: 14px;
padding: 16px;
background: #fbfdff;
}
.timeline-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.badge {
background: rgba(15, 61, 94, 0.1);
color: var(--primary);
padding: 4px 10px;
border-radius: 999px;
font-size: 12px;
}
.badge-soft {
background: rgba(20, 184, 166, 0.1);
color: #0f766e;
}
.timeline-type {
font-size: 13px;
}
.markdown {
line-height: 1.7;
font-size: 14px;
}
.history-list,
.asset-list {
display: grid;
gap: 10px;
margin-top: 12px;
}
.history-item,
.asset-item {
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 12px;
background: #fff;
cursor: pointer;
}
.muted {
color: var(--muted);
font-size: 12px;
}
.footer-tip,
.upload-tip {
margin-top: 18px;
color: var(--muted);
font-size: 12px;
}
@media (max-width: 960px) {
.layout {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<div class="app-shell">
<header>
<div class="brand">
<div class="brand-mark">CC</div>
<div>
<div class="brand-title">冷链闭环智能体 · ColdChain Optimizer</div>
<div class="brand-subtitle">
推理 / 工具行动 / 状态记忆 / 校验验收 / 迭代复盘
</div>
</div>
</div>
<div class="chips">
<div class="chip">医药冷链</div>
<div class="chip">多智能体协作</div>
<div class="chip">资产沉淀</div>
<div class="chip">移动端适配</div>
</div>
</header>
<section class="overview" id="overview">
<div class="overview-card">
<div class="overview-title">累计会话</div>
<div class="overview-value" id="session-count">0</div>
</div>
<div class="overview-card">
<div class="overview-title">闭环步骤</div>
<div class="overview-value" id="step-count">0</div>
</div>
<div class="overview-card">
<div class="overview-title">沉淀资产</div>
<div class="overview-value" id="asset-count">0</div>
</div>
</section>
<main class="layout">
<section class="panel">
<div class="panel-title">冷链场景输入</div>
<div class="panel-subtitle">
输入真实业务场景,系统将自动生成完整闭环,并支持历史回放
</div>
<form id="run-form" class="form-grid">
<div>
<label>会话名称</label>
<input id="name" placeholder="如:华东医药冷链升级计划" />
</div>
<div>
<label>场景描述</label>
<textarea id="scenario" placeholder="描述冷链网络、温控要求、运输路径、服务对象等"></textarea>
</div>
<div>
<label>目标指标</label>
<input id="target" placeholder="如:准时交付率≥98%,温控合规率≥99.5%" />
</div>
<div>
<label>约束条件</label>
<textarea id="constraints" placeholder="如:夜间限行、预算、车辆通行证等"></textarea>
</div>
<div class="btn-row">
<button class="btn-primary" type="submit" id="run-btn">生成闭环</button>
<button class="btn-ghost" type="button" id="demo-btn">填充示例</button>
</div>
</form>
<div class="status-card" id="status-card">等待生成冷链闭环方案</div>
<div class="panel-title" style="margin-top: 18px;">历史会话资产</div>
<div class="history-list" id="history-list"></div>
<div class="panel-title" style="margin-top: 18px;">数据上传(可选)</div>
<div class="history-list">
<div class="history-item">
<div class="muted upload-tip">
可上传冷链线路 CSV/JSON 或二进制温度记录文件,系统将只记录文件名与大小作为资产示例,避免大文件占用 Hugging Face 空间。
</div>
<input type="file" id="file-input" />
<div class="btn-row" style="margin-top: 8px;">
<button class="btn-ghost" type="button" id="upload-btn">上传文件并登记资产</button>
</div>
<div class="muted" id="upload-status">尚未上传任何文件</div>
</div>
</div>
</section>
<section class="panel">
<div class="panel-title">闭环轨迹与资产</div>
<div class="panel-subtitle">按时间顺序展示本轮推理与执行过程(已内置示例会话)</div>
<div class="timeline" id="timeline"></div>
<div class="panel-title" style="margin-top: 18px;">资产沉淀</div>
<div class="asset-list" id="asset-list"></div>
<div class="footer-tip">
提示:设置 .env 的 SILICONFLOW_API_KEY 可接入真实硅基流推理
</div>
</section>
</main>
</div>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
const sessionCountEl = document.getElementById("session-count");
const stepCountEl = document.getElementById("step-count");
const assetCountEl = document.getElementById("asset-count");
const historyListEl = document.getElementById("history-list");
const timelineEl = document.getElementById("timeline");
const assetListEl = document.getElementById("asset-list");
const statusCardEl = document.getElementById("status-card");
const runForm = document.getElementById("run-form");
const runBtn = document.getElementById("run-btn");
const demoBtn = document.getElementById("demo-btn");
const renderMarkdown = (content) => {
if (!content) return "";
return marked.parse(content);
};
const updateOverview = async () => {
const res = await fetch("/api/overview");
const data = await res.json();
sessionCountEl.textContent = data.session_count || 0;
stepCountEl.textContent = data.step_count || 0;
assetCountEl.textContent = data.asset_count || 0;
};
const loadHistory = async () => {
const res = await fetch("/api/sessions");
const data = await res.json();
historyListEl.innerHTML = "";
(data.sessions || []).forEach((item) => {
const div = document.createElement("div");
div.className = "history-item";
div.innerHTML = `
<div><strong>${item.name || "未命名会话"}</strong></div>
<div class="muted">${item.created_at || ""}</div>
<div class="muted">目标:${item.target || "未填写"}</div>
`;
div.addEventListener("click", () => loadSession(item.id));
historyListEl.appendChild(div);
});
};
const stepTypeLabel = (type) => {
const map = {
reasoning: "推理决策",
tool_action: "工具行动",
memory: "状态记忆",
validation: "校验验收",
iteration: "迭代复盘",
};
return map[type] || type || "步骤";
};
const stepRoleLabel = (role) => {
const map = {
Planner: "规划智能体",
RouteOps: "线路与运力智能体",
Memory: "资产沉淀智能体",
QualityAuditor: "质量合规智能体",
Optimizer: "迭代优化智能体",
};
return map[role] || role || "智能体";
};
const renderTimeline = (steps = []) => {
timelineEl.innerHTML = "";
if (!steps.length) {
timelineEl.innerHTML =
"<div class='muted'>暂无闭环步骤,可点击左侧示例按钮快速体验。</div>";
return;
}
steps.forEach((step) => {
const card = document.createElement("div");
card.className = "timeline-item";
card.innerHTML = `
<div class="timeline-header">
<div class="timeline-type">
<strong>${stepTypeLabel(step.step_type)}</strong>
· ${stepRoleLabel(step.role)}
</div>
<span class="badge badge-soft">步骤 ${step.step_order}</span>
</div>
<div class="markdown">${renderMarkdown(step.content)}</div>
`;
timelineEl.appendChild(card);
});
};
const renderAssets = (assets = []) => {
assetListEl.innerHTML = "";
if (!assets.length) {
assetListEl.innerHTML = "<div class='muted'>暂无资产沉淀</div>";
return;
}
assets.forEach((asset) => {
const card = document.createElement("div");
card.className = "asset-item";
const isMetrics = asset.asset_type === "metrics";
const content = isMetrics
? `<pre class="muted">${asset.content}</pre>`
: renderMarkdown(asset.content);
card.innerHTML = `
<div><strong>${asset.title}</strong></div>
<div class="muted">${asset.created_at || ""}</div>
<div class="markdown">${content}</div>
`;
assetListEl.appendChild(card);
});
};
const loadSession = async (sessionId) => {
const res = await fetch(`/api/session/${sessionId}`);
const data = await res.json();
if (data.error) {
statusCardEl.textContent = data.error;
return;
}
const title = data.session?.name || "冷链运营会话";
statusCardEl.textContent = `正在回放:${title}`;
renderTimeline(data.steps || []);
renderAssets(data.assets || []);
};
runForm.addEventListener("submit", async (event) => {
event.preventDefault();
runBtn.disabled = true;
statusCardEl.textContent = "正在生成闭环方案,请稍候...";
const payload = {
name: document.getElementById("name").value,
scenario: document.getElementById("scenario").value,
target: document.getElementById("target").value,
constraints: document.getElementById("constraints").value,
};
const res = await fetch("/api/run", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
const data = await res.json();
if (data.error) {
statusCardEl.textContent = data.error;
runBtn.disabled = false;
return;
}
statusCardEl.textContent = "闭环生成完成,可继续迭代";
renderTimeline(data.steps || []);
renderAssets(data.assets || []);
await updateOverview();
await loadHistory();
runBtn.disabled = false;
});
const fileInput = document.getElementById("file-input");
const uploadBtn = document.getElementById("upload-btn");
const uploadStatus = document.getElementById("upload-status");
uploadBtn.addEventListener("click", async () => {
if (!fileInput.files || !fileInput.files[0]) {
uploadStatus.textContent = "请先选择要上传的文件";
return;
}
const file = fileInput.files[0];
uploadStatus.textContent = "正在上传与登记资产...";
const formData = new FormData();
formData.append("file", file);
try {
const res = await fetch("/api/upload", {
method: "POST",
body: formData,
});
const data = await res.json();
if (data.error) {
uploadStatus.textContent = data.error;
return;
}
uploadStatus.textContent = `已登记资产:${data.filename}${data.size_kb} KB)`;
await updateOverview();
await loadHistory();
} catch (e) {
uploadStatus.textContent = "上传失败,请稍后重试";
}
});
demoBtn.addEventListener("click", () => {
document.getElementById("name").value = "华南疫苗冷链优化";
document.getElementById("scenario").value =
"覆盖 4 个省会城市与 16 家疾控中心,要求 2-8℃温控,疫苗需 12 小时内送达;" +
"高峰期需提升运力 30%,并确保可追溯与异常预警。";
document.getElementById("target").value =
"准时交付率≥98%,温控合规率≥99.7%,运输成本降低 10%";
document.getElementById("constraints").value =
"夜间限行、高速收费上涨、部分区域冷库容量不足";
});
updateOverview();
loadHistory();
renderTimeline([]);
renderAssets([]);
</script>
</body>
</html>