花1块钱让你的网站支持 ChatGPT

本文正在参加「金石计划 . 瓜分6万现金大奖」

最近 ChatGPT 在技能圈子可太火了,票圈也被刷屏。我也决定来凑个热烈,给自己的博客加一个 ChatGPT 对话功用。

先附上体会链接,源码在底部也能够找到。

花1块钱让你的网站支撑 ChatGPT

体会 ChatGPT

ChatGPT 是 Open AI 练习的一个 AI 对话模型,能够支撑在多种场景下进行智能对话。

花1块钱让你的网站支撑 ChatGPT

想体会 ChatGPT,首先要注册账户,可是这个产品在国内网络并不能直接用,需求自行解决网络问题。

花1块钱让你的网站支撑 ChatGPT

搞定网络问题后,注册时会让你供给邮箱验证,

花1块钱让你的网站支撑 ChatGPT

接着要验证手机号,可是很遗憾国内手机号用不了。

花1块钱让你的网站支撑 ChatGPT

你也能够选择用 Google 账号登录,可是终究还是要验证手机号。

所以咱们需求先找一个国外的能接纳短信验证码的手机号,此时能够上SMS-ACTIVATE。

这是一个在这个星球上数以百万计的服务中注册帐户的网站。咱们供给国际上大多数国家的虚拟号码,以便您能够在线接纳带有确认代码的短信。 在咱们的服务中,还有虚拟号码的长期租借,转发衔接,电话验证等等。

SMS-ACTIVATE 上的价格是卢布,咱们需求运用手机号码做短信验证,经过查询能够发现,最便宜的是印度地区的手机号,零售价格是 10.5 卢布。

花1块钱让你的网站支撑 ChatGPT

按照汇率算了一下,大概是1块多RMB。

花1块钱让你的网站支撑 ChatGPT

SMS-ACTIVATE 支撑用某宝充值,我买了一个印度号,就能够收到来自 Open AI 的验证码了。

花1块钱让你的网站支撑 ChatGPT

留意,这个号码仅仅租用,是有期限的,所以咱们要抓紧时间把注册流程搞完,20分钟过了,这个号码就不是你的了。

注册完 Open AI 的账号后,就能够到 ChatGPT 的 Web工作台体会一把 AI 对话了。

花1块钱让你的网站支撑 ChatGPT

经过 API 接入 Open AI 才干

体会完 ChatGPT 之后,对于搞技能的咱们来说,或许会想着怎样把这个才干接入到自己的产品中。

快速上手

ChatGPT 是 Open AI 练习出来的模型,Open AI 也供给了 API 给开发者们调用,文档和事例也比较全面。

机器学习很重要的一个步骤便是调参,但对于前端开发者来说,大部分人肯定是不知道怎样调参的,那咱们就参阅官方供给的最契合咱们需求的事例就好了,这个 Chat 的事例就非常契合咱们的场景需求。

花1块钱让你的网站支撑 ChatGPT

官方有供给一个 nodejs 的 starter,咱们能够基于此快速上手测验一把。

git clone https://github.com/openai/openai-quickstart-node.git

它的中心代码是这么一部分,其中用到的openai是官方封装好的 NodeJS Library。

const completion = await openai.createCompletion({
    model: "text-davinci-003",
    prompt: '发问内容',
    temperature: 0.9,
    max_tokens: 150,
    top_p: 1,
    frequency_penalty: 0,
    presence_penalty: 0.6,
});

在调用 API 之前需求先在你的 Open AI 账户中生成一个 API Key。

现在官方给到的免费额度是 18 刀,超越的部分就需求自己付费了。计费是依据 Token 来算的,至于什么是 Token,能够参阅Key concepts。

花1块钱让你的网站支撑 ChatGPT

咱们把上面那个 Chat 事例的参数拿过来直接用上,根本上也有个七八分 AI 答复问题的姿态了,这个能够自己去试一试作用,并不杂乱。

接着便是研究一下怎样把这个 starter 的关键代码集成到自己的产品中。

产品剖析

