欧美成人精品手机在线观看_69视频国产_动漫精品第一页_日韩中文字幕网 - 日本欧美一区二区

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

教你對(duì)接電商拍圖識(shí)款接口

freeflydom
2024年11月18日 10:19 本文熱度 585

在網(wǎng)上購(gòu)物時(shí)候,不止可以通過(guò)名稱搜索商品,也可以拍照上傳圖片搜索商品。比如某寶上拍個(gè)圖片就能搜索到對(duì)應(yīng)的商品。

騰訊、阿里都提供了類似的圖像搜索服務(wù),這類服務(wù)原理都差不多:

  • 在一個(gè)具體的圖庫(kù)上,新增或者刪除圖片。
  • 通過(guò)圖片搜索相似的圖片。

本文對(duì)接的是騰訊云的圖像搜索

添加配置

添加 maven 依賴:

<dependency>
    <groupId>com.tencentcloudapi</groupId>
    <artifactId>tencentcloud-sdk-java</artifactId>
    <version>3.1.1129</version>
</dependency>

引入配置:

tencentcloud:
  tiia:
    secretId: ${SECRET_ID}
    secretKey: ${SECRET_KEY}
    endpoint: tiia.tencentcloudapi.com
    region: ap-guangzhou
    groupId: test1

secretId 和 secretKey 都是在 API秘鑰 地址:https://console.cloud.tencent.com/cam/capi,groupId 是圖庫(kù) id。

配置 bean

@Data
@Configuration
@ConfigurationProperties("tencentcloud.tiia")
public class TencentCloudTiiaProperties {
    private String secretId;
    private String secretKey;
    private String endpoint = "tiia.tencentcloudapi.com";
    private String region = "ap-guangzhou";
    private String groupId;
}
@Configuration
@ConditionalOnClass(TencentCloudTiiaProperties.class)
public class TencentCloudTiiaConfig {
    @Bean
    public TiiaClient tiiaClient(TencentCloudTiiaProperties properties) {
        Credential cred = new Credential(properties.getSecretId(), properties.getSecretKey());
        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint(properties.getEndpoint());
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        TiiaClient client = new TiiaClient(cred, properties.getRegion(), clientProfile);
        return client;
    }
}

tiiaClient 是搜圖的核心,在后面新增、刪除、搜索圖片都會(huì)使用到。

圖庫(kù)更新

新建圖庫(kù)之后,需要將圖片批量的導(dǎo)入到圖庫(kù)中。一般開(kāi)始會(huì)批量將上架的圖片批量導(dǎo)入到圖片庫(kù),一般只需要操作一次。

商品有修改、新增、下架操作時(shí),圖片也需要有對(duì)應(yīng)的更新操作。但是每次都更新都同步更新操作,可能會(huì)導(dǎo)致數(shù)據(jù)庫(kù)頻繁更新,服務(wù)器壓力增加,需要改成,每次更新圖片后,同步到緩存中,然后定時(shí)處理緩存的數(shù)據(jù):

騰訊圖像搜索沒(méi)有圖像更新接口,只有圖像刪除和新增的接口,那就先調(diào)用刪除,再調(diào)用新增的接口

刪除圖片

圖片刪除調(diào)用 tiiaClient.DeleteImages 方法,主要注意請(qǐng)求頻率限制。

默認(rèn)接口請(qǐng)求頻率限制:10次/秒

這里就簡(jiǎn)單處理,使用線程延遲處理 Thread.sleep(100),刪除圖片只要指定 EntityId:

@Data
public class DeleteImageDTO {
    private String entityId;
    private List<String> picName;
}

如果指定 PicName 就刪除 EntityId 下面的具體的圖片,如果不指定 PicName 就刪除整個(gè) EntityId。

刪除圖片代碼如下:

public void deleteImage(List<DeleteImageDTO> list) {
    if (CollectionUtils.isEmpty(list)) {
        return;
    }
    list.stream().forEach(deleteImageDTO -> {
        List<String> picNameList = deleteImageDTO.getPicName();
        if (CollectionUtils.isEmpty(picNameList)) {
            DeleteImagesRequest request = new DeleteImagesRequest();
            request.setGroupId(tiiaProperties.getGroupId());
            request.setEntityId(deleteImageDTO.getEntityId());
            try {
                // 騰訊限制qps
                Thread.sleep(100);
                tiiaClient.DeleteImages(request);
            } catch (TencentCloudSDKException | InterruptedException e) {
                log.error("刪除圖片失敗, entityId {} 錯(cuò)誤信息 {}", deleteImageDTO.getEntityId(), e.getMessage());
            }
        } else {
            picNameList.stream().forEach(picName -> {
                DeleteImagesRequest request = new DeleteImagesRequest();
                request.setGroupId(tiiaProperties.getGroupId());
                request.setEntityId(deleteImageDTO.getEntityId());
                request.setPicName(picName);
                try {
                    Thread.sleep(100);
                    tiiaClient.DeleteImages(request);
                } catch (TencentCloudSDKException | InterruptedException e) {
                    log.error("刪除圖片失敗, entityId {}, 錯(cuò)誤信息 {}", deleteImageDTO.getEntityId(), picName, e.getMessage());
                }
            });
        }
    });
}

