ai流式文字返回前端和php的处理办法

发布于:2025-06-07 ⋅ 阅读:(14) ⋅ 点赞:(0)

PHP后端

php端主要是用到ob_flushflush,头改为流式。

基本代码

代码如下:

<?php
header('Content-Type:text/event-stream');
header('Cache-Control:no-cache');
header('Connection:keep-alive');

function streamPostRequest($url,$data){
    $ch=curl_init();

    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,true);
    curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($data));
    curl_setopt($ch,CURLOPT_HTTPHEADER,[
        'Content-Type:application/json',
        'Accept:text/event-stream'
    ]);
    curl_setopt($ch,CURLOPT_WRITEFUNCTION,function($ch,$data){
        
        //如果数据不需要特殊处理,这里可以直接返回
        echo $data;
        ob_flush();
        flush();
        //这里返回数据的长度,如果有特殊处理需要返回处理后的数据长度
        return strlen($data);
    });
    
    curl_exec($ch);
    curl_close($ch);
}

以上代码数据没有特殊处理,数据都会被前端接受到。如果特殊处理前端可能需要在done为true时候接收最后一条数据。

数据特殊处理

如果对数据进行处理,在CURLOPT_WRITEFUNCTION中写,代码如下:

<?php

 curl_setopt($ch,CURLOPT_WRITEFUNCTION,function($ch,$data){
        $start=strpos($data,'{');
        $end=strrpos($data,'}');
        $dataContentStr=substr($data,$start,$end-$start);
        $dataContent=json_decode($dataContentStr,true);
        $r='';
        if($dataContent['docs']){
            //如果这里逻辑复杂,会导致数据返回延迟,需要在前端done为true时接收
            /*code....*/
            $r=$data.'test';
        }else{
            $r=$data;
        }
        echo $r;
        ob_flush();
        flush();
        //这里为最终数据的长度
        return strlen($r);
  });

方法的使用

注意这里要使用file_get_contents接受数据

<?php
//要使用file_get_contents接受数据
$data=file_get_contents('php://input')

$dataArray=json.decode($data,true);

$content=$dataArray['content'];

$json=[
    'query'=>$content,
];

streamPostRequest("http://127.0.0.1:80/test",$json);

前端

基本代码

用的fetch请求方法,这个可以传数据

var abortController:any=null
var generteSwich=false    //中断请求用的
var maxTime=0

async function fetchStreamWithToken(url:string,data:any){
    abortController=new AbortController()
    var i=0
    
    const response=await fetch(url,{
        method:'POST',
        headers:{
            'Content-Type':'application/json',
            'Accept':'text/event-stream',
            'token':getToken() as any,
        },
        body:JSON.stringify($data),
        signal:abortController.signal
    })
    

    //获取可读流
    const reader=response.body?.getReader()
    const decoder=new TextDecoder('utf-8')
    let buffer:any=''
    generateSwich=true

    while(true){
        const {done,value}:any=await reader?.read()
        
        if(done || !generateSwich){
            //如果php数据没直接返回,数据进行特殊处理后返回,需要接受最后数据
            let endData=buffer

            //结束
            setTimeout(()=>{
                //对最后一个数据的处理,处理逻辑按照需求写
                const end=JSON.parse()
                if(end.test){
                    //code...
                }
                

                //更新会话方法
                updateDialogue()
                generateSwich=false  //停止
                
                dialogueList.value[diaId][lth-1].state='success'
            },maxTime)
            break
        }
        
        buffer+=decoder.decode(value,{steam:true})
        //按行展开
        const lines=buffer.split('\n')
        buffer=lines.pop()
        
        for(const line of lines){
            if(line){
              try{

                    const start=line.indexOf('{')
                    const end=line.lastIndexOf('}')
                    if(start===-1 || end===-1){
                        continue;
                    }

                    const content=line.substring(start,end+1)
                    const parsed=JSON.parse(content)
                    let t=parsed.text
                    setTimeout(()=>{
                        if(!generateSwich){
                        r    eturn
                        }
                    dialogueList.value[diaId][lth-1].content+=t
                        if(!dialogueList.value[diaId][lth-1].message_id){
                            dialogueList.value[diaId][lth-1].message_id=parsed.message_id
                        }
                    },60*i)
                    i++
                    maxTime=60*i
                }catch(error){
                    console.log(error)
                    console.log('原始数据',line)
                }
            }
        }


    }
}

结束思考方法

//停止思考
function stopThinking(){

    abortController.abort()
    generateSwich=false
}


网站公告

今日签到

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