Project Docs

共享文件夹快速搜索助手 · README.md

在线查看上传的 Markdown 项目文档。

po-file-search

目录

功能介绍

po-file-search 是采购文件搜索 MVP 服务,用于让 OpenClaw 通过对话方式,从群晖 SMB 文件服务器中按文件夹名称和文件名称快速找到文件,并生成可发送给用户的下载链接。

核心链路:

text
群晖 SMB 共享目录
  ↓ 挂载到 Linux/macOS
手动或每日定时全量扫描文件名/文件夹名
  ↓
OpenClaw 服务器本地 SQLite/FTS 索引
  ↓
OpenClaw/HTTP API 搜索
  ↓
生成下载 token 和下载链接
  ↓
通过钉钉等渠道发送给用户

重要原则:

  • 搜索时查询本地 SQLite/FTS 索引,不依赖群晖搜索。
  • 用户每次搜索时不重新扫描群晖。
  • 当前暂行同步策略只保留每日低频全量同步和手动全量同步。
  • 发送或下载阶段才读取群晖真实文件。
  • 下载链接使用可配置的对外 IP/域名和端口,不使用 127.0.0.1 发给用户。

当前已实现功能

  1. 跨平台系统识别:支持 Linux 和 macOS。
  2. 群晖 SMB 挂载:Linux 使用 CIFS;macOS 可复用 Finder 已挂载 SMB 共享。
  3. 子目录扫描:支持挂载共享目录后只扫描指定子目录。
  4. 本地索引:使用 SQLite + FTS5 保存文件元数据和搜索索引。
  5. 文件搜索:支持 CLI 和 HTTP API。
  6. 搜索结果数量配置max_results = 0 表示返回全部。
  7. 搜索模式配置:支持智能、左包含、右包含、全包含、精准匹配。
  8. 下载链接:支持生成下载 token 和下载链接。
  9. 下载有效期配置token_ttl_minutes = 0 表示永不过期。
  10. 每日定时全量同步:默认每天 23:23 执行一次,可配置。
  11. 手动全量同步:管理员可随时执行全量同步。
  12. HTTP 服务:提供健康检查、搜索、生成链接、下载接口。
  13. 基础审计日志:记录搜索、生成链接、下载事件。
  14. 钉钉 webhook 骨架:可通过 webhook 发送链接消息。
  15. Docker 文件:提供 Dockerfiledocker-compose.yml

运行环境

Linux 生产环境

  • Python 3.9+
  • SQLite FTS5
  • cifs-utils
  • 可访问群晖 SMB 服务

安装 CIFS:

bash
sudo apt-get install -y cifs-utils

macOS 开发环境

  • Python 3.9+
  • 系统自带 mount_smbfs
  • 可通过 Finder 或命令行访问群晖 SMB

macOS 推荐先用 Finder 挂载共享目录,再让程序复用 Finder 挂载路径。

配置文件参数说明

配置文件:

text
config.json

示例:

json
{
  "mounts": [
    {
      "name": "采购共享",
      "server": "192.168.1.26",
      "share": "X.artwork2",
      "mount_point_linux": "/mnt/synology/purchase",
      "mount_point_macos": "/Volumes/采购共享",
      "username": "cg-name_search",
      "password_env": "searchpassword",
      "readonly": true,
      "smb_version": "3.0"
    }
  ],
  "index_db": "./data/file_index.sqlite",
  "scan_roots": [
    {
      "name": "采购共享/artwork",
      "path_from_mount": "采购共享",
      "relative_path": "artwork"
    }
  ],
  "ignored_dirs": ["@eaDir", "#recycle", ".snapshot"],
  "max_results": 10,
  "search_mode": "smart",
  "server": {
    "host": "0.0.0.0",
    "port": 18765
  },
  "download": {
    "base_url": "http://192.168.88.20:18765",
    "token_ttl_minutes": 30
  },
  "dingtalk": {
    "webhook_env": "DINGTALK_WEBHOOK"
  },
  "index": {
    "auto_full_sync_enabled": true,
    "full_sync_time": "23:23",
    "full_sync_on_startup": false
  },
  "logging": {
    "failure_log_file": "./logs/po-file-search-error.log"
  }
}

