需要熟悉 小程序开发
-
界面效果
-
配置项
botId: '你自己的Coze BOTID',
const accessToken = '你自己的 个人 Coze token'; (2个地方配置)
-
界面代码
doubao-chat.js
Page({
data: {
messages: [],
inputValue: '',
conversationId: null,
botId: '你自己的Coze BOTID',
userId: '', // 初始化 userId
},
onLoad() {
// 在页面加载时生成唯一的 user_id
this.setData({
userId: this.generateUUID() // 使用自定义的 UUID 生成函数
});
},
generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
const r = Math.random() * 16 | 0;
const v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
onInput(e) {
this.setData({
inputValue: e.detail.value
});
},
// 发送消息并发起对话
sendMessage() {
const message = this.data.inputValue;
if (!message) return;
// 检查 conversationId 是否为 null
if (!this.data.conversationId) {
// 如果是 null,先创建一个新的会话
this.createEmptyConversation(() => {
this.sendMessage(); // 在会话创建成功后再次调用 sendMessage
});
return;
}
// 添加用户消息到消息列表
this.setData({
messages: [...this.data.messages, { role: 'user', content: message }],
inputValue: ''
});
const accessToken = '你自己的 Coze token'; // 确保使用正确的访问令牌
const requestTask = wx.request({
url: 'https://api.coze.cn/v3/chat', // 确保 URL 正确
method: 'POST',
enableChunked: true,
header: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
data: {
conversation_id: this.data.conversationId, // 可选参数
bot_id: this.data.botId.toString(), // 确保 bot_id 是字符串
user_id: this.data.userId,
stream: true, // 启用流式返回
auto_save_history: true,
additional_messages: [
{
role: 'user',
content: message,
content_type: 'text'
}
]
},
success: (res) => {
console.log('请求完成:', res);
},
fail: (err) => {
console.error('请求失败:', err);
}
});
requestTask.onChunkReceived((res) => {
const chunk = this.utf8ArrayBufferToString(res.data);
console.log('Chunk received:', chunk);
this.handleStreamResponse(chunk);
});
},
// 将 UTF-8 编码的 ArrayBuffer 转换为字符串
utf8ArrayBufferToString(buffer) {
let result = '';
const bytes = new Uint8Array(buffer);
let i = 0;
while (i < bytes.length) {
const byte1 = bytes[i++];
if (byte1 <= 0x7F) {
// 1-byte sequence
result += String.fromCharCode(byte1);
} else if (byte1 <= 0xDF) {
// 2-byte sequence
const byte2 = bytes[i++];
result += String.fromCharCode(((byte1 & 0x1F) << 6) | (byte2 & 0x3F));
} else if (byte1 <= 0xEF) {
// 3-byte sequence
const byte2 = bytes[i++];
const byte3 = bytes[i++];
result += String.fromCharCode(((byte1 & 0x0F) << 12) | ((byte2 & 0x3F) << 6) | (byte3 & 0x3F));
} else if (byte1 <= 0xF7) {
// 4-byte sequence
const byte2 = bytes[i++];
const byte3 = bytes[i++];
const byte4 = bytes[i++];
const codepoint = ((byte1 & 0x07) << 18) | ((byte2 & 0x3F) << 12) | ((byte3 & 0x3F) << 6) | (byte4 & 0x3F);
result += String.fromCodePoint(codepoint);
}
}
return result;
},
// 处理流式响应
handleStreamResponse(chunk) {
// 解析流式响应数据
const events = chunk.split('\n\n');
events.forEach(event => {
if (event.trim()) {
const [eventType, eventData] = event.split('\n');
if (eventType.includes('event:conversation.message.delta')) {
const messageData = JSON.parse(eventData.replace('data:', '').trim());
if (messageData.role === 'assistant') {
this.setData({
messages: [...this.data.messages, { role: 'assistant', content: messageData.content }]
});
}
}
}
});
},
// 创建空对话
createEmptyConversation(callback) {
const accessToken = '你自己的 Coze token'; // 确保使用正确的访问令牌
wx.request({
url: 'https://api.coze.cn/v1/conversation/create', // 假设的创建会话 API 端点
method: 'POST',
header: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
data: {
bot_id: this.data.botId.toString(), // 确保 bot_id 是字符串
user_id: this.data.userId
},
success: (res) => {
if (res.data.code === 0) {
const conversationId = res.data.data.id;
this.setData({
conversationId,
messages: [...this.data.messages, { role: 'system', content: `空会话已创建,ID: ${conversationId}` }]
});
if (callback) callback(); // 执行回调函数
} else {
console.error('创建空会话失败:', res.data.msg);
}
},
fail: (err) => {
console.error('请求失败:', err);
}
});
}
});
doubao-chat.json
{
"usingComponents": {}
}
doubao-chat.wxml
<view class="container">
<view class="chat-window">
<block wx:for="{{messages}}" wx:key="index">
<view class="message {{item.role}}">
<text>{{item.content}}</text>
</view>
</block>
</view>
<input class="input" placeholder="输入消息..." bindinput="onInput" value="{{inputValue}}" />
<view class="button-group">
<button class="create-button" bindtap="createEmptyConversation">创建空对话</button>
<button class="send-button" bindtap="sendMessage">发送</button>
</view>
</view>
doubao-chat.wxss
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.chat-window {
flex: 1;
overflow-y: scroll;
padding: 10px;
}
.message {
margin: 10px;
padding: 10px;
border-radius: 5px;
}
.user {
background-color: #d1e7dd;
align-self: flex-end;
}
.assistant {
background-color: #f8d7da;
align-self: flex-start;
}
.system {
background-color: #e2e3e5;
align-self: center;
}
.input {
border: 1px solid #ccc;
padding: 10px;
width: calc(100% - 20px);
margin: 10px;
}
.button-group {
display: flex;
justify-content: space-between;
padding: 10px;
}
.create-button, .send-button {
flex: 1;
margin: 5px;
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
}