纯php接入月之暗面 kimi moonshot大模型api 实现流式返回数据 实现打字效果
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SSE Chat</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f9;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
.chat-container {
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
width: 400px;
max-width: 90%;
padding: 20px;
display: flex;
flex-direction: column;
}
#chat-box {
border: 1px solid #ccc;
padding: 10px;
border-radius: 4px;
height: 300px;
overflow-y: auto;
margin-bottom: 10px;
}
#message {
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
width: calc(100% - 60px);
margin-right: 10px;
}
#send-btn {
background-color: #007bff;
color: #fff;
border: none;
padding: 10px;
border-radius: 4px;
cursor: pointer;
}
#send-btn:hover {
background-color: #0056b3;
}
.input-container {
display: flex;
}
</style>
<script src="marked.min.js"></script>
</head>
<body>
<div class="chat-container">
<div id="chat-box"></div>
<div class="input-container">
<input type="text" id="message" placeholder="Type your message here">
<button id="send-btn">Send</button>
</div>
</div>
<script>
document.getElementById('send-btn').addEventListener('click', () => {
const message = document.getElementById('message').value;
if (message) {
sendMessage(message);
document.getElementById('message').value = '';
}
});
document.getElementById('message').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const message = document.getElementById('message').value;
if (message) {
sendMessage(message);
document.getElementById('message').value = '';
}
}
});
async function sendMessage(message) {
const response = await fetch('chat.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message })
});
if (response.ok) {
const reader = response.body.getReader();
const decoder = new TextDecoder('utf-8');
let chatBox = document.getElementById('chat-box');
let markdownText = '';
let i = 0;
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split('\n\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonStr = line.slice(6);
if (jsonStr === '[DONE]') {
return;
}
try {
const data = JSON.parse(jsonStr);
if (data.choices && data.choices[0].delta.content) {
const allText = data.choices[0].delta.content;
for (const char of allText) {
let remainingChars = allText.length - i;
let timewait = 40;
if (remainingChars <= 30) timewait = 30;
if (remainingChars <= 10) timewait = 20;
if (remainingChars <= 5) timewait = 10;
markdownText += char;
const htmlText = marked.parse(markdownText);
chatBox.innerHTML = htmlText;
await delay(timewait); // Adding dynamic delay
i++;
}
}
} catch (e) {
console.error('Error parsing JSON:', e);
}
}
}
}
} else {
console.error('Error:', response.status, response.statusText);
}
}
</script>
</body>
</html>
后端php代码
<?php
header('Content-Type: text/event-stream'); // 设置响应头为SSE
header('Cache-Control: no-cache'); // 禁用缓存
header('X-Accel-Buffering: no'); // 禁用Nginx缓冲
$input = file_get_contents('php://input');
$data = json_decode($input, true);
$message = isset($data['message']) ? $data['message'] : '';
$apiUrl = 'https://api.moonshot.cn/v1/chat/completions';
$apiKey = ''; // 替换为你的API密钥
$postData = [
'model' => 'moonshot-v1-8k',
'messages' => [
[
'role' => 'user',
'content' => $message
]
],
'temperature' => 0.3,
'stream' => true
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiUrl);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($curl, $data) {
echo $data;
ob_flush();
flush();
return strlen($data);
});
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Curl error: ' . curl_error($ch);
}
curl_close($ch);
?>