# ImageFind ImageFind 是面向 fnOS/NAS 的私有 AI 媒体库。它提供类似视频网站的浏览、在线播放、上传、 下载和资料管理体验,可索引本地目录、通用 WebDAV、AList 直连库与 AList 加密库,并通过 中英文关键词、番号/演员/标签、OCR/字幕/音频语音、查询图片和已命名人物定位到视频中的具体时间片段。 > 当前版本为可侧载验证的 `0.5.45`。应用声明 fnOS Python 3.12 和 PostgreSQL 依赖,核心运行环境离线安装, > PyTorch、OpenVINO 和各类 AI 依赖在安装对应模型时按需下载;AI 模型权重可在“设置”中 > 按组件下载、通过离线脚本准备或上传完整模型包。 > 上传、移动和回收站操作只会对明确启用写入的资料库生效。 ## 本地开发 要求 Python 3.11–3.13、Node.js 20+、FFmpeg/FFprobe,以及启用 `vector`、`pg_trgm` 扩展的 PostgreSQL 17。业务数据、全文索引和语义向量均由 PostgreSQL 保存,不再使用 SQLite 或 Qdrant 作为运行数据库。启动前通过 `IMAGEFIND_POSTGRES_CONF` 指向 PostgreSQL 客户端配置文件。 ```bash python3 -m venv .venv . .venv/bin/activate pip install -e '.[dev]' npm install --prefix frontend npm run build --prefix frontend IMAGEFIND_DATA_DIR="$PWD/.data" imagefind ``` 打开 `http://127.0.0.1:8765`。本地开发时首次访问需创建不少于 10 个字符的管理员密码; fnOS 安装包会在安装向导中完成这一步。 UI 回归使用 Playwright。Linux 截图机必须安装 `fonts-noto-cjk`,缺少中文字体时测试会直接失败, 避免把方框字保存为视觉基线: ```bash cd frontend npm run test:ui ``` 飞牛真机测试使用独立配置,不在仓库保存 NAS 密码或浏览器会话。先把已登录管理员浏览器的 Playwright `storageState` 保存到仓库外,并准备一个只放测试文件的可写资料库: ```bash IMAGEFIND_FNOS_BASE_URL="https://NAS地址/app/imagefind/" \ IMAGEFIND_FNOS_STORAGE_STATE="/安全目录/fnos-storage-state.json" \ IMAGEFIND_E2E_SOURCE_NAME="ImageFind E2E" \ npm run test:ui:fnos ``` 写入测试只清理本次创建且以 `E2E-` 开头的文件,不会操作其他媒体。 常用配置: | 环境变量 | 默认值 | 说明 | | --- | --- | --- | | `IMAGEFIND_DATA_DIR` | `./data` | 数据库、缩略图、模型和缓存目录 | | `IMAGEFIND_HOST` / `IMAGEFIND_PORT` | `127.0.0.1` / `8765` | 监听地址与端口 | | `IMAGEFIND_POSTGRES_CONF` | 数据目录上级的 `postgres-client.conf` | PostgreSQL 客户端配置文件 | | `IMAGEFIND_DB_POOL_MIN` / `IMAGEFIND_DB_POOL_MAX` | `1` / `8` | PostgreSQL 进程内连接池上下限 | | `IMAGEFIND_DB_POOL_TIMEOUT` | `5` | 等待可用数据库连接的最长秒数 | | `IMAGEFIND_EMBEDDING_BACKEND` | `auto` | `auto`、`openvino`、`torch` 或测试用 `hash` | | `IMAGEFIND_MODEL_BUNDLE_URL` | 空 | 可选:用自建模型包代替默认官方仓库 | | `IMAGEFIND_MODEL_BUNDLE_SHA256` | 空 | 自建模型包的 SHA-256 | | `IMAGEFIND_MODEL_HF_ENDPOINT` | `https://huggingface.co` | Hugging Face 地址,可改为可信镜像 | | `IMAGEFIND_PIP_INDEX_URL` | `https://pypi.tuna.tsinghua.edu.cn/simple` | AI 运行依赖使用的 PyPI 主镜像 | | `IMAGEFIND_PYTORCH_INDEX_URL` | `https://download.pytorch.org/whl/cpu` | PyTorch CPU 专用轮子源,可在设置页留空或修改 | | `IMAGEFIND_MODEL_UPLOAD_GB` | `10` | 手动上传模型包上限(GiB) | | `IMAGEFIND_FFMPEG_PATH` | `ffmpeg` | FFmpeg 可执行文件 | | `IMAGEFIND_REMOTE_MAX_CONNECTIONS` | `3` | WebDAV 扫描、索引和播放的全局并发上限 | | `IMAGEFIND_PREVIEW_CACHE_GB` | `5` | HLS 兼容预览缓存上限(GiB) | | `IMAGEFIND_UPLOAD_CHUNK_MB` | `16` | 浏览器上传分块大小(MiB) | | `IMAGEFIND_UPLOAD_STAGING_GB` | `100` | 未完成上传的暂存配额(GiB) | | `IMAGEFIND_UPLOAD_RESERVE_GB` | `5` | 创建上传任务后仍需保留的磁盘空间(GiB) | | `IMAGEFIND_TRASH_RETENTION_DAYS` | `30` | 回收站记录的默认保留天数 | ## 远程媒体库与加密 通用 WebDAV 和 AList 均在“资料库 → 添加资料库”中配置。扫描器使用递归 `Depth: 1 PROPFIND`,以 ETag、大小和修改时间识别变更。服务端不支持 Range 时,索引或播放可能退化为 完整文件传输,建议先在小目录验证带宽占用。 AList 有两种互斥模式: - **AList 直连**:文件和文件名以明文保存在远端。播放接口向浏览器返回 AList 提供的 302 临时直链,视频流量通常不经过 NAS;直链解析失败时自动回退到认证代理。 - **AList 加密**:使用 `rclone crypt` 加密文件内容、文件名和目录名。应用优先使用 fnOS/系统 已安装的兼容 rclone,缺失时再下载经过版本与 SHA-256 固定的私有副本。上传、 播放、下载、抽帧和 AI 索引均由 NAS 即时解密,因此不能再使用 302 直链,带宽会经过 NAS。 ImageFind 每 60 秒安全核验上次异常退出遗留的 rclone 实例。只有进程身份和应用目录匹配、连续 3 次没有活动连接或 I/O 且观察满 2 分钟时才会自动回收;身份不一致的进程只标记为“待处理”, 不会强制终止。也可以在“设置 → 任务与偏好 → 资源保护”中执行一次立即安全核验。 创建加密库时浏览器会自动下载一次 `imagefind-vault-recovery-*.json`。必须把它存放在密码管理器 或离线介质中;它含有解密所需密钥,但不包含 AList 登录密码。重装后选择“AList 加密 → 从恢复 文件导入”,再输入当前 AList 密码,即可重新挂载原有密文。丢失恢复文件和应用内部数据后, 远端密文无法恢复。 AI 对加密库仍完整可用:NAS 读取并解密所需片段后执行抽帧、OCR、人物与向量分析,远端不会 得到明文索引。代价是首次扫描和播放都需要 NAS 与网盘之间的传输。 也可以先在 fnOS 中挂载 WebDAV,再作为本地目录添加。这种模式通常拥有更好的断线重连和 系统级缓存能力。 ## 上传、下载与文件管理 浏览器上传采用 16 MiB 分块,每块带 SHA-256 校验,单文件 API 上限为 200 GiB,前端按当前 产品约束提示 100 GiB。文件会先完整暂存在应用私有数据目录,再由独立后台通道传输到目标库; 上传过程中断后,服务端会保留已接收分块用于续传;上传中心分别显示“上传至 ImageFind”、 “转存 WebDAV/AList”和“校验加入媒体库”三个阶段,失败的目标传输可直接重试。创建任务 时若无法满足暂存配额或 5 GiB 安全余量,接口会拒绝任务而不是写满系统盘。 开启飞牛“直接 Web/API 访问”后,可在“设置 → 账户与 API”启用 WebDAV 后台上传。标准 WebDAV 客户端必须连接 `http://NAS_IP:8765/webdav/`(端口以应用配置为准),用户名固定为 `imagefind`,密码使用页面创建且只显示一次的专用 REST API Token。飞牛 5666 统一网页网关 不转发标准 DAV 认证和方法,不能作为 WebDAV 服务器地址。上传路径的第一层目录会自动映射为 同名合集,后续目录映射为可任意嵌套的章节或小节;已入库视频可浏览和读取。服务端兼容普通 `PUT`、临时文件加 `MOVE`、`Content-Range` 与 `Upload-Offset` 续传。完整上传会在接收时增量 校验且不再二次扫描暂存文件;客户端因响应丢失重传相同路径和内容时会幂等返回,不会再生成 `(2)`、`(3)` 副本。文件接收完成到媒体入库之间,`HEAD`/`PROPFIND` 仍会返回已接收状态, 避免客户端因短暂 404 重新上传。 本地目录默认只读,必须在资料库卡片上主动启用写入;AList 资料库默认可写。文件面板支持浏览、 新建目录、移动/重命名和移入回收站。回收站内可恢复或永久删除;卸载应用不会删除共享目录、 已授权目录或远端库中的源视频。播放接口支持 HTTP Range;AList 直连下载/播放可使用 302, 其余来源经 ImageFind 认证代理读取,下载会保留原文件名。 后台任务按 AI 识别、上传转存、后台下载和来源扫描分为四条独立通道,各自保持单并发。这样 大文件上云不会阻塞索引,同时避免低功耗 NAS 因多个 AI 或磁盘任务并发而耗尽内存。 ## 自定义分类与 AI 标签 “分类与标签”支持创建任意分类组,例如类型、场景、服装、片商或自定义收藏维度。每个组可设置为 单选或多选;影片资料编辑和批量赋值都会遵守该约束。标签可以移动、合并和删除,旧版字符串标签 在升级时会自动迁移到“未分组”。 每个标签都可以独立启用一种 AI 建议方式: - **画面语义**:使用已生成的 CLIP 画面向量与自定义描述做零样本匹配,适合能从画面判断的场景、 服装和视觉类型。 - **文本规则**:匹配文件名、路径、影片资料、OCR 和文本字幕,适合番号、片商、系列或明确关键词。 AI 结果只会进入“待确认建议”,不会直接覆盖人工标签。索引新视频完成后会自动排队分析已启用 AI 的标签,也可从影片资料或分类页手动重跑。服务启动、状态检查和仅浏览页面都不会加载模型; 模型仍然只在实际索引、图片/语义检索或手动分析需要时延迟初始化。自定义标签的准确度取决于描述、 阈值和素材,不能可靠由画面判断的抽象标签应使用文本规则或保持手动。 ## 系统备份与恢复 “设置 → 系统备份与恢复”可下载单一 `.ifbackup` 加密文件。每个备份都包含本地、WebDAV 与 AList 来源配置、登录凭据和 rclone crypt 密钥;完整范围还包含影片身份、手工资料、分类与标签、 演员、收藏、喜欢、播放进度、偏好和模型/运行依赖镜像配置。备份密码独立于管理员密码,长度为 10–256 个 字符,不会持久化;忘记密码后无法解密。 恢复前需在新系统创建管理员并登录。只有没有来源、影片、AI 人物、演员或用户标签的空系统可以 恢复。当前管理员、会话和 API Token 不会被导入或覆盖;媒体文件、模型、缩略图、OCR、人物聚类、 向量与其他可重建索引也不进入备份。恢复后影片先处于不可播放的待扫描状态,启用的来源会自动排队 扫描,并按来源 ID 与源文件键重新关联原影片 ID。 ## fnOS 视频目录 安装或升级后,fnOS 会创建共享目录 `imagefind/videos`,应用运行用户会自动获得访问权限。 可以把待索引视频放入该目录,再在 ImageFind 中将它添加为本地资料库。 如果视频已经位于其他 NAS 目录,无需搬动文件:在 fnOS 的 ImageFind 应用设置中授权这些 目录,再在 ImageFind 中添加对应路径。`imagefind/videos` 是便于直接导入文件的应用共享目录, 授权目录可用于只读索引已有媒体库;只有在 ImageFind 内明确启用写入后,文件管理和上传操作 才允许修改该目录。AI 索引过程本身不会修改源视频。 fnOS 全新安装时必须输入两次 ImageFind 管理员密码。升级向导中的密码可以留空以保留 现有密码,也可以填写两次来初始化或重置密码。卸载向导默认保留应用数据;勾选清除后会 删除数据库、索引、缓存、模型、凭据和日志,但不会删除 `imagefind/videos`、用户授权目录 或 WebDAV 上的任何源视频。 ## 播放与 HLS 兼容预览 搜索结果优先通过认证后的 Range 接口直接播放,并跳转到命中时间。浏览器不支持源视频的 封装格式或编码时,前端会自动请求命中点附近的 HLS 兼容预览。预览默认最长 180 秒,优先 使用 Intel VAAPI,随后尝试 OpenH264 或 libx264;缓存达到上限后按最久未使用顺序清理。 生成兼容预览会消耗额外 CPU/GPU 和临时空间。远程源还会读取对应时间段;WebDAV 服务端若 忽略 Range,可能退化为完整文件传输。 ## 模型包约定 fnOS 安装包包含 Web 服务与 PostgreSQL 客户端运行依赖,数据库和 pgvector 由声明的 `nxsir.postgresql` fnOS 依赖应用提供;OpenVINO、PyTorch 等**推理运行时** 与体积更大的**模型权重**不随包发布,而是在首次安装对应 AI 组件时按需下载。设置页的在线安装 会从 Hugging Face 下载画面/多语言模型及 Whisper small,从 Open Model Zoo 下载人物模型。Whisper 会导出为 OpenVINO FP16;安装后以单任务串行方式自动补齐旧影片的带时间轴语音索引。应用启动 和状态检查都不会加载模型到内存,只有搜索或索引实际需要时才延迟初始化。 语音识别默认采用“中文优先 + 准确率优先”:先读取音轨语言,再从最多 3 个高语音占比片段检测, 无法判断时使用中文,并以 5-beam 解码。每个时间片段会经过字符损坏、异常文字脚本、重复输出、 无语音幻觉和文本密度校验,低质量片段不会进入搜索。设置页可切换智能检测、固定中文和三档质量, 也可扫描存量旧转写;明显低质量的视频会自动排队重新识别。 “设置 → AI 与网络”可分别配置 Hugging Face、PyPI 和 PyTorch CPU 下载源。PyPI 默认使用已直连 验证的清华镜像;HTTP/HTTPS 代理有独立开关,关闭后保留加密凭据但所有 AI 下载直接连接,启用后 才用于模型与运行依赖下载。pip 安装期间每隔约 5 秒更新阶段和等待时间,任务重启排队时会重置为 0%,避免把等待中的组件误显示为卡住。 无法直接访问官方仓库时,可以在其他电脑准备下述 ImageFind 模型包,再通过设置页“上传模型包” 手动安装。服务端以流式方式写入应用数据目录,不会先占用 fnOS 的 `/tmp`;安装前会检查压缩包 路径、解压体积和必需目录,并以原子方式替换现有模型。 模型包是 `.tar.gz`,根目录必须包含 `manifest.json` 以及: ```text visual/image/ # clip-ViT-B-32 SentenceTransformer 模型 visual/text/ # clip-ViT-B-32-multilingual-v1 文本模型 ocr/ # 可选:det.onnx、rec.onnx、cls.onnx faces/ # 可选:detector.xml/.bin、reidentification.xml/.bin audio/ # 可选:Whisper small OpenVINO FP16 模型和处理器配置 ``` 视觉模型变化后需要重建画面向量;应用不会静默切换向量空间。 生成模型包不会修改源模型目录: ```bash python3 scripts/build-model-bundle.py /path/to/models dist/imagefind-models.tar.gz --version 1 ``` ## 构建 fnOS 安装包 发布构建只面向 x86_64 fnOS,需要官方 `fnpack`、Node.js、带 Hatchling/Pillow 的构建环境, 以及 `.fnos-wheel-cache/python312` 中完整的 Python 3.12 核心 wheelhouse。fnOS 端声明依赖 `python312`;AI 推理依赖不会进入 FPK,而是在安装对应模型时按锁文件下载。发布包只内置: ```text vendor/libOpenCL.so.1 ``` 安装依赖并构建: ```bash python3 -m venv .release-venv .release-venv/bin/pip install -e '.[dev]' ./scripts/build-fnos.sh ``` 默认输出为 `dist/imagefind-0.5.45-x86_64.fpk`。FFmpeg/FFprobe 与 rclone 在运行时优先使用 兼容的系统版本,缺失时按固定版本和 SHA-256 动态下载。0.5.45 不读取或迁移旧 SQLite 数据库; 安装时直接初始化 PostgreSQL schema,升级脚本不会擅自删除用户数据或旧 runtime 目录。 当前仓库中的 manifest、权限和资源声明是 侧载模板;正式发布前必须用目标 fnOS 版本配套的官方 `fnpack` 校验,并在真实 N100 设备上 验证安装/升级向导、启停、GPU 权限、端口跳转和两种卸载数据行为。 解出安装包内的 `app.tgz` 后,可以在 x86_64 Linux 构建机上运行制品级冒烟: ```bash ./scripts/smoke-fnos-package.sh /path/to/extracted/app /tmp/imagefind-smoke 18765 ``` ## API 登录后在“设置”创建独立 API Token。请求使用 `Authorization: Bearer `。 OpenAPI 文档位于 `/api/docs`,主要入口是: - `POST /api/v1/query-images` - `POST /api/v1/search` - `POST /api/v1/uploads` 与 `/api/v1/uploads/{id}/chunks/{index}` - `POST /api/v1/models/install`、`POST /api/v1/models/upload` - `PATCH /api/v1/models/config`、`POST /api/v1/models/proxy/test`、`DELETE /api/v1/models/{component}` - `/api/v1/sources`、`/api/v1/files`、`/api/v1/trash` - `POST /api/v1/sources/alist/restore` - `GET/POST /api/v1/backups`、`GET /api/v1/backups/{id}/download`、`POST /api/v1/backups/restore` - `/api/v1/tag-groups`、`/api/v1/tags`、`POST /api/v1/videos/tags/bulk` - `/api/v1/tag-suggestions`、`POST /api/v1/tag-suggestions/analyze`、`POST /api/v1/tag-suggestions/decide` - `PATCH /api/v1/videos/{video_id}/state` - `GET/PATCH /api/v1/speech/config`、`POST /api/v1/speech/reconcile` - `GET /api/v1/videos/{video_id}/transcript`、`POST /api/v1/videos/{video_id}/transcript/reindex` - `/api/v1/profile`、`/api/v1/series`、`POST /api/v1/videos/series/bulk` - `GET /api/v1/storage/usage` - `/api/v1/preferences`、`/api/v1/activity`、`GET /api/v1/events` - `/api/v1/jobs`、`/api/v1/people`、`/api/v1/actors` - `GET /api/v1/system/diagnostics` - `POST /api/v1/system/resources/rclone/reconcile` ## 隐私与范围 - 视频可位于本机或用户配置的远端;关键帧、人脸特征、文字、向量和密钥只保存在本机。 - WebDAV 凭据通过应用主密钥加密;主密钥文件权限为 `0600`。 - 首版只支持管理员;fnOS 提供稳定的用户身份 API 后再接入系统多用户 ACL。 - 支持文本字幕、烧录在画面内的文字和带时间轴的 Whisper 语音转写;不包含 PGS/VobSub 图片字幕。