精选

Pexels api结合百度翻译优化以图搜图功能

前言

大家好,我是 Leo哥,昨天在写以图搜图的功能的时候,遇到了一些问题,关于百度以图搜图 api的一些问题。 本地 main 方法测试也不行,接口测试也不行。

返回响应是{"status": 1009,"msg": "system error","data": null}

通过debug以及排查了半天,还是无果,于是中午吃了饭跟 leikooo佬跟探讨了一番。

原来leikooo佬也是遇到这个问题。猜测可能是因为百度 api 的参数发现了变化,并且本身他就也只支持 png的以图搜图。 后面 leikooo佬给我提供了一个思路,一个国内可以访问的 api,那就是Pexels。但是这个网站其实并不支持以图搜图功能, 不过我们可以灵活拓展一下,可以使用关键字来进行检索图片,然后再获取到其图片列表就可以了,话不多说,直接开干。

改进代码

准备工作

首先我们需要登录到该网站。 免费素材图片

然后注册一个账号,也可以和我一样这里直接使用谷歌进行注册登录。

然后点击 图片和视频 API

然后创建一个api秘钥,记得复制下来,保存好,一会我们需要使用它。

上手代码

接下来,我们需要改造我们之前的代码。

首先在 sub 包下面创建一个新的类 PexelsImageSearch

