QQ聊天機器人例項
阿新 • • 發佈:2021-03-25
部落格和更新地址:[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返回處理結果。
至此,聊天機器人部署