我之前有在自己的博客中做过一个简略的 WebSocket 谈天功用,而在 AI 对话这个需求中,前端 UI 部分根本上能够参阅着WebSocket 谈天功用改改,工作量不是很大,主要工作量还是在前后端的逻辑和对接上面。

花1块钱让你的网站支撑 ChatGPT

ChatGPT 的这个产品形式,它不是一个常规的 WebSocket 全双工对话,而是像咱们平常调接口相同,产生用户输入后,客户端发送恳求到服务端,等待服务端响应,最终反应给用户,它仅仅是从界面上看起来像是谈天,实际上不是一个标准的谈天进程。所以前后端交互主要还是靠 HTTP 接口对接。

中心要素 Prompt

openai.createCompletion调用时有一个很重要的参数prompt,它是对话的上下文信息,只要这个信息满意完好,AI 才干正确地做出反应。

举个比如,假设在对话进程中有2个回合。

// 回合1
你:爱因斯坦是谁?
AI: 爱因斯坦(Albert Einstein)是20世纪最重要的物理学家,他被誉为“时空之父”。他发现了相对论,并取得诺贝尔物理学奖。

第一个回合中,传参prompt爱因斯坦是谁?,机器人很好了解,立刻能给出契合实际的回复。

// 回合2
你:他做了什么奉献?
AI: 他为社会做出了许多奉献,例如改善公共卫生、建立教育基础设施、提高农业生产才干、促进经济发展等。

第二个回合传参prompt他做了什么奉献?,看到机器人的答复,你或许会觉得有点离谱,由于这根本便是驴唇不对马嘴。可是仔细想想,这是由于机器人不知道上下文信息,所以机器人不能了解代表的意义,只能经过他做了什么奉献?整句话去推测,所以从成果上看便是契合语言的逻辑,可是不契合咱们给出的语境。

假如咱们把第二个回合的传参prompt改成你: 爱因斯坦是谁?nAI: 爱因斯坦(Albert Einstein)是20世纪最重要的物理学家,他被誉为“时空之父”。他发现了相对论,并取得诺贝尔物理学奖。n你: 他做了什么奉献?nAI:,机器人就能够了解上下文信息,给出接下来的契合逻辑的答复。

// 改善后的回合2
你:他做了什么奉献?
AI: 爱因斯坦对科学有着严重的奉献,他发明晰相对论,改变了人们对国际、物理定律和世界的知道,并为量子力学奠定了基础。他还发现了...

所以,咱们的初步结论是:prompt参数应该包含此次对话主题的较完好内容,才干保证 AI 给出的下一次答复契合咱们的根本认知。

前后端交互

对于前端来说,咱们通常重视的是,我给后端发了什么数据,后端反应给我什么数据。所以,前端重视点之一便是用户的输入,用上面的比如说,爱因斯坦是谁?他做了什么奉献?这两个内容,应该分别作为前端两次恳求的参数。并且,对于前端来说,咱们也不需求考虑后端传给 Open AI 的prompt是不是完好,只要把用户输入的内容合理地传给后端就够了。

对于后端来说,咱们要重视 session 问题,每个用户应该有属于自己和 AI 的私密对话空间,不能和其他的用户对话串了数据,这个能够基于 session 完成。前端每次传过来的信息只要简略的用户输入,而后端要重视与 Open AI 的对接进程,结合用户的输入以及会话中保留的一些信息,合并成一个完好的prompt传给 Open AI,这样才干得到正常的对话进程。

所以根本的流程应该是这个姿态:

花1块钱让你的网站支撑 ChatGPT

咱们依据这个流程输出第一版代码。

后端V1版别代码

router.get('/chat-v1', async function(req, res, next) {
    // 取得用户输入
    const wd = req.query.wd;
    // 结构 prompt 参数
    if (!req.session.chatgptSessionPrompt) {
        req.session.chatgptSessionPrompt = ''
    }
    const prompt = req.session.chatgptSessionPrompt + `n发问:` + wd + `nAI:`
    try {
        const completion = await openai.createCompletion({
            model: "text-davinci-003",
            prompt,
            temperature: 0.9,
            max_tokens: 150,
            top_p: 1,
            frequency_penalty: 0,
            presence_penalty: 0.6,
            stop: ["n发问:", "nAI:"],
        });
        // 调用 Open AI 成功后,更新 session
        req.session.chatgptSessionPrompt = prompt + completion.data
        // 回来成果
        res.status(200).json({
            code: '0',
            result: completion.data.choices[0].text
        });
    } catch (error) {
        console.error(error)
        res.status(500).json({
            message: "Open AI 调用反常"
        });
    }
});

