# triple-modal-search
**Repository Path**: kml/triple-modal-search
## Basic Information
- **Project Name**: triple-modal-search
- **Description**: Triple-modal similarity search: image / text / audio retrieval with SigLIP, BGE and ECAPA embeddings + FAISS
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-08-26
- **Last Updated**: 2026-08-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 🖼️📝🎤 三模态分离检索系统(Triple-Modal Search)
**图搜图 · 文搜文 · 音搜音 —— 三个完全隔离的向量空间中的相似度检索。**
> English version: [README.md](README.md)
本项目是一个**完全本地化、隐私安全**的相似内容搜索引擎:从你自己的素材库中,找到与查询最相似的图片、文本和音频。
每个模态由独立的深度学习嵌入模型 + FAISS 向量索引支撑,三个空间互不干扰。
| 模态 | 检索方式 | 嵌入模型 | 向量维度 |
|------|---------|---------|---------|
| 🖼️ 图像 | 上传图片 → 搜相似图片 | [SigLIP](https://huggingface.co/google/siglip-so400m-patch14-384) (so400m, 384px) | 1152 |
| 📝 文本 | 输入语句 → 搜相似文本 | [BGE-base-zh-v1.5](https://huggingface.co/BAAI/bge-base-zh-v1.5)(中文优化) | 768 |
| 🎤 语音 | 上传音频/录音 → 搜相似音频 | [ECAPA-TDNN](https://huggingface.co/speechbrain/spkrec-ecapa-voxceleb)(SpeechBrain 声纹) | 1024 |
## ✨ 特性
- **三独立面板**:图像 / 文本 / 语音检索完全隔离,互不干扰
- **相似度阈值可调**:每次查询可调阈值,返回 Top-K 结果
- **双界面**
- 🌐 **Web 前端**:纯手写原生 JS 前端(检索 / 模型管理 / 仪表盘 / 存储后端切换)
- 💻 **CLI 命令行**:功能完整的命令行工具,便于脚本化与自动化
- 🧪 另附 Gradio WebUI(`main.py`)
- **可插拔存储后端**:本地 FAISS / Redis / MySQL / Elasticsearch,通过 `data/storage_config.json` 一键切换
- **GPU 加速**:FP16 半精度推理,无 GPU 时自动回退 CPU
- **完全本地离线**:模型缓存于磁盘,无需 API Key,数据不出本机
- **可迁移**:所有路径基于项目根目录相对定位;模型可打包,解压后 `restore.py` 一键恢复
- **一键启动**:`start.py` 自动完成建虚拟环境 → 装依赖 → 下模型 → 启动服务 → 打开浏览器
## 🏗️ 架构
```
┌─────────────────────────────────────────────┐
│ Web 前端 (原生 JS) │
│ 图像页 · 文本页 · 语音页 · 仪表盘 │
└──────────────────────┬──────────────────────┘
│ REST /api/*
┌──────────────────────▼──────────────────────┐
│ FastAPI 后端 (api_server.py) │
│ Gradio WebUI (main.py) │
│ CLI 命令行 (cli.py) │
└──────────────────────┬──────────────────────┘
┌────────────────┬─────────────┼──────────────┬────────────────┐
▼ ▼ ▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ SigLIP │ │ BGE │ │ ECAPA │ │ FAISS │ │ Redis / │
│ (图像) │ │ (文本) │ │ (语音) │ │ 索引 │ │ MySQL/ES │
└───────────┘ └───────────┘ └──────────┘ └──────────┘ └──────────┘
嵌入向量 嵌入向量 嵌入向量 向量存储
```
数据流:素材放入 `data/{image,text,audio}_lib` → 扫描入库(模型提向量 → FAISS 索引)→ 查询(上传/输入/录音)
→ 按相似度返回排序结果。
## 🚀 快速开始
### 环境要求
- Python **3.9+**
- 约 6 GB 磁盘空间(模型:SigLIP ~2.2 GB、BGE ~1.1 GB、ECAPA ~0.2 GB)
- 可选:NVIDIA GPU + CUDA(无 GPU 也可用 CPU 模式,速度较慢)
### 安装与启动
```bash
# 一键启动(自动建虚拟环境、装依赖、下模型、启动服务、打开浏览器)
python start.py
# 或手动安装
pip install -r requirements.txt
python api_server.py # FastAPI + Web 前端,地址 http://127.0.0.1:7860
# python main.py # 或使用 Gradio WebUI
```
### 首次使用
1. 将素材放入素材库目录:`data/image_lib/`、`data/text_lib/`(`.txt`)、`data/audio_lib/`
2. 在 Web 界面点击「扫描导入」,或运行 `python cli.py scan`
3. 开始检索!上传图片 / 输入语句 / 上传或录制音频
## 💻 CLI 用法
`cli.py` 仅使用 Python 标准库(argparse),零额外依赖。
```bash
# 查看系统状态:库规模、设备、存储后端、模型缓存情况
python cli.py status
# 扫描素材库并导入新文件(递归、自动去重)
python cli.py scan # 全部模态
python cli.py scan --modality image # 仅图像
python cli.py scan --folder 子目录 # 仅指定子文件夹
# 相似度检索
python cli.py search image query.jpg # 图搜图
python cli.py search text "深度学习" # 文搜文
python cli.py search audio query.wav # 音搜音
python cli.py search image q.jpg --top-k 10 --threshold 0.8 --json
# 手动录入文本
python cli.py add text "要入库的文本"
# 清空索引(带确认)
python cli.py clear image --yes
# 启动 Web 服务
python cli.py serve # FastAPI + 前端(默认)
python cli.py serve --webui # Gradio WebUI
# 模型管理
python cli.py models # 查看当前模型
python cli.py models --set image google/siglip-base-patch16-224 # 切换模型
# 预下载模型(适合离线环境准备)
python cli.py download --modality all
```
### JSON 输出
`search` 命令加 `--json` 即可输出机器可读结果:
```bash
python cli.py search text "机器学习" --json
```
## 📡 REST API(端口 7860)
| 方法 | 端点 | 说明 |
|------|------|------|
| `POST` | `/api/image/search` | 上传图片 → 检索相似图片 |
| `POST` | `/api/image/scan` | 扫描 `image_lib` 导入新图片 |
| `POST` | `/api/image/upload` | 直接上传图片入库 |
| `GET` | `/api/image/count` | 图像库总数 |
| `DELETE` | `/api/image/clear` | 清空图像索引 |
| `POST` | `/api/text/search` | 文本查询 → 相似文本 |
| `POST` | `/api/text/add` | 手动录入文本 |
| `POST` | `/api/text/scan` | 扫描 `text_lib` 导入新文本 |
| `POST` | `/api/audio/search` | 上传音频 → 相似音频 |
| `POST` | `/api/audio/scan` | 扫描 `audio_lib` 导入新音频 |
| `GET` | `/api/status` | 系统状态(模型加载、设备、库规模) |
## 📁 项目结构
```
├── api_server.py # FastAPI 后端 + 托管前端静态文件
├── main.py # Gradio WebUI 入口
├── cli.py # 命令行工具
├── start.py # 一键安装/启动(venv、依赖、模型、服务)
├── restore.py # 解压便携包后恢复模型缓存
├── config.py # 全局配置(路径、阈值、维度、设备)
├── model_config.py # 分模态模型注册与切换
├── download_tracker.py # 模型下载进度监控
├── image_db.py / text_db.py / audio_db.py # 模态数据库(存储可插拔)
├── image_utils.py / text_utils.py / audio_utils.py # 嵌入向量提取
├── storage/ # 向量存储抽象:FAISS / Redis / MySQL / ES
├── frontend/ # 原生 JS Web 前端
├── data/
│ ├── image_lib/ # 图片素材
│ ├── text_lib/ # 文本素材(.txt)
│ ├── audio_lib/ # 音频素材
│ ├── index/ # FAISS 索引文件(运行时生成)
│ └── storage_config.json # 存储后端配置
└── requirements.txt
```
## ⚙️ 配置
### 存储后端
编辑 `data/storage_config.json`:
```json
{
"backend": "local",
"local": {"index_dir": "data/index"},
"redis": {"host": "127.0.0.1", "port": 6379, "password": "", "db": 0},
"mysql": {"host": "127.0.0.1", "port": 3306, "user": "root", "password": "", "database": "vector_db"},
"es": {"host": "http://127.0.0.1:9200", "user": "", "password": ""}
}
```
将 `"backend"` 改为 `redis` / `mysql` / `es` 即可切换,上层 `*_db.py` 接口完全不变。
### 嵌入模型
模型 ID 持久化在 `data/model_config.json`(首次运行自动生成)。切换方式:
```bash
python cli.py models --set image google/siglip-base-patch16-224
python cli.py models --set text BAAI/bge-small-zh-v1.5
```
> ⚠️ 切换模型会改变向量空间,切换后需要重新扫描入库。
### 阈值与设备
见 `config.py`:`IMAGE_THRESHOLD`、`TEXT_THRESHOLD`、`AUDIO_THRESHOLD`、`MAX_RESULTS`、`FP16_INFER`、`DEVICE`。
## ❓ 常见问题
**为什么第一次查询很慢?** 模型是懒加载的,首次使用时才加载到显存,之后查询很快。
**如何离线运行?** 在有网机器上执行一次 `python cli.py download`,然后拷贝
`~/.cache/huggingface` 与 `~/.cache/speechbrain`(或便携包 `.model_cache` + `restore.py` 恢复)。
**可以换模型吗?** 可以,见「嵌入模型」一节;`model_config.py` 里预置了部分备选轻量模型。
**语音检索是声纹识别,不是语音转写。** ECAPA 直接从波形提取声音特征——它找的是*音色相似*的音频,全程不做 ASR 文字转写。
## 💖 支持项目
如果这个项目对你有帮助,欢迎请我喝杯咖啡:
| 支付宝 | 微信 |
|:------:|:----:|
|
|
|
## 📄 License
MIT