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