前端V1版别关键代码

const sendChatContentV1 = async () => {
    // 先显示自己说的话
    msgList.value.push({
        time: format(new Date(), "HH:mm:ss"),
        user: "我说",
        content: chatForm.chatContent,
        type: "mine",
        customClass: "mine",
    });
    loading.value = true;
    try {
        // 调 chat-v1 接口,等成果
        const { result } = await chatgptService.chatV1({ wd: chatForm.chatContent });
        // 显示 AI 的答复
        msgList.value.push({
            time: format(new Date(), "HH:mm:ss"),
            user: "Chat AI",
            content: result,
            type: "others",
            customClass: "others",
        });
    } finally {
        loading.value = false;
    }
};

花1块钱让你的网站支撑 ChatGPT

根本的对话才干现已有了,可是最明显的缺陷便是一个回合等得太久了,咱们期望他速度更快一点,至少在交互上看起来快一点。

流式输出(服务器推 + EventSource)

还好 Open AI 也支撑 stream 流式输出,在前端能够合作 EventSource 一起用。

You can also set thestreamparameter totruefor the API to stream back text (asdata-only server-sent events).

根本的数据流是这个姿态的:

花1块钱让你的网站支撑 ChatGPT

后端改造如下:

router.get('/chat-v2', async function(req, res, next) {
    // ...省掉部分代码
    try {
        const completion = await openai.createCompletion({
            // ...省掉部分代码
            // 增加了 stream 参数
            stream: true
        }, { responseType: 'stream' });
        // 设置响应的 content-type 为 text/event-stream
        res.setHeader("content-type", "text/event-stream")
        // completion.data 是一个 ReadableStream,res 是一个 WritableStream,能够经过 pipe 打通管道,流式输出给前端。
        completion.data.pipe(res)
    }
    // ...省掉部分代码
});

前端抛弃运用 axios 建议 HTTP 恳求,而是改用 EventSource。

const sendChatContent = async () => {
    // ...省掉部分代码
    // 先显示自己说的话
    msgList.value.push({
        time: format(new Date(), "HH:mm:ss"),
        user: "我说",
        content: chatForm.chatContent,
        type: "mine",
        customClass: "mine",
    });
    // 经过 EventSource 取数据
    const es = new EventSource(`/api/chatgpt/chat?wd=${chatForm.chatContent}`);
    // 记载 AI 答复的内容
    let content = "";
    // ...省掉部分代码
    es.onmessage = (e) => {
        if (e.data === "[DONE]") {
            // [DONE] 标志数据完毕,调用 feedback 反应给服务器
            chatgptService.feedback(content);
            es.close();
            loading.value = false;
            updateScrollTop();
            return;
        }
        // 从数据中取出文本
        const text = JSON.parse(e.data).choices[0].text;
        if (text) {
            if (!content) {
                // 第一条数据来了,先显示
                msgList.value.push({
                    time: format(new Date(), "HH:mm:ss"),
                    user: "Chat AI",
                    content: text,
                    type: "others",
                    customClass: "others",
                });
                // 再拼接
                content += text;
            } else {
                // 先拼接
                content += text;
                // 再更新内容,完成打字机作用
                msgList.value[msgList.value.length - 1].content = content;
            }
        }
    };
};

从代码中能够发现前端在 EventSource message 接纳完毕时,还调用了一个 feedback 接口做反应。这是由于在运用 Pipe 输出时,后端没有记载 AI 答复的文本,考虑到前端现已处理了文本,这儿就由前端做一次反应,把本次 AI 答复的内容完好回传给后端,后端再更新 session 中存储的对话信息,保证对话上下文的完好性。

feedback 接口的完成比较简略:

