处理了一些编码错误

new_test
Bifang 2026-05-11 17:04:30 +08:00
parent 0560f56a90
commit 4c2629a0bf
6 changed files with 568 additions and 141 deletions

View File

@ -1,49 +1,48 @@
```json
{ {
"sub_topics": [ "sub_topics": [
{ {
"title": "宽带安装维护与网络指标汇报", "title": "宽带装维进度与九零工程转化退单指标",
"time_interval": "00:00:01 - 00:02:40", "time_interval": "00:00:01 - 00:03:06",
"overview": "本周汇报宽带上门安装量、维护质量及转化率指标。受天气影响安装量约400户累计上门超1000户但距3000户目标进度靠后弱光值降至0.51逼近目标月度转化率87.35%接近90%退单率控制在6.53%。" "overview": "会议通报了宽带装维进度上周上门量达580户累计超1000户但距离3000户目标进度偏后。九零工程月度转化率为87.35%退单率为6.53%主要受用户原因、天气及改约影响。PCTN蓝单当周转化率为56.82%月度为75.29%退单率达44.29%,需持续优化流程。"
}, },
{ {
"title": "退单原因分析与PCDN专线治理", "title": "PCDN专线学校限速协调与审核流程优化",
"time_interval": "00:02:41 - 00:05:31", "time_interval": "00:03:07 - 00:05:31",
"overview": "本周剖析宽带退单因素及PCDN专线网络质量恶化应对情况。退单主因为用户不安装及改约兰单转化率当周56.82%、月度75.29%未达80%目标PCDN专线因学校出口带宽问题恶化已上报市公司分析IP并协调建立后台限速机制。" "overview": "针对PCDN专线指标恶化问题会议指出主要受开学后两所学校IP地址滥用影响已报市公司分析并拟采取限速措施。同时提出优化审核流程建议剔除一线审批同意的退单并将该指标纳入综合运维考核。目前正协调全资建立后台自动限速机制以提升管控效率。"
}, },
{ {
"title": "基站攻坚、专线护航与故障通报", "title": "网络质量攻坚、基站维护与二级站点拆除计划",
"time_interval": "00:05:33 - 00:07:56", "time_interval": "00:05:33 - 00:09:35",
"overview": "本周通报基站攻坚、政企专线护航进度及当周故障情况。超频基站故障已处理恢复5G参数调整试点持续观察118条专线存量73条已巡检56条剩余17条确保月底前完成当周收故障33件其中9件为光缆等网络问题。" "overview": "网络质量方面超频基站故障已及时处理恢复5G基站参数调整试点将观察信号弱化改善效果。二级基站拆除工作进展顺利剩余75站预计4月15日前全量完成下电与资费调整。此外118条专线已按计划推进巡检下周将针对新收到的网络质量综合评估体系分解目标。"
}, },
{ {
"title": "二级站点拆除与网络质量评估体系", "title": "综合部行政事务推进、渠道评估与气象人员管理",
"time_interval": "00:07:57 - 00:09:35",
"overview": "本周通报当周故障、二级站点拆除进度及新评估体系部署。当周故障中网络相关9件二级站点剩余75站计划两周内拆除目标4月15日前全量调整资费内部已提前收到网络质量综合评估体系文件下周将分解指标制定目标。"
},
{
"title": "综合部项目推进与行政事务协调",
"time_interval": "00:09:46 - 00:12:39", "time_interval": "00:09:46 - 00:12:39",
"overview": "本周汇报重点项目跟进、物资采购及渠道产能评估进展。花果山项目无变化,无人机验收本周推动;建委框架清单及投资计划已汇报完成;打印机采购拟采用外派点保障招投标需求;渠道产能评估宣贯会已开,方案本周专题汇报。" "overview": "综合部推进了建委清单整理、投资计划汇报及市场终端占比措施制定,并落实了招投标打印设备的保障方案。渠道产能评估已召开宣贯会并梳理方案,预计本周专题汇报。同时强调气象工作人员纪律管理,并指出基金工作清单与宣传工作因兼职原因有所滞后,需加快进度。"
}, },
{ {
"title": "工会经费公示与体育文化节筹备", "title": "工会经费管控、暖心工程升级与体育文化节筹备",
"time_interval": "00:12:40 - 00:19:50", "time_interval": "00:12:40 - 00:19:50",
"overview": "本周通报工会经费压降使用方案及第四届体育文化节筹备情况。今年工会经费全面压降食堂改造及直升机引水方案已获批体育文化节方阵需25人目前缺编9人已决议由各部门抽调并于周二至周四排练参与者享绩效加分。" "overview": "受经费压降影响工会将推行节支增效食堂改造升级及下半年直升机引水方案已获批。全年规划六场大型文体活动重点筹备第四届体育文化节当前方阵人员缺口9人需各部门今日落实并安排下班后排练。参会者可获得绩效加分以激励积极性。"
}, },
{ {
"title": "招待费管控与区级评优申报", "title": "主题教育落实、招待费通报与区级奖项申报策略",
"time_interval": "00:19:51 - 00:26:58", "time_interval": "00:19:51 - 00:27:28",
"overview": "本周通报2025年招待费预算执行情况及区级评优申报进展。2025年招待费整体超预算14%综合部超支107%已调整预算,正气部招待需统筹分配;区国资委管辖企业评优已启动,委办与社保局联合经办,需提前对接名额分配以争取优势。" "overview": "主题教育已按要求完成基层学习2025年招待费超预算14%,综合部超支明显,需统筹对外接待安排。针对河川区担当作为奖项申报,会议建议先向委办及社保局领导摸底意向,若入围希望不大则避免无效投入。目前申报材料已提交区领导,需持续跟进审批进度。"
}, },
{ {
"title": "查企商客业务通报与工作作风整顿", "title": "商客市场复盘、查企进度与管理层执行力要求",
"time_interval": "00:27:32 - 00:35:21", "time_interval": "00:27:29 - 00:35:15",
"overview": "本周通报查企与商客市场业绩及工作作风纪律要求。查企完成6900万价值提升发展1110户重点提升低价值宽带商客收入88.5万环比增1万领导强调需养成日事日清习惯针对专线及在线指标需当日量化回复并落实措施。" "overview": "商客市场1月收入88.5万元同比提升草街等分局增幅超2万价值拓展排名第6。查企工作聚焦低价值用户提值与融合套餐推广本周开展5场活动但签约未达预期。管理层严厉强调工作执行力要求养成“日事日清”习惯并限期提交各项指标的具体保障方案。"
}, },
{ {
"title": "市场客服指标复盘与年度考核部署", "title": "满意度考核反思、客服指标管控与年度KPI部署",
"time_interval": "00:35:22 - 00:46:16", "time_interval": "00:35:16 - 00:46:16",
"overview": "本周复盘市场客服指标并部署市公司年度考核工作。市场部需提前谋划二季度声势本周汇报招聘及渠道进度满意度暴露正气部管理松懈80-20指标全市倒数第二需每日通报考核明确工信部有责及离网率为KPI要求提前沟通口径强化执行力。" "overview": "针对近期满意度测评排名靠后会议批评市场部与政企部思想松懈要求主管亲自抓并落实客户会参与机制。客服端将强化80/20指标管控技巧每日输出日报并预警离网率将纳入今年KPI考核。最后强调需提前与市公司沟通年度考核口径确保公平得分并提升整体执行力。"
} }
] ]
} }
```

