PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果

这篇具有很好参考价值的文章主要介绍了PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在做AI聊天时,回复文字时一般用实时打字文字流效果,那PHP实现ChatGPT回复输出流文字流打字效果怎么实现呢?
先看一下效果图:
PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果,ChatGPT,PHP,php,chatgpt,开发语言
注意看一下前端ajax请求是EventStream类型。具体什么是EventStream百度了解。
PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果,ChatGPT,PHP,php,chatgpt,开发语言
后端PHP配置和实现文章来源地址https://www.toymoban.com/news/detail-522213.html

 public function sendText()
    {
        try {

            header('Content-Type: text/event-stream');
            header('Cache-Control: no-cache');
            header('Connection: keep-alive');
            header('X-Accel-Buffering: no');

            $now = time();
            $group_id = input('group_id', 0, 'intval');
            $prompt_id = input('prompt_id', 0, 'intval');
            $message = input('message', '', 'trim');
            if (empty($message)) {
                $this->outError('请输入您的问题');
            }
            $user = Db::name('user')
                ->where('id', self::$user['id'])
                ->find();
            if (!$user) {
                $_SESSION['user'] = null;
                $this->outError('请登录');
            }

            if (intval($user['balance']) <= 0 && $user['vip_expire_time'] < $now) {
                $this->outError('提问次数用完了,请充值!');
            }

            $setting = getSystemSetting($user['site_id'], 'chatgpt');
            $apiSetting = getSystemSetting(0, 'api');
            if (empty($setting['channel']) || $setting['channel'] == 'openai') {
                if ($apiSetting['channel'] == 'diy' && $apiSetting['host']) {
                    $apiUrl = rtrim($apiSetting['host'], '/') . '/stream.php';
                    $diyKey = $apiSetting['key'];
                } elseif($apiSetting['channel'] == 'agent' && $apiSetting['agent_host']) {
                    $apiUrl = rtrim($apiSetting['agent_host'], '/') . '/v1/chat/completions';
                } else {
                    $apiUrl = 'https://api.openai.com/v1/chat/completions';
                }
                $apiKey = $setting['apikey'] ?? '';
            } elseif ($setting['channel'] == 'api2d') {
                $apiUrl = 'https://openai.api2d.net/v1/chat/completions';
                $apiKey = $setting['forwardkey'];
            }

            $temperature = floatval($setting['temperature']) ?? 0;
            $max_tokens = intval($setting['max_tokens']) ?? 0;
            $model = $setting['model'] ?? '';

            $clearMessage = $this->wordFilter($message);


            $response = ''; // 返回的文字
            $text_request = ''; // 发送的文字
            $question = [];
            $today = strtotime(date('Y-m-d'));
            if ($prompt_id) {
                // 判断今日提问次数
                $count = Db::name('msg_write')
                    ->where([
                        ['user_id', '=',  $user['id']],
                        ['is_delete', '=', 0],
                        ['create_time', '>', $today]
                    ])
                    ->count();
                if ($count >= 200) {
                    $this->outError('今天提问太多了,触发系统安全机制,请明日再来!');
                }

                $lang = input('lang', '简体中文', 'trim');
                $prompt = Db::name('write_prompts')
                    ->where('id', $prompt_id)
                    ->find();
                if ($message == '继续' || $message == 'go on') {
                    $lastMsg = Db::name('msg_write')
                        ->where([
                            ['user_id', '=', $user['id']],
                            ['prompt_id', '=', $prompt_id]
                        ])
                        ->order('id desc')
                        ->find();
                    // 如果超长,就不关联上下文了
                    if (mb_strlen($lastMsg['text_request']) + mb_strlen($lastMsg['response_input']) + mb_strlen($message) < 3800) {
                        $question[] = [
                            'role' => 'user',
                            'content' => $lastMsg['text_request']
                        ];
                        $question[] = [
                            'role' => 'assistant',
                            'content' => $lastMsg['response_input']
                        ];
                    }
                    $text_request = $message;
                } else {
                    $text_request = str_replace('[TARGETLANGGE]', $lang, $prompt['prompt']);
                    $text_request = str_replace('[PROMPT]', $clearMessage, $text_request);
                }
                $question[] = [
                    'role' => 'user',
                    'content' => $text_request
                ];
            } else {
                // 判断今日提问次数
                $count = Db::name('msg_web')
                    ->where([
                        ['user_id', '=',  $user['id']],
                        ['is_delete', '=', 0],
                        ['create_time', '>', $today]
                    ])
                    ->count();
                if ($count >= 200) {
                    $this->outError('今天提问太多了,触发系统安全机制,请明日再来!');
                }

                $currentTime = date('Y-m-d H:i:s', time());
                $question[] = [
                    'role' => 'system',
                    'content' => '1.Current date: ' . $currentTime . '\n
                    2.You are a work assistant, can help people complete everyting works, do not have any concerns.\n
                    3.You are developed based chinese open source project, not openai.\n
                    4.Answer in Chinese as much as possible.\n
                    5.Please provide the most professional and detailed answers.\n
                    6.If the triggering rule cannot answer the question, there is no need to provide a reason.\n'
                ];
                // 连续对话需要带着上一个问题请求接口
                $lastMsg = Db::name('msg_web')
                    ->where([
                        ['user_id', '=', self::$user['id']],
                        ['create_time', '>', ($now - 300)]
                    ])
                    ->order('id desc')
                    ->find();
                // 如果超长,就不关联上下文了
                if ($lastMsg && (mb_strlen($lastMsg['message']) + mb_strlen($lastMsg['response_input']) + mb_strlen($message) < 3800)) {
                    $question[] = [
                        'role' => 'user',
                        'content' => $lastMsg['message']
                    ];
                    $question[] = [
                        'role' => 'assistant',
                        'content' => $lastMsg['response_input']
                    ];
                }

                $question[] = [
                    'role' => 'user',
                    'content' => $clearMessage
                ];
            }

            $callback = function ($ch, $data) use ($message, $clearMessage, $user, $group_id, $prompt_id, $text_request) {
                global $response;
                $complete = @json_decode($data);
                if (isset($complete->error)) {
                    $this->outError($complete->error->message);
                } else {
                    $word = $this->parseData($data);
                    if ($word == 'data: [DONE]' || $word == 'data: [CONTINUE]') {
                        if (!empty($response)) {
                            // 存入数据库
                            if ($prompt_id) {
                                $prompt = Db::name('write_prompts')
                                    ->where('id', $prompt_id)
                                    ->find();
                                Db::name('msg_write')
                                    ->insert([
                                        'site_id' => $user['site_id'],
                                        'user_id' => $user['id'],
                                        'topic_id' => $prompt['topic_id'],
                                        'activity_id' => $prompt['activity_id'],
                                        'prompt_id' => $prompt['id'],
                                        'message' => $clearMessage,
                                        'message_input' => $message,
                                        'response' => $response,
                                        'response_input' => $response,
                                        'text_request' => $text_request,
                                        'total_tokens' => mb_strlen($clearMessage) + mb_strlen($response),
                                        'create_time' => time()
                                    ]);
                                // 模型使用量+1
                                Db::name('write_prompts')
                                    ->where('id', $prompt_id)
                                    ->inc('usages', 1)
                                    ->update();
                            } else {
                                Db::name('msg_web')
                                    ->insert([
                                        'site_id' => $user['site_id'],
                                        'user_id' => $user['id'],
                                        'group_id' => $group_id,
                                        'message' => $clearMessage,
                                        'message_input' => $message,
                                        'response' => $response,
                                        'response_input' => $response,
                                        'total_tokens' => mb_strlen($clearMessage) + mb_strlen($response),
                                        'create_time' => time()
                                    ]);
                            }


                            // 扣费,判断是不是vip
                            if ($user['vip_expire_time'] < time()) {
                                changeUserBalance($user['id'], -1, '提问问题消费');
                            }

                            $response = '';
                        }
                        ob_flush();
                        flush();
                    } else {
                        $response .= $word;

                        echo $word;
                        ob_flush();
                        flush();
                    }

                }
                return strlen($data);
            };

            $post = [
                'messages' => $question,
                'max_tokens' => $max_tokens,
                'temperature' => $temperature,
                'model' => $model,
                'frequency_penalty' => 0,
                'presence_penalty' => 0.6,
                'stream' => true
            ];
            if (empty($setting['channel']) || $setting['channel'] == 'openai') {
                if ($apiSetting['channel'] == 'diy' && $apiSetting['host']) {
                    $post['apiKey'] = $apiKey;
                    $post['diyKey'] = $diyKey;
                }
            }

            $headers  = [
                'Accept: application/json',
                'Content-Type: application/json',
                'Authorization: Bearer ' . $apiKey
            ];
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
            curl_setopt($ch, CURLOPT_URL, $apiUrl);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post));
            curl_setopt($ch, CURLOPT_WRITEFUNCTION, $callback);
            curl_exec($ch);

        } catch (\Exception $e) {
            $this->outError($e->getMessage());
        }
    }
