Commit a4d362c5 by 侯昆

Merge branch 'master' of http://gitlab.coralcodes.com:30000/shil0009/cihai

# Conflicts:
#	serverside/cihai-core/src/main/java/com/dookay/cihai/core/aip/AipImageClassifyClient.java
2 parents caf9335b 6d444bb4
Showing 18 changed files with 576 additions and 49 deletions
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip;
import com.dookay.cihai.core.aip.enums.ImageInputTypeEnum;
import com.dookay.cihai.core.aip.enums.ScanResultTypeEnum;
import com.dookay.cihai.core.aip.model.GeneralRecognitionResult;
import com.dookay.cihai.core.aip.model.ImageResult;
import com.dookay.cihai.core.aip.model.ScanResult;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Collections;
/**
*
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Component
@Slf4j
public class AipDefaultClient {
@Autowired
private AipImageClassifyClient aipImageClassifyClient;
@Autowired
private AipOcrClient aipOcrClient;
/**
* 图片扫描
* @param
* @author luxor
* @date 2017/12/7
*/
public ScanResult scan(String imageBase64) throws JSONException {
ScanResult result = new ScanResult();
GeneralRecognitionResult generalRecognitionResult = aipOcrClient.generalRecognition(imageBase64, ImageInputTypeEnum.BASE64);
if(generalRecognitionResult.getWordsResultNum()>0){
result.setType(ScanResultTypeEnum.WORDS.getValue());
result.setWordsList(generalRecognitionResult.getWordsResult());
}else{
result.setType(ScanResultTypeEnum.PICTURE.getValue());
ImageResult imageResult = aipImageClassifyClient.getImageResult(imageBase64);
result.setWordsList(Collections.singletonList(imageResult.getName()));
}
return result;
}
}
......@@ -18,7 +18,6 @@ package com.dookay.cihai.core.aip;
import com.alibaba.fastjson.JSON;
import com.baidu.aip.imageclassify.AipImageClassify;
import com.baidu.aip.util.Base64Util;
import com.dookay.cihai.core.aip.enums.ImageInputTypeEnum;
import com.dookay.cihai.core.aip.model.ImageResult;
import com.dookay.coral.common.core.exception.ServiceException;
......@@ -27,14 +26,10 @@ import org.codehaus.plexus.util.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.*;
/**
* 图片识别客户端
......@@ -52,7 +47,7 @@ public class AipImageClassifyClient {
public static final String SECRET_KEY = "YUGcqkGioxrceK4CgD3wB90vmmG7KzRf";
/**
* 获取动物图片识别结果列表,可能会有多个结果
* 获取动物图片识别结果列表,会有多个结果
* @param
* @author luxor
* @date 2017/12/7
......@@ -71,12 +66,11 @@ public class AipImageClassifyClient {
log.info(image);
}
// 调用接口
return parseResult(res);
}
/**
* 获取动物图片识别结果列表,可能会有多个结果
* 获取植物图片识别结果列表,会有多个结果
* @param
* @author luxor
* @date 2017/12/7
......@@ -95,7 +89,6 @@ public class AipImageClassifyClient {
log.info(image);
}
// 调用接口
return parseResult(res);
}
......@@ -134,15 +127,13 @@ public class AipImageClassifyClient {
if(StringUtils.isBlank(imageBase64)){
return new ImageResult();
}
String image = imageBase64.replace("data:image/png;base64,","")
.replace("data:image/jpg;base64,","")
.replace("data:image/jpeg;base64,","");
String image = AipUtils.fixImage(imageBase64);
log.info("image:"+image);
List<ImageResult> imageResultList = this.getAnimalDetect(image,ImageInputTypeEnum.BASE64);
List<ImageResult> imageResultList2 = this.getPlantDetect(image,ImageInputTypeEnum.BASE64);
imageResultList.addAll(imageResultList2);
log.info(JSON.toJSONString(imageResultList));
return imageResultList.stream().filter(x->x.getScore()<0.99).sorted(Comparator.comparing(ImageResult::getScore).reversed()).findFirst().orElse(new ImageResult());
return imageResultList.stream().filter(x-> !Objects.equals(x.getName(), "非动物")).sorted(Comparator.comparing(ImageResult::getScore).reversed()).findFirst().orElse(new ImageResult());
}
}
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip;
import com.baidu.aip.ocr.AipOcr;
import com.dookay.cihai.core.aip.enums.ImageInputTypeEnum;
import com.dookay.cihai.core.aip.model.GeneralRecognitionResult;
import com.dookay.cihai.core.aip.model.ImageResult;
import com.dookay.coral.common.core.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.stereotype.Component;
import org.springframework.util.Base64Utils;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 图文文字识别客户端
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Component
@Slf4j
public class AipOcrClient {
//设置APPID/AK/SK
public static final String APP_ID = "10492789";
public static final String API_KEY = "MfnPaNqkmPyyU6GecceDmkFt";
public static final String SECRET_KEY = "f7saVfLEXKC6AG6TU3CEfG0iUCXXY2kn";
/**
* 通用文字识别
* @param
* @param image
* @author luxor
* @date 2017/12/7
*/
public GeneralRecognitionResult generalRecognition(String image, ImageInputTypeEnum typeEnum) throws JSONException {
// 初始化一个AipOcr
AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
// 自定义参数定义
HashMap<String, String> options = new HashMap<String, String>();
options.put("detect_direction", "true");
options.put("language_type", "CHN_ENG");
//调用接口
JSONObject res;
// 参数为本地图片路径
if(typeEnum == ImageInputTypeEnum.PATH){
res = client.basicGeneral(image, options);
}else{
image = AipUtils.fixImage(image);
byte[] file = Base64Utils.decodeFromString(image);
res = client.basicGeneral(file, options);
log.info(image);
}
return parseResult(res);
}
/**
* 解析结果
* @param
* @author luxor
* @date 2017/12/7
*/
private GeneralRecognitionResult parseResult(JSONObject res) throws JSONException {
if(res.has("error_code")){
log.info("图像识别错误:"+res.toString(2));
throw new ServiceException("图像识别错误:"+res.toString(2));
}else{
GeneralRecognitionResult result = new GeneralRecognitionResult();
result.setWordsResultNum(res.getInt("words_result_num"));
List<String> wordsList = new ArrayList<>();
JSONArray jsonArray = res.getJSONArray("words_result");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonObject = jsonArray.getJSONObject(i);
wordsList.add(jsonObject.getString("words"));
}
result.setWordsResult(wordsList);
return result;
}
}
}
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip;
import java.io.*;
import java.util.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
public class AipUtils {
/**
* 读取txt文件的内容
* @param file 想要读取的文件对象
* @return 返回文件内容
* @author luxor
* @date 2017/12/7
*/
public static String txt2String(File file){
StringBuilder result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
String s = null;
while((s = br.readLine())!=null){//使用readLine方法,一次读一行
result.append(s);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
/**
* @param
* @author luxor
* @date 2017/12/7
*/
public static String fixImage(String imageBase64){
return imageBase64.replace("data:image/png;base64,","")
.replace("data:image/jpg;base64,","")
.replace("data:image/jpeg;base64,","");
}
/**
* 文件转base64字符串
* @param file
* @return
* @author luxor
* @date 2017/12/7
*/
public static String encodeBase64File( File file) throws Exception {
FileInputStream inputFile = new FileInputStream(file);
byte[] buffer = new byte[(int) file.length()];
inputFile.read(buffer);
inputFile.close();
return new BASE64Encoder().encode(buffer);
}
}
......@@ -250,7 +250,7 @@ public final class AipWordUtilBean {
* @author houkun
* @date 2017/12/6
*/
private List<LexerItem> getLexerItems(String document) throws JSONException {
public List<LexerItem> getLexerItems(String document) throws JSONException {
List<String> documents = splitDocument(document, 10000);
List<LexerItem> lexerItems = new ArrayList<>();
for (String s : documents) {
......
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip.enums;
import com.dookay.coral.common.core.enums.IEnum;
/**
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
public enum ScanResultTypeEnum implements IEnum {
PICTURE(1, "图片"),
WORDS(2,"文字");
private int value;
private String description;
ScanResultTypeEnum(int value, String description) {
this.value = value;
this.description = description;
}
@Override
public int getValue() {
return value;
}
@Override
public String getDescription() {
return description;
}
public static ScanResultTypeEnum valueOf(Integer value) {
ScanResultTypeEnum[] values = ScanResultTypeEnum.values();
for (ScanResultTypeEnum item : values) {
if (item.value == value) {
return item;
}
}
return null;
}
}
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip.model;
import lombok.Data;
import java.util.List;
/**
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Data
public class GeneralRecognitionResult {
/*识别结果数,表示words_result的元素个数*/
private Integer wordsResultNum;
/*识别结果字符串数字*/
private List<String> wordsResult;
}
/*****************************************
* *
* @dookay.com Internet make it happen *
* ----------- ----------------------- *
* dddd ddddd Internet make it happen *
* o o o Internet make it happen *
* k k k Internet make it happen *
* a a a Internet make it happen *
* yyyy yyyyy Internet make it happen *
* ----------- ----------------------- *
* Code is far away from bug with the *
* animal protecting *
* 神兽保佑,代码无bug  *
* *
****************************************/
package com.dookay.cihai.core.aip.model;
import lombok.Data;
import java.util.List;
/**
* 图像扫描结果
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Data
public class ScanResult {
/*图像、文字*/
private Integer type;
/*结果文字列表*/
private List<String> wordsList;
}
......@@ -81,6 +81,8 @@ public class WordDomain implements Serializable {
private String wordSpell;
private String category;
private String wordAlias;
}
......@@ -6,6 +6,8 @@ import tk.mybatis.mapper.entity.Example;
import com.dookay.coral.common.core.persistence.criteria.QueryCriteria;
import com.dookay.cihai.core.word.domain.WordDomain;
import java.util.List;
/**
* 词条
*
......@@ -18,12 +20,27 @@ public class WordQuery extends Query {
private String keyword;
private List<String> keywordList;
@Override
public QueryCriteria toCriteria() {
QueryCriteria queryCriteria = new QueryCriteria(WordDomain.class);
Example.Criteria criteria = queryCriteria.createCriteria();
if (valid(keyword)) {
String str = "%" + keyword + "%";
criteria.andCondition(String.format("(word like '%s' or word_alias like '%s')", str, str));
}
if (valid(keywordList)) {
String sql = "";
for (int i = 0; i < keywordList.size(); i++) {
if (i == 0) {
sql += " word like '%" + keywordList.get(i) + "%'";
} else {
sql += " or word like '%" + keywordList.get(i) + "%'";
}
}
System.out.println(sql);
criteria.andCondition(sql);
}
//todo 写查询逻辑
return queryCriteria;
......
package com.dookay.cihai.core.aip;
import com.alibaba.fastjson.JSON;
import com.dookay.cihai.core.CihaiCoreApplicationTests;
import com.dookay.cihai.core.aip.model.ScanResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import java.io.File;
/**
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Slf4j
public class AipDefaultClientTest extends CihaiCoreApplicationTests {
@Autowired
private AipDefaultClient aipDefaultClient;
@Test
public void scan() throws Exception {
File file = ResourceUtils.getFile("classpath:daxiang.txt");
String image = AipUtils.txt2String(file);
ScanResult result = aipDefaultClient.scan(image);
log.info(JSON.toJSONString(result));
}
}
\ No newline at end of file
......@@ -8,11 +8,7 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import static org.junit.Assert.*;
/**
* @author Luxor
......@@ -26,32 +22,13 @@ public class AipImageClassifyClientTest extends CihaiCoreApplicationTests {
@Test
public void getImageResult() throws Exception {
File file = ResourceUtils.getFile("classpath:daxiang.txt");
System.out.println(txt2String(file));
String image = txt2String(file);
File file = ResourceUtils.getFile("classpath:mudan.txt");
System.out.println(AipUtils.txt2String(file));
String image = AipUtils.txt2String(file);
log.info(image);
ImageResult imageResult = aipImageClassifyClient.getImageResult(image);
Boolean flag = imageResult.getScore()<0.99;
log.info(JSON.toJSONString(imageResult));
}
/**
* 读取txt文件的内容
* @param file 想要读取的文件对象
* @return 返回文件内容
*/
public static String txt2String(File file){
StringBuilder result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
String s = null;
while((s = br.readLine())!=null){//使用readLine方法,一次读一行
result.append(s);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
}
\ No newline at end of file
package com.dookay.cihai.core.aip;
import com.alibaba.fastjson.JSON;
import com.dookay.cihai.core.CihaiCoreApplicationTests;
import com.dookay.cihai.core.aip.enums.ImageInputTypeEnum;
import com.dookay.cihai.core.aip.model.GeneralRecognitionResult;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import java.io.*;
import static org.junit.Assert.*;
/**
* @author Luxor
* @version v0.0.1
* @since 2017/12/7
*/
@Slf4j
public class AipOcrClientTest extends CihaiCoreApplicationTests {
@Autowired
private AipOcrClient aipOcrClient;
@Test
public void generalRecognition() throws Exception {
File file = ResourceUtils.getFile("classpath:wenzi.txt");
String image = AipUtils.txt2String(file);
GeneralRecognitionResult result = aipOcrClient.generalRecognition(image, ImageInputTypeEnum.BASE64);
log.info(JSON.toJSONString(result));
}
@Test
public void generalRecognition2() throws Exception {
File file = ResourceUtils.getFile("classpath:daxiang.txt");
String image = AipUtils.txt2String(file);
GeneralRecognitionResult result = aipOcrClient.generalRecognition(image, ImageInputTypeEnum.BASE64);
log.info(JSON.toJSONString(result));
}
/**
* 读取txt文件的内容
* @param file 想要读取的文件对象
* @return 返回文件内容
*/
public static String txt2String(File file){
StringBuilder result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
String s = null;
while((s = br.readLine())!=null){//使用readLine方法,一次读一行
result.append(s);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
}
\ No newline at end of file
data:image/png;base64,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
\ No newline at end of file
......@@ -14,16 +14,23 @@
package com.dookay.cihai.wechat.controller;
import com.dookay.cihai.core.aip.AipImageClassifyClient;
import com.dookay.cihai.core.aip.AipWordUtilBean;
import com.dookay.cihai.core.aip.model.ImageResult;
import com.dookay.cihai.core.aip.model.LexerItem;
import com.dookay.cihai.core.theme.domain.ThemeDomain;
import com.dookay.cihai.core.theme.query.ThemeQuery;
import com.dookay.cihai.core.theme.service.IThemeService;
import com.dookay.cihai.core.word.domain.WordDomain;
import com.dookay.cihai.core.word.domain.CustomDictionaryDomain;
import com.dookay.cihai.core.word.query.CustomDictionaryQuery;
import com.dookay.cihai.core.word.query.WordQuery;
import com.dookay.cihai.core.word.service.ICustomDictionaryService;
import com.dookay.cihai.core.word.service.IWordService;
import com.dookay.coral.common.web.constant.MediaTypes;
import com.dookay.coral.common.web.controller.BaseController;
import com.dookay.coral.common.web.response.JsonResult;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -32,6 +39,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author 石磊
......@@ -52,6 +60,9 @@ public class HomeController extends BaseController {
@Autowired
private AipWordUtilBean aipWordUtilBean;
@Autowired
private AipImageClassifyClient aipImageClassifyClient;
/**
* @author 石磊
* @date 2017/12/6
......@@ -71,7 +82,10 @@ public class HomeController extends BaseController {
@RequestMapping(value = "/home/search", method = RequestMethod.GET)
@ResponseBody
public JsonResult search(String keyword) {
System.out.println("进入搜索");
System.out.println("进入搜索:" + keyword);
if (StringUtils.isBlank(keyword)) {
return errorResult("搜索内容不能为空");
}
String result = null;
boolean inDic = false;
List<CustomDictionaryDomain> dictionaryDomainList = customDictionaryService.getList(new CustomDictionaryQuery());
......@@ -88,7 +102,19 @@ public class HomeController extends BaseController {
ThemeQuery query = new ThemeQuery();
query.setKeyword(result);
ThemeDomain themeDomain = themeService.getFirst(query);
if (themeDomain == null) return errorResult(String.format("暂无\"%s\"检索结果", keyword));
if (themeDomain == null) {
WordQuery wordQuery = new WordQuery();
wordQuery.setKeyword(result);
WordDomain wordDomain = wordService.getFirst(wordQuery);
if (wordDomain == null) {
List<LexerItem> items = aipWordUtilBean.getLexerItems(result);
wordQuery.setKeywordList(items.stream().map(n -> n.getItem()).collect(Collectors.toList()));
wordQuery.setKeyword(null);
wordDomain = wordService.getFirst(wordQuery);
if (wordDomain == null) return errorResult(String.format("暂无\"%s\"检索结果", keyword));
}
return successResult("success", "/word/baike/" + wordDomain.getId());
}
System.out.println(themeDomain);
return successResult("success", "/theme/detail/" + themeDomain.getId());
} catch (Exception ex) {
......@@ -96,4 +122,33 @@ public class HomeController extends BaseController {
}
}
/**
* @author 石磊
* @date 2017/12/7
* @description 图片搜索
*/
@RequestMapping(value = "/image/search", method = RequestMethod.POST, produces = MediaTypes.JSON_UTF_8)
@ResponseBody
public JsonResult imageSearch(String image) {
System.out.println("进入图片检索");
try {
ImageResult imageResult = aipImageClassifyClient.getImageResult(image);
String name = imageResult.getName();
System.out.println(name);
WordQuery wordQuery = new WordQuery();
wordQuery.setKeyword(name);
WordDomain wordDomain = wordService.getFirst(wordQuery);
if (wordDomain == null) {
List<LexerItem> items = aipWordUtilBean.getLexerItems(name);
wordQuery.setKeywordList(items.stream().map(n -> n.getItem()).collect(Collectors.toList()));
wordQuery.setKeyword(null);
wordDomain = wordService.getFirst(wordQuery);
if (wordDomain == null) return errorResult("暂无检索结果");
}
return successResult("success", "/word/baike/" + wordDomain.getId());
} catch (Exception ex) {
return errorResult("暂无检索结果");
}
}
}
......@@ -57,7 +57,6 @@
wx.stopRecord({
success: function (res) {
myApp.dialog.preloader();
var localId = res.localId;
wx.translateVoice({
localId: localId, // 需要识别的音频的本地Id,由录音相关接口获得
......@@ -105,9 +104,19 @@
localId: localIds[0], // 图片的localID
success: function (res) {
myApp.dialog.preloader();
var localData = res.localData; // localData是图片的base64数据,可以用img标签显示
alert(localData);
jQuery.post("/image/search",{image:localData},function (data) {
myApp.dialog.close();
if (data.code == "OK") {
// myApp.view.main.router.load({
// url:data.data
// });
location.href = data.data;
} else {
myApp.dialog.alert(data.message);
}
})
}
});
......
......@@ -290,7 +290,7 @@
<div class="navbar">
<div class="navbar-inner">
<div class="left">
<a class="link back" href="/">
<a class="link back js-jump-page" href="/">
<i class="iconfont icon-jiantou"></i>
<span class="ios-only">返回</span>
</a>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!