uniapp 对接deepseek

发布于:2025-06-19 ⋅ 阅读:(20) ⋅ 点赞:(0)

废话不多说直接上代码

// 小程序专用流式服务 
export const streamChatMiniProgram = (messages, options = {
	secret: ""
}) => {

	return new Promise((resolve, reject) => {

	
		// 构建请求数据 
		const requestData = {
			model: 'deepseek-chat',
			messages,
			stream: true,
			max_tokens: 2048,
			temperature: 0.7
		};

		// 平台特定配置
		const requestConfig = {
			url: 'https://api.deepseek.com/v1/chat/completions',
			method: 'POST',
			header: {
				'Accept-Charset': 'utf-8',
				'Content-Type': 'application/json',
				'Authorization': `Bearer ${options.secret}`
			},
			data: JSON.stringify(requestData),
			// responseType: 'text',
			enableChunked: true, // 关键配置:启用分块传输
			// enableHttp2: true,
			timeout: 30000
		};

		// 跨平台适配 
		// #ifdef MP-WEIXIN || MP-QQ 
		requestConfig.enableChunked = true;
		// #endif 

		// #ifdef MP-ALIPAY || MP-BAIDU 
		requestConfig.enableChunked = false;
		// #endif 

		// 发起请求 
		const requestTask = wx.request({
			...requestConfig,

			// 分块数据接收处理 
			chunked: requestConfig.enableChunked,

			success: (res) => {

				if (res.statusCode !== 200) {
					reject(new Error(`API错误: ${res.statusCode}`));
				}
			},

			fail: (err) => {
				reject(new Error(`请求失败: ${err.errMsg}`));
			}
		});
	
		try {
			
			// requestTask.onHeadersReceived((chunk)=>{
			// 	console.log("onHeadersReceived")
			// })
			
			// requestTask.onProgressUpdate((chunk)=>{
			// 	console.log("onProgressUpdate")
			// })
			
			// const decoder = new TextDecoder('utf-8') // 显式指定UTF-8
			requestTask.onChunkReceived((chunk) => {
				
				try {
					if (!requestTaskMap.get(requestTask.uniqueId)) {
						return;
					}
					// 缓冲区初始化为空字符串 
					let buffer = '';
					buffer += utf8Decode(chunk
						.data
					) //decoder.decode(chunk.data,  { stream: true });// String.fromCharCode.apply(null, new Uint8Array(chunk.data));

					// SSE格式解析 
					const lines = buffer.split('\n');
					buffer = '';

					for (const line of lines) {
						if (line.trim() === '') continue;
						if (line.startsWith('data:')) {
							const dataStr = line.replace('data:', '').trim();

							// 结束标记处理 
							if (dataStr === '[DONE]') {
								resolve(fullResponse);
								return;
							}

							// 解析JSON内容 
							try {
								const data = JSON.parse(dataStr);
								if (data.choices?.[0]?.delta?.content) {
									const content = data.choices[0].delta.content;
									fullResponse += content;

									// 实时事件通知 
									uni.$emit('deepseek_stream_update', {
										partial: content,
										full: fullResponse
									});
								}
							} catch (e) {
								console.error('JSON 解析错误', e);
								uni.$emit('deepseek_stream_update', {
									partial: 'JSON 解析错误',
									e,
									full: 'JSON 解析错误',
									e
								});

							}
						}
					}
				} catch (err) {
					uni.$emit('deepseek_stream_update', {
						partial: JSON.stringify(err),
						full: JSON.stringify(err)
					});
				}
			});

		} catch (err) {
			uni.$emit('deepseek_stream_update', {
				partial: JSON.stringify(err),
				full: JSON.stringify(err)
			});
		}



		// 存储任务引用以便中断 
		console.log("requestTask=", requestTask)
		requestTaskMap.set(requestTask.uniqueId, requestTask);

		let fullResponse = '';
	});
};


export function utf8Decode(buffer) {
	let uint8 = new Uint8Array(buffer);
	let str = '';
	let i = 0;

	while (i < uint8.length) {
		const byte = uint8[i++];

		// 单字节字符 (0-127)
		if (byte < 0x80) {
			str += String.fromCharCode(byte);
		}
		// 双字节字符 
		else if ((byte & 0xE0) === 0xC0) {
			const byte2 = uint8[i++];
			str += String.fromCharCode(
				((byte & 0x1F) << 6) | (byte2 & 0x3F)
			);
		}
		// 三字节字符(支持中文)
		else if ((byte & 0xF0) === 0xE0) {
			const byte2 = uint8[i++];
			const byte3 = uint8[i++];
			str += String.fromCharCode(
				((byte & 0x0F) << 12) |
				((byte2 & 0x3F) << 6) |
				(byte3 & 0x3F)
			);
		}
		// 四字节字符(简单兼容)
		else if ((byte & 0xF8) === 0xF0) {
			i += 3; // 跳过后续字节
			str += ''; // 替换字符占位
		}
	}

	return str;
}
// 请求任务管理器 
const requestTaskMap = new Map();
// 中断指定请求
export const abortStreamRequest = (requestId) => {
	const task = requestTaskMap.get(requestId);
	if (task) {
		task.abort();
		requestTaskMap.delete(requestId);
	}
};
// 中断所有请求
export const abortAllRequests = () => {
	requestTaskMap.forEach(task => {
		task.abort()
	});
	requestTaskMap.clear();
};

调用

async startStream() {
				if (!this.message) {
					return;
				}
				const userMessage = {
					id: Date.now(),
					role: 'user',
					content: this.message
				};
				this.messages.push(userMessage);
				this.message = ""

				// 构建对话历史 
				const messages = this.messages.map(m => ({
					role: m.role,
					content: m.content
				}));

				this.currMessage = {
					content: "",
					role: "assistant",
					thinking: true
				}
				this.messages.push(this.currMessage)
				// 发起流式请求
				this.loading = true

				const response = await streamChatMiniProgram(messages, {
					secret: this.deepSeekSecret
				});
				this.loading = false
				this.currMessage = undefined
				this.$nextTick(()=>{
					this.scrollBottom()
				})

			}


网站公告

今日签到

点亮在社区的每一天
去签到