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

news2025/6/9 23:19:59

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
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2405961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解JavaScript设计模式之闭包与高阶函数

目录 前言小序一场失败面试面试后的觉醒 闭包变量作用域&#xff1a;谁的地盘听谁的变量的生命周期&#xff1a;该走了&#xff0c;不该走的还在闭包的更多作用&#xff1a;不只是谈恋爱&#xff0c;还能干活&#xff01;1、封装私有变量&#xff1a;你的变量我来守护2、延长变…

springboot启动mapper找不到方法对应的xml

数据源配置 目录结构 idea中mapper.java 可以找到对应的mapper.xml文件 启动却找不到 因为mapper.db1会被识别为文件名 而非目录结构 调整为这种

MQTT协议:物联网时代的通信基石

MQTT协议&#xff1a;物联网时代的通信基石 在当今快速发展的物联网&#xff08;IoT&#xff09;时代&#xff0c;设备之间的通信变得尤为重要。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议作为一种轻量级的消息传输协议&#xff0c;正逐渐成为物联…

Electron通信流程

前言 今天讲Electron框架的通信流程&#xff0c;首先我们需要知道为什么需要通信。这得益于Electron的多进程模型&#xff0c;它主要模仿chrome的多进程模型如下图&#xff1a; 作为应用开发者&#xff0c;我们将控制两种类型的进程&#xff1a;主进程和渲染器进程 。 …

华为云Flexus+DeepSeek征文|华为云Flexus服务器dify平台通过自然语言转sql并执行实现电商数据分析

目录 前言 1 华为云Flexus服务器部署Dify平台 1.1 华为云Flexus服务器一键部署Dify平台 1.2 设置账号登录Dify&#xff0c;进入平台 2 构建自然语言转SQL并执行的应用 2.1 创建应用并启动工作流设计 2.2 应用框架设计 2.3 自然语言转SQL模块详解 2.4 代码执行模块实现…

IDEA中微服务指定端口启动

在使用IDEA开发SpringBoot微服务时&#xff0c;经常需要开启多个服务实例以测试负载均衡&#xff0c;以下几种方法开启不同端口。 直接在配置文件中指定 # application.propertiesserver.port8001指定VM参数 点击Modify options&#xff0c;选择Add VM options&#xff0c;值…

Spring Cloud Alibaba Seata安装+微服务实战

目录 介绍核心功能三层核心架构安装微服务实战创建三个业务数据库编写库存和账户两个Feign接口订单微服务 seata-order-service9701库存微服务 seata-store-service9702账户微服务 seata-account-service9703测试结果 总结 介绍 Spring Cloud Alibaba Seata 是一款开源的分布式…

FMC STM32H7 SDRAM

如何无痛使用片外SDRAM? stm32 已经成功初始化了 STM32H7 上的外部 SDRAM&#xff08;32MB&#xff09; 如何在开发中无痛使用SDRAM 使它像普通 RAM 一样“自然地”使用? [todo] 重要 MMT(Memory Management Tool) of STM32CubeMx The Memory Management Tool (MMT) disp…

部署DNS从服务器

部署DNS从服务器的目的 DNS域名解析服务中&#xff0c;从服务器可以从主服务器上获得指定的区域数据文件&#xff0c;从而起到备份解析记录与负载均衡的作用&#xff0c;因此通过部署从服务器可以减轻主服务器的负载压力&#xff0c;还可以提升用户的查询效率。 注意&#xf…

Android Camera Hal中通过Neon指令优化数据拷贝

背景描述&#xff1a; Camera apk普通相机模式录像操作时&#xff0c;一般是同时请求两个流&#xff0c;即预览流和录像流。对于两个流输出图像格式和分辨率相同的情况下&#xff0c;是不是可以通过一个流拷贝得到另一个流的数据&#xff0c;进而节省掉一个Sensor输出处理两次…

C# winform教程(二)----button

