从零实现一个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/...

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

相关推荐
用户938515635073 小时前
useRef + Web Worker 实战:React 如何优雅地拥抱多线程
前端·javascript·react.js
liangshanbo12155 小时前
Express SSE 流式输出实战:从入门 Demo 到 AI 生产级架构
人工智能·架构·express
To_OC7 小时前
从一个名字编辑组件开始,我把 React + TS 的数据流和副作用彻底搞明白了
前端·react.js·typescript
Darling噜啦啦8 小时前
useRef 的三个段位:从 DOM 引用到 Web Worker,彻底搞懂 React 的"非响应式"利器
react.js
张元清9 小时前
React useEvent Hook:告别过期闭包的稳定回调 (2026)
javascript·react.js
用户938515635079 小时前
从 DOM 编程到声明式 UI:React useRef 与 useState 底层全解析
前端·javascript·react.js
kisshyshy9 小时前
前端路由进化史:从刷新白屏到SPA,手写一个Hash路由就懂了!
前端·javascript·react.js
YH552698410 小时前
ChatGPT里的GPT-5.6怎么选?
人工智能·gpt·chatgpt
名字还没想好☜10 小时前
React 用 Portal + Context 实现全局 Toast:一次调用、自动消失与队列管理
前端·javascript·react.js·react·next.js
人工智能培训11 小时前
中小企业低成本落地AI工具实操方案
大数据·人工智能·gpt·机器学习·agi