1、最近速度慢是因为 OpenAI 对于免费账号限速了,在 platform.openai.com 绑定了信用卡的才是之前的正常速度;
2、限速指的是流式请求时,首个 token 返回需要 20 秒左右,而绑定了信用卡的账号,在 2 秒左右;
3, $url = IP.'/v1/chat/completions';反向代理https://api.openai.com的IP。调用对话接口
<script type="text/javascript">
var qaIdx = 0,contentIdx=0,answers = [],answerWords=[],typing=false,typingIdx=0,contentEnd=false,answerContent='',codeStart=false,lastWord='',lastLastWord='';
// *发送对话消息
$(".chatbtn").click(function(){
var message=$(".layui_textarea_inner").val();
qaIdx+=1;
$("#user_"+qaIdx).html(message);
$("#answer_"+qaIdx).html(m'AI思考中……');
$('.scrollbar-wrapper').scrollTop($('.scrollbar-wrapper')[0].scrollHeight);
// 点击发送按钮后,输入框里的文字恢复原状
$(".layui_textarea_inner").val('');
answers[qaIdx] = $('#answer_'+qaIdx);
getAnswer(message,'web',last_id,0,0,modelname);
function getAnswer(messagesa,platform,group_id,prompt_id,role_id,model){
const url = "/web/duihua/sendText?message="+messagesa+"&platform="+platform+"&group_id="+group_id+"&prompt_id="+prompt_id+"&role_id="+role_id+"&model="+model;
const eventSource = new EventSource(url);
// open:订阅成功(和后端连接成功)
eventSource.addEventListener("open", (event) => {
console.log("连接已建立", JSON.stringify(event));
});
// message:后端返回信息,格式可以和后端协商
eventSource.addEventListener("message", (event) => {
console.log("接收数据:", JSON.parse(event.data));
try {
var result = JSON.parse(event.data);
if(result.code==1001 ){
console.log("停止接收数据");
layer.msg(result.msg,{icon:2,title:''});
}
contentIdx += 1;
// 向数组的末尾添加一个或多个元素,并返回新的长度
answerWords.push(result.word);
console.log('开始执行打印函数');
//打印文字
// 不要用Apache,要用Nginx,似乎是因为Apache对flush()方法支持有问题,无论怎么搞,最终还是一次性输出事件流;
typingWords();
} catch (error) {
console.log(error);
}
});
// error:错误(可能是断开,可能是后端返回的信息)
eventSource.addEventListener("error", (event) => {
console.error("发生错误:", JSON.stringify(event));
});
//echo 'event: close'.PHP_EOL; 告诉前端,结束了,该说再见了
// echo 'data: Connection closed'.PHP_EOL.PHP_EOL; 告诉前端,连接已关闭会执行下面的代码
eventSource.addEventListener("close", (event) => {
console.log("连接已关闭", JSON.stringify(event.data));
eventSource.close();
contentEnd = true;
contentIdx = 0;
typingIdx = 0;
answerWords = [];
console.log((new Date().getTime()), 'answer end');
});
}
function typingWords(){
if(contentEnd && contentIdx==typingIdx){
clearInterval(typingTimer);
answerContent = '';
answerWords = [];
answers = [];
qaIdx += 1;
typingIdx = 0;
contentIdx = 0;
contentEnd = false;
lastWord = '';
lastLastWord = '';
input.disabled = false;
sendButton.disabled = false;
console.log((new Date().getTime()), 'typing end');
return;
}
if(contentIdx<=typingIdx){
return;
}
if(typing){
return;
}
typing = true;
if(!answers[qaIdx]){
answers[qaIdx] = $('#answer_' +qaIdx);
}
const content = answerWords;
if(content.indexOf('`') != -1){
if(content.indexOf('```') != -1){
codeStart = !codeStart;
}else if(content.indexOf('``') != -1 && (lastWord + content).indexOf('```') != -1){
codeStart = !codeStart;
}else if(content.indexOf('`') != -1 && (lastLastWord + lastWord + content).indexOf('```') != -1){
codeStart = !codeStart;
}
}
lastLastWord = lastWord;
lastWord = content;
answerContent = content;
answers[qaIdx].html(answerContent);
typingIdx += 1;
typing = false;
}
})
</script>
<?php
// 这行代码设置 HTTP 响应的 Content-Type 为 text/event-stream,这是服务器发送事件(SSE)的 MIME 类型。
header('Content-Type: text/event-stream');
// 这行代码设置 HTTP 响应的 Cache-Control 为 no-cache,告诉浏览器不要缓存此响应。
header('Cache-Control: no-cache');
// 这行代码设置 HTTP 响应的 Connection 为 keep-alive,保持长连接,以便服务器可以持续发送事件到客户端。
header('Connection: keep-alive');
// 这行代码设置 HTTP 响应的自定义头部 X-Accel-Buffering 为 no,用于禁用某些代理或 Web 服务器(如 Nginx)的缓冲。
// 这有助于确保服务器发送事件在传输过程中不会受到缓冲影响。
header('X-Accel-Buffering: no');
$a=['0'=>'天','1'=>'涯','2'=>'何','3'=>'处','4'=>'有','5'=>'我','6'=>'鑫','7'=>'','8'=>'空','9'=>'?'];
for( $i = 0 ; $i <= 9 ; $i++ ){
echo 'data: '.json_encode(['code'=>1000, 'word'=>$a[$i]]).PHP_EOL.PHP_EOL;;
ob_flush();
flush();
sleep(1);
}
echo 'event: close'.PHP_EOL; // 告诉前端,结束了,该说再见了
echo 'data: Connection closed'.PHP_EOL.PHP_EOL; // 告诉前端,连接已关闭
exit();