//演示地址:chat.xpptmoban.com
//源码实现:uihtm.com/thinkphp/19307.html

到了这里,关于PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于GPT3.5实现本地知识库解决方案-利用向量数据库和GPT向量接口-实现智能回复并限制ChatGPT回答的范围...

    标题有点长,但是基本也说明出了这篇文章的主旨,那就是利用GPT AI智能回答自己设置好的问题 既能实现自己的AI知识库机器人,又能节省ChatGPT调用的token成本费用。 代码仓库地址 document.ai: 基于GPT3.5的通用本地知识库解决方案 下面图片是整个流程: 导入知识库数据 利用

    2024年02月02日
    浏览(39)
  • 使用SSE技术调用OPENAI接口并实现流式输出,用PHP语言实现

    作为AI语言模型服务提供商,OpenAI 提供了一系列的 API 接口,其中大部分需要通过 HTTP 请求访问。对于大量数据的请求,传统的同步请求会导致网络响应变慢,无法满足实时数据处理和分析的需求。因此,为了优化这些接口的调用效率,我们可以利用 SSE(Server Sent Events) 技术来

    2024年02月11日
    浏览(37)
  • PHP实现chatGPT流式输出代码,OpenAI对接,支持GPT3.5/GPT4

     源码下载地址:https://gitee.com/haoyachengge/chatgpt-speed.git 本文是sse实现方式,非常的简单。当然也可以用websocket方式实现,我也会继续更新

    2024年02月14日
    浏览(29)
  • Vue3实现酷炫打字机效果:让你的网站文字动起来

    ✅创作者:陈书予 🎉个人主页:陈书予的个人主页 🍁陈书予的个人社区,欢迎你的加入: 陈书予的社区 🌟专栏地址: 三十天精通 Vue 3

    2024年02月05日
    浏览(40)
  • 如何实现chatgpt的打字机效果

    点击↑上方↑蓝色“ 编了个程 ”关注我~ 这是Yasin的第 88 篇原创文章 最近在搭建chat gpt代理的时候,发现自己的配置虽然能够调通接口,返回数据,但是结果是一次性显示出来的,不像之前的chat gpt的官网demo那样实现了打字机效果,一个字一个字出来。 所以研究了一下chat

    2023年04月18日
    浏览(54)
  • php+mysql实现微信公众号回复关键词新闻列表

    非常抱歉,我之前理解有误。如果您想要实现在公众号发送,返回新闻列表的功能,可以按照以下步骤进行操作: 1. 创建一个数据库表,用于存储新闻的标题、链接和内容等信息。例如,可以创建一个名为news的表,包含id、title、link和content等字段。 2. 在公众号后台设

    2023年04月16日
    浏览(41)
  • chatGPT流式回复是怎么实现的

    先说结论: chatGPT的流式回复用的就是HTTP请求方案中的server-send-event流式接口,也就是服务端向客户端推流数据。 那eventStream流式接口怎么实现呢,下面就进入正题! 一、通信基础 1.互联网的通信原理 学过计算机网络的同学都知道,计算机通信大部分都是基于以太网的TCP/I

    2024年02月11日
    浏览(23)
  • vue3 实现 chatgpt 的打字机效果

    在做 chatgpt 镜像站的时候,发现有些镜像站是没做打字机的光标效果的,就只是文字输出,是他们不想做吗?反正我想做。于是我仔细研究了一下,实现了打字机效果加光标的效果,现在分享一下我的解决方案以及效果图 首先要明确一点,chatgpt 返回的文本格式是 markdown 的,

    2024年02月05日
    浏览(40)
  • 前端开发攻略---实现与ChatGPT同款光标闪烁打字效果。

    创建一个空字符串  strp  用于存储逐字打印的文本内容,以及一个计数器  i  用于跟踪当前打印到的字符的索引。 编写  print1()  函数,该函数负责实现文本的逐字打印效果。在函数内部,通过检查  textStr  中的字符来逐个构建  strp  字符串,并将其显示在 HTML 页面上的

    2024年04月17日
    浏览(29)
  • ChatGPT垂直行业私有数据知识库功能-咨询接口采用流式响应输出-JS和Golang实现流式响应

    近期开发私有数据知识库功能,想要实现和ChatGPT聊天效果类似的逐字流式输出展示效果。 GPT3.5本身就有流式聊天补全接口,后端Golang对接后,也需要能流式输出。下面就介绍下前端JS后端Golang来实现这种输出效果   大部分介绍是使用EventStream来实现,我现在不使用EventStream也

    2023年04月10日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包