引言
在这个充满创新和技术的时代,人工智能和大数据已经渗透到生活的方方面面。作为一名想要踏上AIGC全栈之路的小白,很多时候会感觉无从下手,不知道该如何开始。如果你也和我一样有这样的困惑,那么不妨来看看下面的小demo,也许能为你揭开AIGC全栈之路的神秘面纱。
项目介绍AI
今天我们通过一个小demo来聊聊如何通过openAI+JS+json-serve在传统前后端项目中搭载一个AI问答助理。 该项目涉及前端、后端和AI端的协作,主要介绍了三端的功能和合作流程。整体项目相对简单,具体包括:
-
前端------负责页面展示和通过 Ajax 与后端和AI端进行交互。
-
后端------使用 json-server 模拟数据库,提供接口给前端,处理数据存储与交互。
-
AI端------调用 OpenAI 接口,根据用户数据回答用户提出的问题,并将处理结果传递给前端展示给用户。
效果图:

准备工作
文件夹创建
创建一个新文件夹,并在这个文件夹下再创建3个子文件夹:ai_server(AI端)、backend(后端)、frontend(前端)。
初始化
分别进入ai_server(AI端)和 backend(后端)的终端 输入:
csharp
npm init -y
将其初始化为后端项目。
成功后会出现package.json文件。

package.json 是项目配置文件,使用npm init -y 命令会自动在 Node.js 项目的根目录下创建一个新的package.json文件,并自动填充一些默认信息。这些默认信息包括项目的名称、版本、描述以及依赖项等。
前端
Bootstrap
Bootstrap 是一个流行的开源前端框架,用于开发响应式和移动设备优先的网站设计。它提供了一套用于快速开发界面的 CSS 和 JavaScript 组件,帮助开发者构建现代、响应式的网页设计。
使用 Bootstrap 非常简单,如果只需引入其 CSS 部分,只需要在 HTML 文件中添加以下代码:
html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
通过这一行代码,您就能够在项目中引入 Bootstrap 的 CSS 文件,从而利用其提供的样式和组件来快速构建出现代风格的界面。Bootstrap的使用使得页面设计和布局变得更加便捷和一致,有助于提升用户体验和整体视觉效果。
具体使用可以查看全局 CSS 样式 · Bootstrap v3 中文文档 | Bootstrap 中文网 (bootcss.com)
本项目也是采用bootstrap进行开发的。
HTML部分
从效果图可以看出,本项目的HTML结构非常简单,只由 标题+表格+表单组成。
html
<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>
</tbody>
</table>
<!-- 表单 -->
<div class="row">
<form name="aiForm">
<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>
<!-- AI回答展示 -->
<div class="row" id="message"></div>
</div>
</div>
关键点:label(for) + input(id)
在前端开发中,label(for) + input(id)组合常用于创建表单标签与输入字段的关联,具有提高可访问性、用户体验和易用性的作用。这种做法使表单结构更清晰,允许灵活设计样式,同时符合HTML规范,有助于代码可维护性。通过在标签中设置for属性指向对应的input id (for与id一致) ,用户可以通过点击标签来聚焦对应的输入字段,从而改善用户体验和操作便捷性。
JS部分
这是前端最重要的部分,利用ajax与后端和AI端进行交互。
与后端联调------获取用户数据
这部分讲解与后端进行联调,并使用ajax与后端进行交互,获取用户数据,并将其渲染至页面中。
请求地址由后端提供,将在后端部分进行讲解。
js
const oBody = document.querySelector("#user_table tbody");
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("");
})
document.querySelector("#user_table tbody")
用于选择包含用户数据的表格的 tbody 元素。usersData
存储后端返回用户数据,便于之后传递给AI端。- 通过 Fetch API 发起 GET 请求获取 http://localhost:3000/users 的数据。
- 第一个
.then()
将响应转换为 JSON 格式。 - 第二个
.then()
接收 JSON 格式的用户数据,将数据赋值给usersData
变量,并通过将数据映射到 HTML 表格行的方式将用户数据渲染到网页上。 join("")
将数组转化为以空字符连接字符串,如果不加,数组会发生隐式转换从而变成以逗号连接的字符串,如果对类型转换不熟悉的,可以看看我之前的文章面试官:[] == ![],返回什么?为什么? - 掘金 (juejin.cn)
与AI端联调------获取AI回答
这部分讲解与AI端进行联调,并使用ajax与AI端进行交互,传递用户问题
以及用户数据
,并获取openAI回答展示到页面上。
js
const oMessage = document.querySelector("#message");
const oForm = document.forms['aiForm'];
oForm.addEventListener('submit', function (event) {
// 阻止表单默认提交行为
event.preventDefault();
// 获取用户输入
const question = this["question"].value.trim();
// console.log(question);
if (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;
})
}
})
代码与上一部分大差不差不做过多解释。
后端 ------ 提供用户数据
本项目只是一个小demo,因此我们将借助json-server来实现一个虚拟的后端服务器环境,在此之前,先简单介绍一下json-server数据模拟库。
json-server 数据模拟库
json-server
是一个用于快速搭建基于 JSON 文件的 RESTful API 的工具,可以帮助开发者快速搭建一个模拟的后端服务器,用于开发和测试前端应用程序。使用 json-server
可以避免复杂的后端开发,特别适合快速原型开发或前后端分离开发。
以下是一些关于 json-server
数据模拟库的特点和基本用法:
- 快速搭建:通过简单的命令行操作和配置文件,即可搭建一个虚拟的 RESTful API 服务器。
- 基于 JSON 数据:利用 JSON 文件来模拟数据,并通过 RESTful 接口进行访问和操作。
- 支持路由:可以自定义路由规则,定义不同的 URL 对应不同的数据。
- 支持过滤和查询:可以使用一些参数进行数据的过滤和查询,方便前端开发调试。
- 内置中间件:支持一些内置中间件,如身份验证、请求日志等,可以满足基本的开发需求。
本项目就是使用json-server来快速搭建一个模拟的后端服务器。
搭建流程
1. 通过npm安装 json-server
在backend的终端中输入:
css
npm i json-server
成功后package.json文件中dependencies会自动添加json-server依赖:

