mirror of
https://github.com/lllin000/PaperForge.git
synced 2026-07-22 06:50:53 +00:00
fix(skill): split vault-browse from paper-search, add browsing flow to vault-knowledge
This commit is contained in:
parent
80aa37a091
commit
f031fd26ef
7 changed files with 50 additions and 12 deletions
|
|
@ -38,6 +38,8 @@ class RuntimeInstaller:
|
|||
[sys.executable, "-m", "pip", "install", package_spec],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=120,
|
||||
)
|
||||
return (result.returncode == 0, result.stdout, result.stderr)
|
||||
|
|
@ -96,6 +98,8 @@ class RuntimeInstaller:
|
|||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
return result.returncode == 0 and bool(result.stdout.strip())
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ class VaultInitializer:
|
|||
["cmd", "/c", "mklink", "/J", str(zotero_link), zotero_path],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=30,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class EnvChecker:
|
|||
def install_dependencies(self) -> bool:
|
||||
deps = ["requests", "pymupdf", "pillow"]
|
||||
try:
|
||||
subprocess.run([sys.executable, "-m", "pip", "install"] + deps, check=True, capture_output=True)
|
||||
subprocess.run([sys.executable, "-m", "pip", "install"] + deps, check=True, capture_output=True, encoding="utf-8", errors="replace")
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
|
@ -178,7 +178,7 @@ class EnvChecker:
|
|||
return p
|
||||
# 4. 通过 where 命令检测
|
||||
try:
|
||||
result = subprocess.run(["where", "zotero"], capture_output=True, text=True, timeout=5)
|
||||
result = subprocess.run(["where", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5)
|
||||
if result.returncode == 0:
|
||||
for line in result.stdout.strip().split("\n"):
|
||||
p = Path(line.strip())
|
||||
|
|
@ -196,7 +196,7 @@ class EnvChecker:
|
|||
return p
|
||||
# 通过 which 检测
|
||||
try:
|
||||
result = subprocess.run(["which", "zotero"], capture_output=True, text=True, timeout=5)
|
||||
result = subprocess.run(["which", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5)
|
||||
if result.returncode == 0:
|
||||
return Path(result.stdout.strip())
|
||||
except Exception:
|
||||
|
|
@ -213,7 +213,7 @@ class EnvChecker:
|
|||
if p.exists():
|
||||
return p
|
||||
try:
|
||||
result = subprocess.run(["which", "zotero"], capture_output=True, text=True, timeout=5)
|
||||
result = subprocess.run(["which", "zotero"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5)
|
||||
if result.returncode == 0:
|
||||
return Path(result.stdout.strip())
|
||||
except Exception:
|
||||
|
|
@ -527,6 +527,8 @@ def headless_setup(
|
|||
["cmd", "/c", "mklink", "/J", str(zotero_link_path), str(zotero_data)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=30,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
|
|
@ -767,6 +769,8 @@ def headless_setup(
|
|||
[sys.executable, "-m", "pip", "install", "--upgrade"] + install_target,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=120,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
|
|
@ -775,6 +779,8 @@ def headless_setup(
|
|||
[sys.executable, "-m", "pip", "install", "--upgrade"] + git_target,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=120,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -782,6 +788,8 @@ def headless_setup(
|
|||
[sys.executable, "-c", "import paperforge; print(getattr(paperforge, '__version__', '?'))"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=15,
|
||||
)
|
||||
new_ver = _new.stdout.strip() or "?"
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ Agent 读到本文件后,首先根据用户意图路由到对应的 reference
|
|||
|
||||
| 用户意图 | 典型输入 | 加载文件 |
|
||||
|---------|---------|---------|
|
||||
| 文献检索 | "找一下骨科...文献", "查一下 TGF-beta", "库里有没有支架材料的", "搜一下 Smith 的文章", "collection 里有没有", "看一下库里内容", "看一下文献库", "库里有什么", "浏览文献" | [references/paper-search.md](references/paper-search.md) |
|
||||
| 查看 Vault 概况 | "看一下库里内容", "看一下文献库", "库里有什么", "浏览文献" | [references/vault-knowledge.md](references/vault-knowledge.md) |
|
||||
| 文献检索 | "找一下骨科...文献", "查一下 TGF-beta", "库里有没有支架材料的", "搜一下 Smith 的文章", "collection 里有没有" | [references/paper-search.md](references/paper-search.md) |
|
||||
| 三阶段精读(指定论文) | `/pf-deep <query>`, `pf-deep <query>`, "精读 XXX", "深度阅读 XXX", "带我读", "组会讲这篇", "读一下这篇" | [references/deep-reading.md](references/deep-reading.md) |
|
||||
| 三阶段精读(查看队列) | `/pf-deep`(无参数), "精读队列", "有哪些该读了" | [references/deep-reading.md](references/deep-reading.md) |
|
||||
| 论文问答 | `/pf-paper <query>`, `pf-paper <query>`, "做这篇的问答", "帮我看看 XXX", "这篇文章讲了什么", "查一下" | [references/paper-qa.md](references/paper-qa.md) |
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
- "库里有没有讲支架材料的"
|
||||
- "这个 collection 有哪些文献"
|
||||
- "搜一下 Smith 2024 的文章"
|
||||
- "看一下库里内容" / "看一下文献库"
|
||||
- "库里有什么" / "浏览文献"
|
||||
|
||||
## 流程
|
||||
|
||||
|
|
@ -67,6 +65,16 @@ Agent 直接读 `index_path`,在 JSON 中筛选:
|
|||
- `这篇讲了什么` → 进入 [paper-qa.md](paper-qa.md) 流程
|
||||
- 不需要继续 → 结束
|
||||
|
||||
### Step 6: 写作辅助场景
|
||||
|
||||
如果用户原始意图包含**写作/优化/参考文献/综述/引用**等,搜索结果不是终点:
|
||||
|
||||
1. 提示用户圈选最相关的 3-5 篇
|
||||
2. 对每篇进入 [deep-reading.md](deep-reading.md) 或至少通读 formal note + fulltext 关键段落
|
||||
3. 读完所有选定论文后,Agent 整合知识辅助写作
|
||||
|
||||
> 示例:"我从库里 X 篇文献中提取了以下关键发现……要不要基于这些帮你写 XX 部分?"
|
||||
|
||||
## 注意事项
|
||||
|
||||
- 如果是大型 library(>500 篇),优先用 paper_resolver 而不是全量读 JSON
|
||||
|
|
|
|||
|
|
@ -2,6 +2,22 @@
|
|||
|
||||
本文件是 Agent 理解 PaperForge Vault 的共享参考。精读、问答、检索等所有工作流都先从这里获取基础概念。
|
||||
|
||||
## 浏览场景
|
||||
|
||||
用户说"看一下库里内容"、"看一下文献库"、"库里有什么"、"浏览文献"时,Agent 展示 Vault 概况:
|
||||
|
||||
1. 跑 `paths` 获取 `literature_dir` 和 `index_path`
|
||||
2. 列出 `literature_dir` 下所有 domain(领域文件夹名)
|
||||
3. 读 formal-library.json,统计每个 domain:论文总数、OCR 完成数、无 PDF 数
|
||||
4. 输出概览:
|
||||
|
||||
```
|
||||
Vault: D:\...\Vault
|
||||
Domains: 骨科 (550 papers, 520 OCR done), 运动医学 (263 papers, 129 OCR done)
|
||||
```
|
||||
|
||||
如果用户继续问具体内容,Agent 加载 [paper-search.md](paper-search.md) 搜索。
|
||||
|
||||
---
|
||||
|
||||
## 1. 获取路径
|
||||
|
|
|
|||
|
|
@ -278,8 +278,7 @@ def _resolve_plugin_interpreter(vault: Path, plugin_data: dict) -> tuple[str, st
|
|||
for path, extra in system_candidates:
|
||||
try:
|
||||
cmd = [path] + extra + ["--version"]
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=5, text=True)
|
||||
if result.returncode == 0 and "Python" in (result.stdout or ""):
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=5, text=True, encoding="utf-8", errors="replace")
|
||||
return (path, "auto-detected", extra)
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError, OSError):
|
||||
continue
|
||||
|
|
@ -295,7 +294,7 @@ def _query_resolved_version(interp: str, extra_args: list[str]) -> tuple[str | N
|
|||
"""
|
||||
try:
|
||||
cmd = [interp] + extra_args + ["--version"]
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=10, text=True)
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=10, text=True, encoding="utf-8", errors="replace")
|
||||
if result.returncode != 0:
|
||||
return (None, None)
|
||||
output = (result.stdout or "").strip() or (result.stderr or "").strip()
|
||||
|
|
@ -317,7 +316,7 @@ def _query_resolved_package(interp: str, extra_args: list[str], package_name: st
|
|||
"""
|
||||
try:
|
||||
cmd = [interp] + extra_args + ["-m", "pip", "show", package_name]
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=15, text=True)
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=15, text=True, encoding="utf-8", errors="replace")
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
output = (result.stdout or "").strip()
|
||||
|
|
@ -345,7 +344,7 @@ def _query_resolved_module(interp: str, extra_args: list[str], module_name: str)
|
|||
)
|
||||
try:
|
||||
cmd = [interp] + extra_args + ["-c", script]
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=15, text=True)
|
||||
result = subprocess.run(cmd, capture_output=True, timeout=15, text=True, encoding="utf-8", errors="replace")
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
output = (result.stdout or "").strip()
|
||||
|
|
|
|||
Loading…
Reference in a new issue