mounts

参数必填说明
name挂载名称,供 scan_roots[].path_from_mount 引用
server群晖 IP、主机名或域名
shareSMB 共享文件夹名,不是子目录
mount_point_linuxLinux 挂载点
mount_point_macosmacOS 挂载点
username群晖只读账号
password_env密码所在环境变量名,不是密码明文
readonly是否只读挂载,建议 true
smb_versionSMB 协议版本,默认 3.0

scan_roots

参数必填说明
name扫描根名称,写入索引的 root_name
path_from_mount引用 mounts[].name
relative_path挂载目录下要扫描的子目录,空字符串表示扫描挂载根目录
path直接指定本地路径,用于测试或特殊场景

例如真实路径:

text
\\192.168.1.26\X.artwork2\artwork

配置方式:

json
"share": "X.artwork2",
"relative_path": "artwork"

搜索配置

参数说明
max_results默认搜索结果数量;大于 0 表示最多返回 N 条,等于 0 表示返回全部
search_mode默认搜索模式,可被 CLI --mode 或 HTTP search_mode 覆盖

搜索模式:

模式中文别名含义
smart智能智能搜索,先 FTS,再 LIKE/中文切片兜底
left_contains左包含文件名或目录以关键词开头
right_contains右包含文件名或目录以关键词结尾
contains全包含文件名或目录包含关键词
exact精准匹配 / 精确匹配文件名或目录完全等于关键词

HTTP 服务配置

参数说明
server.hostHTTP 服务监听地址,生产建议 0.0.0.0
server.portHTTP 服务监听端口,可配置

下载链接配置

参数说明
download.base_url生成给用户访问的对外下载地址,可配置 IP 或域名
download.token_ttl_minutes下载链接有效期,单位分钟;大于 0 表示 N 分钟过期,等于 0 表示永不过期

注意:发给用户的下载链接不要使用 127.0.0.1

钉钉配置

参数说明
dingtalk.webhook_env钉钉 webhook 地址所在环境变量名

失败运行日志配置

当前运行日志只记录失败事件,不记录成功请求。

json
"logging": {
  "failure_log_file": "./logs/po-file-search-error.log"
}

会记录的失败事件包括:

  • 挂载失败。
  • 手动全量同步失败。
  • 每日全量同步失败。
  • HTTP API 参数错误。
  • 生成下载链接失败。
  • 下载 token 无效或过期。
  • 下载文件不存在。
  • 未处理异常。

日志格式为 JSON Lines,每行一条失败记录,包含时间、事件类型、错误类型、错误信息、上下文和异常堆栈。

索引同步配置

参数说明
index.auto_full_sync_enabled是否启用每日定时全量同步
index.full_sync_time每日全量同步时间,格式 HH:MM,默认 23:23
index.full_sync_on_startup服务启动后是否立即执行一次全量同步
logging.failure_log_file失败运行日志文件路径,只记录失败事件

当前暂行策略:

  • 删除后台增量同步。
  • 每天 23:23 做一次全量同步。
  • 管理员可手动执行全量同步。

如何使用

1. 设置密码环境变量

password_env 填的是环境变量名,不是密码。

例如配置:

json
"password_env": "searchpassword"

运行前设置:

bash
export searchpassword='你的群晖密码'

2. macOS 先人工挂载群晖

Finder 中访问:

text
smb://192.168.1.26/X.artwork2

登录成功后,程序会自动复用 Finder 挂载路径。

3. 检测系统

bash
python3 -m po_file_search --config config.json detect-os

4. 检查或复用挂载

bash
python3 -m po_file_search --config config.json mount

5. 手动全量同步索引

bash
python3 -m po_file_search --config config.json index

6. 搜索文件

默认搜索:

bash
python3 -m po_file_search --config config.json search 'DCC1039S.pdf'

返回全部匹配:

bash
python3 -m po_file_search --config config.json search 'DCC1039S.pdf' --limit 0

指定搜索模式:

bash
python3 -m po_file_search --config config.json search 'DCC1039S.pdf' --mode exact --limit 0

7. 启动 HTTP 服务

bash
python3 -m po_file_search --config config.json serve

后台启动示例:

