随着AI技术的发展,特别是2024年中国AI行业的持续升温,AI全栈开发成为了非常热门且高薪的职业方向。在这个领域,开发者不仅需要掌握传统的Web开发技术,还要具备AI相关的能力;今天我们就来实现一下coze中一个高级的AI功能:AI图标生成,再次提升我们对AI的理解。
AI图标生成
coze(主页 - 扣子 (coze.cn)),国内知名AI应用,今天我们就来学习一下它里面的图标生成功能;效果如下图:
当我们点击“AI生成”时,AI会根据用户输入的“Bot功能介绍”,去调用大模型帮助我们生成相关的图标;AI图标生成的功能不仅让我们可以快速地拿到一个相关的Logo,而且更是颠覆了传统的上传图标的方式。
AI功能的实现
在实现上述功能之前,我们可以先来了解一下,AI全栈式的开发,它不仅集前端、后端和AI服务为一体,更是要做到前后端的一个分离;前端(frontend)、后端(backend)。
前端 frontend
在前端部分,我们可以引入一个比较早期的前端框架库(bootstrap);通过link标签去引入:
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
虽然 bootstrap 框架,我们在实际开发中用的并不多,但利用它的CSS框架依然可以快速完成PC项目页面的开发。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>coze 生成</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet">
<style>
#result img {
width: 120px;
height: 120px;
}
</style>
</head>
<body>
<!-- 布局 -->
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form name="logoForm">
<div class="form-group">
<label for="titleInput">Bot名称:</label>
<input type="text" id="titleInput" name="title" class="form-control" placeholder="请输入名称"
required>
</div>
<div class="form-group">
<label for="descInput">Bot功能介绍:</label>
<textarea name="desc" class="form-control" row="3" id="descInput">
</textarea>
</div>
<div class="form-group">
<button name="loginButton" type="primary" class="btn btn-primary">生成LOGO</button>
</div>
</form>
<div class="col-md-6" id="result"></div>
</div>
</div>
</div>
</body>
</html>
HTML 结构
<div class="col-md-6 col-md-offset-3">:在 Bootstrap 的栅格系统中,每个行默认被分为 12 个等宽的列;"col-md-6" 表示该列将占据 6 个栅格单位,"col-md-offset-3" 表示该列将相对于行的起始位置向右偏移 3 个栅格单位;因此该 div 会在页面上居中显示。
HTML5 中的表单增强
<input type="text" placeholder="请输入名称" required>;HTML5 对表单进行了显著的增强,引入了许多新的功能和特性,其中 placeholder 和 required 都是html5中表单增强的新特性,placeholder: 显示提示文本,当用户开始输入时消失;required: 指定字段是否为必填项。
script 脚本
再来看,在这个AI功能中,前端页面需要进行哪些交互呢?当我们点击按钮时,我们需要把表单的内容进行收集,然后提交给后端进行处理,再拿到后端生成的图片进行展示。
<script>
// forms 是所有表单的集合,可以按名字来获取
const oForm = document.forms["logoForm"]
oForm.addEventListener('submit', function (event) {
event.preventDefault() // 阻止默认提交
const title = this["title"].value.trim()
if (!title) return // html5 有的不支持,两套方案
const btn = this["loginButton"];
btn.disabled = true;
const desc = this["desc"].value.trim()
// console.log(title);
// HTTP 协议
// 请求行 localhost:3000/logo POST
// 请求头
// 请求体 title desc
// 前后端数据交付的格式是json
// 输出是二进制或字符串
// es6 key value 一样的,可以省略
let data = {
title,
desc
}
console.log(JSON.stringify(data));
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>
在上面的代码中,我们有几个需要注意的点;
- 阻止表单的默认提交:在处理表单提交时,通常我们需要阻止表单的默认提交行为,以便我们可以执行自定义的操作;
event.preventDefault()就可以阻止表单的默认提交行为。 - 事件监听中的
this:在事件处理器函数中,this关键字通常指向触发事件的对象。这是因为事件处理器函数是在某个 DOM 元素上注册的,当事件发生时,该函数会被调用,并且this关键字会自动绑定到触发该事件的 DOM 元素。 .trim():trim()方法用于去除字符串两端的空白字符(包括空格、制表符、换行符等)。这意味着即使用户在输入前后添加了空格,trim()方法也会去除这些空格,确保实际使用的值没有多余的空白。fetch向后端发送请求:'Content-Type': 'application/json'表明我们将发送的数据格式是 JSON;前后端数据交付的格式通常都是 json,又因为 HTTP 协议传输的数据是以文本形式的,而不是原生的 JavaScript 对象,所以JSON.stringify(data)被用来将data对象转换为 JSON 字符串,然后作为请求体发送给服务器。- HTTP 通信:一个完整的请求通常由请求行、请求头和请求体三部分组成;请求行包含三部分,Method(方法)、URL(资源的位置) 和 HTTP版本,请求头则包含了一系列键值对,用于提供客户端和服务端之间通信所需的额外信息,如
Content-Type表示实体对象(请求体)的数据类型,Cookie存储客户端状态信息,通常用于会话管理,Authorization用于身份认证,通常包含一个token,请求体的话包含了要发送给服务器的具体数据,对于GET请求,通常没有请求体;而对于POST、PUT等请求,则可以有请求体。 - fetch 请求返回的Promise对象:当你使用
fetchAPI 发起一个网络请求时,它会返回一个 Promise 对象,可以用.then()方法处理fetch返回的Response对象,response.json()是一个异步方法,用于从fetch请求返回的Response对象中解析 JSON 数据;然后我们就可以拿到JSON对象进行操作。
后端 backend
前端页面设计完之后,接下来我们要对后端进行接口(/logo)的开发;我们可以引入 node 中一个流行的后端框架 KOA;
npm init -y // 初始化后端项目
npm i koa // 安装 koa
在这里,我们把单点入口文件设为 main.mjs ,.mjs 文件和 .js 文件之间的主要区别在于它们如何处理模块系统;.mjs 文件 默认使用 ECMAScript 模块(ES Modules),使用 import 和 export 关键字来导入和导出模块,而 .js 文件 默认使用 CommonJS 模块系统,在 Node.js 中使用 require 函数来导入模块,并使用 module.exports 来导出模块。
//导入koa框架
import Koa from 'koa'
//导入koa-router模块,用于创建路由
import Router from 'koa-router'
// koa-bodyparser 中间件,用于解析 POST 请求的 body 部分
import {bodyParser} from '@koa/bodyparser'
// koa-cors 中间件,用于处理跨域资源共享 (CORS)
import cors from '@koa/cors'
// openai 库,用于与 openai 的 api 进行交互
import OpenAI from 'openai'
// 创建一个 openai 的客户端实例,设置密钥和请求基础 URL
const client = new OpenAI({
apiKey: 'xxxxxxxxxxxxxxx',
// gptsapi 会帮我们做openai的请求转发
baseURL: 'https://api.302.ai/v1'
})
// 创建一个 Koa 应用实例
const app = new Koa()
// 创建一个路由对象的实例
const router = new Router()
// 使用 koa-bodyparser 中间件来解析请求体
app.use(bodyParser())
// 使用 koa-cors 中间件来处理跨域请求
app.use(cors())
// 定义一个 POST 路由 '/logo', 用于处理图片生成请求
router.post('/logo',async ctx => {
// console.log(ctx.request.body,'////');
// 从请求体中解构出标题和描述
let {title, desc} = ctx.request.body;
const prompt = `
你是一位资深设计师,
请为标题为${title},功能为${desc}
的移动app应用设计一款logo,
要求 高端大气上档次。
`
// console.log(title, desc);
try {
// 使用 OpenAI 的图像生成 API 生成图片
const response = await client.images.generate({
model: 'dall-e-3',
prompt,
n: 1
})
// 响应成功,构造一个包含图片 URL 的响应体
ctx.body = {
url: response.data[0].url,
}
} catch (error) {
// 异常捕获,构造一个错误响应体
ctx.body = {
status: 500,
error: error.message
}
}
// console.log(response.data[0].url);
})
// 定义一个 GET 路由 '/', 用于返回一个简单的文本响应
router.get('/',ctx => {
ctx.body = '首页'
})
// 将路由对象的路由配置到 Koa 应用上
app.use(router.routes())
// 启动 Koa 服务器并监听 3000 端口
app.listen(3000,() => {
console.log('server is running at http://localhost:3000');
})
来看我们对上面代码的分析:
- 搭建一个后端服务:
new Koa()创建一个 Koa 应用实例,它的实例就是一个后端服务器,它可以用来定义路由、中间件和其他功能,最终用于处理 HTTP 请求并发送响应。
路由 koa-router
- 服务器端引入路由:
koa-router模块,用于创建一个路由实例,路由定义了特定的 URL 路径与处理该路径的函数之间的映射关系,主要分三部分,method(方法),path(路径)和函数(ctx参数),最后通过app.use(router.routes())去进行使用。
ctx 上下文对象
- 上下文对象 ctx:它是对 Node.js 的原生
request和response对象的一种封装,ctx.request包含了请求信息的对象,ctx.response用于构造响应的对象,ctx.body设置响应体的内容。
JSON字符串的解析
- 中间件 bodyParser ;它用于处理 HTTP 请求的主体部分;因为前端给我们传过来的是一串JSON对象字符串,所以我们要把请求体解析成一个JSON对象拿到数据。
CORS
- CORS 解决同源策略:因为前端跑在5500的端口上,而后端又是在3000端口上,这就导致当前端给后端发接口请求后,后端想要给前端返回响应的数据时,会触发浏览器的同源策略,数据安全保护机制,这就会导致后端响应的数据返回不到前端;因此我们可以通过CORS这样一个手段去解决这个问题。
AI生成效果如下
小结
为什么前端开发者需要学习AI?答案很简单:AI是大势所趋。AI不仅是技术发展的必然结果,更是前端用户体验的革命性变化。2024年,随着AI的普及,前端开发将不仅仅局限于传统的用户交互,还将涉及到AI生成内容(AIGC)的领域。以生成Logo为例,传统的方法可能需要用户上传文件,然后通过设计工具进行调整。而在AI全栈开发中,前端可以直接通过调用AI模型(如DALL-E 3),实现基于文本生成图像的功能。这种多模态模型不仅支持文本,还可以处理图片、视频和音频,从而为用户提供更加丰富和多样的交互体验。