Metadata-Version: 2.4
Name: structured-writer-ldxs
Version: 1.0.28
Summary: structured-writer — AI Agent
Home-page: https://github.com/Ldxs001/workbuddy-skills
Author: Ldxs (wUwproject)
Author-email: wuwofc@yeah.net
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: license-file
Dynamic: requires-python
Dynamic: summary

# Structured Writer — 结构化写作智能体

基于 LLM 的结构化长文写作系统。子结构驱动、两级 RAG 增强、续写容断、交互式大纲控制。

## 核心架构

```
用户输入主题
  → [大纲规划器] LLM 生成结构化 JSON 大纲（节×子结构）
      → [交互式大纲] 用户可调整：勾选/排序/字数/重点/RAG
          → [串行写作器] 逐子结构调用 LLM 写作
              ├─ 节级别 RAG 查询（背景资料）
              ├─ 子结构级别 RAG 查询（针对性资料）
              ├─ 前文上下文注入（保连贯性）
              └─ token 耗尽自动续写
                  → 合并 .md 输出
```

## 特性

| 特性 | 说明 |
|------|------|
| **子结构系统** | 每节自动分解为 2-4 个子结构，逐子结构串行写作，`###` 标题分隔 |
| **两级 RAG** | 节级别查背景资料 + 子结构级别查针对性资料，prompt 分两段注入 |
| **续写机制** | 检测 `finish_reason="length"` 自动续写，最多 5 轮。空内容跳过续写 |
| **交互式大纲** | 勾选/取消节和子结构、阿拉伯数字排序、罗马数字子结构排序、字数编辑、重点标记 |
| **大纲双级排序** | 节：1-N；子结构：i-iv（每节独立） |
| **多模板** | 通用公文/新闻报道/论文综述/技术报告/自定义，切换即生效 |
| **实时进度** | 写作过程显示进度条 + 状态文本（RAG查询/写作中/完成） |
| **会话恢复** | 断线重连后恢复大纲和进度 |
| **RAG 冷启动** | 配置页一键启动 rag-assistant 子进程，自动检测在线状态 |

## 快速开始

```bash
pip install structured-writer-ldxs
structured-writer-ldxs --port 8770
```

打开 http://localhost:8770

## 配置

配置 Tab 设置写作者模型（LM Studio / Ollama）、规划者模型、上下文窗口、提示词模板。

### 模型推荐

| 角色 | 推荐模型 | 注意事项 |
|------|---------|---------|
| 写作者 | Qwen3.5-35b-A3B / 同级别 | 推理模型 max_tokens 建议 ≥8192 |
| 规划者 | Qwen3.5-35b-A3B / 同级别 | 大纲生成需要语义理解能力 |

## RAG 对接

本系统依赖 [rag-assistant](https://github.com/Ldxs001/workbuddy-skills/tree/main/agent/rag-assistant) 的知识库查询能力：

1. 启动 rag-assistant（或通过配置页一键冷启动）
2. 配置页填入 rag-assistant 路径，点击冷启动
3. 大纲中勾选 RAG + 选择知识库
4. 系统自动做两级 RAG 查询：节背景 + 子结构针对性

## 高级用法

### 大纲勾选

取消勾选的节/子结构在生成时完全跳过，不写标题也不占字数。

### 续写

LLM 输出被 `max_tokens` 截断时自动追加"请继续写"指令重试。content 为空（推理吃光 token）时放弃续写，不卡死。

## PyPI

```bash
pip install structured-writer-ldxs
```

## 许可证

Apache 2.0 © wUwproject


---

## 更新说明

## [1.0.28] - 2026-07-27
### 新增
- **每子结构字数可编辑**：章节字数改为子结构字数之和（自动实时求和），子结构字数输入框直接可改；取消勾选的子结构不计入章节字数
- **进度条按过滤后子结构总数计算**：取消勾选的子结构不再计入进度分母
- **RAG 离线时复选框禁用**：8767 未上线时 RAG 复选框 disabled＋title 提示；上线后自动同步 KB 下拉框
- **子结构辅助知识模态框**：每个子结构 "+" 按钮 → 弹窗支持文本输入 + .txt/.md 文件上传（FileReader 前端读取）
- **RAG 与辅助知识 Prompt 分离注入**：`【RAG 参考资料】` 和 `【辅助知识】` 两段独立标注
- **前文回顾字数可配置**：配置页 "写作参数" 新增输入框，`context_review_length` 写入 config.json
- **配置项自动合并**：`config_manager.load()` 深层合并（嵌套 dict 中新 key 自动补上）；`update()` 支持写入新增键
- **LLM 模型自动检测**：`_build_payload` 中 model 为空时自动调 `list_models()` 取第一个已加载模型
- **批量自动撰写**：输入框写入多行（每行一个主题）→ 后端 `/api/batch_auto` 逐篇规划+RAG+生成 → 前端轮询批量进度
- **单篇自动撰写**：输入框旁 "自动撰写" 按钮 → 前端 chain `plan→generate`，全量自动 RAG
- **事实自检系统**：配置页 "事实自检" 开关 → 写作 prompt 末尾内嵌 `【事实待核查】` 标记 → LLM 在同一 response 中自检 → 解析标记收集 → 文章末尾编号列表汇总。**零额外 LLM 调用**
- **无问题时也输出自检段落**：即使所有子结构都返回"无"，文章末尾也输出 `## 建议人工复审` + `未发现需标记的问题`
- **会话归档/恢复/删除**：侧边栏每项 "🗂 归档" 按钮 → `data/archives/sessions/` 折叠区 → "↩ 恢复" + "✕ 删除"（`confirm()` 确认）
- **自动会话限额**：`max_sessions`（默认 20）→ 新建会话超出时自动归档最旧非当前会话
- **停止生成**：聊天区底部 "延时停止"（当前子结构写完停）+ "立即停止"（续写边界停）→ 保留已写内容输出 .md
- **规划器优先遵循用户指令**：约束前加 "优先遵循用户明确指定的结构要求"，`sections 数量` 改为 "如用户未指定"
- **规划/写作模型温度可配置**：配置页新增 "温度" 输入框（0-1，step=0.05），规划默认 0.6、写作默认 0.7，持久化到 config.json
- **LLM 客户端 temperature 参数**：`LLMClient.__init__` 加 `temperature`，`chat`/`chat_detailed`/`_build_payload` 默认值改为 `None`（走 `self.temperature`）
- **模型下拉框始终显示已保存的模型**：`refreshModels` 接受 `savedValue` 参数，配置模型不在 API 返回列表时追加 `xxx（已配置）` option
- **RAG 停止按钮**：配置页新增 "停止 RAG" 按钮 → 后端 `_handle_rag_stop` → `taskkill /F /T` 杀进程树 + `netstat` 查 8767 + 等端口释放 + auto-restart 检测
- **RAG 停止后不再显示"运行中"**：`_ragManuallyStopped` 标记阻止轮询跳回运行中状态，直到用户手动点击"冷启动 RAG"
- **RAG 状态轮询加速**：cache-buster 防缓存，间隔 3s→1.5s，启动后立即查一次

### 变更
- **自检从额外 LLM 调用改为内嵌标记**：删除 `FACT_CHECK_PROMPT` 和独立 `SELF_CHECK_SYSTEM_PROMPT`，改为在写作 prompt 末尾追加 `【事实待核查】` 标注要求，response 里直接解析
- **规划器 `max_tokens` 从配置读**：删除硬编码 4096，改用 `max(4096, llm_client.max_tokens)`
- **写作器/规划器 LLM 客户端统一工厂**：`_create_writer_client()` / `_create_planner_client()` 传 `temperature`
- **Planner/writer temperature 硬编码删除**：`planner.py` `temperature=0.6` → `None`；`writer.py` `temperature=0.7` → `None`（走客户端配置）
- **`status_text` 仅 writing 阶段返回**：`get_progress()` 非 writing 阶段返回空字符串，防止加载旧会话显示脏数据
- **状态文本生成时自动清空**：`_handle_generate` 入口调用 `set_status_text("")`
- **配置页提示文案更新**：改为 "推理模型建议不低于 4096（默认最低值），长文建议 8192 以上"

### 修复
- `planner.py` 硬编码 `max_tokens=4096` 导致推理模型 thinking 吃掉全部 token → JSON 输出为空
- `config_manager.py` `update()` 无法写入新增配置键 → `fact_check_enabled` 等不持久化
- `config_manager.py` `load()` 不合并 DEFAULT_CONFIG 缺失项 → 旧 config.json 没有新字段
- 自检 `max_tokens` 各值（2048/8192/512）导致推理模型 thinking 吃光 → 改为 `None`（走配置的 81920）
- 自检使用独立 system prompt → LLM 混淆角色 → 改为共享 `WRITER_SYSTEM_PROMPT`
- 自检额外 LLM 调用导致额外 token 消耗 → 改为内嵌标记法，零额外调用
- 加载旧会话时 `_status_text` 脏数据被轮询读出并显示
- 章节字数 input 可编辑但子结构字数不变 → 数据不一致
- 子结构取消勾选后章节字数不减 → 重算函数忽略未勾选
- 模型下拉框加载时显示"(请选择)"而非已保存模型 → `refreshModels` 接受 `savedValue` 回退
- RAG 冷启动后无法关闭 → 新增停止按钮 + 后端进程树 kill + 端口释放等待
- RAG 停止后轮询仍跳回"运行中" → `_ragManuallyStopped` 标记保护
- RAG 状态检测被浏览器缓存 → 加 `?_=Date.now()` cache-buster

---