bash
nohup env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json serve \
  > /tmp/po-file-search-server.log 2>&1 &

HTTP API 使用

健康检查

bash
curl http://192.168.88.20:18765/health

搜索文件

bash
curl -X POST http://192.168.88.20:18765/search_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"query":"DCC1039S.pdf","search_mode":"exact","limit":0}'

参数:

参数必填说明
query搜索关键词
limit返回数量,0 表示全部,不传则使用 max_results
search_mode搜索模式,不传则使用配置中的 search_mode
modesearch_mode 的别名
user_id审计用用户 ID

生成下载链接

bash
curl -X POST http://192.168.88.20:18765/send_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"file_id":21559,"channel":"link","user_id":"test-user"}'

参数:

参数必填说明
file_id搜索结果中的文件 ID
channellink 仅生成链接;dingtalk 通过 webhook 发送
recipient接收人或群 ID,审计用
user_id操作用户 ID,审计用

下载文件

浏览器打开返回的 download_url 即可下载。

LinuxOS 部署详细步骤

本节说明在 LinuxOS 上部署 po-file-search 的完整步骤。

1. 安装系统依赖

Debian / Ubuntu:

bash
sudo apt-get update
sudo apt-get install -y python3 python3-venv python3-pip cifs-utils curl

CentOS / Rocky Linux / RHEL:

bash
sudo yum install -y python3 python3-pip cifs-utils curl

说明:

依赖用途
python3运行程序
cifs-utils挂载群晖 SMB 共享目录
curl测试 HTTP API
SQLite FTS5Python 标准库 sqlite3 通常已包含,用于本地索引

检查 Python:

bash
python3 --version

2. 准备项目目录

进入项目目录:

bash
cd /opt/po-file-search

如果是从当前代码复制到 Linux,确保目录结构类似:

text
po-file-search/
  README.md
  config.example.json
  po_file_search/
  docs/
  data/

3. 准备配置文件

bash
cp config.example.json config.json

Linux 重点配置示例:

json
{
  "mounts": [
    {
      "name": "采购共享",
      "server": "192.168.1.26",
      "share": "X.artwork2",
      "mount_point_linux": "/mnt/synology/purchase",
      "mount_point_macos": "/Volumes/采购共享",
      "username": "cg-name_search",
      "password_env": "searchpassword",
      "readonly": true,
      "smb_version": "3.0"
    }
  ],
  "scan_roots": [
    {
      "name": "采购共享/artwork",
      "path_from_mount": "采购共享",
      "relative_path": "artwork"
    }
  ],
  "server": {
    "host": "0.0.0.0",
    "port": 18765
  },
  "download": {
    "base_url": "http://Linux服务器IP或域名:18765",
    "token_ttl_minutes": 30
  },
  "index": {
    "auto_full_sync_enabled": true,
    "full_sync_time": "23:23",
    "full_sync_on_startup": false
  },
  "logging": {
    "failure_log_file": "./logs/po-file-search-error.log"
  }
}

注意:

  • share 是 SMB 共享文件夹名,不是子目录。
  • 如果真实路径是 \192.168.1.26\X.artwork2rtwork,则:
  • share = X.artwork2
  • relative_path = artwork
  • download.base_url 必须配置为用户能访问的 Linux 服务器 IP 或域名,不要用 127.0.0.1

4. 设置群晖密码环境变量

如果配置里是:

json
"password_env": "searchpassword"

则 Linux 上执行:

bash
export searchpassword='你的群晖密码'

如果使用 systemd 部署,建议放到环境文件,例如:

bash
sudo mkdir -p /etc/po-file-search
sudo tee /etc/po-file-search/env >/dev/null <<'EOF'
searchpassword=你的群晖密码
EOF
sudo chmod 600 /etc/po-file-search/env

5. 挂载群晖 SMB

方式 A:程序执行挂载,适合测试

预览挂载命令:

bash
python3 -m po_file_search --config config.json mount --dry-run

执行挂载通常需要 root 权限:

bash
sudo -E python3 -m po_file_search --config config.json mount

-E 用于保留 searchpassword 环境变量。

方式 B:系统负责挂载,推荐生产

