# 视觉探索引擎 **Repository Path**: bingbingyihao/visual-exploration-engine ## Basic Information - **Project Name**: 视觉探索引擎 - **Description**: 以图搜图 - 视觉探索引擎 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 0 - **Created**: 2026-06-08 - **Last Updated**: 2026-09-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 视觉探索引擎 > 以图搜图 - 基于 AI 向量检索的视觉探索系统 ## 项目简介 视觉探索引擎是一个基于深度学习的以图搜图系统。用户上传一张图片后,系统会自动提取图片的特征向量,并在图片池中搜索视觉上相似的图片。同时利用 AI 视觉模型自动分析图片内容,生成分类和标签。 ## 技术栈 | 层级 | 技术 | |------|------| | 后端 | Spring Boot 2.7.18 + MyBatis-Plus 3.5.3.1 + Lombok(JDK 17) | | 向量数据库 | Milvus 2.4(2560 维向量,IVF_FLAT 索引 + IP 度量) | | AI 服务 | 阿里云 DashScope (qwen3-vl-embedding / qwen-vl-max) | | 前端 | Vue 3.2 + Vue Router 4 + Axios(Vue CLI 5 构建) | | 关系数据库 | MySQL 8.0(utf8mb4) | | 代码格式 | Spotless + Palantir Java Format / ESLint + Prettier | ## 功能特性 - **图片上传** - 支持拖拽或点击上传,支持 JPG/PNG/WebP 格式 - **向量提取** - 调用 DashScope 多模态模型将图片转为 2560 维特征向量 - **图片分析** - AI 自动识别图片分类(风景/建筑/人物/动物等)和提取标签 - **以图搜图** - 上传新图片或使用图片池中已有图片进行搜索 - **图片池管理** - 分页浏览、分类筛选、按相似度排序展示结果 - **实时进度** - 上传进度展示、搜索结果相似度百分比显示 ## 系统架构 ``` ┌─────────────┐ ┌──────────────────┐ ┌─────────────────┐ │ Vue 3 前端 │────▶│ Spring Boot 后端 │────▶│ Milvus 向量库 │ └─────────────┘ └────────┬─────────┘ └─────────────────┘ │ ┌──────▼──────┐ ┌─────────────────┐ │ MySQL DB │ │ DashScope AI API│ └─────────────┘ └─────────────────┘ ``` ## 环境要求 ### 基础软件版本 | 软件 | 版本 | 说明 | |------|------|------| | JDK | **17**(必须) | `pom.xml` 里 `maven.compiler.source/target = 17`,用 JDK 8/11 会编译失败 | | Maven | 3.6.3+(建议 3.8 / 3.9) | 后端构建;Spotless 2.43.0 要求 Maven 3.6.0+ | | Node.js | 16.x / 18.x LTS | Vue CLI 5 要求 Node ≥ 12,建议直接用 16 或 18 | | npm | 8+ | 随 Node.js 分发 | | MySQL | 8.0 | 需要 utf8mb4 字符集 | | Milvus | 2.4.x standalone | gRPC 端口 `19530`,官方 Docker Compose 部署 | | Docker | 20.10+ / Docker Compose v2 | 仅用于启动本地 Milvus,已有远端 Milvus 可跳过 | | Git | 2.30+ | 仓库托管在 Gitee | ### 后端依赖版本(`code/SpringBoot/pom.xml`) | 依赖 | 版本 | 用途 | |------|------|------| | spring-boot-starter-parent | 2.7.18 | 父 POM,统一管理 Spring 生态版本 | | mybatis-plus-boot-starter | 3.5.3.1 | ORM / 分页 | | mysql-connector-java | 8.0.33 | MySQL JDBC 驱动 | | milvus-sdk-java | 2.4.2 | 向量库客户端(与 Milvus 2.4.x 服务端对应) | | okhttp | 4.12.0 | 调用 DashScope HTTP 接口 | | org.json | 20231013 | DashScope 响应解析 | | hutool-all | 5.8.15 | 通用工具类 | | lombok | 由父 POM 管理 | 注解生成 getter/setter/log | | spring-boot-starter-log4j2 | log4j2 2.21.1 | 日志实现(排除默认 logback);违反条款 agent 的过程明细单独落文件,见 `docs/violation-clause-agent-log.md` | | spotless-maven-plugin | 2.43.0 | 格式化(palantir-java-format 2.50.0) | ### 前端依赖版本(`code/vue/package.json`) | 依赖 | 版本 | 用途 | |------|------|------| | vue | ^3.2.13 | 框架 | | vue-router | ^4.6.4 | 路由 | | axios | ^1.3.4 | HTTP 请求 | | @vue/cli-service | ~5.0.0 | 构建 / dev server | | @vue/cli-plugin-babel | ~5.0.0 | Babel 转译 | | @vue/cli-plugin-eslint | ~5.0.0 | 构建期 ESLint 集成 | | eslint | ^8.57.0 | 代码检查(ESLint 9 flat config 不适用,请按 8.x 安装) | | eslint-plugin-vue | ^9.27.0 | Vue 3 规则集 | | @vue/eslint-config-prettier | ^9.0.0 | ESLint 与 Prettier 冲突规避 | | prettier | ^3.3.0 | 代码格式化 | ### 其他前置条件 - 阿里云 DashScope API Key,且账号已开通 `qwen3-vl-embedding`、`qwen-vl-max` 模型 - 运行环境可访问公网(调用 DashScope 接口) - 图片上传大小上限 100MB(`spring.servlet.multipart.max-*`) ## 快速开始 ### 1. 克隆仓库 ```bash git clone https://gitee.com/bingbingyihao/visual-exploration-engine.git cd visual-exploration-engine ``` ### 2. 准备 MySQL 执行初始化脚本,创建 `visual_exploration` 库和 `image` 表: ```bash mysql -u root -p < code/SpringBoot/src/main/resources/sql/init.sql ``` 验证: ```sql SHOW TABLES FROM visual_exploration; -- 应看到 image 表 ``` ### 3. 准备 Milvus 集合**不需要手动创建**,后端启动时 `MilvusCollectionInitializer` 会自动完成建集合、建索引、load 到内存。 如果用 Docker 起本地 Milvus standalone(版本号按实际替换): ```bash curl -sfL https://github.com/milvus-io/milvus/releases/download/v2.4.0/milvus-standalone-docker-compose.yml -o docker-compose.yml docker compose up -d docker compose ps # 状态应为 Up (healthy) curl http://localhost:9091/healthz # 返回 {"health":"OK"} ``` 已有远端 Milvus 的话,跳过本节,直接改配置里的 `milvus.host` / `milvus.port`。 需要重置向量库时(例如更换 embedding 模型导致维度变化),删除旧集合后重启后端即可自动重建: ```bash pip install pymilvus python code/SpringBoot/src/main/resources/milvus/clear.py ``` ### 4. 配置后端 编辑 `code/SpringBoot/src/main/resources/application.properties`: ```properties # 数据库(密码必改) spring.datasource.url=jdbc:mysql://localhost:3306/visual_exploration spring.datasource.username=root spring.datasource.password=你的密码 # DashScope API Key(必填) dashscope.api-key=你的dashscope-api-key # 图片本地存储目录(必改,仓库里是本机绝对路径) image.storage.path=C:/your/path/to/uploads/images # Milvus(默认值可用) milvus.host=localhost milvus.port=19530 milvus.database=default milvus.collection=image_vectors # 模型名(一般不用改) dashscope.model=qwen3-vl-embedding dashscope.vision-model=qwen-vl-max ``` | 配置项 | 默认值 | 说明 | |--------|--------|------| | `server.port` | 8080 | 后端端口 | | `cors.allowed-origins` | `http://localhost:8081` | 前端地址。**图片的访问 URL 由它拼接而成**,改前端端口时必须同步改这里 | | `spring.servlet.multipart.max-file-size` | 100MB | 单张图片上限 | | `mybatis-plus.configuration.log-impl` | StdOutImpl | 会在控制台打印 SQL,生产建议关掉 | 存储目录不存在会自动创建,无需手工建文件夹。 ### 5. 启动后端 方式一:命令行(开发用) ```bash cd code/SpringBoot mvn spring-boot:run ``` 方式二:IDEA —— 直接运行 `com.boot.MainApplication`。运行前确认 Project SDK 为 JDK 17。 方式三:打 jar 包(部署用) ```bash cd code/SpringBoot mvn clean package -DskipTests java -jar target/SpringBoot-1.0.0.jar ``` 启动成功日志中会出现 `Milvus collection 'image_vectors' initialized successfully.`,服务监听 `http://localhost:8080`。 > **注意**:Spotless 的 `check` 目标绑定在 `validate` 阶段,因此 `mvn spring-boot:run` / `mvn package` 会先做格式校验,格式不合规会直接构建失败。先执行 `mvn spotless:apply` 修好,或临时用 `-Dspotless.check.skip=true` 跳过。 ### 6. 启动前端 ```bash cd code/vue npm install npm run serve ``` 默认运行在 `http://localhost:8081`,`vue.config.js` 已把 `/api` 代理到 `http://localhost:8080`,因此前端代码里统一用相对路径 `/api/...` 请求,无需额外配置跨域。 浏览器打开 `http://localhost:8081` 即可使用。 ### 7. 前端生产构建 ```bash cd code/vue npm run build # 产物在 code/vue/dist ``` `dist/` 已在 `.gitignore` 中,不提交。 ## 常用命令 | 场景 | 命令 | 执行目录 | |------|------|----------| | 后端开发启动 | `mvn spring-boot:run` | `code/SpringBoot` | | 后端打包 | `mvn clean package -DskipTests` | `code/SpringBoot` | | 跳过格式校验 | `mvn clean package -DskipTests -Dspotless.check.skip=true` | `code/SpringBoot` | | Java 格式化 | `mvn spotless:apply` | `code/SpringBoot` | | Java 格式检查 | `mvn spotless:check` | `code/SpringBoot` | | 前端开发启动 | `npm run serve` | `code/vue` | | 前端构建 | `npm run build` | `code/vue` | | 前端 lint(带自动修复) | `npm run lint` | `code/vue` | | 前端格式化 | `npm run format` | `code/vue` | | 一键格式化全部 | `./scripts/format.ps1`(PowerShell)/ `./scripts/format.sh`(bash) | 仓库根目录 | | 只检查格式不修改 | `./scripts/format.ps1 check` / `./scripts/format.sh check` | 仓库根目录 | 代码格式化配置遵循《研发团队开发规范》:Java 用 Palantir Java Format(4 空格缩进、120 行宽、K&R 大括号),前端用 ESLint + Prettier(2 空格缩进、单引号、无分号、100 行宽)。提交前建议先跑一次 `check`。 ## API 接口 | 方法 | 路径 | 参数 | 说明 | |------|------|------|------| | POST | `/api/images/upload` | `file` | 上传图片(自动提取向量 + AI 分析) | | GET | `/api/images/pool` | `page`(默认1) / `size`(默认20) / `category`(可选) | 分页获取图片池 | | POST | `/api/search/similar` | `file` / `topK`(默认20) | 上传查询图片搜索相似图片 | | POST | `/api/search/similar/{imageId}` | `topK`(默认20) | 用图片池中已有图片搜索 | | GET | `/api/images-static/{fileName}` | - | 图片静态资源访问(映射到 `image.storage.path`) | | POST | `/api/violation-clause/match` | - | 触发「图片外挂类型 → 违反条款说明」匹配(后台单任务,处理中重复触发只返回进度) | | GET | `/api/violation-clause/progress` | - | 查询违反条款匹配进度 | | GET | `/api/violation-clause/list` | `page`(默认1) / `size`(默认20) / `keyword`(可选) | 分页查询已生成的违反条款记录 | 所有接口统一返回 `{ code, msg, data }` 结构,`code = 200` 为成功,前端在 `src/api/request.js` 的响应拦截器里统一处理。 ## 项目结构 ``` visual-exploration-engine/ ├── code/ │ ├── SpringBoot/ # 后端(Maven 单模块) │ │ ├── pom.xml # 依赖 + spring-boot / spotless 插件 │ │ ├── uploads/images/ # 图片本地存储目录(运行时生成) │ │ └── src/main/ │ │ ├── java/com/boot/ │ │ │ ├── MainApplication.java # 启动类 │ │ │ ├── config/ # CorsConfig / MilvusConfig / │ │ │ │ # MilvusCollectionInitializer / │ │ │ │ # MybatisPlusConfig / StorageConfig / WebConfig │ │ │ ├── controller/ # ImageController / SearchController │ │ │ ├── dto/ # ImageUploadResponse / PageResult / SearchResult │ │ │ ├── entity/ # Image(对应 image 表) │ │ │ ├── mapper/ # ImageMapper │ │ │ ├── service/ # ImageService / VectorSearchService │ │ │ └── utils/ # Result(统一响应体) │ │ └── resources/ │ │ ├── application.properties # 端口/数据库/Milvus/DashScope 配置 │ │ ├── sql/init.sql # 建库建表脚本 │ │ └── milvus/clear.py # 删除向量集合(重置用) │ └── vue/ # 前端(Vue CLI 5) │ ├── package.json # 依赖与 serve/build/lint/format 脚本 │ ├── vue.config.js # devServer 8081 + /api 代理到 8080 │ ├── babel.config.js │ ├── .eslintrc.cjs # ESLint 配置(生效的这份) │ ├── .eslintignore │ ├── .prettierrc # Prettier 配置 │ ├── public/ # index.html、favicon │ └── src/ │ ├── main.js # 应用入口 │ ├── App.vue # 根组件 │ ├── api/ # request.js(axios 实例)/ image.js │ ├── components/ # 通用组件(Message.vue) │ ├── router/index.js # 路由 │ ├── views/Home.vue # 页面组件 │ └── styles/global.css # 全局样式 ├── scripts/ │ ├── format.ps1 # Windows 一键格式化 │ └── format.sh # Linux/macOS/Git Bash 一键格式化 ├── .gitignore ├── LICENSE └── README.md ``` > 说明:`code/vue/package.json` 里的 `eslintConfig` 字段不会被加载——同目录存在 `.eslintrc.cjs` 时它优先级更高,ESLint 配置只改 `.eslintrc.cjs`。 ## 工作原理 1. **上传阶段** - 用户上传图片,后端保存到本地存储,记录到 MySQL 2. **向量提取** - 将图片转为 Base64,调用 DashScope `qwen3-vl-embedding` 模型获取 2560 维向量 3. **向量存储** - 将向量插入 Milvus 向量数据库,关联 image_id 4. **内容分析** - 调用 DashScope `qwen-vl-max` 视觉模型,分析图片分类和标签 5. **搜索阶段** - 对查询图片执行同样的向量提取,在 Milvus 中用内积 (IP) 检索最相似向量 6. **结果返回** - 按相似度排序,关联 MySQL 中的图片元数据返回前端 ## 常见问题 | 现象 | 原因 / 处理 | |------|-------------| | 构建报 `Spotless...files had formatting violations` | 代码未格式化。执行 `mvn spotless:apply` 后重试 | | 编译报 `unsupported class file version 61.0` 之类 | 使用的不是 JDK 17(`mvn -v` 与 IDEA 的 Project SDK 都要看) | | 启动日志出现 `Failed to initialize Milvus collection` | Milvus 未启动或 `milvus.host/port` 不对;后端本身仍会启动,但搜索功能不可用 | | 换 embedding 模型后搜索结果异常 | 维度与旧集合不一致,用 `clear.py` 删集合后重启后端重建 | | 图片上传成功但列表显示不出图 | 图片 URL 由 `cors.allowed-origins` 拼接,确认它和实际前端地址一致;再检查 `image.storage.path` 目录权限 | | 上传后 `has_vector=0`、无向量 | DashScope Key 无效、模型未开通或网络不通,看后端日志中的向量提取异常 | | ESLint 改了规则没生效 | `package.json` 的 `eslintConfig` 不参与加载,只改 `.eslintrc.cjs` | | 需要改端口 | 三处联动:`server.port`、`code/vue/vue.config.js` 的 `devServer.port` 与 `proxy.target`、`cors.allowed-origins` | | 违反条款匹配过程看不懂、要复盘某条判定 | 看 `logs/violation-clause-agent.log`(含每轮检索切片、大模型输入输出、最终条款说明),说明见 `docs/violation-clause-agent-log.md` | | 日志文件没生成,或控制台日志变成「时间 类名 方法名」两行格式 | Log4j2 被 jar 内置的 `log4j2.xml`(milvus-sdk-java)抢先初始化。确认 `application.yml` 的 `logging.config: classpath:log4j2-spring.xml` 存在且未被覆盖 | ## License Apache 2.0