一:最终实现效果展示
二:具体实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文心千帆</title>
<style>
body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,dialog,figure,footer,header,hgroup,nav,section,input,select,option,textarea{margin:0;padding:0;}
* {
box-sizing: border-box;
}
body {
background-color: #64a6ff;
background-image: linear-gradient(270deg,#2a71ff,#64a6ff);
font-family: "Calibri", "Roboto", sans-serif;
}
.chat_window {
position: absolute;
width: calc(100% - 20px);
max-width: 800px;
height: 750px;
border-radius: 10px;
background-color: #fff;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
background-color: #f8f8f8;
overflow: hidden;
}
.top_menu {
background-color: #fff;
width: 100%;
padding: 10px 0;
height: 40px;
box-shadow: 0 1px 30px rgba(0, 0, 0, 0.1);
}
.top_menu .buttons {
margin: 3px 0 0 20px;
position: absolute;
}
.top_menu .buttons .button {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
margin-right: 5px;
position: relative;
}
.top_menu .buttons .button.close {
background-color: #f5886e;
}
.top_menu .buttons .button.minimize {
background-color: #fdbf68;
}
.top_menu .buttons .button.maximize {
background-color: #a3d063;
}
.top_menu .title {
text-align: center;
color: #333;
font-size: 14px;
}
.messages {
position: relative;
list-style: none;
padding: 20px 10px 0 10px;
margin: 0;
height: 610px;
overflow: hidden;
overflow-y: scroll;
}
.messages .message {
clear: both;
overflow: hidden;
margin-bottom: 20px;
transition: all 0.5s linear;
opacity: 0;
}
.messages .message.left .avatar {
background-color: #f5886e;
background-size: 100%;
float: left;
}
.messages .message.left .text_wrapper {
background-color: #ffe6cb;
margin-left: 20px;
}
.messages .message.left .text_wrapper::after,
.messages .message.left .text_wrapper::before {
right: 100%;
border-right-color: #ffe6cb;
}
.messages .message.left .text {
color: #c48843;
}
.messages .message.right .avatar {
background-color: #fdbf68;
float: right;
}
.messages .message.right .text_wrapper {
background-color: #c7eafc;
margin-right: 20px;
float: right;
}
.messages .message.right .text_wrapper::after,
.messages .message.right .text_wrapper::before {
left: 100%;
border-left-color: #c7eafc;
}
.messages .message.right .text {
color: #45829b;
}
.messages .message.appeared {
opacity: 1;
}
.messages .message .avatar {
width: 50px;
height: 50px;
border-radius: 50%;
display: inline-block;
}
.messages .message .text_wrapper {
display: inline-block;
padding: 20px;
border-radius: 6px;
width: calc(100% - 85px);
min-width: 100px;
position: relative;
}
.messages .message .text_wrapper::after,
.messages .message .text_wrapper:before {
top: 18px;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.messages .message .text_wrapper::after {
border-width: 13px;
margin-top: 0px;
}
.messages .message .text_wrapper::before {
border-width: 15px;
margin-top: -2px;
}
.messages .message .text_wrapper .text {
font-size: 18px;
font-weight: 300;
}
.bottom_wrapper {
position: relative;
width: 100%;
background-color: #fff;
padding: 20px;
height:100px;
position: absolute;
bottom: 0;
}
.bottom_wrapper .message_input_wrapper {
display: inline-block;
height: 45px;
border-radius: 10px;
border: 1px solid #bcbdc0;
width: calc(100% - 160px);
position: relative;
padding: 0 20px;
}
.bottom_wrapper .message_input_wrapper .message_input {
border: none;
height: 100%;
box-sizing: border-box;
width: calc(100% - 40px);
position: absolute;
outline-width: 0;
color: #333;
background-color: #fff;
}
.bottom_wrapper .send_message {
width: 140px;
height: 45px;
display: inline-block;
border-radius: 10px;
background-color: #64a6ff;
border: 2px solid #64a6ff;
background-image: linear-gradient(90deg,#2a71ff,#64a6ff);
color: #fff;
cursor: pointer;
transition: all 0.2s linear;
text-align: center;
float: right;
}
.bottom_wrapper .send_message:hover {
color: #fff;
background-color: #64a6ff;
}
.bottom_wrapper .send_message .text {
font-size: 18px;
font-weight: 300;
display: inline-block;
line-height: 48px;
}
.message_template {
display: none;
}
</style>
</head>
<body>
<div class="chat_window">
<div class="top_menu">
<div class="buttons">
<div class="button close"></div>
<div class="button minimize"></div>
<div class="button maximize"></div>
</div>
<div class="title">文心千帆</div>
</div>
<ul class="messages"></ul>
<div class="bottom_wrapper clearfix">
<div class="message_input_wrapper">
<input class="message_input" placeholder="请输入..." />
</div>
<div class="send_message">
<div class="icon"></div>
<div class="text">发送</div>
</div>
</div>
</div>
<div class="message_template">
<li class="message">
<div class="avatar"></div>
<div class="text_wrapper">
<div class="text"></div>
</div>
</li>
</div>
<script src="./static/js/jquery.js"></script>
<script>
(function() {
var Message;
Message = function(arg) {
this.text = arg.text, this.message_side = arg.message_side;
this.draw = (function(_this) {
return function() {
var $message;
$message = $($('.message_template').clone().html());
$message.addClass(_this.message_side).find('.text').html(_this.text);
$('.messages').append($message);
return setTimeout(function() {
return $message.addClass('appeared');
}, 0);
};
})(this);
return this;
};
$(function() {
var getMessageText, message_side, sendMessage;
var canInput = false;
message_side = 'right';
getMessageText = function() {
var $message_input;
$message_input = $('.message_input');
return $message_input.val();
};
sendMessage = function(text,role) {
var $messages, message;
if (text.trim() === '') {
return;
}
$('.message_input').val('');
$messages = $('.messages');
message_side = message_side === 'left' ? 'right' : 'left';
message = new Message({
text: text,
message_side: message_side
});
message.draw();
$messages.animate({
scrollTop: $messages.prop('scrollHeight')
}, 300);
};
$('.send_message').click(function(e) {
var msg_url = "https://www.XXX.com/active/shop/run";
var msg_content = getMessageText();
if(msg_content === '' || msg_content.trim().length === 0)
{
return;
}
sendMessage(msg_content,'user');
$('.message_input').attr('readonly', true);
// 请求Ajax
$.ajax({
type: 'POST',
url: msg_url,
data: {msg: msg_content},
dataType: 'json',
beforeSend:function(){
$(".title").text('正在输入中...');
},
success: function (resp){
$(".title").text('文心千帆');
var datas = resp;
if (datas.code == 1) {
sendMessage(datas.msg,'assistant');
} else {
alert(datas.msg);
}
$('.message_input').attr('readonly', false);
return false;
}
});
});
$('.message_input').keyup(function(e) {
if (e.which === 13) {
var msg_url = "https://www.XXX.com/active/shop/run";
var msg_content = getMessageText();
var canInput = true;
if(msg_content === '' || msg_content.trim().length === 0)
{
return;
}
sendMessage(msg_content,'user');
$('.message_input').attr('readonly', true);
// 请求Ajax
$.ajax({
type: 'POST',
url: msg_url,
data: {msg: msg_content},
dataType: 'json',
beforeSend:function(){
$(".title").text('正在输入中...');
},
success: function (resp){
$(".title").text('文心千帆');
var datas = resp;
if (datas.code == 1) {
sendMessage(datas.msg,'assistant');
} else {
alert(datas.msg);
}
$('.message_input').attr('readonly', false);
return false;
}
});
}
});
sendMessage('你好! :)','assistant');
});
}).call(this);
</script>
</body>
</html>
PHP 代码
<?php
// +----------------------------------------------------------------------
// | Author: xiaozhe
// +----------------------------------------------------------------------
namespace api\food\controller;
use cmf\controller\RestBaseController;
use bdchat\Chat;
class ShopController extends RestBaseController
{
public function run() {
// 对话
$datas = $this->request->post();
$msg = $datas['msg'];
if (empty($msg)) {
$result['code'] = 0;
$result['msg'] = '请求参数有误!';
exit(json_encode($result));
}
include_once CMF_ROOT . 'vendor/baidubce/Chat.php';
$chat = new Chat('client_id','client_secret');
$messages = [];
$my_msg = [];
$my_msg['role'] = 'user';
$my_msg['content'] = $msg;
$messages['messages'][] = $my_msg;
$data = json_encode($messages,JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$response = $chat->runErnieBotTurbo($data);
$res = json_decode($response,true);
if (empty($res['result'])) {
$result['msg'] = '这个问题我还不是很清楚,您换个问法再试试';
} else {
$result['msg'] = $res['result'];
}
$result['code'] = 1;
exit(json_encode($result));
}
}
<?php
namespace bdchat;
class Chat {
private $client_id;
private $client_secret;
private $message;
public function __construct($client_id, $client_secret) {
$this->client_id = $client_id;
$this->client_secret = $client_secret;
}
public function runErnieBot($message) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/completions?access_token={$this->getAccessToken()}",
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>$message,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
public function runErnieBotTurbo($message) {
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat/eb-instant?access_token={$this->getAccessToken()}",
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS =>$message,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
/**
* 使用 AK,SK 生成鉴权签名(Access Token)
* @return string 鉴权签名信息(Access Token)
*/
private function getAccessToken(){
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://aip.baidubce.com/oauth/2.0/token?client_id=".$this->client_id."&client_secret=".$this->client_secret."&grant_type=client_credentials",
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Accept: application/json'
),
));
$response = curl_exec($curl);
curl_close($curl);
$rtn = json_decode($response);
return $rtn->access_token;
}
}