当前位置: 首页 > news >正文

【慧游鲁博】【11】后端 · Spring Boot 集成 Python 配置

文章目录

    • 1. 为当前项目创建专属的 Python 环境
    • 2. 安装缺失的模块
    • 3. 在 IDEA 中配置 Python 解释器
    • 4. 集成 Python 脚本到 Spring Boot
      • 4.1 创建Python服务封装
        • 工作流程
      • 4.2 创建Java服务层
      • 4.3 创建REST控制器

关于在本机运行后端程序时,在 Spring Boot 项目中集成 Python 脚本的环境说明


1. 为当前项目创建专属的 Python 环境

推荐使用conda创建:

conda create --name 环境名 python=版本号

激活环境(Windows):

conda activate 环境名

激活后,终端提示符会显示环境名:

在这里插入图片描述

如图 “cxsx

从文件创建环境:

conda env create -f environment.yml

2. 安装缺失的模块

pip install -r requirements.txt

3. 在 IDEA 中配置 Python 解释器

  1. 安装 Python 插件
    • File > Settings > Plugins,搜索 “Python”,安装 JetBrains 官方插件。
    • 重启 IDEA。
  2. 添加 Python SDK
    • File > Project Structure > Platform Settings > SDKs
    • 点击 +,选择 Python SDK
    • 指定 Python 解释器路径(如 venv/bin/python 或系统 Python 路径)。

在这里插入图片描述

在这里插入图片描述

4. 集成 Python 脚本到 Spring Boot

修改文件如下:

在这里插入图片描述

在这里插入图片描述

4.1 创建Python服务封装

在resources目录下创建python_scripts/clip_service.py:

在这里插入图片描述

# clip_service.py
import open_clip
import torch
from PIL import Image
import json
import numpy as np
from numpy.linalg import norm
import requests
from io import BytesIO
import sysdef load_model():model, preprocess, _ = open_clip.create_model_and_transforms("ViT-B-32",pretrained="laion2b_s34b_b79k")device = "cuda" if torch.cuda.is_available() else "cpu"return model.to(device).eval(), preprocess, devicemodel, preprocess, device = load_model()def download_image(url):response = requests.get(url)img = Image.open(BytesIO(response.content)).convert("RGB")return imgdef get_image_embedding(image_url):img = download_image(image_url)tensor = preprocess(img).unsqueeze(0).to(device)with torch.no_grad():feat = model.encode_image(tensor)feat = feat / feat.norm(dim=-1, keepdim=True)return feat.cpu().numpy()[0]def cosine(a, b):return float(np.dot(a, b) / (norm(a) * norm(b)))def match_image(image_url, db_path, w_text=0.2, w_image=0.8):img_vec = get_image_embedding(image_url)with open(db_path, "r", encoding="utf-8") as f:records = json.load(f)best = Nonebest_score = -1.0for rec in records:txt_vec = rec.get("text_embedding")img_db_vec = rec.get("image_embedding")if txt_vec is None or img_db_vec is None:continuesim_text = cosine(img_vec, np.array(txt_vec))sim_img = cosine(img_vec, np.array(img_db_vec))score = w_text * sim_text + w_image * sim_imgif score > best_score:best_score = scorebest = recreturn best, best_scoreif __name__ == "__main__":# 命令行调用示例: python clip_service.py <image_url> <db_path>image_url = sys.argv[1]db_path = sys.argv[2]result, score = match_image(image_url, db_path)print(json.dumps({"result": result,"score": score}))

clip_service.py程序是一个基于 CLIP模型的图像匹配服务,主要功能是:

  1. 加载预训练的 CLIP 模型
  2. 计算输入图像的嵌入向量(embedding)
  3. 在数据库中查找与输入图像最相似的记录
  4. 返回匹配结果和相似度分数
工作流程
  1. 程序启动时加载 CLIP 模型
  2. 从命令行获取输入图像 URL 和数据库路径
  3. 下载输入图像并计算其嵌入向量
  4. 从数据库加载所有记录
  5. 对每条记录计算:
    • 输入图像与记录文本嵌入的相似度
    • 输入图像与记录图像嵌入的相似度
    • 加权综合评分 (默认文本权重 0.2,图像权重 0.8)
  6. 返回评分最高的记录

