登录

前端对接直连GPT3.5流式传输completion接口实现逐字打印的效果

GPT3.5的chat补全接口,有一个参数叫stream,如果是true就会以EventStream流式传输的形式把数据逐字返回

前端展示上就可以实现一个打字机的效果,针对网络不好的情况,这种逐渐输出也是比一次性全部输出要好的多


之前,花费好长时间,没搞明白怎么去把stream流的数据拿出来,在微博咨询了easy同学后,使用他的库,终于能拿到流式数据了


库的地址是:

https://github.com/easychen/api2d-js


在vue下使用,可以npm install api2d,然后就可以直接去用了

  import Api2d from 'api2d';

const api = new Api2d(key, apiBaseUrl);

// Chat completion
const ret = await api.completion({
    model:'gpt-3.5-turbo',
    messages: [
        {
            "role":"user",
            "content":"Hello"
        }
    ],
    stream: true, // Supports streaming, note that when stream is true, the return value is undefined
    onMessage: (string)=> {
        console.log( "SSE returned, the complete string received is:", string );
    },
    onEnd: (string)=> {
        console.log( "end", string );
    }
});


// Embeddings
const ret = await api.embeddings({
    input: "hello world"
});
console.log( ret );

api.setKey( 'newkey' ); // set key
api.setApiBaseUrl( 'https://...your openai proxy address' );


我的实现代码部分:

	const timeout = 1000*20; // 60秒超时
				const api = new Api2d(this.secret, "https://api.openai.com", timeout);
				// chat 补全
				let i=0;
				const ret = api.completion({
					model:'gpt-3.5-turbo',
					messages: _this.message,
					stream: true, // 支持 stream,注意stream为 true 的时候,返回值为undefined
					onMessage: (string)=> {
						console.log( "SSE返回:", string );
						if(i==0){
							let showMessage={
								isme:false,
								avator:"https://goflychat.oss-cn-hangzhou.aliyuncs.com/static/upload/avator/2022June/32a988a3c2f8700119fa1f5da1b6a4bd.png",
								content:"",
								time:tools.shortTime(tools.getNowDate())
								}
							_this.msgList.push(showMessage);
						}else{
							_this.msgList[_this.msgList.length-1].content=string;
							_this.scrollBottom();
						}
						i++;
						
					},
					onEnd: (string)=> {
						console.log( "end", string );
						_this.sendDisable=false;
						_this.originMessage=""
						string=tools.trim(string,"\n");
						_this.message.push({
							"role": "assistant", 
							"content": string
							});
						_this.alertSound();
						_this.scrollBottom();
					}
				});
				ret.catch(function(error) {
				  console.log(error);
				  _this.$message({
				    message:error,
				    type: 'error'
				  });
				  _this.sendDisable=false;
				});