前后端分离,做AI的全栈开发(以文生图为实例进行实操)
前言
很多人想问前端为什么要学习AI?
前端开发者学习人工智能(AI)可以带来多方面的好处。
- 增强用户体验:前端用户体验因AI带来了改变和创新,而aigc是一种用户体验
- 智能交互:AI可以使得前端应用更加智能,例如通过自然语言处理(NLP)技术实现聊天机器人,提供更自然的交互方式。
- 数据可视化:AI可以帮助前端开发者更好地理解和展示数据,通过智能数据可视化提供更深入的洞察。
- 提高开发效率:AI工具可以自动化一些前端开发任务,如代码生成、布局优化等,从而提高开发效率。
- 适应未来趋势:AI是大势所趋,24年是中国AI元年,创建了许多AGI之路的模型如最有名的
gpt4o
集合(文本、图片、视频、音频),未来是AGI的世界
举个例子:
目前很火爆的coze
中logo
的生成
- 传统是文件上传
- 而现在的用户体验是使用aigc文生图等dalle-3 多模态模型(文本、图片、视频、音频)
根据输入的Bot名称及Bot的功能介绍便可以自动生成专属的logo
正文
模仿coze来制作一个类似的项目
前端 frontend
完成框架的构建
利用bootstrap
中的css框架做PC框架项目时可以快速完成页面开发
container row col
可以快速完成页面布局
除了Bootstrap
之外,还有许多其他优秀的前端框架,它们各自具有特点,适合不同的项目需求。以下是一些与Bootstrap
类似或可作为其替代的前端框架:Foundation
、Bulma
、Material-UI
、Semantic UI
、Vuetify
等
<!-- 容器布局 -->
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form name="logoForm">
<div class="from-group">
<label for="titleInput">Bot名称:</label>
<input type="text" id="titleInput" name="title"
class="form-control" placeholder="输入Bot名称" required><!--required表示必填项,会阻止提交-->
</div>
<div class="from-group">
<label for="descInput">Bot功能介绍:</label>
<textarea name="desc" class="form-control" row="3" id="descInput"></textarea>
</div>
<div class="from-group">
<button name="loginButton" type="primary" class="btn btn-primary">生成logo</button>
</div>
<div class="col-md-6" id="result">
</div>
</div>
</form>
</div>
</div>
</div>
使用JS操作DOM处理表单提交事件
用户提交表单时,通过JavaScript控制表单数据的收集和初步验证,并阻止表单的默认提交行为
- 获取表单对象:
const oForm = document.forms["logoForm"];
通过document.forms
集合根据表单logoForm
的属性,获取到对应的表单元素。(forms 是所有表单的集合,可以按名字来获取)
2. 添加事件监听器:
oForm.addEventListener('submit', function(event) {
});
为表单元素添加了一个submit
事件监听器。当表单被提交时,会触发这个event
函数内的代码执行。
- 阻止默认提交行为:
event.preventDefault();
阻止了表单的默认提交行为,即阻止页面刷新或跳转到新的URL。这样就可以在JavaScript中处理表单数据,而不是让浏览器按照默认方式处理。
- 获取并处理表单数据:
const title = this["title"].value.trim();
const desc = this["desc"].value.trim();
分别获取表单中名为title
和desc
的输入字段的值,使用.trim()
方法去除两端的空白字符(如空格、换行符等)。这是HTML5中字符串新增的方法。
- 检查标题是否为空:
if (!title) return;
如果标题(title
)为空(全是空白字符或根本没输入),则直接返回,不再执行后续代码,这可以防止提交空白表单。
- 禁用提交按钮:
const btn = this["loginButton"];
btn.disabled = true;
防止用户在数据正在处理或发送请求期间多次点击提交按钮,从而避免重复提交。
前后端交接时刻
使用JavaScript的fetch
API向服务器发送一个HTTP POST请求的过程。
- 构造请求体数据:
let data = {
title,
desc
};
- 向服务器发起POST请求:
fetch('http://localhost:3000/logo', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
一个典型的HTTP请求包括:
- 请求行:包含方法(GET、POST等)、请求URI和协议版本。
- 请求头:一系列键值对,提供关于请求的附加信息,如
Content-Type(请求体类型)、Accept(响应体类型)、User-Agent(浏览器信息)、Host(域名)、Referer(来源)、Cookie(会话信息)
等。- 请求体:可选部分,用于POST等方法提交的数据。
URL: 'http://localhost:3000/logo'
指定了请求的目标服务器地址和端口号以及资源路径。
method: 'POST'
指定了请求方法为POST,表示向服务器发送数据。
headers: 设置了请求头,其中'Content-Type': 'application/json'
告诉服务器,发送的数据格式是JSON。
body: JSON.stringify(data)
是经过序列化后的请求体内容,即之前构造的包含title
和desc
的对象转换成的JSON字符串。
- 处理从服务器返回的响应
使用fetch
API处理HTTP响应的链式then
方法,用于异步操作成功后的数据处理。具体解析如下:
- 解析响应体为JSON:
.then(res => res.json())
当前then
方法接收来自上一个Promise(即fetch
请求的响应)的结果res
,然后调用.json()
方法将其响应体内容转换为JSON对象。这是处理HTTP响应体的标准做法,特别是当服务器返回的是JSON格式的数据时。
- 处理转换后的JSON数据:
.then(data => {
btn.disabled = false; // 启用按钮
console.log(data);
if (data.status === 200) {
let url = data.url;
document.getElementById('result').innerHTML = `<img src="${url}" alt="">`;
}
});
- 启用按钮:首先将之前禁用的提交按钮重新启用,允许用户再次点击提交。
- 日志输出:通过
console.log(data)
打印出从服务器接收到的数据,便于调试。 - 条件判断:检查
data.status
是否为200
,这是HTTP状态码,表示请求成功。 - 展示结果:如果状态码为200,则从
data
中提取图片URL,并使用这个URL动态地创建一个<img>
标签,将其插入到ID为result
的HTML元素内。这样,从服务器返回的图片URL所指向的图片就会显示在这个位置。
综上所述,这部分代码负责处理从服务器返回的响应,一旦数据成功转换为JSON格式,就执行相应的逻辑,包括重新激活提交按钮、检查响应状态以及根据响应内容动态更新页面上的内容。这是现代Web开发中处理异步请求和响应的典型模式。
<script>
const oFrom = document.forms["logoForm"];
oFrom.addEventListener('submit', function(event) {
event.preventDefault();
// 获取表单数据
const title = this["title"].value.trim();
if (!title) return // html5有的不支持
const desc = this["desc"].value.trim();
const btn = this["loginButton"];
btn.disabled = true;//禁用按钮,只能发送一次请求
let data = {
title,
desc
}
fetch ('http://localhost:3000/logo',{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
//响应 json
.then(res => res.json())
.then(data =>{
btn.disabled = false;//启用按钮
console.log(data);
if(data.status === 200){
let url = data.url
document.getElementById('result').innerHTML = `<img src="${url}" alt="">`
}
})
})
</script>
后端 backend
使用Node.js
编写的简单后端服务,使用了Koa
框架和一些中间件来创建一个Web服务。实现了一个简单的API,允许客户端发送包含应用标题和功能的POST
请求,然后后端使用OpenAI
的模型生成一个Logo,并返回Logo的URL。如果请求失败或发生错误,将返回相应的状态码和错误信息。
- 导入依赖:
导入了Koa
框架、Koa-Router
用于路由管理、@koa/bodyparser
用于解析请求体、@koa/cors
用于处理跨域问题,以及OpenAI
库来调用OpenAI的API。
import Koa from 'koa';// 后端简单的框架
import Router from 'koa-router';
import {bodyParser} from '@koa/bodyparser';
import cors from '@koa/cors';
import OpenAI from'openai';
- 初始化OpenAI客户端:使用提供的API密钥和自定义的baseURL初始化OpenAI客户端实例。
const client = new OpenAI({
apiKey: '*************************************',
baseURL: '***********'
});
- 创建Koa应用和路由:初始化Koa应用实例
app
和路由实例router
。
const app = new Koa();
const router = new Router();
- 中间件配置:应用中使用了两个中间件——
bodyParser
用于解析请求中的JSON或UrlEncoded数据,cors
用于处理跨域请求。
app.use(bodyParser())
app.use(cors())
- 定义路由处理逻辑:定义了一个POST类型的路由
/logo
,当此路由被访问时,执行异步函数处理逻辑。
router.post('/logo',async(ctx) => {
let title = ctx.request.body.title
let desc = ctx.request.body.desc
console.log(title,desc)
const prompt = `
1.你是一位资深的设计师
2.请你为标题名为${title},功能为${desc}应用设计一款logo
3.要求高端大气上档次`
try{
const response = await client.images.generate({
model: 'dall-e-3',
prompt,
n: 1,
});
ctx.body = {
status:200,
url: response.data[0].url
}
}
catch(e){
ctx.body = {
status:500,
error: e.message
}
}
})
- 从请求体中提取
title
和desc
。 - 构造一个
prompt
其中包含了请求体中的内容,用于指导OpenAI的图像生成模型 - 使用
try-catch
结构来处理异步操作:- 使用OpenAI客户端调用
images.generate
方法,传入模型名称dall-e-3
,提示字符串prompt
和生成数量n
。 - 如果成功,将生成的Logo的URL返回给客户端。
- 如果发生错误,捕获异常并返回错误信息。
- 使用OpenAI客户端调用
- 注册路由并启动服务器:将路由应用到Koa应用中,然后监听3000端口,启动服务器并在控制台打印启动信息。
app.use(router.routes())
app.listen(3000, () => {
console.log('server is running at http://localhost:3000');
});
(附上后端完整代码)
import Koa from 'koa';// 后端简单的框架
import Router from 'koa-router';
import {bodyParser} from '@koa/bodyparser';
import cors from '@koa/cors';
import OpenAI from'openai';
const client = new OpenAI({
apiKey: '*************************************',
baseURL: '***********'
});
const app = new Koa();
const router = new Router();
app.use(bodyParser())
app.use(cors())
router.post('/logo',async(ctx) => {
let title = ctx.request.body.title
let desc = ctx.request.body.desc
console.log(title,desc)
const prompt = `
1.你是一位资深的设计师
2.请你为标题名为${title},功能为${desc}应用设计一款logo
3.要求高端大气上档次`
try{
const response = await client.images.generate({
model: 'dall-e-3',
prompt,
n: 1,
});
ctx.body = {
status:200,
url: response.data[0].url
}
}
catch(e){
ctx.body = {
status:500,
error: e.message
}
}
})
app.use(router.routes())
app.listen(3000, () => {
console.log('server is running at http://localhost:3000');
});
总结
前后端交互是Web开发中的重要组成部分,涉及到客户端(前端)和服务器端(后端)之间的数据交换和通信。以下是前后端交互的基本过程:
- 用户操作:用户在前端界面上进行操作,比如填写表单、点击按钮等。
- 前端发送请求:前端应用将用户的请求转换为HTTP请求,并通过互联网发送给服务器。这个请求通常包含URL、HTTP方法(如GET、POST、PUT、DELETE等)、请求头和请求体。
- 服务器接收请求:服务器接收到来自前端的HTTP请求,并通过路由机制将请求分发到相应的处理函数。
- 处理请求:服务器端的应用程序根据请求的类型和内容执行相应的逻辑处理,比如查询数据库、调用外部API等。
- 生成响应:处理完成后,服务器生成一个HTTP响应,包括状态码(如200表示成功,404表示未找到等)、响应头和响应体(通常是JSON、XML或其他格式的数据)。
- 发送响应:服务器将HTTP响应发送回前端。
- 前端接收响应:前端接收到服务器的响应后,根据响应的状态码和内容进行相应的处理,比如显示数据、显示错误信息等。
- 更新界面:前端使用响应中的数据更新用户界面,比如填充表格、显示图片等。
- 循环交互:用户可能会根据更新后的界面继续进行操作,从而开始新一轮的前后端交互。
转载自:https://juejin.cn/post/7383086531043737641