一、button的使用方法 主要使用方法几乎都在属性内&#xff0c;我们操作也在这个界面 二、作用 用户点击时触发事件&#xff0c;事件有很多种&#xff0c;可以根据需要选择。 三、常用属性 虽然属性很多&#xff0c;但是常用的并不多 3.常用属性 名称内容含义AutoSize自动调…

Python编码格式化之PEP8编码规范

文章目录 概要PEP8编码风格py文本组织规范命名规范编码风格 PEP8编码检查工具pylintflake8PyCharm中配置检查工具 PEP8编码格式化工具blackautopep8PyCharm配置格式化工具本地git配置hook 总结 概要 在Python项目开发过程中&#xff0c;代码的可读性和一致性对于项目的长期维护…

【Zephyr 系列 14】使用 MCUboot 实现 BLE OTA 升级机制:构建安全可靠的固件分发系统

🧠关键词:Zephyr、MCUboot、OTA 升级、BLE DFU、双分区、Bootloader、安全固件管理 📌面向读者:希望基于 Zephyr 为 BLE 设备加入安全 OTA 升级功能的开发者 📊预计字数:5200+ 字 🧭 前言:为什么你需要 OTA? 随着设备部署数量增多与产品生命周期延长,远程升级(…

K8S认证|CKS题库+答案| 8. 沙箱运行容器 gVisor

目录 8. 沙箱运行容器 gVisor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、官网找模板 3&#xff09;、创建 RuntimeClass 4&#xff09;、 将命名空间为 server 下的 Pod 引用 RuntimeClass 5&#xff09…

Selenium4+Python的web自动化测试框架

一、什么是Selenium&#xff1f; Selenium是一个基于浏览器的自动化测试工具&#xff0c;它提供了一种跨平台、跨浏览器的端到端的web自动化解决方案。Selenium主要包括三部分&#xff1a;Selenium IDE、Selenium WebDriver 和Selenium Grid。 Selenium IDE&#xff1a;Firefo…

【论文解读】MemGPT: 迈向为操作系统的LLM

1st author: Charles Packer paper MemGPT[2310.08560] MemGPT: Towards LLMs as Operating Systems code: letta-ai/letta: Letta (formerly MemGPT) is the stateful agents framework with memory, reasoning, and context management. 这个项目现在已经转化为 Letta &a…

vb监测Excel两个单元格变化,达到阈值响铃

需求 在Excel中实现监控两个单元格之间的变化范围&#xff0c;当达到某个设定的值的范围内时&#xff0c;实现自动响铃提示。 实现&#xff1a; 首先设置Excel&#xff0c;开启宏、打开开发者工具&#xff0c;点击visual Basic按钮&#xff0c;然后在左侧双击需要监测的shee…

node 进程管理工具 pm2 的详细说明 —— 一步一步配置 Ubuntu Server 的 NodeJS 服务器详细实录 7

前言 我以 Ubuntu Server 打造的 NodeJS 服务器为主题的系列文章&#xff0c;经过五篇博客&#xff0c;我们顺利的 安装了 ubuntu server 服务器&#xff0c;并且配置好了 ssh 免密登录服务器&#xff0c;安装好了 服务器常用软件安装, 配置好了 zsh 和 vim 以及 通过 NVM 安装…

Flask与Celery 项目应用(shared_task使用)

目录 1. 项目概述主要功能技术栈 2. 项目结构3. 环境设置创建虚拟环境并安装依赖主要依赖 4. 应用配置Flask应用初始化 (__init__.py)Celery应用初始化 (make_celery.py) 5. 定义Celery任务 (tasks.py)任务说明 6. 创建API端点 (views.py)API端点说明 7. 前端界面 (index.html)…

二叉树-226.翻转链表-力扣(LeetCode)

一、题目解析 翻转可以理解为树的左右子树交换&#xff0c;从根到叶子节点&#xff0c;但是这里交换的是链接的指针&#xff0c;而不是单纯的交换值&#xff0c;当出现nullptr时&#xff0c;也是可以交换链接的&#xff0c;交换值的话就不行了。 二、算法原理 依旧的递归&…