新增圖片

新增圖片調(diào)用 tiiaClient.CreateImage 方法,這里也需要注意調(diào)用頻率的限制。除此之外還有兩個(gè)限制:

  • 限制圖片大小不可超過(guò) 5M
  • 限制圖片分辨率不能超過(guò)分辨率不超過(guò) 4096*4096

既然壓縮圖片需要耗時(shí),那就每次上傳圖片先壓縮一遍,這樣就能解決調(diào)用頻率限制的問(wèn)題。壓縮圖片引入 thumbnailator:

<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.20</version>
</dependency>

壓縮工具類:

/**
 * 圖片壓縮
 * @param url             圖片url
 * @param scale           壓縮比例
 * @param targetSizeByte  壓縮后大小 KB
 * @return
 */
public static byte[] compress(String url, double scale, long targetSizeByte) {
    if (StringUtils.isBlank(url)) {
        return null;
    }
    long targetSizeKB = targetSizeByte * 1024;
    try {
        URL u = new URL(url);
        double quality = 0.8;
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
        do {
            Thumbnails.of(u).scale(scale) // 壓縮比例
                    .outputQuality(quality) // 圖片質(zhì)量
                    .toOutputStream(outputStream);
            long fileSize = outputStream.size();
            if (fileSize <= targetSizeKB) {
                return outputStream.toByteArray();
            }
            outputStream.reset();
            if (quality > 0.1) {
                quality -= 0.1;
            } else {
                scale -= 0.1;
            }
        } while (quality > 0 || scale > 0);
    } catch (IOException e) {
        log.error(e.getMessage());
    }
    return null;
}

通過(guò)縮小圖片尺寸和降低圖片質(zhì)量將圖片壓縮到固定的大小,這里都會(huì)先壓縮一遍。解決調(diào)用頻率限制的問(wèn)題。

限制圖片的分辨率也是使用到 thumbnailator 里面的 size 方法。

thumbnailator 壓縮圖片和限制大小,不能一起使用,只能分來(lái)調(diào)用。

設(shè)置尺寸方法:

/**
 * 圖片壓縮
 * @param imageData
 * @param width           寬度
 * @param height          高度
 * @return
 */
public static byte[] compressSize(byte[] imageData,String outputFormat,int width,int height) {
    if (imageData == null) {
        return null;
    }
    ByteArrayInputStream inputStream = new ByteArrayInputStream(imageData);
    try {
        BufferedImage bufferedImage = ImageIO.read(inputStream);
        int imageWidth = bufferedImage.getWidth();
        int imageHeight = bufferedImage.getHeight();
        if (imageWidth <= width && imageHeight <= height) {
            return imageData;
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
        Thumbnails.of(bufferedImage)
                .size(width,height)
                .outputFormat(outputFormat)
                .toOutputStream(outputStream);
        return outputStream.toByteArray();
    } catch (IOException e) {
        log.error(e.getMessage());
    }
    return null;
}

這里的 width 和 height 并不是直接設(shè)置圖片的長(zhǎng)度和長(zhǎng)度,而是不會(huì)超過(guò)這個(gè)長(zhǎng)度和寬度。如果有一個(gè)超過(guò)限制大小,壓縮尺寸,長(zhǎng)寬比保持不變。

新增圖片需要指定 EntityId、url 以及 picName。

@Data
public class AddImageDTO {
    private String entityId;
    private String imgUrl;
    private String picName;
}

解決了圖片壓縮問(wèn)題,上傳圖片就比較簡(jiǎn)單了:

public void uploadImage(List<AddImageDTO> list) {
    if (CollectionUtils.isEmpty(list)) {
        return;
    }
    list.stream().forEach(imageDTO -> {
        String imgUrlStr = imageDTO.getImgUrl();
        if (StringUtils.isBlank(imgUrlStr)) {
            // 跳過(guò)當(dāng)前元素
            return;
        }
        CreateImageRequest request = new CreateImageRequest();
        request.setGroupId(tiiaProperties.getGroupId());
        request.setEntityId(imageDTO.getEntityId());
        String imageUrl = imageDTO.getImgUrl();
        // 限制大小
        byte[] bytes = ImageUtils.compress(imageUrl,0.6,1024 * 5);
        String imageFormat = imageUrl.substring(imageUrl.lastIndexOf(".") + 1);
        // 限制分辨率
        bytes = ImageUtils.compressSize(bytes,imageFormat,4096,4096);
        request.setImageBase64(new String(Base64.encodeBase64(bytes), StandardCharsets.UTF_8));
        //JSONObject tagJson = new JSONObject();
        //tagJson.put("code","搜索字段");
        //request.setTags(JSONObject.toJSONString(tagJson));
        request.setPicName(imageDTO.getPicName());
        try {
            tiiaClient.CreateImage(request);
        } catch (TencentCloudSDKException e) {
            log.error("圖像上傳失敗 error:{}", e.getMessage());
        }
    });
}

Tags 圖片自定義標(biāo)簽,設(shè)置圖片的參數(shù),搜索的時(shí)候就可以根據(jù)參數(shù)搜索到不同的圖片。

更新圖片

一般商品更新,將數(shù)據(jù)存入緩存中:

  String value = "demo key";
  SetOperations<String, Object> opsForSet = redisTemplate.opsForSet();
  opsForSet.add(RedisKeyConstant.PRODUCT_IMAGE_SYNC_CACHE_KEY, value);

再定時(shí)執(zhí)行任務(wù):

public void syncImage() {
    while (true) {
        SetOperations<String, Object> operations = redisTemplate.opsForSet();
        Object obj = operations.pop(RedisKeyConstant.PRODUCT_IMAGE_SYNC_CACHE_KEY);
        if (obj == null) {
            log.info("暫未發(fā)現(xiàn)任務(wù)數(shù)據(jù)");
            return;
        }
        String pop = obj.toString();
        if (StringUtils.isBlank(pop)) {
            continue;
        }
        DeleteImageDTO deleteImageDTO = new DeleteImageDTO();
        deleteImageDTO.setEntityId(pop);
        try {
            this.deleteImage(Collections.singletonList(deleteImageDTO));
        } catch (Exception e) {
            log.error("刪除圖片失敗,entityId {}",pop);
        }
        // todo 獲取數(shù)據(jù)具體的數(shù)據(jù)
        String imageUrl="";
        // todo picName 需要全局唯一
        String picName="";
        AddImageDTO addImageDTO = new AddImageDTO();
        addImageDTO.setEntityId(pop);
        addImageDTO.setImgUrl(imageUrl);
        addImageDTO.setPicName(picName);
        try {
            this.uploadImage(Collections.singletonList(addImageDTO));
        } catch (Exception e) {
            log.error("上傳圖片失敗,entityId {}",pop);
        }
    }
}

operations.pop 從集合隨機(jī)取出一個(gè)數(shù)據(jù)并移除數(shù)據(jù),先刪除圖片,再?gòu)臄?shù)據(jù)庫(kù)中查詢是否存在數(shù)據(jù),如果存在就新增圖片。

