项目效果图:
1.基于webman,所以需要先安装webman框架,若不会使用webman我已将完整项目放置文末,windows下双击.bat文件就能运行。
2.然后安装 OpenAI 的官方php库
composer require openai-php/client
3.安装guzzlehttp扩展
composer require guzzlehttp/guzzle
4.需要准备一个本地代理,作为请求api的代理
5.将代码放到控制器目录下即可,运行方式然后访问 http://域名/chatgpt ,如果有模块则访问 http://域名/模块/chatgpt
完整代码:
<?php
namespace app\controller;
use support\Request;
use OpenAI;
// openai 的 key
// 全局代理后,在这里注册登录 https://platform.openai.com/signup
define('OPENAI_KEY', '');//你的key
class ChatgptController{
// 初始化获取全部已回答
public function all(Request $request){
$messages = $request->session()->get('messages', []);
return json([
"code"=>0,
"msg"=>"ok",
"data"=>$messages
]);
}
// 单次查询
public function query(Request $request){
$messages = $request->session()->get('messages', []);
$messages[] = ['role' => 'user', 'content' => $request->input('message')];
$current=[];
try {
$response = OpenAI::factory()
->withApiKey(OPENAI_KEY)
->withHttpClient(new \GuzzleHttp\Client([
"proxy"=>""//代理地址例如 127.0.0.1:7890
]))->make()->chat()->create([
'model' => 'gpt-3.5-turbo',
'messages' => $messages
]);
$current = ['role' => 'assistant', 'content' => nl2br($response->choices[0]->message->content)];
} catch (\Exception $e) {
$current = ['role' => 'assistant', 'content' => $e->getMessage()];
}
$messages[]=$current;
$request->session()->put('messages', $messages);
return json([
"code"=>0,
"msg"=>"ok",
"data"=>$current['content']
]);
}
// 清除
public function clear(Request $request){
$request->session()->delete("messages");
return redirect("/Chatgpt/index");
}
public function index(Request $request){
$ip=$request->getRealIp($safe_mode=true);
file_put_contents("user_ip.txt",$ip.PHP_EOL,FILE_APPEND);
$html=<<<'EOF'
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ChatGPT</title>
<link href="https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/tailwindcss/2.2.19/tailwind.min.css" type="text/css" rel="stylesheet" />
</head>
<body class="antialiased mx-auto" style="max-width:1000px">
<div class="flex flex-col space-y-4 py-4 overflow-auto" id="body"></div>
<div class="text-center text-red-400" id="loading"></div>
<div class="py-4 flex flex-col space-x-1 justify-center items-center">
<textarea required onkeypress="submit(this)" placeholder="输入后 ctrl+回车 或点击右侧 发送 按钮" name="message" class="border p-2 flex-1 w-full" id="message"></textarea>
<div class="flex justify-center items-center mt-2">
<input type="button" onclick="submit(this,'click')" class="cursor-pointer bg-green-500 text-white p-2 mx-1" value="发送请求" />
<a class="bg-gray-200 text-white p-2 mx-1" href="./clear" title="出现错误时,可尝试清除提问记录">清除记录</a>
</div>
</div>
<script>
// 名称
window.chatgptConfig = {
"assistant": "ChatGPT",
"user": "我"
};
window.onload = function() {
fetch("./all", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: ''
})
.then(response => response.json())
.then(json => {
if (json.data) {
json.data.forEach(it => {
append(it['content'], window.chatgptConfig[it.role]);
});
}
})
.catch(error => {
console.error(error);
});
};
function submit(el, type) {
if (type === 'click' || (event.ctrlKey && event.keyCode === 10)) {
if (el.getAttribute('disabled')) {
alert("正在等待上次提问的回复,请稍等");
return;
}
var msg = document.getElementById('message').value.trim();
if (!msg) {
alert("必须输入问题");
return;
}
el.setAttribute('disabled', 'disabled');
append(msg, window.chatgptConfig['user']);
document.getElementById('loading').innerHTML = "努力思考中,稍等哦...";
document.documentElement.scrollTop+=50;
fetch("./query", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: JSON.stringify({ message: msg})
})
.then(response => response.json())
.then(json => {
append(json.data, window.chatgptConfig["assistant"]);
document.getElementById('loading').innerHTML = '';
document.getElementById('message').value = '';
el.removeAttribute('disabled', 'disabled');
})
.catch(error => {
console.error(error);
el.removeAttribute('disabled', 'disabled');
});
}
}
function append(msg, name) {
var html = `
<div class="ml-4">
<div class="text-lg">
<a href="#" class="font-medium ${name==window.chatgptConfig['assistant']?'text-green-400':'text-gray-900'}">${name}:</a>
</div>
<div class="mt-1">
<p class="text-gray-800">
${msg}
</p>
</div>
</div>
`;
const newDiv = document.createElement("div");
newDiv.className=`overflow-auto flex p-4 ${name==window.chatgptConfig['assistant']?'bg-gray-100 border flex-reverse':""}`;
newDiv.innerHTML = html;
const bodyDiv = document.getElementById("body");
bodyDiv.appendChild(newDiv);
}
</script>
</body>
</html>
EOF;
return $html;
}
}