前言
通过一个项目带你从前端到全栈再到AI全栈,体验不一样的感觉。
通过这个项目,你能亲身体验到AI为传统项目带来的颠覆性变革,从提升用户体验到优化业务流程,乃至开拓全新的应用场景,每一处都将闪耀着AI的智慧之光。这不仅是一次技术的升级,更是一次思维模式的飞跃,让你在实践中领悟科技与创新的无限可能,享受AI技术带来的前所未有的魅力与震撼。
纯前端
通过引入Bootstrap ,可以使用Bootstrap 提供的丰富的预定义 CSS 样式和 JavaScript 组件达到快速构建用户界面的效果。
html
复制代码
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
通过在HTNL文件中引入这个CSS文件,我们可以使用它提供的一系列的 CSS 样式和类。在没有后端提供数据的情况下,只能将数据写在前端直接渲染。
HTML
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI全栈</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row col-md-6 col-md-offset-3">
<h1>AI赋能的用户表</h1>
<table class="table table-striped" id="user_table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>家乡</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>张三</td>
<td>北京</td>
</tr>
<tr>
<td>2</td>
<td>李四</td>
<td>上海</td>
</tr>
<tr>
<td>3</td>
<td>李明</td>
<td>上海</td>
</tr>
<tr>
<td>4</td>
<td>王五</td>
<td>深圳</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
实现效果:
全栈
通过前后端分离的方法分别在不同的文件内编写前端和后端代码。前端负责构建一个界面并且向后端发起数据请求动态更新页面的数据内容;而后端负责为前端提供数据。
后端
我们通过Node.js实现数据的提供。
-
首先初始化一个后端项目:
csharp复制代码npm init -y
-
安装
json-server
包。json-server
是用于快速搭建基于 JSON 文件的模拟 HTTP API 服务器的工具。通过使用json-server
模拟一个后端接口。css复制代码npm i json-server
创建一个users.json
文件,在里面输入用户数据。
JavaScript
复制代码
{
"users": [
{
"id":1,
"name": "张三",
"hometown": "北京"
},
{
"id": 2,
"name": "李四",
"hometown": "上海"
},
{
"id": 3,
"name": "李明",
"hometown": "上海"
},
{
"id": 4,
"name": "王五",
"hometown": "深圳"
}
]
}
准备向外提供数据。在package.json
文件中找到名为"scripts"
的键,并且将里面的内容删除,在里面添加"dev": "json-server users.json"
。
javascript
复制代码
"scripts": {
"dev": "json-server users.json"
},
执行以下指令。
arduino复制代码npm run dev
执行这个指令后会启动json-server
,并且让 json-server
基于名为 users.json
的 JSON 文件来搭建模拟的后端服务。 json-server
会把 users.json
文件中的数据以特定的接口形式暴露出来。
我们查看最后提供的接口http://localhost:3000/users
的内容。其内容为:
前端
在没有后端的情况下,只能将数据写在前端里。但是如果有后端传输数据,前端就只需要发起数据请求并且在获取数据后进行渲染就好了。
html
复制代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI全栈</title>
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="row col-md-6 col-md-offset-3">
<h1>AI赋能的用户表</h1>
<table class="table table-striped" id="user_table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>家乡</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<script>
const oBody = document.querySelector('#user_table tbody')
fetch('http://localhost:3000/users')
.then(data => data.json())
.then(users => {
oBody.innerHTML = users.map(user => `
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.hometown}</td>
</tr>
`).join('')
})
</script>
</body>
</html>
在JavaScript部分中通过fetch
方法向'http://localhost:3000/users'
发送请求获取数据;当获取到数据后将其装换为JSON格式;然后把获取到的用户数据进行遍历,再在页面上渲染出来。
其中要加上jion('')
的原因是map()
返回的是一个字符串数组,并不是我们想要的一整个字符串,所有通过jion('')
将该数组内的字符串拼接成一个整体。
以下是不添加jion('')
的效果,表格之间存在着逗号,原因是map()
返回的字符串数组在后续操作中会隐式调用toString()
转换为字符串类型。
添加jion('')
后的效果图:
全栈+AI
在以上全栈的基础上为引入AI做准备。
前端
HTML部分
在原有的前端基础上添加表单用于实现向AI询问用户表相关问题的功能。我们不需要自己手敲表单代码,只需要在Bootstrap 中找到自己喜欢的表单模板进行简单修改就好了。
表单用于提交数据。在没有ajax
之前的传统方法是通过跳转页面,数据会发送到该页面进行处理;在ajax
出现后方式改变了,首先通过dom结构获取数据再用ajax手动提交数据给服务器,不用跳转页面而是在当前页面接收服务器返回的响应并进行相应处理。
html
复制代码
<div class="container">
<div class="row col-md-6 col-md-offset-3">
<h1>AI赋能的用户表</h1>
<table class="table table-striped" id="user_table">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>家乡</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
<div class="row col-md-6 col-md-offset-3">
<form name="aiForm" method="get" action="http://www.baidu.com">
<div class="form-group">
<label for="questionInput">向AI提问:</label>
<input type="text" name="question" class="form-control" id="questionInput" placeholder="请输入相关问题">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
<h4 class="row col-md-6 col-md-offset-3" id="message">
</h4>
</div>
通过使表单中label
标签的for
属性值和input
标签的id
属性值相同,这样可以实现在页面表单中点击label
部分可以直接跳转到对应的input
输入框中。
JavaScript部分
在前端的JavaScript部分中,可以分为两部分。一部分是从json-server
生成的模拟接口中获取数据并且渲染在页面上;另外一部分是通过监听表单的提交事件触发AI服务功能回答关于用户表相关的问题。
详细解释监听表单事件的操作:
- 通过
event.preventDefault()
可以阻止表单的默认行为,也就是阻止表单的页面跳转操作。 - 通过
this['question'].value.trim()
获取用户在页面输入的问题。 - 接入AI服务:
- 向服务器传输一个名为
question
的查询参数,其值是变量question
的值,并且也传输了一个名为users
的查询参数,其值是将usersData
进行JSON
序列化后的值。(usersData
是一个数组,里面的元素是对象,每个对象代表一条用户数据) - 获取服务器返回的值,并且渲染在页面上展示给用户。
- 向服务器传输一个名为
javascript
复制代码
const oMessage = document.querySelector('#message')
const oBody = document.querySelector('#user_table tbody')
const oForm = document.forms['aiForm']
let usersData = []
//获取数据
fetch('http://localhost:3000/users')
.then(data => data.json())
.then(users => {
usersData = users
oBody.innerHTML = users.map(user => `
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.hometown}</td>
</tr>
`).join('')
})
//监听表单的提交事件
oForm.addEventListener('submit', function (event) {
//用于阻止事件的默认行为。表单点击提交按钮会默认提交表单,所以需要阻止默认行为(跳转页面)
event.preventDefault()
//通过name属性去查找表单元素,获取表单数据。这样性能更好
const question = this['question'].value.trim()//this指向表单
//接入AI服务器
fetch(`http://localhost:8888/users?question=${question}&users=${JSON.stringify(usersData)}`)//深拷贝
.then(data => data.json())
.then(res => {
oMessage.innerHTML = res.message
})
})
效果展示:
用户在输入框内输入问题,点击提交后会在下方展示AI对该问题的回答。
AI
这个项目的AI服务通过后端实现。
首先创建一个后端文件。
csharp
复制代码
npm init -y
然后安装openai
和dotenv
模块。
css
复制代码
npm i openai
npm i dotenv
创建一个JavaScript文件实现AI问答服务。
-
引入依赖模块:
javascript复制代码const http = require('http'); const url = require('url'); const OpenAI = require('openai'); require('dotenv').config();
其中
http
和url
是Node.js的内置模块,分别用于创建HTTP服务器和解析URL。OpenAI
用于与OpenAI的API进行交互。dotenv
用于从.env
文件加载环境变量。 -
初始化OpenAI客户端:
javascript复制代码const client = new OpenAI({ apiKey: process.env.OPENAI_KEY, baseURL: 'https://api.chatanywhere.tech/v1' })
创建一个
.env
文件,在里面设置一个OPENAI_KEY
变量,将其值设置为自己的API密钥。使用环境变量
process.env.OPENAI_KEY
设置API密钥,并指定代理基地址为https://api.chatanywhere.tech/v1
。通过该代理转发对OpenAI的请求。 -
创建HTTP服务器:
通过使用
http.createServer()
方法创建服务器,并传入一个异步处理函数。此函数会在每次接收到HTTP请求时被调用。(req是请求对象,res是响应对象)javascript复制代码const server = http.createServer(async function (req, res) {})
-
设置CORS头部:通过
res.setHeader()
方法设置响应头,允许来自任何源的跨域请求,并指定了允许的HTTP方法(GET
,POST
,OPTIONS
)和请求头(Content-Type
,Authorization
)。javascript复制代码res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
-
当请求对象的URL包含
/users
时,- 解析请求对象的URL内的查询参数。
- 通过结构的方法从查询参数中提取
question
和users
。 - 构建一个
prompt
存储提供给AI的提示指令,里面包含着用户的提问和用户信息。 - 调用OpenAI API的
chat.completions.create
方法,使用gpt-3.5-turbo
模型生成回复,同时设置temperature
为0以降低回复的随机性。 - 处理API响应,将回复内容包装在一个JSON对象中。
- 将响应的状态码设置为200,指定响应的内容是JSON类型,然后将JSON字符串化的结果作为响应体发送给客户端。
javascript复制代码if (req.url.indexOf('/users' >= 0)) { const parseUrl = url.parse(req.url, true) const { question, users } = parseUrl.query const prompt = ` ${users} 回答问题:${question},做出简短回答。 ` const response = await client.chat.completions.create({ model: 'gpt-3.5-turbo', messages: [{ role: "user", content: prompt }], temperature: 0, // 控制输出的随机性,0表示更确定的输出 }); const result = response.choices[0].message.content || ''; let info = { message: result } res.statusCode = 200; res.setHeader('Content-Type', 'text/json'); res.end(JSON.stringify(info)) }
-
-
启动服务器:监听8888端口。
JavaScript复制代码server.listen(8888, function () { console.log('服务器启动了'); })
效果展示
快动手创建属于自己的AI项目吧,逐步走向AI全栈工程师。
源文:从前端到全栈再到 AI 全栈:体验 AI 为项目带来的颠覆性变革
如有侵权请联系站点删除!
技术合作服务热线,欢迎来电咨询!