1
0
mirror of synced 2026-10-11 17:46:44 +08:00

🆕 #4028 【公众号】实现 OCR 菜单识别的接口

This commit is contained in:
Copilot
2026-07-14 14:29:19 +08:00
committed by GitHub
parent 83d7744425
commit 124ff523f3
7 changed files with 176 additions and 1 deletions

View File

@@ -0,0 +1,47 @@
package me.chanjar.weixin.common.bean.ocr;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import me.chanjar.weixin.common.util.json.WxGsonBuilder;
import java.io.Serializable;
import java.util.List;
/**
* OCR菜单识别结果.
*
* @author GitHub Copilot
*/
@Data
public class WxOcrMenuResult implements Serializable {
private static final long serialVersionUID = -8062516251827437945L;
@SerializedName("img_size")
private WxOcrImgSize imgSize;
@SerializedName("items")
private List<Items> items;
public static WxOcrMenuResult fromJson(String json) {
return WxGsonBuilder.create().fromJson(json, WxOcrMenuResult.class);
}
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
@Data
public static class Items implements Serializable {
private static final long serialVersionUID = 3066181677009102792L;
@SerializedName("text")
private String text;
@SerializedName("pos")
private WxOcrPos pos;
@Override
public String toString() {
return WxGsonBuilder.create().toJson(this);
}
}
}

View File

@@ -7,6 +7,7 @@ import me.chanjar.weixin.common.bean.ocr.WxOcrCommResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingLicenseResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrIdCardResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrMenuResult;
import java.io.File;
@@ -130,4 +131,22 @@ public interface WxOcrService {
* @throws WxErrorException .
*/
WxOcrCommResult comm(File imgFile) throws WxErrorException;
/**
* 菜单OCR识别接口
* 文件大小限制:小于2M
* @param imgUrl 图片url地址
* @return WxOcrMenuResult
* @throws WxErrorException .
*/
WxOcrMenuResult menu(String imgUrl) throws WxErrorException;
/**
* 菜单OCR识别接口
* 文件大小限制:小于2M
* @param imgFile 图片文件对象
* @return WxOcrMenuResult
* @throws WxErrorException .
*/
WxOcrMenuResult menu(File imgFile) throws WxErrorException;
}

View File

@@ -138,4 +138,23 @@ public class WxMaOcrServiceImpl implements WxOcrService {
FILE_COMM, imgFile);
return WxOcrCommResult.fromJson(result);
}
@Override
public WxOcrMenuResult menu(String imgUrl) throws WxErrorException {
try {
imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// ignore cannot happen
}
final String result = this.service.post(String.format(MENU, imgUrl), (String) null);
return WxOcrMenuResult.fromJson(result);
}
@Override
public WxOcrMenuResult menu(File imgFile) throws WxErrorException {
String result = this.service.execute(OcrDiscernRequestExecutor.create(this.service.getRequestHttp()),
FILE_MENU, imgFile);
return WxOcrMenuResult.fromJson(result);
}
}

View File

@@ -403,6 +403,8 @@ public class WxMaApiUrlConstants {
String FILE_BIZ_LICENSE = "https://api.weixin.qq.com/cv/ocr/bizlicense";
String COMM = "https://api.weixin.qq.com/cv/ocr/comm?img_url=%s";
String FILE_COMM = "https://api.weixin.qq.com/cv/ocr/comm";
String MENU = "https://api.weixin.qq.com/cv/ocr/menu?img_url=%s";
String FILE_MENU = "https://api.weixin.qq.com/cv/ocr/menu";
}
public interface Product {

View File

@@ -143,4 +143,24 @@ public class WxMpOcrServiceImpl implements WxOcrService {
FILE_COMM.getUrl(this.mainService.getWxMpConfigStorage()), imgFile);
return WxOcrCommResult.fromJson(result);
}
@Override
public WxOcrMenuResult menu(String imgUrl) throws WxErrorException {
try {
imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
// ignore cannot happen
}
final String result = this.mainService.post(String.format(MENU.getUrl(this.mainService.getWxMpConfigStorage()),
imgUrl), (String) null);
return WxOcrMenuResult.fromJson(result);
}
@Override
public WxOcrMenuResult menu(File imgFile) throws WxErrorException {
String result = this.mainService.execute(OcrDiscernRequestExecutor.create(this.mainService.getRequestHttp()),
FILE_MENU.getUrl(this.mainService.getWxMpConfigStorage()), imgFile);
return WxOcrMenuResult.fromJson(result);
}
}

View File

@@ -533,7 +533,17 @@ public interface WxMpApiUrl {
/**
* 通用印刷体OCR识别(文件)
*/
FILE_COMM(API_DEFAULT_HOST_URL, "/cv/ocr/comm");
FILE_COMM(API_DEFAULT_HOST_URL, "/cv/ocr/comm"),
/**
* 菜单OCR识别
*/
MENU(API_DEFAULT_HOST_URL, "/cv/ocr/menu?img_url=%s"),
/**
* 菜单OCR识别(文件)
*/
FILE_MENU(API_DEFAULT_HOST_URL, "/cv/ocr/menu");
private final String prefix;
private final String path;

View File

@@ -11,6 +11,7 @@ import me.chanjar.weixin.common.bean.ocr.WxOcrCommResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingLicenseResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrDrivingResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrIdCardResult;
import me.chanjar.weixin.common.bean.ocr.WxOcrMenuResult;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
@@ -137,6 +138,22 @@ public class WxMpOcrServiceImplTest {
System.out.println(result);
}
@Test
public void testMenu() throws WxErrorException {
final WxOcrMenuResult result = this.service.getOcrService().menu("https://res.wx.qq.com/op_res/apCy0YbnEdjYsa_cjW6x3FlpCc20uQ-2BYE7aXnFsrB-ALHZNgdKXhzIUcrRnDoL");
assertThat(result).isNotNull();
System.out.println(result);
}
@Test
public void testMenu2() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("mm.jpeg");
File tempFile = FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), TestConstants.FILE_JPG);
final WxOcrMenuResult result = this.service.getOcrService().menu(tempFile);
assertThat(result).isNotNull();
System.out.println(result);
}
private InputStream getImageStream(String url) {
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
@@ -390,5 +407,46 @@ public class WxMpOcrServiceImplTest {
assertThat(result).isNotNull();
System.out.println(result);
}
@Test
public void testMenu() throws Exception {
String returnJson = "{\n" +
" \"errcode\": 0, \n" +
" \"errmsg\": \"ok\", \n" +
" \"items\": [\n" +
" {\n" +
" \"text\": \"红烧肉\", \n" +
" \"pos\": {\n" +
" \"left_top\": {\n" +
" \"x\": 575, \n" +
" \"y\": 519\n" +
" }, \n" +
" \"right_top\": {\n" +
" \"x\": 744, \n" +
" \"y\": 519\n" +
" }, \n" +
" \"right_bottom\": {\n" +
" \"x\": 744, \n" +
" \"y\": 532\n" +
" }, \n" +
" \"left_bottom\": {\n" +
" \"x\": 573, \n" +
" \"y\": 532\n" +
" }\n" +
" }\n" +
" }\n" +
" ], \n" +
" \"img_size\": {\n" +
" \"w\": 1280, \n" +
" \"h\": 720\n" +
" }\n" +
"}";
when(wxService.post(anyString(), anyString())).thenReturn(returnJson);
final WxMpOcrServiceImpl wxMpOcrService = new WxMpOcrServiceImpl(wxService);
final WxOcrMenuResult result = wxMpOcrService.menu("abc");
assertThat(result).isNotNull();
System.out.println(result);
}
}
}