生产环境更推荐用 /etc/fstab 或 systemd mount 先挂载群晖,然后程序只读访问挂载目录。

示例凭证文件:

bash
sudo tee /etc/synology-credential >/dev/null <<'EOF'
username=cg-name_search
password=你的群晖密码
EOF
sudo chmod 600 /etc/synology-credential

手动测试挂载:

bash
sudo mkdir -p /mnt/synology/purchase
sudo mount -t cifs //192.168.1.26/X.artwork2 /mnt/synology/purchase   -o credentials=/etc/synology-credential,ro,vers=3.0,iocharset=utf8

检查挂载:

bash
mountpoint -q /mnt/synology/purchase && echo mounted
ls -la /mnt/synology/purchase
ls -la /mnt/synology/purchase/artwork

/etc/fstab 示例:

text
//192.168.1.26/X.artwork2 /mnt/synology/purchase cifs credentials=/etc/synology-credential,ro,vers=3.0,iocharset=utf8,_netdev,nofail 0 0

加载 fstab:

bash
sudo mount -a

6. 手动全量同步索引

首次部署后建议先手动全量同步一次:

bash
python3 -m po_file_search --config config.json index

成功后输出类似:

json
{"indexed": 92108}

7. 启动 HTTP 服务

前台启动:

bash
python3 -m po_file_search --config config.json serve

后台启动:

bash
nohup env searchpassword='你的群晖密码'   python3 -m po_file_search --config config.json serve   > /tmp/po-file-search-server.log 2>&1 &

健康检查:

bash
curl http://Linux服务器IP或域名:18765/health

预期返回:

json
{"ok": true}

8. 搜索测试

CLI 搜索:

bash
python3 -m po_file_search --config config.json search 'DCC1039S.pdf' --mode exact --limit 0

HTTP 搜索:

bash
curl -X POST http://Linux服务器IP或域名:18765/search_purchase_file   -H 'Content-Type: application/json'   -d '{"query":"DCC1039S.pdf","search_mode":"exact","limit":0}'

9. 生成下载链接测试

file_id 替换为搜索结果中的 ID:

bash
curl -X POST http://Linux服务器IP或域名:18765/send_purchase_file   -H 'Content-Type: application/json'   -d '{"file_id":21559,"channel":"link","user_id":"linux-test"}'

然后用返回的 download_url 在浏览器中下载。

10. systemd 服务示例

创建服务文件:

bash
sudo tee /etc/systemd/system/po-file-search.service >/dev/null <<'EOF'
[Unit]
Description=PO File Search Service
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
WorkingDirectory=/opt/po-file-search
EnvironmentFile=/etc/po-file-search/env
ExecStart=/usr/bin/python3 -m po_file_search --config config.json serve
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

启动:

bash
sudo systemctl daemon-reload
sudo systemctl enable po-file-search
sudo systemctl start po-file-search

查看状态:

bash
sudo systemctl status po-file-search
journalctl -u po-file-search -f

停止:

bash
sudo systemctl stop po-file-search

11. Linux 部署常见问题

问题可能原因处理方式
mount: bad usage 或找不到 cifs未安装 cifs-utils安装 cifs-utils
Permission denied挂载需要 root 权限使用 sudo -E 或系统挂载
环境变量未设置password_env 指定的环境变量不存在export searchpassword=... 或 systemd EnvironmentFile
下载链接打不开download.base_url 配成了 127.0.0.1 或防火墙未放行改为服务器 IP/域名,开放端口
搜索不到新文件本地索引未同步手动执行 python3 -m po_file_search --config config.json index 或等待每日全量同步
容器内挂载失败Docker 默认无挂载权限推荐宿主机挂载后 volume 只读映射

程序部署方式

方式一:本机直接运行

适合开发和 MVP 验证。

bash
cp config.example.json config.json
export searchpassword='你的群晖密码'
python3 -m po_file_search --config config.json mount
python3 -m po_file_search --config config.json index
python3 -m po_file_search --config config.json serve

方式二:后台运行

bash
nohup env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json serve \
  > /tmp/po-file-search-server.log 2>&1 &

停止:

bash
pkill -f 'python3 -m po_file_search --config config.json serve'

方式三:Docker 部署