clip_service.py脚本文件仅对队友提供的 python demo 文件 image.py 做了微小修改,我主要是负责后续的将demo探索的功能集成到项目中,这也是本博客的目的

4.2 创建Java服务层

PythonService.java

public interface PythonService {/*** 根据图片URL匹配文物* @param imageUrl 图片URL* @return 匹配结果*/Result<ArtifactMatchResult> matchArtifact(String imageUrl);
}

PythonServiceImpl.java

@Service
@RequiredArgsConstructor
public class PythonServiceImpl implements PythonService {private static final String PYTHON_SCRIPT_PATH = "src/main/resources/python_scripts/clip_service.py";private static final String DB_PATH = "src/main/resources/python_scripts/shandong_museum_multimodal_embeddings.json";@Overridepublic Result<ArtifactMatchResult> matchArtifact(String imageUrl) {try {String pythonPath = "E:\\anaconda\\envs\\cxsx\\python.exe";  // 注意转义反斜杠ProcessBuilder pb = new ProcessBuilder(pythonPath,PYTHON_SCRIPT_PATH,imageUrl,DB_PATH);pb.redirectErrorStream(true);Process process = pb.start();// 读取Python脚本输出BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));StringBuilder output = new StringBuilder();String line;while ((line = reader.readLine()) != null) {System.out.println(line);output.append(line);}int exitCode = process.waitFor();if (exitCode != 0) {return Result.fail(ErrorCode.SYSTEM_ERROR, "Python脚本执行失败");}ArtifactMatchResult result = parseResult(output.toString());if (result.getArtifact() == null) {return Result.fail(ErrorCode.DATA_NOT_FOUND, "未找到匹配的文物");}return Result.success(result);} catch (Exception e) {return Result.fail(ErrorCode.SYSTEM_ERROR, "文物匹配失败: " + e.getMessage());}}private ArtifactMatchResult parseResult(String jsonOutput) throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();JsonNode root = mapper.readTree(jsonOutput);JsonNode resultNode = root.path("result");double score = root.path("score").asDouble();if (resultNode.isMissingNode()) {return new ArtifactMatchResult(null, score);}Artifact artifact = mapper.treeToValue(resultNode, Artifact.class);return new ArtifactMatchResult(artifact, score);}
}

Artifact.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public
class Artifact {private String name;private String description;private List<Double> text_embedding;  // 改为下划线命名private List<Double> image_embedding; // 改为下划线命名
}

ArtifactMatchResult.java

@Data
@AllArgsConstructor
public
class ArtifactMatchResult {private Artifact artifact;private double score;
}

这一系列Java程序实现了一个文物图片匹配服务,通过调用Python脚本进行图像匹配。下面我将详细讲解每个组件的功能和实现细节。

PythonService接口

  • 定义了服务层的接口,声明了文物匹配的方法
  • 使用Result包装返回结果,便于统一处理成功/失败情况
  • 参数为图片URL,返回匹配结果和相似度分数

PythonServiceImpl实现类