View File

@ -2,7 +2,7 @@
# 会议记录 # 会议记录
议 题合川分公司周例会2026年第19期) 议 题合川分公司周例会2026年第X期)
时 间2026年5月8日 10:38—10:50 时 间2026年5月8日 10:38—10:50
@ -10,7 +10,7 @@
主持人:管理员 主持人:管理员
参加人:分公司领导、各部门经理、AI云数中心经理 参加人:分公司领导、各部门负责人及相关岗位人员
议程: 议程:
@ -22,34 +22,31 @@
## 会议内容 ## 会议内容
### 一、各部门汇报 ### 一、市场部、政企部、建维部、综合部︱党群纪检部按议程现场按顺序做汇报。综合部按照领导部署通报周例会领导部署工作推进完成情况各部门按议程现场汇报工作推进情况建维部通报宽带装维进度上周上门580户累计超1000户、九零工程转化退单指标及二级站点拆除计划综合部汇报建委清单整理、渠道产能评估、工会经费管控、体育文化节筹备及区级奖项申报策略市场与政企部复盘商客市场收入与查企进度并通报满意度测评情况。重点工作按节点推进部分指标需优化落实。
建维部汇报宽带上门安装量及网络指标受天气影响安装进度略缓累计上门超1000户但距3000户目标进度靠后弱光值降至0.51逼近目标月度转化率87.35%接近90%退单率6.53%PCDN专线因学校出口带宽问题恶化已上报市公司协调IP分析与后台限速机制超频基站故障已恢复118条专线存量巡检有序推进剩余17条确保月底前完成二级站点剩余75座计划两周内拆除新网络质量综合评估体系下周将分解目标。综合部通报无人机验收及建委框架清单已汇报完成打印机采购拟采用外派点保障招投标工会经费全面压降第四届体育文化节方阵缺编9人需各部门抽调2025年招待费整体超预算14%需统筹管控区级评优申报需提前对接争取名额。市场部与政企部通报查企完成6900万价值提升发展1110户商客收入88.5万环比增长二季度营销活动需提前谋划满意度及80-20指标全市排名靠后需每日通报市公司年度考核工信部有责、离网率需提前沟通口径并强化执行落实。
--- ---
### 二、部署强调 ### 二、部署强调
#### 分公司领导强调: #### 分领导强调:
1. **网络与运维方面:** 1. **工作要求与执行力:**
- 弱光值与转化率指标需持续压降改善月度转化率当前87.35%已接近90%目标,需纳入运维阶段性考核跟踪。 - 养成“日事日清、日清日结”工作习惯,阶段性汇报进展与困难,严禁工作拖延数月无反馈。
- PCDN专线网络质量恶化主因学校出口带宽需协调市公司分析IP地址并建立后台自动限速机制避免被动退单。 - 工作安排需第一时间量化回复领导,而非仅依赖周报记录,确保推进闭环。
- 二级站点拆除需抢抓进度剩余75座争取两周内全部完成下电与资费调整确保4月15日前全量完成。 2. **指标保障与方案落实:**
- 内部已提前收悉网络质量综合评估体系,下周须针对指标进行分解并制定具体目标。 - 限期提交专线、商客等核心指标的具体保障措施与责任人,拒绝空谈,确保目标达成。
- 针对满意度测评靠后问题,批评相关部门思想松懈,主管需亲自抓客户会参与机制,杜绝“亡羊补牢”式管理。
3. **客服管控与KPI预警**
- 强化80/20指标管控技巧市场部需每日输出日报至分管领导。
- 预警离网率将纳入今年KPI考核要求摸透市公司考核口径与可控操作空间提前布局。
2. **市场与客服方面:** ---
- 二季度营销活动需提前谋划造势打破传统淡季思维重点推进签约、3人融合及AI终端业务避免业务推进疲软。
- 满意度及80-20指标目前全市排名靠后市场部与政企部须吃透市公司考核技巧每日输出日报通报进度。
- 正气部满意度管理存在松懈,主管须亲自抓客户会落实,严禁“亡羊补牢”式被动应对,满意度工作须常态化管控。
3. **综合与行政方面:** #### 分公司主要领导强调:
- 工会经费全面压降,需以节电耗用更少的钱办更好的事,食堂改造及直升机引水方案已获批推进,下半年启用节约成本。
- 第四届体育文化节方阵目前缺编9人需各部门于本周内抽调人员周二至周四下班后集中排练参与者享绩效加分。
- 2025年招待费整体超预算14%,综合部超支严重已调整预算,其他部门须合理规划时间进度,正气部对外招待需统筹分配客户经理资源。
- 区级担当作为评优已启动,需提前对接区委办与人力社保局了解名额分配机制,避免盲目申报浪费精力。
4. **考核与作风建设方面:** 1. **执行力与文化塑造:**
- 全体员工须养成“日事日清、日清日结”工作习惯,任务安排须当日量化回复并落实具体措施,严禁拖延数月无进展。 - 各级管理人员及一线员工必须具备强执行力,知晓方法却不落实的工作作风不可接受。
- 市公司年度考核指标已明确为工信部有责及离网率,各部门须提前沟通考核口径,避免因信息不对称在起跑线落后。 - 各部门需提前摸底市公司年度考核口径与潜在风险,提前沟通争取公平得分,避免起跑线落后。
- 强化执行力建设,管理层至一线员工须明确目标与路径,杜绝“知道怎么做却不去做”的作风问题,确保年度考核稳妥达标。 2. **协同联动与考核前置:**
- 加强分管领导与牵头部门联动,必要时共同向上沟通,确保考核工作前置。
- 面对考核指标需主动出击,通过努力改善得分,而非被动等待。