bash
docker compose up -d --build

推荐生产方式:宿主机挂载群晖 SMB,容器通过只读 volume 读取挂载目录。

方式四:Linux 生产建议

  1. 使用只读群晖账号。
  2. 使用 systemd/fstab 或运维脚本完成 SMB 挂载。
  3. 使用本服务运行 HTTP API。
  4. 通过 index.auto_full_sync_enabledindex.full_sync_time 控制每日全量同步。
  5. download.base_url 配置为内网可访问 IP 或 HTTPS 域名。

索引同步策略

当前暂行方案:

text
每天 23:23 全量同步一次,可配置
不做后台增量同步
支持管理员手动全量同步

原因:当前 92,108 个文件实测:

同步类型耗时
全量同步约 289 秒
无变化目录级增量同步约 291 秒

结论:瓶颈主要是 SMB 目录遍历/扫描,不是 SQLite 写入。因此后台增量同步暂时删除,避免白天频繁压 NAS。

手动全量同步:

bash
python3 -m po_file_search --config config.json index

调整每日同步时间:

json
"index": {
  "auto_full_sync_enabled": true,
  "full_sync_time": "23:23",
  "full_sync_on_startup": false
}

关闭每日同步:

json
"index": {
  "auto_full_sync_enabled": false,
  "full_sync_time": "23:23",
  "full_sync_on_startup": false
}

常用命令

bash
# 语法检查
python3 -m compileall po_file_search tests

# 检测系统
python3 -m po_file_search --config config.json detect-os

# 预览挂载命令
python3 -m po_file_search --config config.json mount --dry-run

# 确保挂载或复用已有挂载
python3 -m po_file_search --config config.json mount

# 手动全量同步索引
python3 -m po_file_search --config config.json index

# 搜索文件
python3 -m po_file_search --config config.json search '关键词'

# 搜索并返回全部结果
python3 -m po_file_search --config config.json search '关键词' --limit 0

# 指定搜索模式
python3 -m po_file_search --config config.json search '关键词' --mode exact

# 启动 HTTP API 服务
python3 -m po_file_search --config config.json serve

# 查看失败运行日志
tail -f logs/po-file-search-error.log

# Docker 启动
docker compose up -d --build

项目结构

text
po-file-search/
  README.md
  AGENTS.md
  config.example.json
  requirements.txt
  Dockerfile
  docker-compose.yml
  data/
    .gitkeep
  docs/
    PRD.md
    DatabaseSchema.md
  po_file_search/
    __init__.py
    __main__.py
    audit.py
    cli.py
    config.py
    downloads.py
    indexer.py
    mounter.py
    platforms.py
    scheduler.py
    searcher.py
    sender.py
    server.py
  tests/
    test_basic.py

文档

注意事项

  1. share 必须是 SMB 共享文件夹名,不是子目录。
  2. 如果要扫描共享文件夹下的子目录,用 scan_roots[].relative_path
  3. password_env 是环境变量名,不是密码明文。
  4. 下载链接发给用户时不要使用 127.0.0.1
  5. macOS 本地调试推荐先用 Finder 挂载 SMB。
  6. 搜索结果中的真实 full_path 只用于服务内部,不应直接暴露给普通用户。
  7. 当前钉钉能力是 webhook 消息骨架,不是完整钉钉内部应用文件上传。
  8. 当前不做后台增量同步。

后续增强

  • 群晖 File Station API / Universal Search PoC,减少 SMB 扫描。
  • 手动刷新指定目录。
  • 业务上传事件触发局部刷新。
  • 企业级权限系统接入。
  • 钉钉内部应用文件上传/单聊发送。
  • 文件正文搜索。

共享文件范围变更操作指南

当需要调整本服务允许搜索的群晖目录范围时,通常只需要修改 config.json 中的 scan_roots,不需要修改 servershare

例如要从原范围:

text
\\192.168.1.26\X.artwork2\artwork

变更为新范围:

text
\\192.168.1.26\X.artwork2\1.包材印刷品\01-包装印刷品

对应关系是:

text
server = 192.168.1.26
share = X.artwork2
relative_path = 1.包材印刷品/01-包装印刷品

