前言
如今的时代,前端、后端与AI之间的关系日益紧密,它们共同推动着现代技术栈的发展和数字化转型。前端主要负责用户界面的构建和交互体验的设计,确保用户能够直观、流畅地与应用程序交互。后端则处理数据的逻辑处理、存储和安全等后端服务,为前端提供必要的数据支持。- 在很多场景中,前端收集用户数据,后端利用AI进行处理和分析,再将结果反馈给前端展示,形成了从前端到后端再到AI,再回到前端的闭环。这种协同不仅提高了应用的智能化水平,也增强了用户体验和业务效率。前端、后端与AI在现代技术生态中相互融合,共同推动了技术进步和创新应用的涌现,为用户带来了更加智能、高效和个性化的数字体验。
今天,小编新学了一个小demo,主要功能就是当你在输入框输入你想要询问的关于用户的问题时,他能够AI正确的回答你的问题给你答案。就像你运用GPT提问各种问题它都能给你答案一样,是不是感觉很神奇?迫切的想知道它是如何实现的?别急,我带你来慢慢了解,首先咱们的这个demo是怎么组成的呢?它的上半部分是一个同学列表,显示的就是一个数据部分,还记得我之前跟你们聊过的ajax吗,咱们待会也会用到这个技术,不太了解这个技术的小伙伴可以去看看我之前的这篇文章:Ajax技术的三种实现方法。这里咱们的数据是异步的,异步来获取的,那么这个数据要怎么异步获取呢?之前咱们基本都是通过fetch方法,url地址里请求一个后端接口里的数据,是一个现成的数据,不是自己写的,今天,小编带大家来自己动手造一个这样的接口,实现同样的功能,以一个小demo就走通前端、后端、在加上AI.牛逼!话不多说,直接开干!
大体思路:
首先,一个项目大体上是要由前端界面和后端数据来实现,前端主要实现界面的框架和样式,后端数据库负责提供数据,因为这个小demo咱们还调用了openai的大模型gpt-3.5-turbo,用来实现AI的搜索回复能力,因此还需要一个ai_server文件夹,首先创建一个ai_user文件夹,在它里面创建三个子文件夹,分别为ai_server,backend负责后端相应的代码,frontend负责前端相应的代码,可以看到这里咱们的前后端代码都是分离的。很方便。
前端html部分
咱们先来实现这个表单,在head部分里面先引入bootstrap类,<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet"> bootstrap是一个企业级的css库,bootstrap给我们提供了一些基本的css类,可以让我们快速的完成一些前端开发。
<div class="container">
<div class="row col-md-6 col-md-offset-3">
<h1>AI能力驱动的userData</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> -->
</tbody>
</table>
</div>
这样用一个表格虽然可以帮我们实现这样的数据部分,但是这样实现的数据是死的,是静态的,但是一般这种数据都是在数据库里面的。不好,所以可以看到我上面的代码注释掉了它,这里咱们利用bootstrap css框架 快速完成界面搭建,完成了布局,还需要有数据,但不能是死的,所以咱们需要动态获取数据,用DOM编程用fetch获取数据源的数据,这里就来到了前后端交互的地方,前后端联调。
<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="请输入您想问的users相关问题">
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
</div>
<div class="row" id="message">
</div>
</div>
在上面的这个html代码中,<label for="questionInput">向AI助理提问:</label> 创建了一个标签,通过for属性与输入框关联,提高表单的可访问性。引入name="question" 为输入框命名,提交表单时该名称将作为键,值为用户输入的内容。placeholder="请输入您想问的users相关问题" 提供了占位提示文本,当输入框为空时显示给用户看。
后端部分
如何让backend文件夹成为后端文件呢?
第一步:初始化
首先咱们要在这个文件夹的终端命令行下输入npm init -y,初始化为后端项目,楚河汉界,与前端的代码实现了分离。
npm init -y
这个命令会创建一个默认的package.json文件:
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"-": "^0.0.1",
"json": "^11.0.0",
"json-server": "^1.0.0-beta.0",
"management": "^1.0.2",
"node": "^18.20.3",
"package": "^1.0.1",
"server": "^1.0.39"
}
}
第二步 :在backend文件夹的终端中安装json-server库,为咱们的前端提供需要的数据。
npm i json-server
这个包可以立马为我们的前端提供数据。
json-sever是什么呢?
json-server是一个轻量级的伪REST API服务器,它可以帮助开发者快速搭建一个模拟的后台服务器环境,以便于前端开发人员在没有完整后端服务的情况下进行独立开发和测试。Json-server基于Node.js构建,可以读取一个JSON文件作为数据库,支持CRUD(创建Create、读取Read、更新Update、删除Delete)操作。简单的说,就是让json文件快速编程后端数据的package.
第三步:创建JSON数据文件
在backend文件夹下创建一个名为users.json的文件,这个文件里的数据将作为咱们的模拟数据库。
{
"users":[
{
"id":1,
"name":"张三",
"hometown":"南昌"
},
{
"id":2,
"name":"李四",
"hometown":"抚州"
},
{
"id":3,
"name":"王五",
"hometown":"南昌"
},
{
"id":4,
"name":"廖总",
"hometown":"赣州"
},
{
"id":5,
"name":"罗总",
"hometown":"赣州"
}
]
}
第四步:添加脚本
有这样一份数据后,怎么样向外提供这份数据呢?这个时候咱们就需要在在 package.json 文件中添加一个新的脚本命令,在 scripts 部分添加以下内容:
{
"scripts": {
"dev": "json-server users.json"
}
}
执行这个脚本会启动一个模拟的API服务器,使得你可以用HTTP请求来操作users.json里的数据,
第五步:运行服务器
在终端中输入运行一下命令来启动json-server
npm run dev
运行,让它跑起来!启动成功后终端显示如下:
咱们就启动了一个后端服务,本地的localhost:3000,也就是一个请求数据接口地址,当咱们访问它时,可以拿到刚刚的 users.json 作为数据源。
json-server还有个更牛逼的地方,当你在后面的/加上2加上3对应的id时,它可以继续去访问详情页:
到这里咱们可以看到咱们的前后端都是分离的,前端通过html,和用js中的fetch来完成页面的动态,后端通过json-seerver快速提供数据接口,已经把界面做到了小企业的级别,后端使用轻量级的json-server,虽然都是同一门语言,但是它们是不一样的,前端文件中没有package.json.后端中通过dev脚本将项目跑起来,前端只需通过这种方式,添加页面所需的json文件,就可以将项目跑起来,而且界面是完整的,咱们要完成前端开发html,css,js,也就是说咱们不能把数据写死了,要用ajax技术将数据导入进去才算写完了前端项目,这套代码也是前端需要会的后端代码,等到后端真正把接口给到咱们之后,咱们再把本地的/users地址换成它给你从数据库里取出来数据的地址,这样。咱们的前端代码是不是一点都不用动,我们换个地址就可以了。也就是用json文件伪造下数据,到时候只要把localhost改成后端给的线上地址就可以了,万一后端没有写完数据接口这样你不用等着后端的给你这个接口,可以提高开发效率。
在利用 json-server搭建了后端之后,我们可以通过Fetch发送 请求到 ,然后咱们将这些数据渲染到干刚刚创建的表格中。接下来,我们需要将用户输入的问题传递给 AI 大模型进行处理,实现向 AI 提问的功能。
OpenAI的接入
ai_server文件夹的实现
第一步:初始化为后端文件
npm init -y 实现AI提问功能本质上也是后端功能,步骤和刚刚一样。
第二步:导入OpenAI库
1、在终端输入npm i openai,该命令会在项目中安装openai这个包,有了这个包就可以使用OpenAI的API接口了。
-
下载和安装包:从npm仓库下载
openai包及其依赖到项目的node_modules目录。 -
更新
package.json:执行完这个命令会将openai添加到dependencies字段,记录为项目依赖。完成后如下所示:
2、npm i dotenv
Dotenv 是一个 Node.js 的第三方模块,用于加载环境变量。它的作用是从一个名为 .env 的文件中加载环境变量,并将这些变量添加到 Node.js 的 process.env 对象中,将项目的私密内容封装到.env文件中不向外处暴露,可以很大的提高项目的安全性能。 如下所示:
到这里该项目所需的环境已经搭建完毕。
第三步:Http服务的搭建
在ai_server文件夹下新建一个main,js的js文件,内容如下:
// ai openai, :8888/users?question=
// node 的内置模块
// - 搭建http服务
const http = require('http');
const url = require('url');
const OpenAI = require('openai');
require('dotenv').config(); // 读取环境变量
const client = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
//proxy 代理
baseURL: 'https://api.chatanywhere.tech/v1'
})
const server = http.createServer(async function (req, res) {
res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有来源访问,也可以指定具体的域名,如'http://example.com'
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); // 允许的请求方法
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// http 基于请求响应的简单协议 req 请求 res 响应
if (req.url.indexOf('/users') >= 0) {
// users ai 服务
const parsedUrl = url.parse(req.url, true);
// console.log(parsedUrl);
const { question, users } = parsedUrl.query;
console.log(question, users)
const prompt = `
${users}
请根据以上用户的json数据,回答${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 || '';
console.log(result);
let info = {
message: result
}
res.statusCode = 200;
res.setHeader('Content-Type', 'text/json');
res.end(JSON.stringify(info))
}
})
server.listen(8888, function () {
console.log('服务器启动了')
})
我来给小伙伴们解释一下这段代码:
以上代码的主要作用是创建一个基于Node.js的HTTP服务器,该服务器作为一个简单的API接口,使用了Node.js的内置
http模块和第三方模块url、OpenAI以及dotenv利用OpenAI的聊天模型(gpt-3.5-turbo模型)来处理用户提出的问题。
导入模块和配置
http: Node.js内置模块,用于创建HTTP服务器。url: 解析URL的内置模块,用于从请求中提取查询参数。OpenAI: 第三方库,用于调用OpenAI API与AI模型交互。dotenv: 第三方库,用于加载.env文件中的环境变量,这里是获取OpenAI的API密钥。
通过require语句导入这些模块,并使用dotenv.config()加载环境变量,然后实例化OpenAI客户端,其中baseURL指定了代理的API端点。
创建http服务器
res.setHeader('Access-Control-Allow-Origin', '*'); // 允许所有来源访问,也可以指定具体的域名,
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); // 允许的请求方法
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
1.使用http.createServer()方法创建一个HTTP服务器,传入一个异步函数作为回调处理请求和响应。
2.设置响应头允许跨域访问,允许任何源('*'),允许GET、POST和OPTIONS请求方法,以及指定允许的请求头。
请求逻辑处理:
- 条件判断: 当接收到的HTTP请求的URL中包含
/users路径时,进入该代码块执行。 - 解析URL查询参数: 使用Node.js的
url模块解析请求的URL,并将其转换为一个对象。这里包含question和users这两个查询参数。 - 构建prompt: 根据解析得到的
question和users参数构建一个prompt字符串。这个prompt会包含用户提供的一段JSON格式的用户数据,并要求AI模型根据这些数据回答question所提出的问题。如果模型无法回答,则返回“不清楚”。 - 调用OpenAI API: 使用之前设置的OpenAI客户端,异步调用
chat.completions.create方法。这个方法会发送一个包含构建好的prompt的消息给GPT-3.5-turbo模型,并设定模型的随机性为0,意味着希望得到最确定、最一致的回复。 - 处理API响应: 从OpenAI API得到的响应中提取第一个选择(
response.choices[0])的message内容,这即为AI生成的回答。如果没有内容,则默认为空字符串。 - 准备响应数据: 将AI的回答包装成一个JSON对象,键为
message。 - 设置响应头和状态码: 为了正确响应客户端,设置了HTTP响应的状态码为200(表示成功),并指定了响应的内容类型为
text/json。 - 发送响应: 最后,使用
res.end方法将JSON格式的答案信息发送回客户端。
启动服务器
调用server.listen(8888)使服务器在本地8888端口上监听HTTP请求。
这样,通过访问服务器提供的端点,用户可以与 AI 助理进行实时的对话交互,向其提出问题并获取回答,从而在项目中实现了一个简单的 AI 对话功能。完成了这些功能后,咱们就差像后端发送请求获取用户数据了
frontend下JS部分:获取用户数据
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;
// console.log(usersData);
// console.log(users);
oBody.innerHTML = users.map(user => `
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.hometown}</td>
</tr>
`).join('')
})
我给大家来分析一下这个代码:
获取数据
1.使用
fetch()从http://localhost:3000/users(该地址为后端项目封装数据的地址,查询方式见上文) 获取数据。2.数据返回后,将其转换为JSON格式,并将结果赋值给
usersDate。3.遍历
usersDate,动态创建表格行(<tr>)并添加到oBody中。
这里有个需要注意的地方,就是这个.join("")的使用, oBody.innerHTML本来要的是一个字符串文件,但是我们得到内容却是一个数组,那不是会报错吗?怎么办呢?因此,咱们可以调用.join("")将它转化为字符串。但是如果不使用.join(""),其实他也能正常拿到这份数据不会报错,为什么呢?这里就是面试官在面试的时候很可能会问到你的问题了,想想,为啥呢?其实这里是发生隐式转换。隐式转换会将数组中的每个元素和字符串相加,然后将结果拼接成一个字符串,形式是每个数组元素之间以逗号分隔。因此,如果不使用 `join("")`,则 `oBody.innerHTML` 的值将是一个以逗号分隔的字符串。但是相比之下会多一些,分隔就是。因此咱们需要用.join(" ")中间加空格,阻止它发生隐式转换。
oForm.addEventListener('submit', function(event) {
// 阻止表单的默认行为
event.preventDefault();
// name 属性去找 性能更好
const question = this["question"].value.trim();
// console.log(question);
fetch(`http://localhost:8888/users?question=${question}&users=${JSON.stringify(usersData)}`)
.then(data => data.json())
.then(res => {
console.log(res)
document.querySelector('#message').innerHTML = res.message
})
})
fetch(http://localhost:8888/users?question=${question}&users=${JSON.stringify(usersData)}) 这里前端向AI服务器发送请求,对用户进行相应的访问,得到AI的回复。
表单提交处理
- 给表单添加事件监听器到表单,当表单被提交时触发。
- 使用
event.preventDefault()阻止表单的默认提交行为(防止页面跳转)。- 获取用户在
questionInput输入框中输入的问题。- 使用
fetch()向http://localhost:8888/users发送问题和用户数据的GET请求。
fetch(http://localhost:8888/usersquestion=${question}&users=${JSON.stringify(usersDate)})5.服务器返回的数据转为JSON格式,并且从中获取
message属性,最后将其内容显示在oMessage元素内。
好啦!现在这个界面基本完成,如果此时新来了一位用户,我们要为这个数据源添加一个用户,那就应该上表单,让表单提交,大家可能会说,这简单嘛,用form写一个表单就行了,但是咱们现在用过bootstrop呀,可以不用自己写代码,直接上bootstrap官网上找到那份代码直接用过来。大家可以直接去这里看看:bootstrap全局css属性
将上面这份表单代码复制过来直接用就行了,是不是很方便。
最后,让咱们来看看效果吧:
在前端界面用node运行main.js.启动咱们的服务器
浏览器运行咱们的前端项目,在输入框中输入谁和谁是老乡?
后端在接收到用户给出的请求时,调用OpenAi的接口立马给出了问题的答案。
nice!完美!!
总结
在前端文件夹中我们使用bootstrap快速搭建完成前端html的页面,以及表单的完成,在后端文件夹中安装json-server库,创建一个名为users.json的文件为前端提供数据,同时安装dev脚本运行命令启动json-sever模拟服务器,得到一个数据请求接口的地址,这就是前端所需要的接口,在这里与前端交互,前端的HTML页面与后端的Node.js服务器代码配合工作,用户可以在界面上查看用户数据,输入问题。在ai_server文件夹中导入OpenAI库,detenv库,和配置url模块以及创建http服务器,在这里调用AI大模型来回复用户输入的问题,前端通过fetch向AI服务器发送请求,对用户进行访问,得到AI的回复,实现了前端与AI的交互。至此,前端、后端、AI实现交互,AI全栈就此完成。
虽然这是一个简单的小项目,却让我们对前后端项目交互对AI全栈都有了一个更深的了解,在这个AI全栈的时代,我们更应该拥抱AI.好啦!今天的分享就到这里!感兴趣的小伙伴可以自己去动手实现实现哦,有不懂的地方也可以评论区留言交流哈。也欢迎各位大佬批评指正。