2. 创建JSON对象
创建一个users.json文件,存储json数据。

在users.json文件中放入以下内容:
json
{
"users": [
{
"id": 1,
"name": "小旺车",
"hometown": "丰城"
},
{
"id": 2,
"name": "肖战",
"hometown": "重庆"
},
{
"id": 3,
"name": "郭文韬",
"hometown": "青海"
},
{
"id": 4,
"name": "椰汁",
"hometown": "上饶"
},
{
"id": 5,
"name": "积米者",
"hometown": "潮汕"
}
]
}
这部分就是你要传递给前端的用户数据。
json对象:
是一种轻量级的数据交换格式,基于JS对象的语法,但独立于任何编程语言,通常用于在客户端和服务器之间传输数据。
语法
:使用键值对的形式表示数据,使用大括号{}
表示对象,使用方括号[]
表示数组,每个键值对之间使用逗号,
分隔。
数据类型
:支持字符串、数字、布尔值、数组、对象、以及null
值作为数据类型。
3. 定义dev
脚本
这个脚本是启动模拟的后端服务器的入口,后期想要从后端获取数据,请先启动该脚本。
将package.json文件中的scripts修改为以下样式:
json
"scripts": {
"dev": "json-server users.json"
},
- scripts:用于定义各种命令脚本。
- "dev": "json-server users.json":这一行代码定义了一个名为 dev 的脚本命令,执行时会启动
json-server
服务器并使用users.json
文件作为数据源。
4. 启动dev脚本
你可以选择在终端输入:
arduino
npm run dev
或者直接点击scripts上的调试进行运行

运行成功后,控制台返回如下:

箭头所指也就是前端的fetch请求地址。
后端完成效果图
后端启动后,前端就可以获取到用户数据并展现到界面中。