注意:

  • share 仍然是 SMB 共享文件夹名 X.artwork2
  • 子目录写到 scan_roots[].relative_path
  • Windows 路径中的 \ 在 JSON 配置里建议写成 /

推荐变更步骤

1. 修改 config.json

把原配置:

json
"scan_roots": [
  {
    "name": "采购共享/artwork",
    "path_from_mount": "采购共享",
    "relative_path": "artwork"
  }
]

改成:

json
"scan_roots": [
  {
    "name": "采购共享/包装印刷品",
    "path_from_mount": "采购共享",
    "relative_path": "1.包材印刷品/01-包装印刷品"
  }
]

不要把 share 改成完整路径。下面这种写法是错误的:

json
"share": "X.artwork2/1.包材印刷品/01-包装印刷品"

2. 确认新目录存在

macOS:

bash
ls -la "/Volumes/X.artwork2/1.包材印刷品/01-包装印刷品"

LinuxOS:

bash
ls -la "/mnt/synology/purchase/1.包材印刷品/01-包装印刷品"

3. 清空旧索引

因为 scan_roots[].name采购共享/artwork 改成了 采购共享/包装印刷品,旧 root_name 下的索引不会被新同步自动清理。

为了保证索引范围干净,推荐直接删除旧索引库:

bash
rm -f data/file_index.sqlite data/file_index.sqlite-*

4. 重新全量同步索引

bash
python3 -m po_file_search --config config.json index

成功后会输出类似:

json
{"indexed": 12345}

5. 重启服务

如果使用 systemd:

bash
sudo systemctl restart po-file-search

如果手动后台运行:

bash
pkill -f 'python3 -m po_file_search --config config.json serve'
nohup env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json serve \
  > /tmp/po-file-search-server.log 2>&1 &

6. 验证服务和搜索

健康检查:

bash
curl http://你的服务器IP或域名:18765/health

搜索验证:

bash
python3 -m po_file_search --config config.json search '新目录中的文件关键词' --limit 10

HTTP 搜索验证:

bash
curl -X POST http://你的服务器IP或域名:18765/search_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"query":"新目录中的文件关键词","limit":10}'

共享文件范围变更:macOS 与 LinuxOS 差异说明

本节补充实际变更共享范围时,macOS 和 LinuxOS 的操作差异。推荐在执行范围变更前先停止服务,避免 SQLite 索引库被运行中的服务进程占用。

通用变更流程

不论 macOS 还是 LinuxOS,推荐流程都是:

text
1. 停止 po-file-search 服务
2. 确认新目录在挂载路径下可访问
3. 修改 config.json 的 scan_roots
4. 清空旧 SQLite 索引文件
5. 手动执行一次全量同步
6. 启动服务
7. 健康检查、搜索验证、下载验证

为什么要先停止服务

如果服务还在运行,可能持有旧的 SQLite 数据库文件。此时删除或重建索引,可能出现:

text
sqlite3.OperationalError: attempt to write a readonly database
sqlite3.OperationalError: disk I/O error

因此变更范围前建议先停止服务。

macOS 操作步骤

1. 停止服务

如果是手动后台运行:

bash
if [ -f /tmp/po-file-search-server.pid ]; then
  kill $(cat /tmp/po-file-search-server.pid) 2>/dev/null || true
fi
pkill -f 'python3 -m po_file_search --config config.json serve' || true

2. 确认 Finder/SMB 挂载

macOS 推荐先在 Finder 里连接:

text
smb://192.168.1.26/X.artwork2

程序会复用 Finder 挂载路径,例如:

text
/Volumes/X.artwork2

检查新目录:

bash
ls -la "/Volumes/X.artwork2/1.包材印刷品/01-包装印刷品"

如果刚调整过群晖权限但命令行看不到目录,请在 Finder 中断开 X.artwork2 后重新连接,再重试。

3. 修改 config.json

json
"scan_roots": [
  {
    "name": "采购共享/包装印刷品",
    "path_from_mount": "采购共享",
    "relative_path": "1.包材印刷品/01-包装印刷品"
  }
]

4. 清空旧索引

macOS 默认 zsh 对不存在的通配符会报错,所以推荐用 Python 删除:

