+1

Chatbot đọc suy nghĩ của bạn - Akinator Chatbot

Mayfest2023

Hoàn cảnh

Gần đây Chatbot GPT khá hot, có thể trả lời tất cả các câu hỏi, giải quyết các vấn đề mà bạn đang gặp phải. Nhưng để đọc suy nghĩ của bạn thì sao? Nói là đọc suy nghĩ thì cao siêu quá, ở đây mình muốn đề cập đến: Bạn nghĩ về 1 nhân vật (có thật hoặc hư cấu), Bot có thể đoán được bạn đang nghĩ đến nhân vật nào.

GPT chắc không làm được việc đó, và mình biết 1 ứng dụng có thể làm được việc đó đó là Akinator

Giới thiệu về Akinator:

Akinator có thể đọc được suy nghĩ của bạn và cho bạn biết bạn đang nghĩ đến nhân vật nào. Hãy nghĩ về một nhân vật có thật hoặc hư cấu, trả lời một số câu hỏi và Akinator sẽ cố gắng đoán xem đó là ai.

Qua 1 loạt các câu "tra khảo" thì bot sẽ đoán bạn đang nghĩ về ai 😄

Ứng dụng giải trí rất tốt, đoán khá đúng (nếu đó là nhân vật nổi tiếng 😂😂😂 )

Và mình chợt có ý tưởng là làm ứng dụng Chatbot sử dụng tri thức của Akinator và tích hợp vào các nền tảng Chat (ở đây mình tích hợp vào Facebook Messenger)

Cách thực hiện

Tiếp cận

Ở đây ứng dụng Chatbot của mình sử dụng tri thức của Akinator, do đó mình cần tìm hiểu xem ứng dụng hoạt động như thế nào.

Đầu tiên, mình vào trang https://en.akinator.com và dùng ứng dụng, sau đó inspect trang web xem khi chạy nó call những API nào để mình sử dụng lại API đó. Và cũng tìm ra 2 API chính:

API khi mới khởi tạo: https://en.akinator.com/new_session

API khi mình trả lời câu hỏi: https://en.akinator.com/answer_api

Và như trong 2 ảnh trên, thì API cần rất nhiều param để truyền vào, và nhiệm vụ của mình là hiểu các giá trị của các param và sinh giá trị tương ứng để truyền lên API. Chưa gì đã thấy ngại rồi, thế là cái tính lười nổi lên, mình lên Google search "Akinator api".

Bụp, có ngay API sử dụng NodeJS: https://github.com/jgoralcz/aki-api

Có sẵn rồi chả nhẽ lại không xài --> Xài thôi 😆😆😆

Vì mình có Project khung (PHP - Laravel) xử lý tương tác với Facebook Messenger rồi https://github.com/south1907/knowledge-chatbot Project này đã xử lý việc nhận, trả lời tin nhắn Facebook Messenger. Nên việc cần làm sẽ là:

  • API xử lý tri thức Akinator (sử dụng NodeJS)
  • Update phần xử lý Chatbot tương tác với API tri thức Akinator

Giả sử nếu mình search được Package PHP về Akinator API thì mình không cần làm API xử lý tri thức Akinator mà sẽ tích hợp luôn vào Project PHP đó. Hoặc nếu trước đó mình đã có Project bằng NodeJS xử lý việc nhận, trả lời tin nhắn Facebook Messenger, thì mình cũng chỉ việc tích hợp Pakcage aki-api đã search được.

Nhưng không may là sự như vậy: 1 cái PHP, 1 cái NodeJS, nên cách nhanh nhất là đẻ thêm 1 Project NodeJS xử lý trí thức Akinator API 😃)

API xử lý tri thức

Như mình có inspect khi dùng ứng dụng Akinator, sẽ có 2 API: api bắt đầu và api trả lời mỗi câu hỏi. Vì thế, phần xử lý tri thức này cũng cần tương ứng 2 API.

Và tài liệu https://github.com/jgoralcz/aki-api cũng khá đầy đủ để có thể dựng 2 API đó rồi.

  • API khởi tạo