AI端 ------ 提供AI服务
在开始AI端代码编写之前,我们要先来了解一下之后要使用的http模块 、url模块 以及dotenv模块。
模块介绍
http模块
http模块提供了创建HTTP服务器和客户端的功能。通过它可以轻松地构建和处理HTTP服务端和客户端的请求和响应。
http模块的一些常见功能和用法:
- 创建HTTP服务器:
-
使用
http.createServer()
方法可以创建一个HTTP服务器。你可以传入一个回调函数,该函数在每次接收到请求时被调用。 -
通过在回调函数中操作
request
和response
对象,可以处理客户端发来的请求并发送响应。 -
request对象 :request对象代表客户端的
HTTP请求
,其中包含了客户端发送的所有信息,如请求头、请求体、请求参数等。通过request对象,可以访问和处理客户端请求的各种属性和数据。request
对象中常用的属性和方法:- request.url:获取请求的URL路径。
- request.metho:获取请求的HTTP方法(GET、POST等)。
- request.headers:获取请求头信息。
- request.params:获取请求中的参数(对应路由参数或查询参数)。
- request.body:获取请求体的内容(在POST请求中常用)。
-
response对象 :response对象代表服务器向客户端发送的
HTTP响应
,通过response对象,可以设置响应的状态码、响应头和响应体,并向客户端发送数据。response
对象中常用的属性和方法:- response.statusCode:设置响应的状态码。
- response.setHeader():设置响应头信息。
- response.write():向响应体中写入数据。
- response.end():结束响应过程并发送响应给客户端。
- 监听端口:
- 使用
server.listen()
方法可以让HTTP服务器监听指定的端口,以便接受客户端的请求。
- HTTP客户端:
- 除了创建服务器,http模块还可以作为HTTP客户端发送HTTP请求到其他服务器。
- 通过
http.request()
方法可以向其他服务器发送GET或POST请求,并处理返回的响应数据。
- 处理请求事件:
- HTTP服务器提供了一系列事件,如
request
事件,当服务器接收到一个请求时就会触发该事件。 - 还有
connection
事件、close
事件等,可以让你在不同的情况下执行相应的逻辑。
通过使用http模块,可以方便地构建各种类型的HTTP服务器、客户端,并进行HTTP请求和响应的处理。
url模块
url模块用于处理URL字符串的解析、格式化以及操作。该模块提供了一系列方法,使开发者能够方便地处理URL相关的操作,如解析URL、构建URL、提取URL的各个部分等。
url模块常用方法和功能:
- 解析URL字符串:
- 使用
url.parse()
方法可以将URL字符串解析为一个URL对象,包含了URL的各个组成部分,如协议、主机、路径、查询参数等。
- 构建URL字符串:
- 使用
url.format()
方法可以根据传入的URL对象构建一个URL字符串。
- 处理相对路径:
- 使用
url.resolve()
方法可以用于解析相对路径,返回一个完整的URL字符串。
- URL对象操作:
url
模块还提供了其他方法,如url.resolveObject()
用于解析URL对象,url.resolve()
用于处理URL的路径解析。
通过使用url模块,可以轻松地解析、构建和操作URL,这在Web开发和服务器编程中非常有用。通过url模块,你能够处理URL的各个部分,从而更好地控制和管理URL相关的操作,使得处理URL变得更加便捷和高效。
dotenv模块
dotenv模块 用于加载环境变量和从.env
文件中读取配置。在开发Node.js应用程序时,通常需要存储敏感信息或配置参数,如API密钥、数据库连接字符串等。
dotenv模块允许你从一个名为.env
的文件中加载这些配置,使得管理环境变量和配置变得更加简单和安全。
AI端代码编写
代码流程
总体来说,AI端代码以以下流程进行:
- 创建HTTP服务器,并为CORS设置响应头,并且处理跨域问题。
- 处理特定路径的API请求,通过URL解析查询参数。
- 构建请求提示内容,并调用OpenAI的API生成回答。
- 将生成的回答作为JSON响应发送回客户端。
- 启动服务器,监听8888端口。
1. 安装openai和dotenv包
在ai_server的终端中输入:
npm i openai
npm i dotenv
2. 创建main.js文件(主文件)和.env(存放openai key)文件

在 .env文件 中存入openai Key,格式为:
OPENAI_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxx
放入你自己
的openai Key
可以通过chatanywhere/GPT_API_free: Free ChatGPT API Key,免费ChatGPT API,支持GPT4 API(免费),ChatGPT国内可用免费转发API,直连无需代理。可以搭配ChatBox等软件/插件使用,极大降低接口使用成本。国内即可无限制畅快聊天。 (github.com),点击箭头所指位置获取免费openai Key.