bash
python3 - <<'PY'
from pathlib import Path
for p in Path('data').glob('file_index.sqlite*'):
    print('remove', p)
    p.unlink()
PY

不要使用不安全的通配符命令依赖,例如在 zsh 中直接执行:

bash
rm -f data/file_index.sqlite data/file_index.sqlite-*

当通配符没有匹配时可能报错。

5. 重新全量同步

bash
/usr/bin/time -p env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json index

示例结果:

text
{"indexed": 27471}
real 48.05

6. 启动服务

bash
nohup env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json serve \
  > /tmp/po-file-search-server.log 2>&1 &
echo $! > /tmp/po-file-search-server.pid

7. 验证

健康检查:

bash
curl http://192.168.88.20:18765/health

搜索验证:

bash
python3 -m po_file_search --config config.json search 'Thumbs.db' --mode exact --limit 5

生成下载链接:

bash
curl -X POST http://192.168.88.20:18765/send_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"file_id":8,"channel":"link","user_id":"scope-change-test"}'

下载验证:

bash
curl -L -o /tmp/test-download.pdf '返回的 download_url'
file /tmp/test-download.pdf

LinuxOS 操作步骤

LinuxOS 的核心区别是:通常不依赖 Finder,而是由系统或程序挂载 SMB 到 mount_point_linux

1. 停止服务

如果使用 systemd:

bash
sudo systemctl stop po-file-search

如果手动后台运行:

bash
pkill -f 'python3 -m po_file_search --config config.json serve' || true

2. 确认 SMB 已挂载

假设 Linux 挂载点为:

text
/mnt/synology/purchase

检查挂载:

bash
mountpoint -q /mnt/synology/purchase && echo mounted

如果未挂载,可用系统挂载或程序挂载:

bash
sudo -E python3 -m po_file_search --config config.json mount

3. 确认新目录存在

bash
ls -la "/mnt/synology/purchase/1.包材印刷品/01-包装印刷品"

如果目录不存在,请检查:

  • 群晖权限是否给到 Linux 使用的账号。
  • mounts[].share 是否仍为 X.artwork2
  • relative_path 是否写错。
  • Linux 是否挂载了正确的群晖共享。

4. 修改 config.json

同 macOS:

json
"scan_roots": [
  {
    "name": "采购共享/包装印刷品",
    "path_from_mount": "采购共享",
    "relative_path": "1.包材印刷品/01-包装印刷品"
  }
]

5. 清空旧索引

Linux bash 下可以执行:

bash
rm -f data/file_index.sqlite data/file_index.sqlite-*

也可以使用跨平台 Python 方式:

bash
python3 - <<'PY'
from pathlib import Path
for p in Path('data').glob('file_index.sqlite*'):
    print('remove', p)
    p.unlink()
PY

6. 重新全量同步

bash
/usr/bin/time -p env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json index

7. 启动服务

systemd:

bash
sudo systemctl start po-file-search

或手动:

bash
nohup env searchpassword='你的群晖密码' \
  python3 -m po_file_search --config config.json serve \
  > /tmp/po-file-search-server.log 2>&1 &

8. 验证

健康检查:

bash
curl http://Linux服务器IP或域名:18765/health

搜索验证:

bash
curl -X POST http://Linux服务器IP或域名:18765/search_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"query":"新目录中的文件关键词","limit":10}'

生成下载链接验证:

bash
curl -X POST http://Linux服务器IP或域名:18765/send_purchase_file \
  -H 'Content-Type: application/json' \
  -d '{"file_id":实际文件ID,"channel":"link","user_id":"scope-change-test"}'

本次实际变更结果示例

本次从:

text
\\192.168.1.26\X.artwork2\artwork

变更为:

text
\\192.168.1.26\X.artwork2\1.包材印刷品\01-包装印刷品

最终配置:

json
"scan_roots": [
  {
    "name": "采购共享/包装印刷品",
    "path_from_mount": "采购共享",
    "relative_path": "1.包材印刷品/01-包装印刷品"
  }
]

重新索引结果:

text
indexed: 27471
耗时: 约 48 秒

服务验证:

json
{"ok": true}

下载链路验证:

text
HTTP/1.0 200 OK
Content-Type: application/pdf