app.post('/start', async (req, res) => {
	let user_id = req.body.user_id;
	let region = req.body.region;
	if (!region) {
		region = region_default
	}

	if (list_region.includes(region)) {
		try {
			const aki = new Aki({ region, childMode, proxy });
			await aki.start();
			myCache.set( user_id, aki, 10000 );
			res.json(aki);
		}
		catch(err) {
			console.log("loi roi")
			res.json({});
		}
	} else {
		res.json({});
	}

});

input là user_id: user nào chat khởi tạo Ở đây, mình sẽ lưu cache object Aki lại với key là user_id. Có thể hiểu đây sẽ lưu phiên tương tác cho từng User chat với Bot.

  • API trả lời Bot
app.post('/answer', async (req, res) => {
	console.log(req.body)
	let user_id = req.body.user_id;
	let answer = req.body.answer;

	let aki = myCache.get( user_id );

	if (aki) {
		await aki.step(answer);

		if (aki.progress >= 70 || aki.currentStep >= 78) {
			// winnnnnn
			await aki.win();
		}
		myCache.set( user_id, aki, 10000 );
	}

	res.json(aki);
});

input là: user_id: user nào trả lời answer: câu trả lời là gì. Bot Akinator sẽ gợi ý bạn 5 câu trả lời: Yes, No, Don't know, Probably, Probably not. Trường answer sẽ tương ứng với 5 câu trả lời đó (giá trị từ 0 -> 4)

Nếu phần xử lý với câu trả lời của bạn có điểm >= 70 điểm

Đây là điểm chắc chắn của Bot khi đưa ra đáp án cuối cùng, qua một vài lần test thì mình thấy 70 điểm là ngưỡng ok nhất.

Code đầy đủ đây nhé: https://github.com/south1907/akinator-service/blob/main/index.js

Xử lý Chatbot

Có API tri thức rồi, tiếp thì cần xử lý Chatbot tích hợp API đó.

Mình sẽ bỏ qua phần xử lý nhận tin nhắn, xử lý tin nhắn Facebook Messenger mà tập trung vào việc xử lý tích hợp Akinator như thế nào thôi.

Tương tự, cũng có 2 phần: Khởi tạo và trả lời câu hỏi của Bot

Ở đây, để đơn giản, thì khi người dùng chat "start" thì mình mới hiểu là bắt đầu trò chơi

if ($query['type'] == 'text') {
    $message = mb_strtolower($query['content']);

    if (strpos($message, 'start') !== false) {
        $region = 'en';
        $result = self::getStart($PID, $region);
    }
}
private static function getStart($PID, $region) {
        $result = [];
        $result[] = [
            'id'	=>	null,
            'type'	=>	'text',
            'message'	=>	'Hello, I am Ây Ai Đây. Think about a real or fictional character. I will try to guess who it is'
        ];
        $start = self::start($PID, $region);
        if ($start) {
            if (array_key_exists('answers', $start)) {
                $count = 0;
                $listReply = [];
                foreach ($start['answers'] as $ans) {
                    $listReply[] = [
                        "content_type"		=> "text",
                        "title"		=> $ans,
                        "payload"	=> "AKI::answer|" . $count
                    ];
                    $count += 1;
                }

                $currentStep = $start['currentStep'] + 1;
                $result[] = [
                    'id'	=>	null,
                    'type'	=>	'quick_reply',
                    'message'	=>	$currentStep . '. ' . $start['question'],
                    'quick_replies' => json_encode($listReply)
                ];
            }
        } else {
            $result[] = [
                'id'	=>	null,
                'type'	=>	'text',
                'message'	=>	'Have a trouble, type "start" to restart'
            ];
        }

        return $result;
    }
private static function start($userId, $region) {
        $data = [
            'user_id'   =>  $userId,
            'region'   =>  $region
        ];
        $dataJson = json_encode($data);
        $CLIENT_AKI = env("AKI_API_URL", "") . '/start';
        $response = CurlHelper::send($CLIENT_AKI, $dataJson);
        if ($response) {
            return json_decode($response->getBody()->getContents(), true);
        }
        return null;
    }

