我一路走来,从后端到前端,从前端到AI,我走向了人生中的第一个AI全栈项目的开发!
前言
很多年前,我就觉得AI是个很神奇的东西,一直感觉非常神圣高大上,直到我学了计算机,能运用一些它的基础理论知识开发一些小小项目的时候,成就感非常强烈,解开她隐于薄雾中的面纱后,才发现AI也是我这普通人可以接触甚至小小运用的,玩起小时候那些感觉非常神奇的玩具也少了些欢喜和惊讶,有点儿
欲买桂花同载酒,终不似,少年游
的感觉啦!
在当今科技日新月异的时代,AI全栈技术以其独有的魅力,重塑着每一个行业的核心竞争力。作为一名致力于探索智能科技边界的旅者,掌握AI全栈技术已成为解锁未来创新的关键密钥。本文将深入浅出地引领读者步入AI全栈的世界,旨在助力每一位AI追梦者构筑坚实的技术根基,赋能未来,驱动智慧革新。
今天就让我们一起来完成第一个真正意义上的AI全栈开发!
1. 建立全栈AI项目目录
我们通过前端,后端,AI项目三者分离的方式来建立目录,能够使我们的工作更加高效。
2. 建立列表和提交表单
<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>
<div class="row col-md-6 col-md-offset-3">
<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>
<div class="row" id="message"></div>
</div>
大家可以看见我们的html部分的大致形式,大致就是建立了一张表里面包括我们的若干个同学信息,但是我们目前是得不到的,我们稍后会通过获取后端数据来达到实现效果。然后后面设置了一个简单的表单。这里我们引入了一个css库
更方便我们的操作。
3.初始化后端文件
我们首先对后端文件夹进行初始化,输入npm init -y 指令,后端项目文件就会多一个包。
当看见这个东西的时候,我们就初始化完毕了哦。
4. 引入json-server库
由于我们前端要向后端获取数据,但是我们不可能等到后端做完了再拿数据,因此我们造一个伪接口,进行操作,那样的话我们最终只要替换掉获取地址即可。
首先我们先 npm i json-server 引入这个库,
接下来我们就会多出这两个文件,第一个是这个库的依赖文件,里面有我们需要的json-server ,其他的为项目依赖文件。
5. 运行后端脚本
我们接下来创建一个users.json的文件,里面放入我们的基本同学信息.
然后我们在后端的package.json里增加一个dev,我们使用json-server
来模拟一个后台API,用于开发环境下的数据交互。
然后我们在终端输入npm run dev,这样子我们的接口就造好且跑起来啦!
6. js操作获取数据
<script>
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((item) =>
`<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.hometown}</td>
</tr>`
).join('')
})
当我们运行npm run dev时,会弹出一个地址 localhost:3000/users,这个时候我们点进去就会发现是我们的自定义信息,这个时候我们运用fetch获取这个地址然后通过js的基本操作将它们显示到页面上。所以我们这个时候的页面将会是这样子。
到此我们前后端的交互任务就完成啦!
7.AI部分初始化
我们的AI部分也要通过npm init -y 来初始化为一个后端项目。
8. 引入openai库
npm i openai 后,又会多出这两个东西。分别是库依赖文件,还有自带json文件。
9. 引入dotenv库, 封装ai
为了便于理解我们先将AI部分整段代码放下。然后进行仔细讲解。
// 内置模块
// 搭建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,
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');
if (req.url.indexOf('/users') >= 0) {
const parseUrl = url.parse(req.url, true)
const { question, users } = parseUrl.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))
}
res.end('hello')
})
server.listen(8888, function () {
console.log("服务器启用了");
})
我们引入dotenv库,并且将我们的密钥放入其中。
至此我们AI部分的准备工作也完成啦!
10. 搭建AI与前端桥梁
const http = require('http')我们通过这段代码获取一个http对象,在这里我们要知道这个库node自带,因此不需要我们重新引入。
const server = http.createServer(async function (req, res)
res.end('hello')
server.listen(8888, function () {
console.log("服务器启用了");
})
我们截取这三段代码进行讲解。首先我们要搭建一个服务器连接AI与前端,然后如果访问了这个端口我们就用hello去响应,设置一个监听事件。包括访问端口以及设置成功后的打印值。
我们如果运行了这段文件,会显示这个信息,就是监听的作用。
我们直接访问端口,会弹出hello。
而req.url代表的是我们在访问时localhost:8888之后带的地址。
这个时候的判断就有了意义,我们判断用户是不是从这个端口进来的。
这里建议大家自行调试,这里非常重要!
11. 获取地址
const url = require('url')
const parseUrl = url.parse(req.url, true)
const { question, users } = parseUrl.query
console.log(parseUrl);
console.log(question, users);
我们截取部分代码进行讲解,我们也同样用了一个node自带的库,通过它我们去把地址给变成一个对象。我们输入http://localhost:8888/users?question=123进行访问。 然后打印结果
我们可以发现我们需要的东西就在其中。
12. 解决跨域问题
我们通过这段代码解决跨域问题。
13. AI与前端交互
至此大局已定,我们设置prompt指令,选择合适的模型,打印结果。具体说明和上次的差不多,不再赘述。
我们这样提问。
结果十分准确!
然后我们将结果封装成对象,采用JSON.stringify(info)再次封装。
然后回到我们的前端,我们传入问题,和对象数组(JSON.stringify())这里也要进行封装,之后把AI传回的结果进行打印就可以啦!
最终效果如下
14.完整代码
14.1完整前端代码
因为后端主要是操作,几乎没有什么代码,我们给出前端和AI部分的主代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>友友</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能力驱动的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>
<div class="row col-md-6 col-md-offset-3">
<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>
<div class="row" id="message"></div>
</div>
<script>
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((item) =>
`<tr>
<td>${item.id}</td>
<td>${item.name}</td>
<td>${item.hometown}</td>
</tr>`
).join('')
})
oForm.addEventListener('submit', function (event) {
event.preventDefault()
const question = this["question"].value.trim()
fetch(`http://localhost:8888/users?question=${question}&users=${JSON.stringify(usersData)}`)
.then(data => data.json())
.then(res => {
document.querySelector('#message').innerHTML = res.message
})
})
</script>
</body>
</html>
14.2 完整AI部分代码
// 内置模块
// 搭建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,
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');
if (req.url.indexOf('/users') >= 0) {
const parseUrl = url.parse(req.url, true)
const { question, users } = parseUrl.query
console.log(parseUrl);
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))
}
res.end('hello')
})
server.listen(8888, function () {
console.log("服务器启用了");
})
15.小结
身为AI全栈探险家,我们穿梭在数据密林,用代码剑雕刻算法,让机器学会思考。从前端界面的美学魔术,到后端逻辑的精密布局,我们一手打造智能世界的通行护照。在0与1的奇幻之旅中,我们不仅是技术的编织者,更是创意梦想的实现者,用一行行代码,为未来筑基,让我们从此之后,一起踏上AI全栈开发的道路,越挫越勇吧!
转载自:https://juejin.cn/post/7373489827244441636