router.post('/feedback', function(req, res, next) {
    if (req.body.result) {
        req.session.chatgptSessionPrompt += req.body.result
        res.status(200).json({
            code: '0',
            msg: "更新成功"
        });
    } else {
        res.status(400).json({
            msg: "参数过错"
        });
    }
});

我这儿仅仅给出一种简略的做法,实际产品中或许要考虑的会更多,或许应该在后端自行处理 session 内容,而不是依靠前端的反应。

终究的作用大概是这个姿态:

约束拜访频次

由于 Open AI 也是有免费额度的,所以在调用频率和次数上也应该做个约束,防止被恶意调用,这个也能够经过 session 来处理。我这儿也供给一种比较粗糙的处理方式,详细请往下看。实际产品中或许会写 Redis,写库,加定时使命之类的,这方面我也不够专业,就不多说了。

针对拜访频率,我暂定的是 3 秒内最多调用一次,咱们能够在调用 Open AI 成功之后,在 session 中记载时间戳。

req.session.chatgptRequestTime = Date.now()

当一个新的恳求过来时,能够用当前时间减去上次记载的chatgptRequestTime,判断一下是不是在 3 秒内,假如是,就回来 HTTP 状态码 429;假如不在 3 秒内,就能够持续后边的逻辑。

if (req.session.chatgptRequestTime && Date.now() - req.session.chatgptRequestTime <= 3000) {
    // 不允许在3s里重复调用
    return res.status(429).json({
        msg: "请降低恳求频次"
    });
}

关于恳求次数也是相同的道理,我这儿也写得很简略,实际上还应该有跨天整理等逻辑要做。我这儿偷懒了,暂时没做这些。

if (req.session.chatgptTimes && req.session.chatgptTimes >= 50) {
    // 实际上还需求跨天整理,这儿先偷懒了。
    return res.status(403).json({
        msg: "抵达调用上限,欢迎明天再来哦"
    });
}

同一个论题也不能聊太多,不然传给 Open AI 的 prompt 参数会很大,这就或许会消耗很多 Token,也有或许超越 Open AI 参数的约束。

if (req.session.chatgptTopicCount && req.session.chatgptTopicCount >= 10) {
    // 一个论题聊的次数超越约束时,需求强行重置 chatgptSessionPrompt,换个论题。
    req.session.chatgptSessionPrompt = ''
    req.session.chatgptTopicCount = 0
    return res.status(403).json({
        msg: "这个论题聊得有点深入了,不如换一个"
    });
}

切换论题

客户端应该也有切换论题的才干,不然 session 中记载的信息或许会包含多个论题的内容,或许导致与用户的预期不符。那咱们做个接口就好了。

router.post('/changeTopic', function(req, res, next) {
    req.session.chatgptSessionPrompt = ''
    req.session.chatgptTopicCount = 0
    res.status(200).json({
        code: '0',
        msg: "能够测验新的论题"
    });
});

结语

总的来说,Open AI 开放出来的智能对话才干能够满意根本需求,可是还有很大改善空间。我在文中给出的代码仅供参阅,不保证功用上的完美。

附上源码地址,能够点个 star 吗,球球了[认真脸]。

Java大猿帅
分享 收藏 点赞(0)
上一篇
GitHub Copilot X来了,我让 GPT-4 帮我写了一篇分析文章|太强了
下一篇
TypeScript类型推论和类型断言

PHP网站源码洛阳百搜标王朝阳网站优化推荐上海高端网站设计公司茂名百度爱采购报价白银百度网站优化排名报价昆明建站哪家好兴安盟网络营销公司郴州网页设计价格黔西南网站改版推荐宜宾企业网站设计多少钱宝安百度竞价哪家好佛山网站推广系统塔城SEO按天计费多少钱长治如何制作网站公司大理建设网站公司云浮SEO按天收费多少钱聊城关键词排名包年推广公司南昌seo优化价格黄山模板推广鞍山seo排名哪家好吉祥模板网站建设赤峰SEO按天扣费多少钱崇左网页制作公司本溪seo网站推广报价沈阳网站优化排名公司广东优化价格洛阳百度竞价包年推广公司大浪企业网站制作报价汕尾网站优化排名报价雅安网站改版价格歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

PHP网站源码 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化