可行版本1.0.0

new_test
Bifang 2026-05-11 12:32:27 +08:00
parent bdbdc674c6
commit 56c7e227af
4 changed files with 103 additions and 30 deletions

View File

@ -160,8 +160,15 @@ function renderMeetingStatus(meeting) {
function refreshActionButtons() { function refreshActionButtons() {
const canProcess = Boolean(state.meetingId) && !state.processing && !state.guideBusy; const canProcess = Boolean(state.meetingId) && !state.processing && !state.guideBusy;
const currentMeeting = meetingById(state.meetingId);
$("#btn-process").disabled = !canProcess; $("#btn-process").disabled = !canProcess;
$("#btn-process").textContent = state.processing ? "总结中" : state.guideBusy ? "等待" : "总结"; $("#btn-process").textContent = state.processing
? "总结中"
: state.guideBusy
? "等待"
: currentMeeting?.has_summary
? "重总结"
: "总结";
const canEditResult = Boolean(state.meetingId) && !state.processing && !state.guideBusy; const canEditResult = Boolean(state.meetingId) && !state.processing && !state.guideBusy;
$("#btn-toggle-result-edit").disabled = !canEditResult; $("#btn-toggle-result-edit").disabled = !canEditResult;
@ -268,6 +275,64 @@ function pushStandaloneReparseLine(text) {
box.textContent = lines.slice(-6).join("\n"); box.textContent = lines.slice(-6).join("\n");
} }
async function streamTemplateGuideReparse(templateName, userNotes = "", handlers = {}) {
const params = new URLSearchParams();
if (userNotes.trim()) {
params.set("user_notes", userNotes.trim());
}
const suffix = params.toString() ? `?${params.toString()}` : "";
const source = new EventSource(
`/api/templates/${encodeURIComponent(templateName)}/guide/reparse/stream${suffix}`,
);
try {
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") {
handlers.onStatus?.(payload.data);
return;
}
if (payload.type === "chunk") {
const chunk = payload.data?.text || "";
if (chunk) {
contentAcc += chunk;
handlers.onChunk?.(chunk, contentAcc, payload.data);
}
return;
}
if (payload.type === "done") {
resolve(payload.data || { name: templateName, content: contentAcc });
return;
}
if (payload.type === "error") {
reject(new Error(payload.data || "解析失败"));
}
};
source.onerror = () => {
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 || "");
return result;
} finally {
source.close();
}
}
async function runStandaloneGuideReparseFlow() { async function runStandaloneGuideReparseFlow() {
const templateName = state.templateName; const templateName = state.templateName;
const userNotes = $("#reparse-modal-notes").value || ""; const userNotes = $("#reparse-modal-notes").value || "";
@ -1084,24 +1149,14 @@ async function reparseTemplateGuideFromModal(userNotes = "") {
} }
async function runTemplateGuideReparse(templateName, userNotes = "") { async function runTemplateGuideReparse(templateName, userNotes = "") {
const params = new URLSearchParams(); return streamTemplateGuideReparse(templateName, userNotes, {
if (userNotes.trim()) { onStatus() {
params.set("user_notes", userNotes.trim()); $("#guide-modal-subtitle").textContent = "正在结合补充说明重新解析模板...";
} },
const suffix = params.toString() ? `?${params.toString()}` : ""; onChunk(_chunk, contentAcc) {
const result = await api(`/api/templates/${encodeURIComponent(templateName)}/guide/reparse${suffix}`, { $("#process-guide-editor").value = contentAcc;
method: "POST", },
}); });
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 || "");
return result;
} }
function startMeetingProcess(userNotes = "") { function startMeetingProcess(userNotes = "") {
@ -1225,12 +1280,24 @@ $("#btn-process-guide-edit").addEventListener("click", async () => {
} }
}); });
$("#btn-process-guide-reparse").addEventListener("click", () => { $("#btn-process-guide-reparse").addEventListener("click", async () => {
if (state.processing || state.guideBusy) { if (state.processing || state.guideBusy) {
return; return;
} }
showReparseGuidePrompt(); $("#btn-process-guide-reparse").disabled = true;
try {
if (state.processGuideEditMode) {
await saveProcessGuideFromModal();
}
hideReparseGuidePrompt();
closeModal("modal-process-guide");
openStandaloneReparseModal();
} catch (error) {
toast(error.message, "err");
} finally {
$("#btn-process-guide-reparse").disabled = false;
}
}); });
$("#btn-reparse-guide-cancel").addEventListener("click", () => { $("#btn-reparse-guide-cancel").addEventListener("click", () => {

View File

@ -1,9 +1,10 @@
- 严格保留模板的Markdown标题层级体系# 总标题 > ## 内容主体 > ### 一级板块 > #### 发言人/细分板块),后续生成时不得随意更改层级关系。 - 标题层级固定为 `# 会议记录``## 会议内容``### 章节标题``#### 发言人强调``1. **方面名称**``- 具体条目`,共六级层级,后续生成须严格保持该层级结构
- 顶部元数据议题、时间、地点、主持人、参加人必须基于实际会议信息填充所有占位符X、XX、XXX等需替换为真实数据严禁原样输出。 - 会议基本信息(议题、时间、地点、主持人、参加人、议程)为固定区块,信息必须完整保留,不可省略
- “议程”区块需保留标题,其下列表项数量与内容严格按实际会议流程动态调整,无实际议程时省略该区块。 - 议程列表项为固定结构(各部门汇报、领导指示部署),顺序不可调整,但具体部门名称可按实际参会情况替换
- “汇报通报”区块需替换具体部门名称与量化数据,若会议记录中无汇报环节,则整体省略该小节,不强行补齐。 - 所有 `X`、`XX`、`XXX` 形式占位符须替换为真实内容,禁止原样输出
- “领导部署/强调”区块需保留结构框架,将占位姓名替换为实际发言人;该区块下的发言人数量、业务分类标题(**XX方面**)及下级详情列表需与真实讲话内容严格对应,动态增减,无依据时直接省略。 - 所有数字占位符(如 `X项`、`XX项`)须替换为具体统计数字,禁止原样输出
- 所有示例性文字、演示性标题及占位内容必须在生成前全部替换为实际业务内容,禁止保留模板中的示例字符。 - 领导强调部分的结构(多个 `#### X总强调` 依次排列,每个下面分多个 `1. **方面**` 条目)为固定格式,每个领导强调至少包含一个方面,最多不超过四个
- 使用水平分割线(---)作为区块分隔符,依次分隔头部信息、议程、汇报板块与部署板块,保持文档结构清晰。 - 方面名称(如“政企方面”“市场方面”“云数方面”等)使用 `**加粗**` 格式,后续生成须保持加粗
- 严格保留格式规范领导发言使用有序列表1. 2. 3.),业务分类使用加粗文本(**分类名称:**),具体指示或要点使用无序列表(- ),有内容时必须完整套用此层级格式。 - 具体部署内容使用 `-` 列表项,每方面至少一条,至多三条
- 遵循“无依据不填充”原则,模板中未被实际会议内容支撑的空白项、占位项或示例项必须直接删除,不得虚构或强行对齐模板结构。 - 若某位领导未对某些方面作指示,该方面标题及条目应整体省略,不保留空结构
- 模板中“详见汇报材料”等提示性文字在无对应材料时应删除,不强行保留

View File

@ -621,7 +621,12 @@ async def save_template_guide(name: str, payload: dict):
@app.post("/api/templates/{name}/guide/reparse") @app.post("/api/templates/{name}/guide/reparse")
async def reparse_template_guide(name: str, user_notes: str = ""): async def reparse_template_guide(name: str, user_notes: str = ""):
content = _ensure_template_guide(name, force=True, user_notes=user_notes) try:
content = _ensure_template_guide(name, force=True, user_notes=user_notes)
except HTTPException:
raise
except Exception as exc:
raise HTTPException(500, str(exc) or "Template guide reparse failed") from exc
return {"name": name, "content": content} return {"name": name, "content": content}