Hàm start chính là call sang API NodeJS ở bước trên

Hàm getStart sẽ generate ra các câu trả lời mẫu dạng quick_reply và gửi cho User chat với Bot. Mỗi phương án trả lời sẽ có gắn 1 giá trị payload kiểu AKI::answer| để có thể nhận biết User đã click vào câu trả lời nào.

Tiếp, xử lý khi User click vào câu trả lời.

Sự kiện User trả lời sẽ có payload AKI::answer|0 với 0 là câu trả lời, vậy cần gửi câu trả lời đến API kiến thức NodeJS và đưa ra quyết định

if (strpos($payload, 'AKI::answer') !== false) {
    // xu ly cau tra loi
    $numberAnswer = explode("|", $payload)[1];

    $resAns = self::answerAki($PID, $numberAnswer);
    if ($resAns) {
        if ($resAns['guessCount'] > 0) {
            // co ket qua

            $result[] = [
                'id'	=>	null,
                'type'	=>	'text',
                'message'	=>	'Name: ' . $resAns['answers'][0]['name']
            ];

            $result[] = [
                'id'	=>	null,
                'type'	=>	'image',
                'url'	=>	$resAns['answers'][0]['absolute_picture_path']
            ];
        } else {
            // khong co ket qua, hoi tiep
            $count = 0;
            $listReply = [];
            foreach ($resAns['answers'] as $ans) {
                $listReply[] = [
                    "content_type"		=> "text",
                    "title"		=> $ans,
                    "payload"	=> "AKI::answer|" . $count
                ];
                $count += 1;
            }

            $currentStep = $resAns['currentStep'] + 1;
            $result[] = [
                'id'	=>	null,
                'type'	=>	'quick_reply',
                'message'	=>	$currentStep . '. ' . $resAns['question'],
                'quick_replies' => json_encode($listReply)
            ];
        }
    }
}

sẽ có 2 trường hợp:

  • TH1: Bot đã đoán được Đáp án, khi đó API trả về có 'guessCount' > 0, vậy là Bot chỉ cần trả lời đáp án cuối cùng cho User
  • TH2: Bot chưa tìm ra Đáp án và cần "tra khảo" thêm

Full code phần xử lý Chatbot cho phần tích hợp Akinator ở đây nhé: https://github.com/south1907/knowledge-chatbot/blob/master/app/Helpers/AkiHelper.php

Demo

Video demo: https://youtu.be/NVz7MwSoNEY

Link Bot: https://www.facebook.com/messages/t/107535885282834

Kết luận

Ở phần Tiếp cận thay vì mình phải vọc vạch API của app Akinator từ đầu thì mình có thể search Google xem đã có ai xử lý vấn đề đó chưa. Đây cũng là cách giúp bạn tiết kiệm thời gian hơn, tuy nhiên, nó lại hơi bị phụ thuộc vào yếu tố bên ngoài quá 😄 Vậy, để tiết kiệm thời gian thì mình có thể sử dụng lại những thứ người khác đã làm và nếu có thêm thời gian thì mình tìm hiểu chi tiết cái mình đang sử dụng nó chạy như thế nào.

Trong trường hợp này, mình có sử dụng Package đó, đã đọc xem bên trong nó xử lý như thế nào, và mình cũng viết được 1 Package Python có chức năng tương ứng: https://github.com/south1907/akithon

--> và thế là mình thành công trong việc biến kiến thức của người khác thành cái của mình, kk 😆

À, 1 phút dành cho quảng cáo: Mình nhận làm các tool liên quan đến:

  • Crawl dữ liệu
  • Tool auto marketing: tự động post bài, tự động comment, like, chat,...
  • Tool auto cho các thao tác thực hiện lặp đi lặp lại trên website: quản lý thêm xóa sử, đặt hàng,...

Liên hệ qua facebook: Nam

Link source code:


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.