1. 程式人生 > >QQ聊天機器人例項

QQ聊天機器人例項

部落格和更新地址:[QQ聊天機器人例項](https://www.alsaces.cn/posts/b233fb6a/) #### 前言 此文章為[PHP實現基於Mirai的QQ機器人](https://www.alsaces.cn/posts/d5c92c50)的一部分。 #### 申請API 該聊天機器人需要使用聊天API,通過將機器人接收到的訊息轉發給該介面,介面響應訊息,來實現聊天機器人的效果。 免費的聊天API有: [圖靈機器人](http://www.turingapi.com/) [騰訊智慧閒聊](https://ai.qq.com/console/home) [青雲客智慧聊天機器人API](http://api.qingyunke.com/) 其中圖靈機器人需要實名認證,並且免費額度100/天,聽說會更加智慧~~(沒感覺)~~。 騰訊AI開放平臺的智慧閒聊API介面呼叫額度無限制,響應速度快。 青雲客似乎也是無限制。但是感覺大廠會穩點,所以選用的[騰訊AI開放平臺](https://ai.qq.com)的智慧閒聊API介面服務。 QQ登入[騰訊智慧閒聊](https://ai.qq.com/console/home),點選應用管理->建立應用,應用型別選機器人,其他的隨意,建立完成後儲存得到的APPID和APPKEY,在後面會使用。 #### 例項 在Web伺服器監聽目錄下新建檔案Bot.class.php(以下程式碼需要PHP7以上),內容為 ``` _url = $url; $this->_authKey = array('authKey' => $authKey); } /** * cURL獲取資料 * @param string $url 傳送請求的連結 * @param int $ifPost 是否為post請求(1||0) * @param mixed $postFields post的資料 * @param string $cookie 傳送請求攜帶的cookie * @param mixed $cookieFile cookie檔案 * @param int $ifHeader 是否獲取響應頭資訊(1||0) * @throws Exception 請求失敗 * @return mixed 響應結果 */ public function httpRequest(string $url, int $ifPost = 0, $postFields = '', string $cookie = '', $cookieFile = '', int $ifHeader = 0) { // 模擬http請求header頭 $header = array( "Connection: Keep-Alive", "Accept: text/html, application/xhtml+xml, */*", "Pragma: no-cache", "Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3", "User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)" ); // 初始化一個cURL會話 $ch = curl_init(); // 設定cURL傳輸選項 curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, $ifHeader); curl_setopt($ch, CURLOPT_HTTPHEADER, $header); $ifPost && curl_setopt($ch, CURLOPT_POST, $ifPost); $ifPost && curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); $cookie && curl_setopt($ch, CURLOPT_COOKIE, $cookie); // 傳送cookie變數 $cookieFile && curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile); // 傳送cookie檔案 $cookieFile && curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile); // 寫入cookie到檔案 curl_setopt($ch, CURLOPT_TIMEOUT, 60); // 允許執行的最長秒數 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // 執行cURL會話 $result = curl_exec($ch); // 失敗則丟擲異常 if ($result === false) { throw new Exception('Sending request to ' . $url . ' failed!'); } // 關閉 cURL 會話 curl_close($ch); // 釋放$ch unset($ch); return $result; } /** * 進行認證 * @throws Exception 認證失敗 * @return bool */ public function auth(): bool { $url = $this->_url . '/auth'; $postData = json_encode($this->_authKey); $response = json_decode($this->httpRequest($url, 1, $postData)); if ($response !== false && $response->code === 0) { $this->_sessionKey = $response->session; return true; } else { throw new Exception('Mirai authentication failed!'); } } /** * 校驗Session * @param int $qq Session將要繫結的Bot的qq號 * @throws Exception 校驗Session失敗 * @return bool */ public function verify(int $qq): bool { $url = $this->_url . '/verify'; $postData = json_encode( array( 'sessionKey' => $this->_sessionKey, 'qq' => $qq ) ); $response = json_decode($this->httpRequest($url, 1, $postData)); if ($response !== false && $response->code === 0) { return true; } else { throw new Exception('Validation session failed!' . 'The qq is ' . $qq . '.'); } } /** * 釋放Session * @param int $qq 與該Session繫結Bot的QQ號碼 * @throws Exception 釋放Session失敗 * @return bool */ public function release(int $qq): bool { $url = $this->_url . '/release'; $postData = json_encode( array( 'sessionKey' => $this->_sessionKey, 'qq' => $qq ) ); $response = json_decode($this->httpRequest($url, 1, $postData)); if ($response !== false && $response->code === 0) { return true; } else { throw new Exception('Failed to release session! The qq is ' . $qq . '!'); } } /** * 傳送好友訊息 * @param int $qq 傳送訊息目標好友的QQ號 * @param array $messageChain 訊息鏈,訊息物件構成的陣列 * @param int $quote 回覆訊息的messageId * @throws Exception 傳送好友訊息失敗 * @return int messageId 可引用進行回覆 */ public function sendFriendMessage(int $qq, array $messageChain, $quote = null): int { $url = $this->_url . '/sendFriendMessage'; $postData = json_encode( array( 'sessionKey' => $this->_sessionKey, 'target' => $qq, 'quote' => $quote, 'messageChain' => $messageChain ) ); $response = json_decode($this->httpRequest($url, 1, $postData)); if ($response !== false && $response->code === 0) { return $response->messageId; } else { throw new Exception('Failed to send friend message to qq:' . $qq . '!'); } } } ``` 該類的方法實現了mirai-api-http所提供功能的一部分,包括認證身份、校驗Session、釋放Session和傳送好友訊息,重要引數和功能已在註釋中說明。 然後在同目錄下新建檔案Chatter.class.php,內容為 ``` _url = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat'; $this->_appId = $appId; $this->_appKey = $appKey; $this->_session = $session; } /** * 根據介面請求引數和應用金鑰計算請求籤名 * @param array $params 介面請求陣列 * @return string 簽名結果 */ public function getReqSign(array $params): string { // 字典升序排序 ksort($params); // 拼按URL鍵值對 $str = ''; foreach ($params as $key => $value) { if ($value !== '') { $str .= $key . '=' . urlencode($value) . '&'; } } // 拼接app_key $str .= 'app_key=' . $this->_appKey; // MD5運算+轉換大寫,得到請求籤名 $sign = strtoupper(md5($str)); return $sign; } /** * 執行POST請求,並取回響應結果 * @param array $params 完整介面請求陣列 * @return mixed 返回false表示失敗,否則表示API成功返回的HTTP BODY部分 */ public function doHttpPost(array $params) { $curl = curl_init(); $response = false; do { // 設定HTTP URL (API地址) curl_setopt($curl, CURLOPT_URL, $this->_url); // 設定HTTP HEADER (表單POST) $head = array( 'Content-Type: application/x-www-form-urlencoded' ); curl_setopt($curl, CURLOPT_HTTPHEADER, $head); // 設定HTTP BODY (URL鍵值對) $body = http_build_query($params); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $body); // 呼叫API,獲取響應結果 curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_NOBODY, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); $response = curl_exec($curl); if ($response === false) { $response = false; break; } $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); if ($code != 200) { $response = false; break; } } while (0); curl_close($curl); return $response; } /** * 獲取聊天資訊 * @param string $chatMessage 傳送給機器人介面的訊息 * @return object 機器人返回的結果 */ public function chat(string $chatMessage): object { $postData = array( 'app_id' => $this->_appId, 'session' => $this->_session, 'question' => $chatMessage, 'time_stamp' => strval(time()), 'nonce_str' => strval(rand()), 'sign' => '' ); $postData['sign'] = $this->getReqSign($postData); $response = json_decode($this->doHttpPost($postData)); if ($response->ret === 0) { return $response->data; } else { throw new Exception('Failed to get chat message!'); } } } ``` 該類的方法實現了騰訊智慧閒聊API的介面鑑權和訊息請求功能,重要引數和功能已在註釋中說明。 之後在同目錄下新建檔案index.php,內容為 ``` type === 'FriendMessage' && $message->messageChain[1]->type === 'Plain') { // 例項化一個chatter $chatter = new Chatter('應用標識(AppId)', '應用Key(AppKey)'); // 獲得訊息響應 try { $responseMessage = $chatter->chat($message->messageChain[1]->text); } catch (Exception $e) { // 本地除錯輸出錯誤資訊 // echo $e->getMessage() . ' At file:' . $e->getFile() . ' on line:' . $e->getLine() . '.'; // 發生異常時記錄日誌 error_log($e->getMessage() . ' At file:' . $e->getFile() . ' on line:' . $e->getLine() . '.'); } // 例項化一個bot $bot = new Bot('MiraiHTTPAPI地址', 'Mirai認證Key'); // 機器人QQ號 $botQQ = xxxxxxxxxx; // 訊息鏈 $messageChain = array( array( 'type' => 'Plain', 'text' => $responseMessage->answer ) ); // 傳送訊息的目標QQ $targetQQ = $message->sender->id; try { // 進行認證 $bot->auth(); // 校驗Session $bot->verify($botQQ); // 傳送該訊息 $bot->sendFriendMessage($targetQQ, $messageChain); // 釋放Session $bot->release($botQQ); } catch (Exception $e) { // 本地除錯輸出錯誤資訊 // echo $e->getMessage().' At file:'.$e->getFile().' on line:'.$e->getLine().'.'; // 發生異常時記錄日誌 error_log($e->getMessage() . ' At file:' . $e->getFile() . ' on line:' . $e->getLine() . '.'); } } ``` 以上程式碼獲取了mirai-api-http上報的訊息,並對訊息型別進行了判斷,通過後將訊息轉發到聊天機器人API,之後將獲取的響應結果傳送給目標QQ好友,就實現了與機器人(~~智慧~~)聊天的效果。 #### 部署到伺服器 將該機器人部署到伺服器,首先新建一個動態站點,將以上檔案放入伺服器端的Web伺服器監聽目錄下,並將mirai-api-http配置檔案中的"上報URL"改為檔案所在站點的url。 例如使用nginx建立動態站點api.alsaces.cn,並將以上檔案放入"站點目錄/qqbot/v1/"下,將mirai-api-http配置檔案中的上報URL改為{http://api.alsaces.cn/qqbot/v1/},重啟mirai。 當機器人收到訊息時便會上報至該url,PHP處理接收的訊息,合法則向mirai-api-http返回處理結果。 至此,聊天機器人部署