摘要:微信接入采用的第三方接入微信,具體功能接入還是要看微信公眾號(hào)開發(fā)文檔,架構(gòu)則是上面所說(shuō)的。吐槽一下,騰訊包括微信,他們的文檔確實(shí)沒有阿里做得好。人臉融合結(jié)尾這一塊騰訊人工智能接入已解釋完畢。
前言要想騎自行車,首先不是要學(xué)會(huì)如何造自行車,而是學(xué)會(huì)如何騎行
結(jié)合騰訊AI開放平臺(tái)群里的demo解析,QQ群號(hào):581197347。
這個(gè)項(xiàng)目是我只花費(fèi)兩天時(shí)間做完的,采用的技術(shù)是SpringBoot+SpringCloud+MongoDB。
為啥只要兩天呢,現(xiàn)在是微服務(wù)快速開發(fā)時(shí)代,兩天開發(fā)一個(gè)小型項(xiàng)目真的自己都覺得花費(fèi)時(shí)間太長(zhǎng)。
前端框架采用Layui,如果是微信訪問(wèn)則會(huì)跳到微信端的頁(yè)面。微信接入采用GitHub的第三方接入微信,
具體功能接入還是要看微信公眾號(hào)開發(fā)文檔,架構(gòu)則是上面所說(shuō)的SpringBoot+SpringCloud。數(shù)據(jù)庫(kù)方面采用MongoDB,因?yàn)槲抑恍枰鎴D片文件不需要采集用戶信息。
這是現(xiàn)在上線的項(xiàng)目,您也可以微信掃碼訪問(wèn),都是同一個(gè)鏈接。點(diǎn)擊訪問(wèn)項(xiàng)目
在iphone這邊試了下人臉融合好像不行。因?yàn)槲⑿舑dk要另外設(shè)置。沒ios機(jī)...
這里主要詳解如何接入騰訊第三方AI,其他會(huì)簡(jiǎn)單帶過(guò):騰訊AI官網(wǎng)
為什么選擇騰訊的?而不是選擇阿里,網(wǎng)易,百度呢?主要他們都要認(rèn)證,要錢。(貧窮限制我的選擇)。
開玩笑,言歸正傳,這是因?yàn)殚_發(fā)簡(jiǎn)潔通用,只要會(huì)一種,其他就換湯不換藥。唯一的缺點(diǎn)就是他不保證并發(fā)。如果你只需要一種識(shí)別,并且是穩(wěn)定高并發(fā)的,我建議阿里哈。
騰訊AI技術(shù)文檔這個(gè)文檔的接口鑒權(quán)也就是獲取sign我是不建議你們?nèi)タ吹?,因?yàn)槎疾恢浪谡f(shuō)什么獎(jiǎng)杯,我在這里跟大家講如何獲得sign,后面的接入就可以按照文檔來(lái)操作了。
ps:吐槽一下,騰訊包括微信,他們的文檔確實(shí)沒有阿里做得好。
首先在這里,我說(shuō)明一下,我會(huì)將他作為一個(gè)main主函數(shù)來(lái)運(yùn)行。我也只講一種方式,其他你真的看懂了,自然而然就會(huì)運(yùn)用了。
首先要知道如何獲得簽名也就是我們所謂的Sign和要求計(jì)算的參數(shù)
你可以根據(jù)官方文檔看到我們需要通過(guò)這幾個(gè)參數(shù)來(lái)計(jì)算出簽名,然而他們并沒有說(shuō)明這個(gè)text:騰訊AI開放平臺(tái)是什么,這個(gè)text就是你要接入哪種識(shí)別另外要加入的參數(shù),就比如這里我講解人臉融合,人臉融合根據(jù)文檔要多傳一個(gè)model參數(shù),也就是說(shuō)這個(gè)model也要加入Sign的計(jì)算當(dāng)中。
那么我們知道了sign需要的參數(shù),我們要怎么計(jì)算呢。
直接看文檔對(duì)于初學(xué)者來(lái)說(shuō),看了等于白看,文檔說(shuō)要
1. 獲得參數(shù)對(duì)列表N(字典升級(jí)排序)。 2. 按URL鍵值拼接字符串T,參數(shù)對(duì)列表N的參數(shù)對(duì)進(jìn)行URL鍵值拼接,值使用URL編碼,URL編碼算法用大寫字母。 3. 拼接應(yīng)用密鑰,得到字符串S。 4. 計(jì)算MD5摘要,得到簽名字符串。
獲得Sign說(shuō)實(shí)話,第一次我看這個(gè)文檔我的main函數(shù)運(yùn)行的不少于100遍的出錯(cuò)。那要怎么接入呢? 如果你看的懂文檔,請(qǐng)直接略過(guò)這端Sign簽名
時(shí)間戳time_stamp和隨機(jī)字符串nonce_str我們直接可以自己生成的。
String time_stamp = System.currentTimeMillis()/1000+""; String nonce_str = TencentAISign.getRandomString(10);
還有image屬性也就是你上傳的照片,騰訊限定了圖片大小(根據(jù)文檔)和要求原始圖片的base64編碼數(shù)據(jù)
如何限定圖片大小就是你的事了,在這里將如何將圖片進(jìn)行base64編碼,編碼這里我講兩種,一種是本地路徑編碼,另一種根據(jù)Url網(wǎng)絡(luò)資源編碼。
這里我寫一個(gè)工具類,可以根據(jù)本地或者Url分別進(jìn)行base64編碼
public class UrlMethodUtil { public static byte[] local2byte(String url)throws Exception{ //由本地路徑得到byte byte [] imageData = FileUtil.readFileByBytes(url); return imageData; } public static byte[] url2byte(String url)throws Exception { //由url得到byte byte [] imageData = IoUtil.getImageFromNetByUrl(url); return imageData; } }
FileUtil 就是從本地路徑獲得byte[]數(shù)據(jù)
public class FileUtil { /** * 根據(jù)文件路徑讀取byte[] 數(shù)組 */ public static byte[] readFileByBytes(String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { throw new FileNotFoundException(filePath); } else { ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length()); BufferedInputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file)); short bufSize = 1024; byte[] buffer = new byte[bufSize]; int len1; while (-1 != (len1 = in.read(buffer, 0, bufSize))) { bos.write(buffer, 0, len1); } byte[] var7 = bos.toByteArray(); return var7; } finally { try { if (in != null) { in.close(); } } catch (IOException var14) { var14.printStackTrace(); } bos.close(); } } } }
IoUtil就是從Url獲得byte[]數(shù)據(jù)
public class IoUtil { /** * 根據(jù)地址獲得數(shù)據(jù)的字節(jié)流 * @param strUrl 網(wǎng)絡(luò)連接地址 * @return */ public static byte[] getImageFromNetByUrl(String strUrl){ try { URL url = new URL(strUrl); HttpURLConnection conn = (HttpURLConnection)url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(10 * 1000); InputStream inStream = conn.getInputStream();//通過(guò)輸入流獲取圖片數(shù)據(jù) byte[] btImg = readInputStream(inStream);//得到圖片的二進(jìn)制數(shù)據(jù) return btImg; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 從輸入流中獲取數(shù)據(jù) * @param inStream 輸入流 * @return * @throws Exception */ public static byte[] readInputStream(InputStream inStream) throws Exception{ ByteArrayOutputStream outStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len = 0; while( (len=inStream.read(buffer)) != -1 ){ outStream.write(buffer, 0, len); } inStream.close(); return outStream.toByteArray(); } }
然后就可以很輕松的調(diào)用了:
byte [] imageData = UrlMethodUtil.local2byte("E:/demo.png");//本地圖片
byte [] imageData = UrlMethodUtil.url2byte("網(wǎng)絡(luò)資源路徑Url");
得到byte數(shù)組了我們就可以根據(jù)Base64的工具類轉(zhuǎn)化,這里我貼出來(lái),百度一堆
public class Base64Util { private static final char last2byte = (char) Integer.parseInt("00000011", 2); private static final char last4byte = (char) Integer.parseInt("00001111", 2); private static final char last6byte = (char) Integer.parseInt("00111111", 2); private static final char lead6byte = (char) Integer.parseInt("11111100", 2); private static final char lead4byte = (char) Integer.parseInt("11110000", 2); private static final char lead2byte = (char) Integer.parseInt("11000000", 2); private static final char[] encodeTable = new char[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"}; public Base64Util() { } public static String encode(byte[] from) { StringBuilder to = new StringBuilder((int) ((double) from.length * 1.34D) + 3); int num = 0; char currentByte = 0; int i; for (i = 0; i < from.length; ++i) { for (num %= 8; num < 8; num += 6) { switch (num) { case 0: currentByte = (char) (from[i] & lead6byte); currentByte = (char) (currentByte >>> 2); case 1: case 3: case 5: default: break; case 2: currentByte = (char) (from[i] & last6byte); break; case 4: currentByte = (char) (from[i] & last4byte); currentByte = (char) (currentByte << 2); if (i + 1 < from.length) { currentByte = (char) (currentByte | (from[i + 1] & lead2byte) >>> 6); } break; case 6: currentByte = (char) (from[i] & last2byte); currentByte = (char) (currentByte << 4); if (i + 1 < from.length) { currentByte = (char) (currentByte | (from[i + 1] & lead4byte) >>> 4); } } to.append(encodeTable[currentByte]); } } if (to.length() % 4 != 0) { for (i = 4 - to.length() % 4; i > 0; --i) { to.append("="); } } return to.toString(); } }
這樣image的Base64編碼搞定,終于拿到了image屬性了,接下來(lái)就可以準(zhǔn)備開始簽名啦
我們現(xiàn)在擁有的屬性有:appid,appKey,time_stamp,nonce_str,image。再根據(jù)我們要實(shí)現(xiàn)的功能需要的參數(shù)終于可以實(shí)現(xiàn)簽名啦。感覺好麻煩有木有。確實(shí)是挺麻煩的,但這也是一種安全驗(yàn)證的過(guò)程。
那我們?cè)趺磳⑦@么多參數(shù)放在一起計(jì)算出Sign呢?答案可想而知,用Map。
Mapperson_Id_body = new HashMap<>(); person_Id_body.put("app_id", String.valueOf(TencentAPI.APP_ID_AI)); person_Id_body.put("time_stamp",time_stamp); person_Id_body.put("nonce_str", nonce_str); person_Id_body.put("image", img64); person_Id_body.put("model","1"); //這是人臉融合需要的參數(shù),1表示模板1.
在這里我將用在騰訊公眾平臺(tái)群一位大神發(fā)出來(lái)的通用簽名工具類來(lái)簽名
public class TencentAISignSort { /** * SIGN簽名生成算法-JAVA版本 通用。默認(rèn)參數(shù)都為UTF-8適用 * @param HashMapparams 請(qǐng)求參數(shù)集,所有參數(shù)必須已轉(zhuǎn)換為字符串類型 * @return 簽名 * @throws IOException */ public static String getSignature(Map params) throws IOException { // 先將參數(shù)以其參數(shù)名的字典序升序進(jìn)行排序 Map sortedParams = new TreeMap<>(params); Set > entrys = sortedParams.entrySet(); // 遍歷排序后的字典,將所有參數(shù)按"key=value"格式拼接在一起 StringBuilder baseString = new StringBuilder(); for (Map.Entry param : entrys) { //sign參數(shù) 和 空值參數(shù) 不加入算法 if(param.getValue()!=null && !"".equals(param.getKey().trim()) && !"sign".equals(param.getKey().trim()) && !"".equals(param.getValue().trim())) { baseString.append(param.getKey().trim()).append("=").append(URLEncoder.encode(param.getValue().trim(),"UTF-8")).append("&"); } } System.err.println("未拼接APPKEY的參數(shù):"+baseString.toString()); if(baseString.length() > 0 ) { baseString.deleteCharAt(baseString.length()-1).append("&app_key="+TencentAPI.APP_KEY_AI); } System.err.println("拼接APPKEY后的參數(shù):"+baseString.toString()); // 使用MD5對(duì)待簽名串求簽 try { String sign = MD5.getMD5(baseString.toString()); return sign; } catch (Exception ex) { throw new IOException(ex); } } /** * SIGN簽名生成算法-JAVA版本 針對(duì)于基本文本分析接口要求text為GBK的方法 * @param HashMap params 請(qǐng)求參數(shù)集,所有參數(shù)必須已轉(zhuǎn)換為字符串類型 * @return 簽名 * @throws IOException */ public static String getSignatureforNLP(HashMap params) throws IOException { // 先將參數(shù)以其參數(shù)名的字典序升序進(jìn)行排序 Map sortedParams = new TreeMap<>(params); Set > entrys = sortedParams.entrySet(); // 遍歷排序后的字典,將所有參數(shù)按"key=value"格式拼接在一起 StringBuilder baseString = new StringBuilder(); for (Map.Entry param : entrys) { //sign參數(shù) 和 空值參數(shù) 不加入算法 if(param.getValue()!=null && !"".equals(param.getKey().trim()) && !"sign".equals(param.getKey().trim()) && !"".equals(param.getValue().trim())) { if(param.getKey().equals("text")){ baseString.append(param.getKey().trim()).append("=").append(URLEncoder.encode(param.getValue().trim(),"GBK")).append("&"); }else{ baseString.append(param.getKey().trim()).append("=").append(URLEncoder.encode(param.getValue().trim(),"UTF-8")).append("&"); } } } if(baseString.length() > 0 ) { baseString.deleteCharAt(baseString.length()-1).append("&app_key="+TencentAPI.APP_KEY_AI); } // 使用MD5對(duì)待簽名串求簽 try { String sign = MD5.getMD5(baseString.toString()); return sign; } catch (Exception ex) { throw new IOException(ex); } } /** * 獲取拼接的參數(shù) * @param params * @return * @throws IOException */ public static String getParams(HashMap params) throws IOException { // 先將參數(shù)以其參數(shù)名的字典序升序進(jìn)行排序 Map sortedParams = new TreeMap<>(params); Set > entrys = sortedParams.entrySet(); // 遍歷排序后的字典,將所有參數(shù)按"key=value"格式拼接在一起 StringBuilder baseString = new StringBuilder(); for (Map.Entry param : entrys) { //sign參數(shù) 和 空值參數(shù) 不加入算法 baseString.append(param.getKey().trim()).append("=").append(URLEncoder.encode(param.getValue().trim(),"UTF-8")).append("&"); } return baseString.toString(); } }
這樣簡(jiǎn)單一句話就實(shí)現(xiàn)了簽名啦:
向API發(fā)送請(qǐng)求String sign = TencentAISignSort.getSignature(person_Id_body);
person_Id_body.put("sign", sign); //將Sign也放入Map中 //這我就不用說(shuō)了吧,這是頭信息需要的 Mapheaders = new HashMap<>(); //headers頭 headers.put("Content-Type", "application/x-www-form-urlencoded");
HttpResponse responseBD = HttpsUtil4Tencent.doPostTencentAI(TencentAPI.FACEMERGE, headers, person_Id_body); String json = EntityUtils.toString(responseBD.getEntity()); System.out.println(json); //這個(gè)就是我們的要的數(shù)據(jù)了
ps:一堆工具類對(duì)不對(duì)啊哈哈哈,這才叫快速開發(fā)。
//HttpsUtil4Tencent工具類: public class HttpsUtil4Tencent { private static HttpClient wrapClient(String host) { HttpClient httpClient = new DefaultHttpClient(); if (host.startsWith("https://")) { sslClient(httpClient); } return httpClient; } private static void sslClient(HttpClient httpClient) { try { SSLContext ctx = SSLContext.getInstance("TLS"); X509TrustManager tm = new X509TrustManager() { public X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted(X509Certificate[] xcs, String str) { } public void checkServerTrusted(X509Certificate[] xcs, String str) { } }; ctx.init(null, new TrustManager[] { tm }, null); SSLSocketFactory ssf = new SSLSocketFactory(ctx); ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); ClientConnectionManager ccm = httpClient.getConnectionManager(); SchemeRegistry registry = ccm.getSchemeRegistry(); registry.register(new Scheme("https", 443, ssf)); } catch (KeyManagementException ex) { throw new RuntimeException(ex); } catch (NoSuchAlgorithmException ex) { throw new RuntimeException(ex); } } /** * * @Title doPostBD * @param url 接口地址 * @param method 請(qǐng)求方式 * @param headers * @param bodys * @return response * @throws Exception * @author 小帥帥丶 * @date 2017-3-20 * */ public static HttpResponse doPostTencentAI(String url, Mapheaders, Map bodys) throws Exception { HttpClient httpClient = wrapClient(url); HttpPost request = new HttpPost(url); for (Map.Entry e : headers.entrySet()) { request.addHeader(e.getKey(), e.getValue()); } if (bodys != null) { List nameValuePairList = new ArrayList (); for (String key : bodys.keySet()) { nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); } UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList); formEntity.setContentType("application/x-www-form-urlencoded;charset=UTF-8"); request.setEntity(formEntity); } return httpClient.execute(request); } }
得到的json就是騰訊給我們的數(shù)據(jù)。那我們要怎么把json數(shù)據(jù)轉(zhuǎn)為對(duì)象呢。
我的另一篇文章就寫了:Java 跨域 Json字符轉(zhuǎn)類對(duì)象
在人臉識(shí)別這塊,他回應(yīng)的是一串base64的數(shù)據(jù),我們應(yīng)該怎么轉(zhuǎn)為圖片呢
String xmlImg = persion_id.getImage(); response.setContentType("image/*"); // 設(shè)置返回的文件類型 OutputStream toClient = response.getOutputStream(); IoUtil.GenerateImage(xmlImg,toClient);
沒錯(cuò),還是工具類IoUtil。
public class TencentAPI { //自己的APPID public static final Integer APP_ID_AI = 0; //自己的APPKEY public static final String APP_KEY_AI = "******"; public static final String PERSON_ID = "https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr"; //身份證識(shí)別 public static final String PHOTO_SPEAK = "https://api.ai.qq.com/fcgi-bin/vision/vision_imgtotext"; //看圖說(shuō)話 public static final String SCENE_RECOGNITION = "https://api.ai.qq.com/fcgi-bin/vision/vision_scener"; //場(chǎng)景識(shí)別:對(duì)圖行進(jìn)行場(chǎng)景識(shí)別,快速找出圖片中包含的場(chǎng)景信息 public static final String OBJECT_RECOGNITION = "https://api.ai.qq.com/fcgi-bin/vision/vision_objectr"; //物體識(shí)別:對(duì)圖行進(jìn)行物體識(shí)別,快速找出圖片中包含的物體信息 public static final String IMAGE_LABEL = "https://api.ai.qq.com/fcgi-bin/image/image_tag"; //圖像標(biāo)簽識(shí)別:識(shí)別一個(gè)圖像的標(biāo)簽信息,對(duì)圖像分類。 public static final String FACEMERGE="https://api.ai.qq.com/fcgi-bin/ptu/ptu_facemerge"; //人臉融合 }結(jié)尾
這一塊騰訊人工智能AI接入已解釋完畢。如有什么不懂得可以來(lái)問(wèn)下我。我的郵箱是519286925@qq.com
為什么說(shuō)這是大專狗終章呢,因?yàn)槲乙呀?jīng)大三了,這是我最后一篇在大專學(xué)校寫的文章。即將面臨的面試工作或者插本,前方的路如何,我將何去何從。請(qǐng)等我下篇文章:【插本狗初章】或者【工作狗初章】
世上無(wú)難事,只有你會(huì)不會(huì),想不想學(xué)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/70743.html
摘要:鑒權(quán)實(shí)現(xiàn)快速開發(fā)第三方騰訊人工智能接入詳解形式目前已經(jīng)接入文字識(shí)別語(yǔ)音識(shí)別接口服務(wù)調(diào)用服務(wù)項(xiàng)目結(jié)構(gòu)介紹基類通信相關(guān)類簽名公用類類類工具類使用引入即可示例代碼是調(diào)用騰訊中的客戶端,為調(diào)用騰訊中功能的開發(fā)人員提供了一系列的交互方法。 TAIP 是調(diào)用騰訊 AI 接口的 Java 客戶端,為調(diào)用騰訊 AI 功能的開發(fā)人員提供了一系列的交互方法。 Java調(diào)用騰訊AI接口服務(wù)。鑒權(quán)實(shí)現(xiàn)Java...
摘要:提到的云計(jì)算布局,就不得不提到年月中國(guó)領(lǐng)袖峰會(huì)上,三位掌門人針對(duì)云計(jì)算的同臺(tái)論道。且從官方有限的披露資料而言,很難對(duì)現(xiàn)階段的百度云計(jì)算獨(dú)立做評(píng)判。該計(jì)劃提出的發(fā)展目標(biāo)是到年,我國(guó)云計(jì)算產(chǎn)業(yè)規(guī)模達(dá)到億元。提到BAT的云計(jì)算布局,就不得不提到2010年3月中國(guó)IT領(lǐng)袖峰會(huì)上,BAT三位掌門人針對(duì)云計(jì)算的同臺(tái)論道。坐在臺(tái)上的百度和騰訊創(chuàng)始人相繼發(fā)言,李彥宏不客氣的說(shuō),云計(jì)算好比新瓶裝舊酒,技術(shù)上沒...
摘要:而道器相融,在我看來(lái),那煉丹就需要一個(gè)好的丹爐了,也就是一個(gè)優(yōu)秀的機(jī)器學(xué)習(xí)平臺(tái)。因此,一個(gè)機(jī)器學(xué)習(xí)平臺(tái)要取得成功,最好具備如下五個(gè)特點(diǎn)精辟的核心抽象一個(gè)機(jī)器學(xué)習(xí)平臺(tái),必須有其靈魂,也就是它的核心抽象。 *本文首發(fā)于 AI前線 ,歡迎轉(zhuǎn)載,并請(qǐng)注明出處。 摘要 2017年6月,騰訊正式開源面向機(jī)器學(xué)習(xí)的第三代高性能計(jì)算平臺(tái) Angel,在GitHub上備受關(guān)注;2017年10月19日,騰...
閱讀 532·2023-04-25 23:00
閱讀 3539·2021-11-22 13:54
閱讀 1965·2021-10-27 14:14
閱讀 1533·2019-08-30 13:59
閱讀 3571·2019-08-23 16:15
閱讀 2019·2019-08-23 16:06
閱讀 3405·2019-08-23 15:26
閱讀 1318·2019-08-23 13:48