feat: add ImageFind application and release pipelines
This commit is contained in:
@@ -0,0 +1,284 @@
|
||||
# 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 <token>`。
|
||||
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 图片字幕。
|
||||
Reference in New Issue
Block a user