java
复制代码
/** * @author : 程序员Leo * @version 1.0 * @date 2025-02-11 13:50 * @description : 使用 Pexels API 进行图片搜索,不指定页面和每页数量 */ @Slf4j public class PexelsImageSearch { private static final String API_KEY = "刚刚保存的API秘钥"; private static final String ENDPOINT = "https://api.pexels.com/v1/search"; // 默认的页码和每页图片数量 private static final int DEFAULT_PAGE = 1; private static final int DEFAULT_PAGE_SIZE = 20; /** * 使用 Pexels API 搜索图片 * * @param query 搜索关键词 * @return 返回的图片URL列表 */ public List<String> searchPictures(String query) { return searchPictures(query, DEFAULT_PAGE, DEFAULT_PAGE_SIZE); } /** * 使用 Pexels API 搜索图片 * * @param query 搜索关键词 * @param page 当前页数 * @param pageSize 每页返回的图片数量 * @return 返回的图片URL列表 */ public List<String> searchPictures(String query, int page, int pageSize) { List<String> imageUrls = new ArrayList<>(); String apiUrl = String.format( "%s?query=%s&per_page=%d&page=%d", ENDPOINT, query, pageSize, page ); try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(apiUrl) .addHeader("Authorization", API_KEY) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("Pexels API 调用失败,状态码:" + response.code()); } String responseBody = response.body().string(); ObjectMapper objectMapper = new ObjectMapper(); JsonNode photosNode = objectMapper.readTree(responseBody).get("photos"); if (photosNode != null) { for (JsonNode photoNode : photosNode) { // 获取每张图片的原图URL imageUrls.add(photoNode.get("src").get("original").asText()); } } } catch (IOException e) { log.error("调用 Pexels API 失败", e); } return imageUrls; } public static void main(String[] args) { // 测试不指定页面和每页数量的搜索 PexelsImageSearch imageSearch = new PexelsImageSearch(); List<String> imageUrls = imageSearch.searchPictures("code"); System.out.println("搜索到的图片URLs: "); imageUrls.forEach(System.out::println); }

修改 GetImageListApi类

java
复制代码
@Slf4j public class GetImageListApi { /** * 获取图片列表 * * @param query 搜索关键词 * @return 图片搜索结果列表 */ public static List<ImageSearchResult> getImageList(String query) { try { // 使用 Pexels API 搜索图片 PexelsImageSearch imageSearch = new PexelsImageSearch(); List<String> imageUrls = imageSearch.searchPictures(query); // 将图片的URL转为ImageSearchResult对象 return convertToImageSearchResults(imageUrls); } catch (Exception e) { log.error("获取图片列表失败", e); throw new BusinessException(ErrorCode.OPERATION_ERROR, "获取图片列表失败"); } } /** * 将图片URL列表转换为ImageSearchResult列表 * * @param imageUrls 图片URL列表 * @return ImageSearchResult列表 */ private static List<ImageSearchResult> convertToImageSearchResults(List<String> imageUrls) { List<ImageSearchResult> imageSearchResults = new ArrayList<>(); for (String url : imageUrls) { ImageSearchResult result = new ImageSearchResult(); // 使用Pexels提供的原图URL作为缩略图 result.setThumbUrl(url); // 这里假设来源地址与缩略图相同 result.setFromUrl(url); imageSearchResults.add(result); } return imageSearchResults; } public static void main(String[] args) { // 示例:通过 Pexels API 获取与“nature”相关的图片列表 String query = "nature"; List<ImageSearchResult> imageList = getImageList(query); System.out.println("搜索成功,获取到图片列表:" + imageList); }

继续修改ImageSearchApiFacade类

java
复制代码
/** * @author : 程序员Leo * @version 1.0 * @date 2025-02-11 10:03 * @description : */@Slf4j public class ImageSearchApiFacade { /** * 搜索图片 * * @param query 图片关键字 * @return 图片搜索结果列表 */ public static List<ImageSearchResult> searchImage(String query) { // 这里可以通过图像URL获取相关的搜索结果。因为我们使用Pexels,我们可以基于图像URL进行直接搜索。 return GetImageListApi.getImageList(query); } public static void main(String[] args) { // 测试通过图像URL进行以图搜图功能 String imageUrl = "https://www.codefather.cn/logo.png"; List<ImageSearchResult> resultList = searchImage(imageUrl); System.out.println("结果列表:" + resultList); } }

修改PictureController 中的接口方法 因为之前百度以图搜图传递的是图片的 url,但是Pexels 却不支持,所以只能通过传递关键字的方式进行搜索。 所以这里我还需要修改一下传值的方式。

java
复制代码
@ApiOperation(value = "以图搜图") @PostMapping("/search/picture") public Result<List<ImageSearchResult>> searchPictureByPicture(@RequestBody SearchPictureByPictureRequest requestParam) { ThrowUtils.throwIf(ObjectUtil.isNull(requestParam), ErrorCode.PARAMS_ERROR); Long pictureId = requestParam.getPictureId(); ThrowUtils.throwIf(ObjectUtil.isNull(pictureId) || pictureId <= 0, ErrorCode.PARAMS_ERROR); Picture oldPicture = pictureService.getById(pictureId); ThrowUtils.throwIf(ObjectUtil.isNull(oldPicture), ErrorCode.NOT_FOUND_ERROR); List<ImageSearchResult> resultList = ImageSearchApiFacade.searchImage(oldPicture.getName()); return ResultUtils.success(resultList); }

测试

然后重启代码进行测试。 可以看到,基本功能已经实现了。

7cfb15fd304c3c321a328c6fda68f540.png

先不要高兴的太早,但是现在有一个问题,当我们在中文图片名称以图搜图的过程中发现了,会出现与关键字符合的图片或者是直接搜索不到图片。

此时你肯定会产生疑问!!

这里为啥呢,因为这个网站是国外的,人家老外的母语是英文,所以,当遇到一些中文的时候,就会出现问题了。

那么此时该怎么做呢,肯定不能放着不管,不然人家用户使用这个功能的时候,心里估计该骂你了。这是哪个 ** 设计的网站,哈哈哈。

换一个思路,如果中文不识别,咱们在后端代码中,把中文转换为英文再进行搜索不就可以了🐴 ,行不行,试试才知道,继续改代码。

继续优化代码

这里我对接的是百度翻译api,我还是比较喜欢这个的,因为可以白嫖。

类型免费额度超出免费额度价格每秒可同时翻译次数
标准版每月免费5万字符49元/100万字符1次/秒
高级版每月免费100万字符49元/100万字符10次/秒
尊享版每月免费200万字符49元/100万字符100次/秒

三种类型的区别:

  1. 标准版:账户未实名认证的情况下使用只能使用标准版
  2. 高级版:账户个人实名认证的情况下可以使用
  3. 尊享版:账户企业认证的情况下可以使用

怎么样,够良心吧,根本用不完,建议大家也可以使用这个。

百度翻译开通具体步骤

1.注册或登录

先点击上方官网申请地址进入

如果已有账户则选择登录,如果没有则进行注册

2.申请开发者权限

进入开通页面

进入开通页面后,点击立即使用,再在弹框中点击开始注册

选择个人开发者,输入基本信息

此处有两个版本:标准版高级版

标准版每月只有免费5万字符,很少,但不需要认证

高级版每月有免费100万字符,需要实名认证(推荐使用这种方式,只输入一下姓名和身份证号即可)

操作完后进入这一步,点击开通服务

3.开通百度翻译

选择通用翻译API,然后点击下一步

看上一步是否认证

如果认证了则选择高级版即可(如果没认证,选择开通高级版,会让你补填资料认证)

如果没认证,也不想补填资料,则开通标准版

勾选规则确认,然后点击开通

出现下图则表明成功开通百度翻译

4. 获取秘钥

点击此处进入获取密钥页面

点击上面进入获取密钥页面后,密钥信息如下图

红色框里面的就是我们一会要用的 APPID 和秘钥,保存好一会使用。

重构代码

此时需要对我们之前的代码做一些变化,加入一些新的方法。

比如我们首先要把获取到图片的关键字转为英文,然后再调用方法区搜索相似的图片。

PexelsImageSearch 代码修改

java
复制代码
/** * @author : 程序员Leo * @version 1.0 * @date 2025-02-11 13:50 * @description : 使用 Pexels API 进行图片搜索,不指定页面和每页数量 */ @Slf4j public class PexelsImageSearch { private static final String API_KEY = "你的API"; private static final String ENDPOINT = "https://api.pexels.com/v1/search"; private static final String BAIDU_APP_ID = "你的API KEY1 "; private static final String BAIDU_API_KEY = "你的秘钥"; private static final String BAIDU_TRANSLATE_ENDPOINT = "https://fanyi-api.baidu.com/api/trans/vip/translate"; private static final int DEFAULT_PAGE_SIZE = 20; /** * 使用百度翻译将中文转为英文 * * @param query 中文搜索关键词 * @return 英文翻译结果 */ public String translateChineseToEnglish(String query) { try { // 构建百度翻译请求参数 String salt = String.valueOf(System.currentTimeMillis()); String sign = BAIDU_APP_ID + query + salt + BAIDU_API_KEY; String signMd5 = Md5Utils.md5Hex(sign); String url = BAIDU_TRANSLATE_ENDPOINT + "?q=" + query + "&from=zh&to=en&appid=" + BAIDU_APP_ID + "&salt=" + salt + "&sign=" + signMd5; // 发起HTTP请求 HttpResponse response = HttpRequest.get(url).execute(); if (response.getStatus() == 200) { String responseBody = response.body(); // 使用 ObjectMapper 来解析 JSON 数据 ObjectMapper objectMapper = new ObjectMapper(); JsonNode resultNode = objectMapper.readTree(responseBody); if (resultNode != null && resultNode.has("trans_result")) { return resultNode.get("trans_result").get(0).get("dst").asText(); } } } catch (Exception e) { log.error("调用百度翻译 API 失败", e); } // 如果翻译失败,返回原始中文 return query; } /** * 使用 Pexels API 搜索图片 * * @param query 搜索关键词(英文) * @return 返回的图片URL列表 */ public List<String> searchPictures(String query, int totalCount) { List<String> imageUrls = new ArrayList<>(); int page = 1; int fetchedImages = 0; while (fetchedImages < totalCount) { String apiUrl = String.format( "%s?query=%s&per_page=%d&page=%d", ENDPOINT, query, DEFAULT_PAGE_SIZE, page ); try { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(apiUrl) .addHeader("Authorization", API_KEY) .build(); Response response = client.newCall(request).execute(); if (!response.isSuccessful()) { throw new IOException("Pexels API 调用失败,状态码:" + response.code()); } String responseBody = response.body().string(); ObjectMapper objectMapper = new ObjectMapper(); JsonNode photosNode = objectMapper.readTree(responseBody).get("photos"); if (photosNode != null) { for (JsonNode photoNode : photosNode) { // 获取每张图片的原图URL imageUrls.add(photoNode.get("src").get("original").asText()); fetchedImages++; // 如果已经抓取到足够的图片,跳出循环 if (fetchedImages >= totalCount) { break; } } } page++; // 增加页码 // 如果结果为空或已达到所需数量,停止请求 if (photosNode == null || fetchedImages >= totalCount) { break; } } catch (IOException e) { log.error("调用 Pexels API 失败", e); break; } } return imageUrls; } /** * 主方法:搜索中文关键词,翻译为英文并搜索图片 */ public List<String> searchPicturesForChinese(String query, int totalCount) { String translatedQuery = translateChineseToEnglish(query); return searchPictures(translatedQuery, totalCount); } public static void main(String[] args) { // 测试:使用中文搜索并进行翻译,获取 30 张图片 PexelsImageSearch imageSearch = new PexelsImageSearch(); List<String> imageUrls = imageSearch.searchPicturesForChinese("狗", 30); System.out.println("搜索到的图片URLs: "); imageUrls.forEach(System.out::println); } }

GetImageListApi 代码修改

java
复制代码
/** * @author : 程序员Leo * @version 1.0 * @date 2025-02-10 09:18 * @description : */@Slf4j public class GetImageListApi { /** * 获取图片列表 * * @param query 搜索关键词(中文) * @return 图片搜索结果列表 */ public static List<ImageSearchResult> getImageList(String query) { try { // 先将中文关键词翻译为英文 PexelsImageSearch imageSearch = new PexelsImageSearch(); String translatedQuery = imageSearch.translateChineseToEnglish(query); // 使用 Pexels API 搜索图片 List<String> imageUrls = imageSearch.searchPictures(translatedQuery, 30); // 将图片的URL转为ImageSearchResult对象 return convertToImageSearchResults(imageUrls); } catch (Exception e) { log.error("获取图片列表失败", e); throw new BusinessException(ErrorCode.OPERATION_ERROR, "获取图片列表失败"); } } /** * 将图片URL列表转换为ImageSearchResult列表 * * @param imageUrls 图片URL列表 * @return ImageSearchResult列表 */ private static List<ImageSearchResult> convertToImageSearchResults(List<String> imageUrls) { List<ImageSearchResult> imageSearchResults = new ArrayList<>(); for (String url : imageUrls) { ImageSearchResult result = new ImageSearchResult(); // 使用Pexels提供的原图URL作为缩略图 result.setThumbUrl(url); // 这里假设来源地址与缩略图相同 result.setFromUrl(url); imageSearchResults.add(result); } return imageSearchResults; } public static void main(String[] args) { // 示例:通过中文关键词获取图片列表 String query = "自然"; // 中文关键词 List<ImageSearchResult> imageList = getImageList(query); System.out.println("搜索成功,获取到图片列表:" + imageList); } }

ImageSearchApiFacade 代码修改

java
复制代码
@Slf4j public class ImageSearchApiFacade { /** * 搜索图片 * * @param query 图片关键字(中文) * @return 图片搜索结果列表 */ public static List<ImageSearchResult> searchImage(String query) { // 先进行中文转英文 PexelsImageSearch imageSearch = new PexelsImageSearch(); List<String> imageUrls = imageSearch.searchPicturesForChinese(query,30); // 将图片的URL转为ImageSearchResult对象 return convertToImageSearchResults(imageUrls); } /** * 将图片URL列表转换为ImageSearchResult列表 * * @param imageUrls 图片URL列表 * @return ImageSearchResult列表 */ private static List<ImageSearchResult> convertToImageSearchResults(List<String> imageUrls) { List<ImageSearchResult> imageSearchResults = new ArrayList<>(); for (String url : imageUrls) { ImageSearchResult result = new ImageSearchResult(); // 使用Pexels提供的原图URL作为缩略图 result.setThumbUrl(url); // 这里假设来源地址与缩略图相同 result.setFromUrl(url); imageSearchResults.add(result); } return imageSearchResults; } public static void main(String[] args) { // 测试通过中文关键词进行图片搜索 String query = "狗"; List<ImageSearchResult> imageList = searchImage(query); System.out.println("搜索成功,获取到图片列表:" + imageList); } }

测试

重启代码进行测试

可以看到,现在已完全符合我们的预期了。

小结

如果大家有其他好的想法的其他方案欢迎和我沟通~

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
无名小卒
下载 APP