从零实现一个GPT 【React + Express】--- 【4】实现文生图的功能

摘要

这是本系列的第四篇文章,在之前的三篇文章,我们主要实现了对话的功能。通过使用SSE和GPT模型,完成了一个能够自由对话的产品。

在之前的文章里,我们同时也处理了markdown和代码的格式。对话方面就告一段落,后续我们就要针对特定的功能去实现了,而这一篇,主要来实现一下文生图的功能。

使用dall-e-3模型

之前我们在做对话的时候,使用的模型是gpt-3.5-turbo,但是gpt-3.5-turbo模型是不支持文生图的功能的。所以这里我们要使用一个新的模型dall-e-3。dall-e-3是OpenAI开发的第三代文本到图像生成模型。

之前我们做对话的时候,就是调用模型,然后再通过SSE将内容返回给前端。而这次,调用dall-e-3模型会更简单,只需要将对应的query传给模型,模型会返回一个图片的url,至于图片的存储都不需要我们去管。

这么简单的情况下,我们就来直接实现后端部分。

这里我们在router下新建一个picture路由,用来实现我们文生图的接口:

js 复制代码
// routers/picture.js

var express = require('express');
var router = express.Router();
const OpenAi = require('openai');
require('dotenv').config();
const cors = require('cors'); // 引入 cors

const client = new OpenAi({
    apiKey: process.env.OPENAI_API_KEY, // 使用环境变量加载 API 密钥
    baseURL: 'https://api.chatanywhere.tech/v1',
})

router.use(cors());

/* GET users listing. */

router.post('/picture', async function(req, res) {
    const { message } = req.body;
    console.log(message);
    const imageRes = await client.images.generate({
        prompt: message,
        n: 1,
        size: '1024x1024',
        model: 'dall-e-3',
    });
    console.log(imageRes.data[0])
    res.json({
        code: 0,
        msg: '生成成功',
        data: imageRes.data[0].url,
        cardId: Date.now()
    });

    res.end();
});

module.exports = router;

很简单的一个post请求,设置好模型的参数然后把url返回即可,最后在app.js引入。

到这里我们的后端在本篇就实现完了,具体的提交可以看下面:

github.com/TeacherXin/...

前端部分

有了接口,我们就可以实现前端功能了,首先我们在输入框的下面增加一个技能选择,这里的UI我就不贴代码了:

当选中的图像生成这个技能,并且发送query的时候,我们就调用picture这个接口,所以我们需要将是否选中技能这个状态也保存下来:

js 复制代码
// src/page/components/SkillList/store.ts

import { create } from 'zustand';

interface SkillStore {
    selectedSkill: 'picture' | '';
    setSelectedSkill: (skill: 'picture' | '') => void;
}

export const useSkillStore = create<SkillStore>((set) => ({
    selectedSkill: '',
    setSelectedSkill: (skill) => set({ selectedSkill: skill }),
}))

现在呢,我们的dialogCard,就不一定是文本类型了。所以我们加一个isPicture属性,用来决定是否是图片类型。

js 复制代码
// src/page/components/DialogCardList/store.ts

interface DialogCard {
    question: string;
    answer: string;
    cardId: string;
    isPicture?: boolean;
}

如果是图片类型,我们的answer就是代表图片地址的url。

现在我们就可以实现生成图片的send方法了:

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

const sendDataByPicture = (message: string) => {

    inputStore.setInputValue('');
    
    dialogCardListStore.addDialogCard({
        question: message,
        answer: '',
        cardId: '',
        isPicture: true,
    });

    inputStore.setInputLoading(true);

    axios.post('http://localhost:3002/picture', {message}, {signal: controller.signal}).then(res => {
        if (res.data.data && res.data.code === 0) {
            const { data, cardId } = res.data;
            dialogCardListStore.changeLastAnswer(data);
            dialogCardListStore.changeLastId(cardId);
            inputStore.setInputLoading(false);
        }
    })
}

发送完query后,先在dialogCardList里加入一个isPicture的card,然后等响应来了之后,在更新answer和id。

更新数据之后,我们现在修改我们的视图层:

js 复制代码
{dialogCardListStore.dialogCardList.map((item, index) => {
    return (
        <div className={styles.dialogCard} key={item.cardId}>
            <div className={styles.question}>
            <p>{item.question}</p>
        </div>
        {
            item.isPicture ? (
            <div key={item.cardId} className={styles.pictureItem}>
            {
                dialogInputStore.inputLoading && index === dialogCardListStore.dialogCardList.length - 1 ?
                <Spin className={styles.spin} /> :
                <img src={item.answer} alt="" />
            }
            </div>
        ) : (
                <div className={styles.answer}>
                    <ReactMarkDown components={{ code: getCode }}>
                        {item.answer}
                    </ReactMarkDown>
                </div>
            )
        }
        </div>
    );
})}

更多详细的前端代码可以查看下面的提交记录:

github.com/TeacherXin/...

最后,我们可以看下实现的效果:

相关推荐
Liiiks11 小时前
GPT-Image-2来了!实测:文字渲染99%,UI截图像素级还原,前端工作流要变天了
人工智能·gpt·chatgpt·大模型·ai生图·gpt-image-2·图片设计
摆烂工程师12 小时前
GPT-5.5 发布:最贵模型上桌,OpenAI 又把牌局抬高了
chatgpt·openai·ai编程
kyriewen12 小时前
React Hooks原理:为什么不能写在if里?揭开Hook的“魔法”面纱
前端·react.js·前端框架
大龄程序员狗哥15 小时前
第20篇:Transformer架构革命——从“注意力”到ChatGPT的基石(原理解析)
深度学习·chatgpt·transformer
十一.36617 小时前
012-014 对state的理解,初始化state,react中的事件绑定
前端·react.js·前端框架
Agent产品评测局18 小时前
混合云架构适配:企业级智能体灵活部署完整方案与最佳实践 | 2026企业自动化选型硬核指南
运维·人工智能·ai·chatgpt·架构·自动化
一叶飘零_sweeeet18 小时前
2026 年 Q1 大模型终极比拼:从基座到落地,全维度硬核拆解(Java 开发者专属指南)
chatgpt·ai大模型·千问·豆包·智普ai
BingoGo19 小时前
GPT-5.5 开启更强的智能体工作方式
chatgpt
谢尔登19 小时前
【Next】客户端组件和服务端组件
前端·javascript·react.js·架构
旷世奇才李先生20 小时前
React 18\+TypeScript实战: hooks封装与组件设计模式
react.js·设计模式·typescript