从零实现一个GPT 【React + Express】--- 【5】实现网页生成能力

摘要

经过前面的四篇文章,我们已经实现了。文本对话,文生图的两个功能。其实我觉得这个系列这四篇文章就已经够用了。后续,我会继续提供一些额外模型能力的教程。这里读者如果有感兴趣的功能,也可以在评论区留下建议我们一起实现。

网页生成思路

那本篇文章主要来实现一下网页生成的能力,简单描述一下:就是用户输入一段query,然后给用户输出一个网页。那这个功能模型肯定不能支持,不能像文生图一样,给模型一个query,然后他给你部署好一个网页,然后通过url输出给你,这肯定是不行的。

那模型不支持,我们就无法做到了嘛,当然不。作为一个前端开发,我们肯定知道,一个网页代表的就是一个html。那模型有输出html的功能啊,那能不能经过我们的处理,实现这个网页生成的功能呢?

首先我们要给模型一个system,告诉模型你就是个只会写html的助手 。然后,当用户发来一个query之后,我们在query之后拼上请以html的格式输出。 哎,这样模型输出的不就是一个html了吗。

那在后端我们拿到了html的输出,只需要将其通过fs模型写到对应的目录下,再把html对应的目录返回给前端,这不就实现了吗。多么简单。

实现接口

现在,我们来到后端项目中,我们的chat接口要修改一下,我们要区分一下是走之前的对话链路,还是走生成网页的链路:

js 复制代码
//routes/chat.js


router.post('/chat', function(req, res) {
    res.set('Content-Type', 'text/event-stream;charset=utf-8');
    res.set('Access-Control-Allow-Origin', '*');
    res.set('X-Accel-Buffering', 'no');
    res.set('Cache-Control', 'no-cache, no-transform');
    const { message, sessionId, type } = req.body;

    if (type === 'html') {
        getHtml(message, sessionId, res);
        return;
    }

    getChat(message, sessionId, res);
});

直接通过前端传过来的参数来判断,如果type === html,那么就走新的链路。

现在我们来实现一下getHtml方法,首先我们要修改一下模型的system。

js 复制代码
const stream = await client.chat.completions.create({
    messages: [
        { role: 'system', content: '你是一个擅长编写html的代码助手' },
        ...historyList,
        { role: 'user', content: message + ',请以html的格式输出 ,请确保生成的HTML代码是合法的,并且包含基本的结构和语义' },
    ],
    model: 'gpt-3.5-turbo',
    stream: true,
    max_tokens: 5000, // 控制生成的 token 数
});

这样我们就限制了模型的输出一定是以html输出。但是模型输出html的同时,肯定也会输出一些文本,所以我们要把文本中的html部分截断出来,然后再通过fs写入对应的目录下:

js 复制代码
//routes/chat.js

const startIndex = answer.indexOf('<html');
const endIndex = answer.lastIndexOf('</html>');
const html = answer.slice(startIndex, endIndex + 7);

const folderPath = path.join(__dirname, '../public/html');
const fileName = Date.now() + '.html';
const filePath = path.join(folderPath, fileName);

fs.writeFileSync(filePath, html, 'utf8');

最后,我们把文件所在的目录返回给前端,即可。这里肯定要定义一个新的类型事件:

js 复制代码
//routes/chat.js

eventName = 'source';
res.write(`event: ${eventName}\n`);
res.write(`data: ${JSON.stringify({html: `http://localhost:3002/html/${fileName}`})}\n\n`)

后端部分的提交记录如下:

github.com/TeacherXin/...

实现前端部分

node端的部分实现完了,我们来实现前端的部分。

首先我们在SkillList里增加一个技能,对应的类型也添加好。当我们选中这个类型之后,我们的sendData方法就要携带type参数,发送给后端,现在我们修改一下sendData方法:

js 复制代码
//src/page/components/DialogInput/index.tsx

const callbackMap: CallBackMap = {
    message: messageCallback,
    major: majorCallback,
    close: closeCallback,
}

if (skillStore.selectedSkill === 'html') {
    data.type = 'html';
    callbackMap.source = (source) => {
        changeLastHtmlUrl(source.html);
    };
}

connectSSE(url, data, callbackMap);

这里记得我们要对source的事件类型也进行处理一下。

最后修改一下视图层前端部分就实现了,是不是非常简单。

更多的提交内容可以查看:

github.com/TeacherXin/...

最后我们来看一下效果吧:

相关推荐
中微子7 分钟前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
中微子39 分钟前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
前端_学习之路2 小时前
React--Fiber 架构
前端·react.js·架构
coderlin_2 小时前
BI布局拖拽 (1) 深入react-gird-layout源码
android·javascript·react.js
甜瓜看代码2 小时前
1.
react.js·node.js·angular.js
伍哥的传说2 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
Misha韩3 小时前
React Native 一些API详解
react native·react.js
小李飞飞砖3 小时前
React Native 组件间通信方式详解
javascript·react native·react.js
小李飞飞砖3 小时前
React Native 状态管理方案全面对比
javascript·react native·react.js