搜索圖片

圖像搜索調(diào)用 tiiaClient.SearchImage 方法,需要傳圖片字節(jié)流,壓縮圖片需要文件后綴。

@Data
public class SearchRequest {
  private byte[] bytes;
  private String suffix;
}

public ImageInfo [] analysis(SearchRequest searchRequest) throws IOException, TencentCloudSDKException {
    SearchImageRequest request = new SearchImageRequest();
    request.setGroupId(tiiaProperties.getGroupId());
    // 篩選,對(duì)應(yīng)上傳接口 Tags
    //request.setFilter("channelCode=\"" + searchRequest.getChannelCode() + "\"");、
    byte[] bytes = searchRequest.getBytes();
    bytes = ImageUtils.compressSize(bytes,searchRequest.getSuffix(),4096,4096);
    String base64 = Base64.encodeBase64String(bytes);
    request.setImageBase64(base64);
    SearchImageResponse searchImageResponse = tiiaClient.SearchImage(request);
    return searchImageResponse.getImageInfos();
}

根據(jù)返回的 ImageInfos 數(shù)組獲取到 EntityId,就能獲取對(duì)應(yīng)的商品信息了。

總結(jié)

對(duì)接圖像搜索,主要是做圖像的更新和同步操作。相對(duì)于每次更新就同步接口,這種方式對(duì)于服務(wù)器的壓力也比較大,先將數(shù)據(jù)同步到緩存中,然后在定時(shí)的處理數(shù)據(jù),而搜索圖片對(duì)于數(shù)據(jù)一致性相對(duì)比較寬松,分散庫(kù)寫(xiě)入的壓力。

新增圖片使用 thumbnailator 壓縮圖片和縮小圖片,對(duì)于調(diào)用請(qǐng)求頻率限制,新增圖片每次都會(huì)壓縮一次圖片,每次壓縮時(shí)間大概都大于 100ms,解決了請(qǐng)求頻率限制的問(wèn)題。而刪除圖片,就簡(jiǎn)單使用線程休眠的方式休眠 100ms。

做好圖片更新的操作之后,搜索圖庫(kù)使用 tiiaClient.SearchImage 方法就能獲取到對(duì)應(yīng)的結(jié)果信息了。

Github示例

https://github.com/jeremylai7/springboot-learning/blob/master/springboot-test/src/main/java/com/test/controller/ImageSearchController.java

轉(zhuǎn)自https://www.cnblogs.com/jeremylai7/p/18551697


該文章在 2024/11/18 10:19:28 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved