天天160 downloadsAI 小说创作工具(Obsidian 版):建书/建章/建卷、打开文档、保存章节、字数统计,全部基于 Vault MD 文档约定,增加使用说明,增加写作指南的生成,更新章节管理功能,增加书籍磁盘同步功能
Chinese version: README_ZN.md
Network requests. This plugin performs no network activity except LLM chat. All outbound traffic goes exclusively through the official openai SDK to the OpenAI-compatible endpoint that you configure yourself in settings (a local server such as Ollama / LM Studio / llama.cpp, or a provider API like DeepSeek or Qwen DashScope). At runtime the plugin makes exactly three kinds of calls — non-streaming and streaming chat completions, plus one optional GET /models issued only when you run the LLM connection test to confirm your endpoint works; any additional request-related call sites flagged by scanners belong to the bundled SDK's generic HTTP layer and are not used elsewhere by this plugin. There is no telemetry, no analytics, no update checking, and no connection to any author-operated server. Your API key is entered by you in the settings panel, stored locally inside your vault with the rest of the plugin settings, and transmitted only as an authentication header to the endpoint you chose; when left empty (the normal case for local servers) a fixed placeholder value (local-no-auth) stands in its place, so no real secret ever leaves your machine.
Base64 usage (atob / btoa). The plugin's own source code contains zero base64 encode/decode calls. Every occurrence present in the shipped bundle originates from third-party libraries that esbuild bundles: the yaml parser (its standard handler for YAML !!binary tags) and the openai SDK (generic base64 ↔ binary-buffer conversion helpers). They perform ordinary data-format conversions and are not used to obfuscate API keys, hide URLs, or mask code payloads. Nothing in the build is minified or obfuscated — the complete human-readable source is published in the repository; please audit it directly if you have concerns.
This plugin inspects file structures inside your vault through Obsidian's standard app.vault APIs, in exactly two scopes:
work_dir) lists existing folders so you can fuzzy-search where your manuscripts live; this walk starts at the vault root but is deliberately bounded — it descends only 3 levels deep, stops after 500 entries, and skips hidden directories such as .obsidian/; (b) the dockable chat panel's @reference candidate list calls vault.getFiles() when rendering so that any document in your vault can be quoted into an LLM prompt with one keystroke. Both list paths only — no content is read at either point. A file's text is loaded only after you act on it: picking a folder merely sets the scope for later local operations, and referencing a file adds its content to the explicit request sent to the model endpoint you configured yourself (see the Network-requests note above).work_dir). Files outside that folder are never opened or scanned by these features.ArticleWriter turns your vault into an AI-assisted novel workshop. It organizes each story as a folder of plain Markdown files (state doc, outline, world-building, characters, scenes, foreshadowing notes and one folder per chapter) and adds LLM-powered writing commands on top: write / continue / rewrite / polish chapters, strip AI-sounding phrasing, review from a global perspective, plus a dockable chat panel that can quote any vault file via @references. All data stays local; no external services are required beyond the OpenAI-compatible model endpoint you configure yourself.
It is the Obsidian port of the articlewriter Python CLI. Nothing depends on external services — every operation works on the Markdown documents inside your vault through Obsidian's built-in Vault / Workspace APIs. The sync feature was not ported.
<novel root>/<book title>/
├── 故事状态.md # Obsidian "file properties" style: YAML frontmatter holds the version-2 runtime state (title/genre/current volume·scene·chapter/per-chapter metadata); body is free-form notes; legacy story_state.json is auto-migrated with a backup in _backup/ on first save
├── WRITING_GUIDE.md # Story-level writing guide (the user-level one of the same name lives under work_dir)
├── 写作指南汇总.md # Per-book merged guide (auto-generated, change-detected via hash); the only writing-guide content injected into LLM prompts
├── 大纲.md # Master outline
├── 世界观.md # World-building template
├── 卷.md # Volumes (grouping container)
├── 伏笔.md # Foreshadowing log
├── 笔记.md # Notes
└── 第NN章-<标题>/ # One folder per chapter
├── NN-<标题>.md # Chapter body (file prefix is the numeric chapter number)
├── NN-<标题>-大纲.md # Chapter outline
├── NN-<标题>-人物.md # Characters
├── NN-<标题>-人物关系.md # Character relations
├── NN-<标题>-场景.md # Scenes
└── NN-<标题>-信息.md # Chapter info
Volume-level template docs are named after the volume too (e.g. <卷名>-大纲.md, <卷名>-人物.md, <卷名>-人物关系.md, <卷名>-场景.md).
Missing documents are auto-created as "HTML comment example" templates when creating a new book/chapter; existing files are skipped and never overwrite user content. All file names are normalized through safeFilename() (mirrors fsutil.safe_filename). Legacy documents (bare names like 章节.md/卷大纲.md, or older prefix forms like 初见-章节.md) are auto-detected when switching books and can be batch-migrated to the new names (rename only, content untouched).
Search the command palette for "ArticleWriter" or the Chinese description.
| Command | CLI equivalent | Implementation notes |
|---|---|---|
| Create new story | /new |
vault.createFolder + vault.create build the book folder and all template docs, then write the state doc |
| New chapter | /chapter add |
Creates the 第NN章-title/ directory with its 6 documents (named NN-title.md, NN-title-大纲.md, …) and updates the current chapter |
| Chapter list | /chapter list / /open |
Scans chapter folders; picking one opens its body via workspace.getLeaf("tab").openFile and sets it as the current chapter |
| Open outline / world-building / foreshadowing / notes | /outline show, etc. |
Created from template first if missing, then opened |
| Next / previous chapter | /chapter next / prev |
With no current chapter: next → first, prev → last; at a boundary a notice is shown without switching |
| Word count of current chapter / whole book | /count |
Counts pure text characters only (ported count_pure_words: excludes punctuation/symbols/whitespace) |
| Save current chapter | /save |
Reads the focused editor's content and force-flushes it to disk via vault.modify |
| Story status | /status |
Shows title / genre / current chapter / chapter count / total word count |
| View / edit writing guide | /agents view / edit |
Three tiers: story-level <book>/WRITING_GUIDE.md > user-level file of the same name under work_dir > system level = a fixed plugin-data-dir file .obsidian/plugins/articlewriter/WRITING_GUIDE.md (seeded on first run from the built-in default; no longer user-configurable — the old system_guide_path setting was removed). Each tier opens its own file directly; multiple tiers open a picker. Editing saves the full text for the chosen tier and refreshes that book's merged《写作指南汇总》 |
| Generate empty writing-guide templates | — (plugin addition) | Creates a same-format skeleton (section headings kept, body cleared) for both the user-level work_dir/WRITING_GUIDE.md and the current book's WRITING_GUIDE.md; skips any target that already has non-empty content and reports it. Does not touch the system tier |
| Regenerate system writing guide | — (plugin addition) | After a confirmation dialog, overwrites the system-tier .obsidian/plugins/articlewriter/WRITING_GUIDE.md with the built-in default, then best-effort refreshes the current book's merged guide |
| Generate usage guide | — (plugin addition) | Writes 《使用说明.md》(built-in user manual of this plugin) at the work_dir root. Also auto-created and opened when missing at plugin start-up or whenever the work directory is set or switched (only when missing or empty); an existing non-empty file is skipped and never overwritten |
| LLM connection test | /llm test |
Uses the openai SDK against any OpenAI-compatible endpoint (DeepSeek/DashScope/Ollama/LM Studio/llama.cpp…); verifies the active config via GET /models |
| LLM chat window | — (plugin addition) | Persistent dockable panel (custom view, draggable into any workspace area, position survives reloads; message icon in the sidebar as quick entry): multi-turn streaming chat, Enter sends / Shift+Enter newline, dropdown on top switches saved model configs, "Stop generating" only interrupts the current turn; every turn automatically carries a chat-specific prompt (friendly-assistant identity + writing guide + snapshot of the current story context, consistent with the CLI's /llm Q&A behavior), the current story·chapter is shown on top, history is not persisted |
| Writing desk | — (plugin addition) | Persistent dockable panel (book icon in the sidebar as quick entry): work directory, list of all stories (click to switch the current book), genre / writing type / total word count / update time of the current story, chapter list (activating a chapter also syncs its volume), global docs and per-chapter files (click opens them in the editor); story/chapter/file lists all support folder-like expand/collapse (title row or the arrow before a chapter); right-clicking a story/chapter/file row shows a shortcut menu: create/delete story, create/delete chapter, create an article .md at the book root or inside a chapter dir / delete file (all destructive actions require a second confirmation; deletions go to the Obsidian trash so they are recoverable); manual reload via "Refresh" at the top right |
| Relationship panel | — (plugin addition) | Persistent dockable panel (people icon in the sidebar as quick entry): aggregates the current story's relationship cards from the three tiers of 《人物关系.md》 (book / volume / chapter) — character pair, type badge (icon picked by relationship type), status dot (active green / pending yellow / ended grey) and description; click a card (or "Open document" on a group header) to open that tier's source md; the top offers a "Cards / Graph" toggle (kept for the session): Cards = grouped relationship cards, Graph = a circular node-link network (edge colour = relationship type with an in-graph legend, line style = active solid / pending dashed / ended dotted, thicker line = same pair registered in several places; hover a character to highlight its neighbours, hover an edge to highlight just that one, click a node or edge to open the source doc; a zoom bar above the graph (zoom out / zoom in / reset view) scales the whole drawing including character names, and scrolling the mouse wheel over the graph also zooms (the point under the mouse stays fixed across zoom; scroll down = zoom out, scroll up = zoom in). The part cropped by the pane can be reached by holding and dragging the graph itself — no scrollbars appear, dragging is clamped so the graph can never be lost off-view, and "Reset view" returns it to the initial fit-to-pane position), plus the filter box (character/type/status) and a "Refresh" button — no work-directory row and no story list (the panel shows relationships only; switch books via the "Switch current story" command or the Writing desk), groups collapse in card mode, and edits to relationship docs auto-refresh the panel |
| LLM model configuration | (replaces ~/.articlewriter/config.json) |
Obsidian Settings → ArticleWriter, stored in the plugin data directory .obsidian/plugins/articlewriter/data.json (first run presets three standard templates local/deepseek/qwen-dashscope awaiting api_key/model name) |
work_dir for novel writing (mirrors the CLI's --work_dir / /dir). A 《使用说明.md》 usage guide is then dropped into that folder automatically (editable; re-created via the "Generate usage guide" command only when missing or empty)./dir).大纲.md when a book is created, 章节.md when a chapter is created.npm install
npm run build # outputs main.js + manifest.json + styles.css into release/
Development mode (watch): npm run dev.
Manual install: copy main.js, manifest.json, styles.css from release/ to <your vault>/.obsidian/plugins/articlewriter/, then enable the plugin in Obsidian under "Settings → Community plugins".