3. 引入相关包
在main.js中引入相关包
js
const http = require('http');
const url = require('url');
const Openai = require('openai');
require('dotenv').config();
http
模块用于在 Node.js 中创建 HTTP 服务器。url
模块用于 URL 的解析和格式化,获取前端传入的问题和用户数据。openai
: openai库。require('dotenv').config()
:dotenv
模块用于将环境变量从.env
文件中openai Key加载到process.env
中。
4. 构建HTTP服务器
使用http.createServer
方法创建一个HTTP服务器:
js
const server = http.createServer(async function (req, res) {
...
})
req -- request, HTTP请求对象
res -- response, HTTP响应对象
5. 设置CORS头
因为该项目前端(5500)、后端(3000)、AI端(8888)的端口号不同,所以我们需要设置必要的CORS(跨源资源共享)头,以便允许不同来源的请求:
js
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Origin', '*');
:设置允许访问的来源,使用通配符 * 表示允许所有来源访问。res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
:指定在请求中允许的方法, GET、POST 和 OPTIONS。res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
:指定在请求中允许的头部信息, Content-Type 和 Authorization。
6. 处理请求并解析URL及其查询参数
js
if (req.url.indexOf('/users') !== -1) {
const parsedUrl = url.parse(req.url, true);
const { question, users } = parsedUrl.query;
}
if (req.url.indexOf('/users') !== -1)
:检查请求的URL中是否包含'/users'
。如果请求的URL中包含'/users'
,则条件成立,表示客户端正在请求与用户相关的信息。const parsedUrl = url.parse(req.url, true);
:使用url.parse()
方法将请求的URL字符串解析为一个URL对象。这个方法可以将URL分解为各个部分,如协议、主机、路径、查询参数等。const { question, users } = parsedUrl.query;
:通过解构赋值 ,从parsedUrl.query
对象中提取出question
和users
属性的值。这些值是前端通过URL查询字符串传递到服务器端的数据,例如'/users?question=example&users=xxx'
中的查询参数。
7. 实例化openai
实例化openai,同时,设置了一个包含 OpenAI API 密钥的授权标头以及proxy 代理
js
const client = new Openai({
// 使用权限
apiKey: process.env.OPENAI_API_KEY,
// proxy 代理
baseURL: 'https://api.chatanywhere.tech/v1'
});
8. 构建prompt
根据用户数据和问题构建提示信息:
js
const prompt = `
${users}
请根据以上用户的json数据,回答${question}这个问题。
如果回答不了,就返回不清楚,不要凭空捏造。
`
构建prompt的过程就是设计一段文本,其中包含了问题、说明、情境或要求等信息,以引导模型生成期望的文本回复。通过精心构建prompt,可以控制模型输出的内容,使其更贴近需求。
9. 调用OpenAI API
使用OpenAI的API调用gpt-3.5-turbo模型生成回答:
js
const response = await client.chat.completions.create({
// model 模型 gpt-3.5-turbo
model: 'gpt-3.5-turbo',
messages: [{ role: "user", content: prompt }],
temperature: 0, // 控制输出的随机性,0表示更确定的输出
});
// 提取响应结果
const result = response.choices[0].message.content || '';
-
const response = await client.chat.completions.create({...})
:这行代码使用OpenAI API的create
方法异步生成回复。client.chat.completions
是创建对话完成请求的接口。 -
模型选择和设置:指定使用的模型为
gpt-3.5-turbo
。 -
messages: [{ role: "user", content: prompt }]
,使用角色 user 用户向openai提问,content 为上面构建的prompt,包括提问和用户数据。 -
temperature: 0
,temperature参数控制生成的随机性。值越低(接近0),输出越确定和一致;值越高(接近1),输出越随机。 -
const result = response.choices[0].message.content || ''
从响应对象中提取生成的文本内容。response.choices[0]
openai会返回多个回答,选择第一个。response.choices[0].message.content
。使用|| ''
来防止content
为null或undefined的情况。
10. 发送响应
创建包含结果的JSON对象并发送给前端:
js
let info = {
message: result
} ;
// 设置HTTP响应的状态码为200,表示成功。
res.statusCode = 200;
// 设置响应头部的Content-Type为text/json,表明响应内容是JSON格式的数据。
res.setHeader('Content-Type', 'text/json');
// `info`对象转换为JSON字符串,并通过res.end返回
res.end(JSON.stringify(info));
11. 启动服务器
服务器开始监听8888端口(可以自定义端口号),前端请求时也使用该端口号进行访问.
js
server.listen(8888, () => { console.log('server is running'); });
项目运行
- 运行后端
在backend终端输入 npm run dev
运行
- 运行AI端
在backend终端输入 node node .\main.js
运行
- 运行前端

输入问题点击提交就会显示openai的回答。
总结
虽然这只是个小demo,希望这个小demo能为你开启AIGC全栈之路带来一丝启发和帮助,让我们一起在这个充满技术魅力的领域里探索未知!如果你觉得这篇文章有帮助或有所启发,别忘了给我一个鼓励的赞!
源码仓库地址: fullstack/ai_user · WYX0831/WYX_fullstack_ai - 码云 - 开源中国 (gitee.com)