在阅读本文章之前,提醒各位读者,阅读文章需要一点js和node.js基础,没有的化也没有关系,只需要花一点点时间了解一下即可。
准备工作
整体要求
首先,我们需要三个文件夹,分别是frontend(前端),backend(后端),llm(大模型)
在frontend中准备index.html文件
在backend中安装json-server依赖,以及一个user.json文件
在llm中安装openai依赖和一个main.js文件
在安装依赖之前,记得初始化仓库
npm init -y
npm i json-server 安装json-server依赖库
npm i openai 安装openai依赖,用来调用openai大模型
如果没有openai key的读者,可以在302.AI这个国内ai转发平台进行注册,可以免费拿额度
后端部分
{
"user":[
{
"id":1,
"name":"zh",
"hometown":"cs"
},
{
"id":2,
"name":"zh",
"hometown":"hn"
},
{
"id":3,
"name":"zh",
"hometown":"hn"
}
]
}
这是user.json文件内的内容
在backend文件夹中的package.json中把scripts{}里的内容改为
"dev": "json-server --watch user.json --port 3000" 如果3000已经被占用,请改为其他端口
npm run dev 使用该命令使得后端node.js运行起来
这样我们可以在浏览器内输入localhost:3000向后端发送请求,然后在前端获取数据
前端部分
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Users Rag chatbot</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">
<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" action="www.baidu.com">
<div class="from-gropu">
<label for="questionInput">提问</label>
<input
type="text"
id="questionInput"
class="form-control"
name="question"
placeholder="请输入问题"
>
</div>
<button type="submit" class="btn btn-default" name="btn">提交</button>
</form>
</div>
<div class="row" id="message"></div>
</div>
</div>
<script>
// js 主动向后端发送数据请求
// 前端向后端拉取数组
const tableBody = document.querySelector('table tbody')
const oForm = document.forms['aiForm'];
let usersData ;
fetch('http://localhost:3000/user')
// 数据到达前端 二进制 -> json
.then(res => res.json())
.then(users => {
usersData = users;
// console.log(data);
// for in json 对象遍历
for (let user of users){
// console.log(user)
const tr = document.createElement('tr')
for (let key in user){
console.log(key, user[key])
const td = document.createElement('td')
td.innerText = user[key]
tr.appendChild(td)
}
tableBody.appendChild(tr)
}
})
oForm.addEventListener('submit',e=>{
// 事件对象
// console.log(e);
e.preventDefault() // 阻止表单的默认行为
// fetch 在页面不刷新的时候 向ai server 发出请求
// const question = oForm.question.value
// 发送数据到后端
// web 2.0 动态页面开发 js fetch 可以主动拉取数据
const question = oForm.question.value.trim()
if (!question){
alert('请输入问题');
return;
}
console.log(question)
fetch(`http://localhost:1314/api?question=${question}&data=${JSON.stringify(usersData)}`)
.then(data => data.json())
.then(data =>{
console.log(data)
document.getElementById('message').innerText =
data.result
})
})
</script>
</body>
</html>
这是html文件部分,需要的读者可以自取,接下来,我将为你逐一介绍各个部分
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
首先是该文件的引入,它在本文中提供了以下四个类
container row col-md-6 col-md-offset-3
在bootstrap中,默认把每行分为12列,在container中 每row 就会占据col-md-6,也就是6列,并且会偏移col-md-offset-3,也就是向右移动3格,形成居中格局
接下来是js的重点部分讲解:
核心是fetch
在前端,我们使用fetch向后端发起请求来获取数据,也就是以下
fetch('http://localhost:3000/user')
这里就是向http://localhost:3000/user 发起请求,并得到user.json中的数据,接着处理数据
let usersData ;
fetch('http://localhost:3000/user')
// 数据到达前端 二进制 -> json
.then(res => res.json())
.then(users => {}) //在{}内对数据进行处理
这样我们完成了前端向后端发送请求后获取数据的整个过程了
接着我们往table中添加内容
{for (let user of users){
// console.log(user)
const tr = document.createElement('tr')
for (let key in user){
console.log(key, user[key])
const td = document.createElement('td')
td.innerText = user[key]
tr.appendChild(td)
}
tableBody.appendChild(tr)}
其次是form表单
const oForm = document.forms['aiForm'];
oForm.addEventListener('submit',e=>{
// 事件对象
// console.log(e);
e.preventDefault() // 阻止表单的默认行为
// fetch 在页面不刷新的时候 向ai server 发出请求
// const question = oForm.question.value
// 发送数据到后端
// web 2.0 动态页面开发 js fetch 可以主动拉取数据
const question = oForm.question.value.trim()
if (!question){
alert('请输入问题');
return;
}
console.log(question)
fetch(`http://localhost:1314/api?question=${question}&data=${JSON.stringify(usersData)}`)
.then(data => data.json())
.then(data =>{
console.log(data)
document.getElementById('message').innerText =
data.result
})
})
const oForm = document.forms['aiForm']; 我们通过.forms方法拿到整个form表,并为其增加了监听事件 ,以便发出请求和添加数据
在form中input中输入问题和把从后端请求来的user.json数据连接到对应的网址后面,并向网址发送请求,得到返回的数据,然后展现在页面上,也就是以下部分
document.getElementById('message').innerText =
data.result
LLM部分
首先展示main.js
// node 内置的http 模块
const http = require('http')
const OpenAi = require('openai')
const url = require('url');// node 内置的
const client = new OpenAi({
apiKey : your_key,
baseURL : 'https://api.302.ai/v1'
});
const getCompletion = async (prompt, model="gpt-3.5-turbo") => {
// 用户提的问题
const messages = [{
role: 'user',
content: prompt
}];
// AIGC chat 接口
const response = await client.chat.completions.create({
model: model,
messages: messages,
// LLM 生成内容的随机性
temperature: 0.1
})
return response.choices[0].message.content
}
const server = http.createServer(async (req , res) =>{
res.setHeader('Access-Control-Allow-Origin','*');//允许所有来源访问,也可以指定具体的域名,如'http://esample.com'
res.setHeader('Access-Control-Allow-Methods','GET,POST,OPTIONS');//允许的请求方法
res.setHeader('Access-Control-Allow-Headers','Content-Type,Authorization');//允许的请求头
const parseUrl = url.parse(req.url , true)
const queryObj = parseUrl.query
const promot = `
${queryObj.data}
请根据上面的JSON数据,回答${queryObj.question} 这个问题
`
const result = await getCompletion(promot)
let info = {
result
}
res.statusCode = 200
res.setHeader('Content-Type', 'text/json');
res.end(JSON.stringify(info))
})
server.listen(1314)
在文件的开头,我们首先引入对应的模块:
包括用于创建HTTP服务器的http模块、处理URL的url模块,以及一个名为openai的第三方模块
http模块,它提供了创建HTTP服务器和客户端的功能。使用这个模块,你可以建立一个服务器来监听HTTP请求,并发送响应。
openai的第三方模块。通常,这个模块是用来与OpenAI的服务(如GPT-3等API)进行交互的。
Node.js内置的url模块,该模块提供了一些实用工具,用于解析URL或者构造URL字符串。
其次是一个client常量和getCompletion方法,这里是固定模板,需要的读者可以记下
server常量
const server 接受了从index.html中form表单提交过来的数据,我们通过解析链接,得到question和question对应的数据,然后生成prompt转发给AI大模型,交给AI大模型进行分析,得出结论后,以json串的格式返回给前端
最后需要设置server监听1314端口