  • 通过调用Python脚本实现文物图片匹配
  • 处理Python脚本的执行和结果解析
  • 错误处理和结果包装

关键实现细节

1. 路径配置

private static final String PYTHON_SCRIPT_PATH = "src/main/resources/python_scripts/clip_service.py";
private static final String DB_PATH = "src/main/resources/python_scripts/shandong_museum_multimodal_embeddings.json";
  • 定义了Python脚本路径和文物数据库路径
  • 使用相对路径,需要注意项目部署时的路径问题

在这里插入图片描述

2. 执行Python脚本

String pythonPath = "E:\\anaconda\\envs\\cxsx\\python.exe";
ProcessBuilder pb = new ProcessBuilder(pythonPath,PYTHON_SCRIPT_PATH,imageUrl,DB_PATH
);
  • 使用ProcessBuilder构建Python进程
  • 需要指定Python解释器的完整路径(注意Windows下的反斜杠转义,这里我填入的是自己的项目环境中的解释器路径,大家记得替换一下
  • 传递图片URL和数据库路径作为参数

3. 处理脚本输出

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {System.out.println(line);output.append(line);
}
  • 读取Python脚本的标准输出
  • 将输出内容收集到StringBuilder中

4. 错误处理

int exitCode = process.waitFor();
if (exitCode != 0) {return Result.fail(ErrorCode.SYSTEM_ERROR, "Python脚本执行失败");
}
  • 检查Python脚本的退出码
  • 非0退出码表示执行失败

5. 结果解析

private ArtifactMatchResult parseResult(String jsonOutput) throws JsonProcessingException {ObjectMapper mapper = new ObjectMapper();JsonNode root = mapper.readTree(jsonOutput);JsonNode resultNode = root.path("result");double score = root.path("score").asDouble();if (resultNode.isMissingNode()) {return new ArtifactMatchResult(null, score);}Artifact artifact = mapper.treeToValue(resultNode, Artifact.class);return new ArtifactMatchResult(artifact, score);
}
  • 使用Jackson库解析JSON输出
  • 提取匹配分数和文物信息
  • 处理文物不存在的情况

数据模型类Artifact.java

  • 表示文物实体
  • 包含名称、描述和两种嵌入向量
  • 使用Lombok简化代码(自动生成getter/setter等)
  • 字段名与Python脚本输出保持一致(使用下划线)

ArtifactMatchResult.java

  • 包装匹配结果
  • 包含匹配到的文物和相似度分数

4.3 创建REST控制器

// ArtifactController.java
@RestController
@RequestMapping("/artifacts")
@RequiredArgsConstructor
public class ArtifactController {private final PythonService pythonService;@PostMapping("/match")public Result<String> matchArtifact(@RequestBody MatchRequest request) {Result<ArtifactMatchResult> result = pythonService.matchArtifact(request.getImageUrl());String mode = request.getMode();if (!result.isSuccess()) {return Result.fail(result.getCode(), result.getMessage());}Artifact artifact = result.getData().getArtifact();double score = result.getData().getScore();// 构建基础文本String responseText = String.format("识别结果: %s\n\n文物描述: %s\n\n匹配度: %.2f%%",artifact.getName(),artifact.getDescription(),score * 100);return Result.success(responseText); } catch (Exception e) {return Result.fail(500, "图片识别出错: " + e.getMessage()); }// DTO类@Data@NoArgsConstructor@AllArgsConstructorpublic static class MatchRequest {@NotBlank(message = "图片URL不能为空")private String imageUrl;}}

接收小程序端的发来的 图片url 作为请求参数,尝试识别该图片对应的文物并给出识别结果

相关文章:

  • 统计学(第8版)——方差分析Ⅰ(考试用)
  • ES Modules 与 CommonJS 的核心区别详解
  • 台湾住宅IP哪家好,怎么找到靠谱的海外住宅IP代理商
  • Web 架构之微服务拆分原则与反模式
  • Windows网络配置避坑指南
  • 【android bluetooth 框架分析 04】【bt-framework 层详解 2】【如何配置和启动蓝牙profile服务】
  • python里的PDFMiner.six 库介绍
  • 菌菇食用攻略:从营养解析到安全指南,解锁科学食菌
  • 【全志V821_FoxPi】2-2 切换为spi nand方案启动
  • Context7 Mcp Quickstart
  • Kubernetes服务部署——RabbitMQ(集群版)
  • CMake指令: add_sub_directory以及工作流程
  • 前端实习校验函数汇总(未完成)
  • 一个超强的推理增强大模型,开源了,本地部署
  • 驭码CodeRider 2.0 产品体验:在VSCode安装并创建一个雷电小游戏
  • 【Web】腾讯云 COS 静态网站部署与自定义域名 HTTPS 全流程
  • IIS 实现 HTTPS:OpenSSL证书生成与配置完整指南
  • DeepSeek-R1与Claude 4.0 Sonnet:开源与闭源大模型的商业生态博弈
  • Electron-vite【实战】MD 编辑器 -- 大纲区(含自动生成大纲,大纲缩进,折叠大纲,滚动同步高亮大纲,点击大纲滚动等)
  • PyCharm Python IDE
  • 珠海市企业网站制作平台/域名注册万网
  • 常熟网站/株洲做网站
  • 源美网站建设/大学生网页制作成品模板
  • 晴天阴天雨天wordpress/sem和seo是什么职业岗位
  • 郴州文明网网站/2022网络热词30个
  • 游戏网站上做银商为赌博人员/关键词调整排名软件