View File

@ -224,7 +224,7 @@ function loadSettingsDraft(cfg) {
async function persistSettingsDraft() { async function persistSettingsDraft() {
const payload = cloneSettingsDraft(state.settingsDraft || {}); const payload = cloneSettingsDraft(state.settingsDraft || {});
if (!payload.api_profiles.length) { if (!payload.api_profiles.length) {
throw new Error("??????????"); throw new Error("至少保留一个模型配置");
} }
await api("/api/settings", { await api("/api/settings", {
method: "PUT", method: "PUT",
@ -1133,7 +1133,7 @@ async function reparseTemplateGuideFromModal(userNotes = "") {
$("#process-guide-editor").value = result.content || ""; $("#process-guide-editor").value = result.content || "";
$("#guide-modal-title").textContent = `???? ? ${templateName}`; $("#guide-modal-title").textContent = `模板说明 · ${templateName}`;
$("#guide-modal-subtitle").textContent = "确认后开始总结,也可以先补充说明或重解析"; $("#guide-modal-subtitle").textContent = "确认后开始总结,也可以先补充说明或重解析";
setProcessGuideEditMode(false); setProcessGuideEditMode(false);
@ -1450,6 +1450,416 @@ $("#btn-reparse-guide").addEventListener("click", async () => {
openStandaloneReparseModal(); openStandaloneReparseModal();
}); });
renderMeetingStatus = function(meeting) {
const name = $("#sidebar-meeting-name");
const meta = $("#sidebar-meeting-meta");
const tip = $("#selected-meeting-tip");
const summaryBadge = $("#badge-summary");
const topicsBadge = $("#badge-topics");
if (!meeting) {
name.textContent = "当前会议:未选择";
meta.textContent = "请从左侧选择一个会议开始处理。";
tip.textContent = "未选择会议";
summaryBadge.textContent = "未生成总结";
topicsBadge.textContent = "未生成主题 JSON";
summaryBadge.className = "badge muted";
topicsBadge.className = "badge muted";
return;
}
name.textContent = `当前会议:${meeting.name}`;
meta.textContent =
`ID: ${meeting.id} · 导入时间:${meeting.created_at || "未知"} · 原始文件:` +
`${meeting.original_filename || meeting.transcript_filename || "未知"}`;
tip.textContent = `当前处理会议:${meeting.name} (${meeting.id})`;
summaryBadge.textContent = meeting.has_summary ? "已生成总结" : "未生成总结";
topicsBadge.textContent = meeting.has_topics ? "已生成主题 JSON" : "未生成主题 JSON";
summaryBadge.className = meeting.has_summary ? "badge" : "badge muted";
topicsBadge.className = meeting.has_topics ? "badge" : "badge muted";
};
refreshActionButtons = function() {
const canProcess = Boolean(state.meetingId) && !state.processing && !state.guideBusy;
const currentMeeting = meetingById(state.meetingId);
$("#btn-process").disabled = !canProcess;
$("#btn-process").textContent = state.processing
? "总结中"
: state.guideBusy
? "等待"
: currentMeeting?.has_summary
? "重总结"
: "总结";
const canEditResult = Boolean(state.meetingId) && !state.processing && !state.guideBusy;
$("#btn-toggle-result-edit").disabled = !canEditResult;
const resource = state.rightResource;
const canEditSide = Boolean(resource?.editable) && !state.processing && !state.guideBusy;
$("#btn-toggle-side-edit").disabled = !canEditSide;
updateGuideButton(resource);
};
setProcessGuideEditMode = function(editMode) {
state.processGuideEditMode = editMode;
const editor = $("#process-guide-editor");
const button = $("#btn-process-guide-edit");
editor.readOnly = !editMode;
editor.classList.toggle("is-editing", editMode);
button.textContent = editMode ? "保存" : "编辑";
};
syncProcessGuideConfirmLabel = function() {
const meeting = meetingById(state.meetingId);
$("#btn-process-guide-confirm").textContent = meeting?.has_summary ? "重总结" : "确认";
};
persistSettingsDraft = async function() {
const payload = cloneSettingsDraft(state.settingsDraft || {});
if (!payload.api_profiles.length) {
throw new Error("至少保留一个模型配置");
}
await api("/api/settings", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
});
};
resetReparseModalProgress = function() {
$("#reparse-stream-title").textContent = "正在重新解析模板说明...";
$("#reparse-stream-content").textContent = "";
};
openStandaloneReparseModal = function() {
$("#reparse-modal-title").textContent = `模板说明补充 · ${state.templateName}`;
$("#reparse-modal-subtitle").textContent = "可为空;会和系统解析模板一起用于重新解析";
$("#reparse-modal-notes").value = "";
$("#reparse-modal-form").hidden = false;
$("#reparse-modal-progress").hidden = true;
$("#btn-reparse-modal-cancel").disabled = false;
$("#btn-reparse-modal-confirm").disabled = false;
resetReparseModalProgress();
openModal("modal-reparse-guide");
$("#reparse-modal-notes").focus();
};
runStandaloneGuideReparseFlow = async function() {
const templateName = state.templateName;
const userNotes = $("#reparse-modal-notes").value || "";
state.guideBusy = true;
setStatus("right", true, "解析中");
setStandaloneReparseProcessing(true);
resetReparseModalProgress();
pushStandaloneReparseLine(`模板:${templateName}`);
pushStandaloneReparseLine("已提交重解析请求,正在准备说明...");
refreshActionButtons();
try {
const params = new URLSearchParams();
if (userNotes.trim()) {
params.set("user_notes", userNotes.trim());
}
const source = new EventSource(
`/api/templates/${encodeURIComponent(templateName)}/guide/reparse/stream?${params.toString()}`,
);
const result = await new Promise((resolve, reject) => {
let contentAcc = "";
source.onmessage = (event) => {
if (!event.data) {
return;
}
const payload = JSON.parse(event.data);
if (payload.type === "status") {
$("#reparse-stream-title").textContent = "正在重新解析模板说明...";
pushStandaloneReparseLine("已连接模型,开始解析...");
return;
}
if (payload.type === "chunk") {
const chunk = payload.data?.text || "";
if (chunk) {
contentAcc += chunk;
$("#reparse-stream-content").textContent = contentAcc
.replace(/\r\n/g, "\n")
.split("\n")
.slice(-6)
.join("\n");
}
return;
}
if (payload.type === "done") {
source.close();
resolve(payload.data || { name: templateName, content: contentAcc });
return;
}
if (payload.type === "error") {
source.close();
reject(new Error(payload.data || "解析失败"));
}
};
source.onerror = () => {
source.close();
reject(new Error("解析连接中断"));
};
});
state.templates = state.templates.map((item) => (
item.name === templateName ? { ...item, has_guide: true } : item
));
if (state.rightResource?.name === templateName && state.rightResource.type === "template") {
state.rightResource.hasGuide = true;
}
await refreshRightResourceAfterGuideReparse(templateName, result.content || "");
closeModal("modal-reparse-guide");
await openProcessGuideModal();
$("#process-guide-editor").value = result.content || "";
} finally {
state.guideBusy = false;
setStatus("right", false, "空闲");
setStandaloneReparseProcessing(false);
refreshActionButtons();
}
};
resetProcessingStream = function() {
$("#stream-box").style.display = "none";
$("#stream-title").textContent = "";
$("#stream-content").textContent = "";
setStatus("left", false, "空闲");
};
ensureTemplateGuideBeforeProcess = async function() {
const templateMeta = templateMetaByName(state.templateName);
if (templateMeta?.has_guide) {
return;
}
toast("当前模板还没有解析说明,先为你解析模板。");
state.guideBusy = true;
setStatus("left", true, "解析中");
refreshActionButtons();
try {
const result = await api(`/api/templates/${encodeURIComponent(state.templateName)}/guide/reparse`, {
method: "POST",
});
state.templates = state.templates.map((item) => (
item.name === state.templateName ? { ...item, has_guide: true } : item
));
if (
state.rightResource &&
state.rightResource.templateName === result.name &&
state.rightResource.type === "template"
) {
state.rightResource.hasGuide = true;
refreshActionButtons();
}
} finally {
state.guideBusy = false;
setStatus("left", false, "空闲");
refreshActionButtons();
}
};
loadTemplateGuideForProcess = async function() {
const data = await api(`/api/templates/${encodeURIComponent(state.templateName)}/guide`);
$("#guide-modal-title").textContent = `模板说明 · ${state.templateName}`;
$("#guide-modal-subtitle").textContent = "确认后开始总结,也可以先补充说明或重解析";
$("#process-guide-editor").value = data.content || "";
if (!$("#process-extra-notes").dataset.keepValue) {
$("#process-extra-notes").value = "";
}
setProcessGuideEditMode(false);
syncProcessGuideConfirmLabel();
};
saveProcessGuideFromModal = async function() {
const content = $("#process-guide-editor").value;
await api(`/api/templates/${encodeURIComponent(state.templateName)}/guide`, {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ content }),
});
state.templates = state.templates.map((item) => (
item.name === state.templateName ? { ...item, has_guide: true } : item
));
if (
state.rightResource &&
state.rightResource.templateName === state.templateName &&
state.rightResource.type === "template-guide"
) {
state.rightResource.content = content;
}
if (
state.rightResource &&
state.rightResource.name === state.templateName &&
state.rightResource.type === "template"
) {
state.rightResource.hasGuide = true;
}
setProcessGuideEditMode(false);
refreshActionButtons();
toast("说明已保存");
};
openProcessGuideModal = async function() {
openModal("modal-process-guide");
hideReparseGuidePrompt();
$("#guide-modal-title").textContent = `模板说明 · ${state.templateName}`;
$("#guide-modal-subtitle").textContent = "正在准备模板说明...";
$("#process-guide-editor").value = "正在加载模板说明,请稍等...";
$("#process-guide-editor").readOnly = true;
$("#process-guide-editor").classList.remove("is-editing");
$("#process-extra-notes").dataset.keepValue = "1";
$("#btn-process-guide-edit").disabled = true;
$("#btn-process-guide-reparse").disabled = true;
$("#btn-process-guide-confirm").disabled = true;
try {
await ensureTemplateGuideBeforeProcess();
await loadTemplateGuideForProcess();
} catch (error) {
closeModal("modal-process-guide");
throw error;
} finally {
$("#btn-process-guide-edit").disabled = false;
$("#btn-process-guide-reparse").disabled = false;
$("#btn-process-guide-confirm").disabled = false;
delete $("#process-extra-notes").dataset.keepValue;
}
};
reparseTemplateGuideFromModal = async function(userNotes = "") {
const templateName = state.templateName;
state.guideBusy = true;
setStatus("right", true, "解析中");
$("#btn-process-guide-edit").disabled = true;
$("#btn-process-guide-reparse").disabled = true;
$("#btn-process-guide-confirm").disabled = true;
$("#guide-modal-subtitle").textContent = "正在结合补充说明重新解析模板...";
refreshActionButtons();
try {
if (state.processGuideEditMode) {
await saveProcessGuideFromModal();
}
const result = await runTemplateGuideReparse(templateName, userNotes);
$("#process-guide-editor").value = result.content || "";
$("#guide-modal-title").textContent = `模板说明 · ${templateName}`;
$("#guide-modal-subtitle").textContent = "确认后开始总结,也可以先补充说明或重解析";
setProcessGuideEditMode(false);
toast(`说明已更新:${templateName}`);
} finally {
state.guideBusy = false;
setStatus("right", false, "空闲");
$("#btn-process-guide-edit").disabled = false;
$("#btn-process-guide-reparse").disabled = false;
$("#btn-process-guide-confirm").disabled = false;
refreshActionButtons();
}
};
runTemplateGuideReparse = async function(templateName, userNotes = "") {
return streamTemplateGuideReparse(templateName, userNotes, {
onStatus() {
$("#guide-modal-subtitle").textContent = "正在结合补充说明重新解析模板...";
},
onChunk(_chunk, contentAcc) {
$("#process-guide-editor").value = contentAcc;
},
});
};
startMeetingProcess = function(userNotes = "") {
state.processing = true;
setStatus("left", true, "总结中");
refreshActionButtons();
showProcessingView();
$("#stream-box").style.display = "block";
$("#stream-title").textContent = "第一阶段:结构化主题...";
$("#stream-content").textContent = "";
const params = new URLSearchParams({ template_name: state.templateName });
if (userNotes.trim()) {
params.set("user_notes", userNotes.trim());
}
const source = new EventSource(`/api/meetings/${state.meetingId}/process?${params.toString()}`);
let resultAcc = "";
let streamAcc = "";
source.onmessage = async (event) => {
if (!event.data) {
return;
}
const payload = JSON.parse(event.data);
if (payload.type === "status") {
if (payload.data === "preprocessing") {
$("#stream-title").textContent = "第一阶段:结构化主题...";
} else if (payload.data === "preprocessing_done") {
$("#stream-title").textContent = "主题提取完成,开始生成会议总结...";
} else if (payload.data === "summarizing") {
$("#stream-title").textContent = "第二阶段:生成会议总结...";
streamAcc = "";
$("#stream-content").textContent = "";
}
return;
}
if (payload.type === "chunk") {
const { data } = payload;
streamAcc += data.text || "";
$("#stream-content").textContent = streamAcc.replace(/\r\n/g, "\n").split("\n").slice(-4).join("\n");
if (data.stage === 2 && data.chunk_type === "content") {
resultAcc += data.text || "";
}
return;
}
if (payload.type === "done") {
source.close();
state.processing = false;
patchMeeting(state.meetingId, { has_summary: true });
renderMeetingStatus(meetingById(state.meetingId));
showResult(payload.data?.result || resultAcc || "");
toast("会议总结完成");
refreshActionButtons();
return;
}
if (payload.type === "error") {
source.close();
state.processing = false;
resetProcessingStream();
$("#processing-indicator").hidden = true;
refreshActionButtons();
toast(`处理失败:${payload.data}`, "err");
}
};
source.onerror = () => {
source.close();
state.processing = false;
resetProcessingStream();
$("#processing-indicator").hidden = true;
refreshActionButtons();
toast("处理连接中断", "err");
};
};
$("#btn-import").addEventListener("click", () => { $("#btn-import").addEventListener("click", () => {
$("#import-name").value = ""; $("#import-name").value = "";
$("#import-file").value = ""; $("#import-file").value = "";
@ -1466,11 +1876,11 @@ $("#btn-confirm-import").addEventListener("click", async () => {
const name = $("#import-name").value.trim(); const name = $("#import-name").value.trim();
const file = $("#import-file").files[0]; const file = $("#import-file").files[0];
if (!name) { if (!name) {
toast("???????", "err"); toast("请填写会议名称", "err");
return; return;
} }
if (!file) { if (!file) {
toast("???????", "err"); toast("请选择会议文件", "err");
return; return;
} }
@ -1481,13 +1891,13 @@ $("#btn-confirm-import").addEventListener("click", async () => {
const result = await fetch("/api/meetings/import", { method: "POST", body: formData }); const result = await fetch("/api/meetings/import", { method: "POST", body: formData });
if (!result.ok) { if (!result.ok) {
const detail = await result.json().catch(() => ({ detail: "Import failed" })); const detail = await result.json().catch(() => ({ detail: "Import failed" }));
toast(`?????${detail.detail}`, "err"); toast(`导入失败:${detail.detail}`, "err");
return; return;
} }
const payload = await result.json(); const payload = await result.json();
closeModal("modal-import"); closeModal("modal-import");
toast(`?????${name}`); toast(`已导入会议:${name}`);
await refresh(); await refresh();
await selectMeeting(payload.id); await selectMeeting(payload.id);
}); });
@ -1496,11 +1906,11 @@ $("#btn-confirm-import-template").addEventListener("click", async () => {
const name = $("#import-template-name").value.trim(); const name = $("#import-template-name").value.trim();
const file = $("#import-template-file").files[0]; const file = $("#import-template-file").files[0];
if (!name) { if (!name) {
toast("???????", "err"); toast("请填写模板名称", "err");
return; return;
} }
if (!file) { if (!file) {
toast("???????", "err"); toast("请选择模板文件", "err");
return; return;
} }
@ -1511,13 +1921,13 @@ $("#btn-confirm-import-template").addEventListener("click", async () => {
const result = await fetch("/api/templates/import", { method: "POST", body: formData }); const result = await fetch("/api/templates/import", { method: "POST", body: formData });
if (!result.ok) { if (!result.ok) {
const detail = await result.json().catch(() => ({ detail: "Import failed" })); const detail = await result.json().catch(() => ({ detail: "Import failed" }));
toast(`?????${detail.detail}`, "err"); toast(`导入失败:${detail.detail}`, "err");
return; return;
} }
const payload = await result.json(); const payload = await result.json();
closeModal("modal-import-template"); closeModal("modal-import-template");
toast(`??????${payload.name}`); toast(`已导入模板:${payload.name}`);
await refresh(); await refresh();
syncTemplateSelection(payload.name); syncTemplateSelection(payload.name);
await openTemplate(payload.name); await openTemplate(payload.name);
@ -1540,7 +1950,7 @@ $("#cfg-key-select").addEventListener("change", async (event) => {
renderSettingsKeyOptions(); renderSettingsKeyOptions();
try { try {
await persistSettingsDraft(); await persistSettingsDraft();
toast(`??????${$("#cfg-current-model").value}`); toast(`已切换模型:${$("#cfg-current-model").value}`);
} catch (error) { } catch (error) {
toast(error.message, "err"); toast(error.message, "err");
} }
@ -1553,7 +1963,7 @@ $("#btn-save-settings").addEventListener("click", async () => {
const currentName = $("#cfg-key-select").value; const currentName = $("#cfg-key-select").value;
const maxTokens = Number($("#cfg-max-tokens").value || 64000); const maxTokens = Number($("#cfg-max-tokens").value || 64000);
if (!Number.isFinite(maxTokens) || maxTokens < 1) { if (!Number.isFinite(maxTokens) || maxTokens < 1) {
toast("max_tokens ????? 0 ???", "err"); toast("max_tokens 必须大于 0", "err");
return; return;
} }
state.settingsDraft.api_profiles = state.settingsDraft.api_profiles.map((item) => ( state.settingsDraft.api_profiles = state.settingsDraft.api_profiles.map((item) => (
@ -1562,7 +1972,7 @@ $("#btn-save-settings").addEventListener("click", async () => {
try { try {
await persistSettingsDraft(); await persistSettingsDraft();
renderSettingsKeyOptions(); renderSettingsKeyOptions();
toast(`??????${$("#cfg-current-model").value}`); toast(`已保存模型配置:${$("#cfg-current-model").value}`);
} catch (error) { } catch (error) {
toast(error.message, "err"); toast(error.message, "err");
} }
@ -1585,11 +1995,11 @@ $("#btn-confirm-add-model").addEventListener("click", async () => {
const apiKey = $("#cfg-add-api-key").value.trim(); const apiKey = $("#cfg-add-api-key").value.trim();
const maxTokens = Number($("#cfg-add-max-tokens").value || 64000); const maxTokens = Number($("#cfg-add-max-tokens").value || 64000);
if (!modelName || !apiBaseUrl || !apiKey || !Number.isFinite(maxTokens) || maxTokens < 1) { if (!modelName || !apiBaseUrl || !apiKey || !Number.isFinite(maxTokens) || maxTokens < 1) {
toast("??????????", "err"); toast("请完整填写模型配置", "err");
return; return;
} }
if (state.settingsDraft.api_profiles.some((item) => item.name === modelName)) { if (state.settingsDraft.api_profiles.some((item) => item.name === modelName)) {
toast("???????", "err"); toast("模型名称已存在", "err");
return; return;
} }
@ -1606,7 +2016,7 @@ $("#btn-confirm-add-model").addEventListener("click", async () => {
try { try {
await persistSettingsDraft(); await persistSettingsDraft();
closeModal("modal-add-model"); closeModal("modal-add-model");
toast(`??????${modelName}`); toast(`已新增模型:${modelName}`);
} catch (error) { } catch (error) {
toast(error.message, "err"); toast(error.message, "err");
} }
@ -1623,7 +2033,7 @@ $("#btn-key-delete").addEventListener("click", async () => {
try { try {
await persistSettingsDraft(); await persistSettingsDraft();
toast(`??????${targetName}`); toast(`已删除模型:${targetName}`);
} catch (error) { } catch (error) {
toast(error.message, "err"); toast(error.message, "err");
} }

View File

@ -694,6 +694,9 @@ select.btn {
.guide-modal { .guide-modal {
width: min(760px, 100%); width: min(760px, 100%);
padding: 24px; padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
} }
.guide-modal-head { .guide-modal-head {
@ -701,7 +704,6 @@ select.btn {
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: flex-start;
gap: 16px; gap: 16px;
margin-bottom: 16px;
} }
.guide-modal-head h3 { .guide-modal-head h3 {
@ -718,6 +720,7 @@ select.btn {
display: grid; display: grid;
gap: 14px; gap: 14px;
position: relative; position: relative;
min-height: 0;
} }
.guide-editor { .guide-editor {
@ -786,9 +789,10 @@ select.btn {
.reparse-modal { .reparse-modal {
width: min(720px, 100%); width: min(720px, 100%);
min-height: 430px; min-height: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 14px;
} }
.reparse-modal-body { .reparse-modal-body {
@ -798,19 +802,34 @@ select.btn {
} }
.reparse-modal-textarea { .reparse-modal-textarea {
min-height: 190px; min-height: 176px;
height: 190px; height: 176px;
margin-top: 0; margin-top: 0;
} }
.reparse-stream-box { .reparse-stream-box {
width: 100%; width: 100%;
min-height: 240px; min-height: 0;
} }
.reparse-stream-content { .reparse-stream-content {
min-height: 180px; min-height: 152px;
max-height: 180px; max-height: 152px;
overflow: hidden;
scrollbar-width: none;
padding-bottom: 14px;
}
.reparse-stream-content::-webkit-scrollbar {
display: none;
}
#modal-process-guide .modal-actions,
#modal-reparse-guide .modal-actions {
justify-content: flex-end;
flex-wrap: wrap;
padding-top: 14px;
border-top: 1px solid rgba(199, 220, 248, 0.9);
} }
.icon-btn { .icon-btn {

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meeting Summary</title> <title>Meeting Summary</title>
<link rel="stylesheet" href="/assets/styles.css?v=20260511l"> <link rel="stylesheet" href="/assets/styles.css?v=20260511m">
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/13.0.3/marked.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/13.0.3/marked.min.js"></script>
</head> </head>
<body> <body>
@ -25,13 +25,13 @@
<aside class="panel" id="sidebar"> <aside class="panel" id="sidebar">
<div class="panel-header sidebar-header"> <div class="panel-header sidebar-header">
<div class="panel-heading"> <div class="panel-heading">
<span>资源管理器</span> <span>&#36164;&#28304;&#31649;&#29702;&#22120;</span>
<small id="sidebar-meeting-name">当前会议:未选择</small> <small id="sidebar-meeting-name">&#24403;&#21069;&#20250;&#35758;&#65306;&#26410;&#36873;&#25321;</small>
<small id="sidebar-meeting-meta">请从左侧选择一个会议开始处理。</small> <small id="sidebar-meeting-meta">&#35831;&#20174;&#24038;&#20391;&#36873;&#25321;&#19968;&#20010;&#20250;&#35758;&#24320;&#22987;&#22788;&#29702;&#12290;</small>
</div> </div>
<div class="header-badges"> <div class="header-badges">
<span class="badge muted" id="badge-summary">未生成总结</span> <span class="badge muted" id="badge-summary">&#26410;&#29983;&#25104;&#24635;&#32467;</span>
<span class="badge muted" id="badge-topics">未生成主题 JSON</span> <span class="badge muted" id="badge-topics">&#26410;&#29983;&#25104;&#20027;&#39064; JSON</span>
</div> </div>
</div> </div>
<div class="panel-body"> <div class="panel-body">
@ -44,25 +44,25 @@
<section class="panel panel-main" id="result-panel"> <section class="panel panel-main" id="result-panel">
<div class="panel-header"> <div class="panel-header">
<div class="panel-heading"> <div class="panel-heading">
<span>会议结果</span> <span>&#20250;&#35758;&#32467;&#26524;</span>
<div class="status-block"> <div class="status-block">
<div class="status-row"> <div class="status-row">
<span class="status-label">当前状态</span> <span class="status-label">&#24403;&#21069;&#29366;&#24577;</span>
<span class="status-light idle" id="left-status-light"></span> <span class="status-light idle" id="left-status-light"></span>
<span class="status-text" id="left-status-text">空闲</span> <span class="status-text" id="left-status-text">&#31354;&#38386;</span>
</div> </div>
<div class="status-meta" id="selected-meeting-tip">未选择会议</div> <div class="status-meta" id="selected-meeting-tip">&#26410;&#36873;&#25321;&#20250;&#35758;</div>
</div> </div>
</div> </div>
<div class="toolbar"> <div class="toolbar">
<button class="btn primary sm" id="btn-process" disabled>总结</button> <button class="btn primary sm" id="btn-process" disabled>&#24635;&#32467;</button>
<button class="btn sm" id="btn-toggle-result-edit" disabled>编辑</button> <button class="btn sm" id="btn-toggle-result-edit" disabled>&#32534;&#36753;</button>
</div> </div>
</div> </div>
<div class="panel-body panel-scroll" id="result-body"> <div class="panel-body panel-scroll" id="result-body">
<div id="result-empty" class="empty-state"> <div id="result-empty" class="empty-state">
<div class="empty-icon">M</div> <div class="empty-icon">M</div>
<p>选择会议后即可查看结果,或直接开始总结。</p> <p>&#36873;&#25321;&#20250;&#35758;&#21518;&#21363;&#21487;&#26597;&#30475;&#32467;&#26524;&#65292;&#25110;&#30452;&#25509;&#24320;&#22987;&#24635;&#32467;&#12290;</p>
</div> </div>
<div id="processing-indicator" class="processing" hidden> <div id="processing-indicator" class="processing" hidden>
<div class="stream-box" id="stream-box"> <div class="stream-box" id="stream-box">
@ -80,21 +80,21 @@
<section class="panel" id="template-panel"> <section class="panel" id="template-panel">
<div class="panel-header"> <div class="panel-header">
<div class="panel-heading"> <div class="panel-heading">
<span>编辑区</span> <span>&#32534;&#36753;&#21306;</span>
<div class="status-block"> <div class="status-block">
<div class="status-row"> <div class="status-row">
<span class="status-label">当前状态</span> <span class="status-label">&#24403;&#21069;&#29366;&#24577;</span>
<span class="status-light idle" id="right-status-light"></span> <span class="status-light idle" id="right-status-light"></span>
<span class="status-text" id="right-status-text">空闲</span> <span class="status-text" id="right-status-text">&#31354;&#38386;</span>
</div> </div>
<div class="status-meta" id="editor-resource-label">当前资源:模板</div> <div class="status-meta" id="editor-resource-label">&#24403;&#21069;&#36164;&#28304;&#65306;&#27169;&#26495;</div>
</div> </div>
</div> </div>
<div class="toolbar"> <div class="toolbar">
<label class="inline-label" for="tpl-select">模板</label> <label class="inline-label" for="tpl-select">&#27169;&#26495;</label>
<select class="btn sm" id="tpl-select"></select> <select class="btn sm" id="tpl-select"></select>
<button class="btn sm" id="btn-reparse-guide" disabled>解析</button> <button class="btn sm" id="btn-reparse-guide" disabled>&#35299;&#26512;</button>
<button class="btn sm" id="btn-toggle-side-edit" disabled>编辑</button> <button class="btn sm" id="btn-toggle-side-edit" disabled>&#32534;&#36753;</button>
</div> </div>
</div> </div>
<div class="panel-body panel-scroll" id="template-body"> <div class="panel-body panel-scroll" id="template-body">
@ -110,14 +110,14 @@
<div class="modal-box guide-modal"> <div class="modal-box guide-modal">
<div class="guide-modal-head"> <div class="guide-modal-head">
<div> <div>
<h3 id="guide-modal-title">模板使用说明</h3> <h3 id="guide-modal-title">&#27169;&#26495;&#20351;&#29992;&#35828;&#26126;</h3>
<p id="guide-modal-subtitle">确认后开始总结,可先补充一些关注要点</p> <p id="guide-modal-subtitle">&#30830;&#35748;&#21518;&#24320;&#22987;&#24635;&#32467;&#65292;&#21487;&#20808;&#34917;&#20805;&#19968;&#20123;&#20851;&#27880;&#35201;&#28857;</p>
</div> </div>
<button class="icon-btn" id="btn-close-process-guide" aria-label="关闭">×</button> <button class="icon-btn" id="btn-close-process-guide" aria-label="&#20851;&#38381;">&times;</button>
</div> </div>
<div class="guide-modal-body"> <div class="guide-modal-body">
<label class="form-field"> <label class="form-field">
<span>模板说明</span> <span>&#27169;&#26495;&#35828;&#26126;</span>
<textarea id="process-guide-editor" class="guide-editor" spellcheck="false"></textarea> <textarea id="process-guide-editor" class="guide-editor" spellcheck="false"></textarea>
</label> </label>
<div class="guide-inline-prompt" id="reparse-guide-prompt" hidden> <div class="guide-inline-prompt" id="reparse-guide-prompt" hidden>
@ -132,14 +132,14 @@
</div> </div>
</div> </div>
<label class="form-field"> <label class="form-field">
<span>补充说明(可空)</span> <span>&#34917;&#20805;&#35828;&#26126;&#65288;&#21487;&#31354;&#65289;</span>
<textarea id="process-extra-notes" class="guide-notes" spellcheck="false" placeholder="例如:强调哪些结构要保留、哪些内容要重点解释、哪些措辞需要避免"></textarea> <textarea id="process-extra-notes" class="guide-notes" spellcheck="false" placeholder="&#20363;&#22914;&#65306;&#24378;&#35843;&#21738;&#20123;&#32467;&#26500;&#35201;&#20445;&#30041;&#12289;&#21738;&#20123;&#20869;&#23481;&#35201;&#37325;&#28857;&#35299;&#37322;&#12289;&#21738;&#20123;&#25514;&#36766;&#38656;&#35201;&#36991;&#20813;"></textarea>
</label> </label>
</div> </div>
<div class="modal-actions"> <div class="modal-actions">
<button class="btn" id="btn-process-guide-edit">编辑</button> <button class="btn" id="btn-process-guide-edit">&#32534;&#36753;</button>
<button class="btn" id="btn-process-guide-reparse">重解析</button> <button class="btn" id="btn-process-guide-reparse">&#37325;&#35299;&#26512;</button>
<button class="btn primary" id="btn-process-guide-confirm">确认</button> <button class="btn primary" id="btn-process-guide-confirm">&#30830;&#35748;</button>
</div> </div>
</div> </div>
</div> </div>
@ -148,23 +148,23 @@
<div class="modal-box reparse-modal"> <div class="modal-box reparse-modal">
<div class="guide-modal-head"> <div class="guide-modal-head">
<div> <div>
<h3 id="reparse-modal-title">模板使用说明补充</h3> <h3 id="reparse-modal-title">&#27169;&#26495;&#20351;&#29992;&#35828;&#26126;&#34917;&#20805;</h3>
<p id="reparse-modal-subtitle">用于固定模板使用规格,优化最终输出结果(可不填写)</p> <p id="reparse-modal-subtitle">&#29992;&#20110;&#22266;&#23450;&#27169;&#26495;&#20351;&#29992;&#35268;&#26684;&#65292;&#20248;&#21270;&#26368;&#32456;&#36755;&#20986;&#32467;&#26524;&#65288;&#21487;&#19981;&#22635;&#20889;&#65289;</p>
</div> </div>
<button class="icon-btn" id="btn-close-reparse-guide" aria-label="关闭">×</button> <button class="icon-btn" id="btn-close-reparse-guide" aria-label="&#20851;&#38381;">&times;</button>
</div> </div>
<div class="reparse-modal-body" id="reparse-modal-form"> <div class="reparse-modal-body" id="reparse-modal-form">
<textarea id="reparse-modal-notes" class="guide-inline-textarea reparse-modal-textarea" spellcheck="false" placeholder="例如:强调哪些结构必须保留、哪些段落需要重点解释、哪些措辞需要避免"></textarea> <textarea id="reparse-modal-notes" class="guide-inline-textarea reparse-modal-textarea" spellcheck="false" placeholder="&#20363;&#22914;&#65306;&#24378;&#35843;&#21738;&#20123;&#32467;&#26500;&#24517;&#39035;&#20445;&#30041;&#12289;&#21738;&#20123;&#27573;&#33853;&#38656;&#35201;&#37325;&#28857;&#35299;&#37322;&#12289;&#21738;&#20123;&#25514;&#36766;&#38656;&#35201;&#36991;&#20813;"></textarea>
</div> </div>
<div class="reparse-modal-body" id="reparse-modal-progress" hidden> <div class="reparse-modal-body" id="reparse-modal-progress" hidden>
<div class="stream-box reparse-stream-box"> <div class="stream-box reparse-stream-box">
<div class="stream-title" id="reparse-stream-title">正在重新解析模板说明...</div> <div class="stream-title" id="reparse-stream-title">&#27491;&#22312;&#37325;&#26032;&#35299;&#26512;&#27169;&#26495;&#35828;&#26126;...</div>
<pre class="stream-content reparse-stream-content" id="reparse-stream-content"></pre> <pre class="stream-content reparse-stream-content" id="reparse-stream-content"></pre>
</div> </div>
</div> </div>
<div class="modal-actions"> <div class="modal-actions">
<button class="btn" id="btn-reparse-modal-cancel">取消</button> <button class="btn" id="btn-reparse-modal-cancel">&#21462;&#28040;</button>
<button class="btn primary" id="btn-reparse-modal-confirm">确认解析</button> <button class="btn primary" id="btn-reparse-modal-confirm">&#30830;&#35748;&#35299;&#26512;</button>
</div> </div>
</div> </div>
</div> </div>
@ -256,6 +256,6 @@
</div> </div>
<div class="toast" id="toast"></div> <div class="toast" id="toast"></div>
<script type="module" src="/assets/app.js?v=20260511l"></script> <script type="module" src="/assets/app.js?v=20260511m"></script>
</body> </body>
</html> </html>

View File

@ -1,10 +1,12 @@
- 宏观结构可保留,但二级标题模块及三级子项允许按实际内容动态增删,严禁为填充模板强行保留无依据的空白示例项。 - 整体结构需严格保留六大核心模块层级(概述、核心议题、关键问答、重要观点、开发决策、后续行动),标题使用 Markdown `##``###` 规范。
- 所有 `[...]` 占位符、示例性标题如议题1/2/3、关于产品定位等及示例描述必须替换为会议真实信息禁止原样输出。 - 所有 `[占位提示]`、示例性文字及括号内的说明语必须在生成前替换为真实会议内容;若无对应信息,直接省略该占位项,严禁原样输出或保留空括号。
- 示例中的固定子标签(如需求分析、技术评估、开发进度等)仅为参考模板,需根据实际讨论维度灵活调整或替换为通用分类。 - “核心议题”与“重要观点”下的子标题为动态结构,须根据实际讨论内容灵活增减数量与命名,禁止强制凑齐模板示例的固定数量。
- 问答内容必须严格遵循 `Q: [问题] \n A: [回答]` 的配对结构,支持多条问答独立成组,问答对之间可保留分隔线。 - “关键问答”模块需严格保留 `Q:``A:` 的问答对格式;若包含多个问答对,每组之间必须使用 `---` 水平线分隔。
- 重要观点需统一使用 Markdown 引用块(`> `)格式输出,每个观点独立成段,小标题应随实际议题动态生成。 - “重要观点”模块下的每条内容必须使用 Markdown 引用块 `> ` 格式包裹,确保观点与决策的视觉层级独立。
- 后续行动项必须使用 Markdown 复选框列表(`- [ ]`)格式,条目数量严格对应实际待办任务,无明确行动项时该整节应省略。 - “后续行动”模块必须使用 Markdown 复选框 `- [ ] ` 格式列出任务项;任务数量与具体内容按实际分配动态生成,不可沿用模板示例条数。
- 决策项、观点项等列表内容允许数量增减,需保持缩进层级与符号一致性,不强制限定固定条目数。 - 各模块下的细分条目需保留列表与子项结构,但具体标签名称可根据实际业务语境进行合理替换或泛化,确保语义准确。
- 输出需严格遵循 Markdown 排版规范,确保标题层级、列表、引用块、复选框等具有结构意义的格式在有内容时完整保留。 - 模板中未提及或会议内容未覆盖的空白小节、占位示例,一律按“无依据不强行补齐”原则直接删除,不输出空标题、空列表或残留占位符。
- 标题中的 Emoji 装饰符号需保留以维持模板风格一致性;若实际场景不适用,可替换为通用符号或仅保留纯文本,但需全篇保持统一。
- 占位符替换完成后需进行逻辑校验,确保每个标题/标签与其下方的具体内容严格对应,禁止出现格式错位或内容张冠李戴。