从零到英雄:我的第一次全栈应用开发之旅!

289 阅读8分钟

引言

今天我要和大家分享一个超级酷炫的项目——我的第一次AI全栈应用开发之旅,这个项目涉及从前端到后端再到AI模型的整合,最终实现了一个可以根据用户提问来回答问题的小程序,希望我的分享能给正在探索AI世界的你带来一些灵感和帮助。

14.jpg

1. 准备工作

  • 1.建立文件夹

在项目中创建三个文件夹,分别存放后端、前端和AI大模型的内容。这样做的好处是让项目更加井井有条,避免了代码的混乱,就像整理房间一样,把衣服放在衣柜里,鞋子放在鞋柜里,这样找东西的时候就方便多了。

image.png

  • 2.user.json 文件的使用

backend文件夹下创建一个user.json文件。这个文件的作用是模拟数据库,存储我们要展示的用户数据列表。它就像一个迷你版的数据仓库,存放着我们项目的宝贵信息。

以下是我的user.json文件中的内容:

image.png

2. 接下来 实战开始!

22.jpg

2.1 一点点的后端

  • 1.初始化项目

运行npm init -y,这会生成一个package.json文件,记录项目的初始配置。

  • 2. 安装json-server

使用npm i json-server命令安装json-server,这是一个轻量级的假API服务器,非常适合用于开发阶段。

  • 3.设置脚本

package.json里添加如下脚本:

```json
"scripts": {
  "dev": "json-server --watch user.json --port 3001"
}
```

这个脚本的作用是在本地启动一个监听user.json文件变化的服务,并通过端口3001对外提供服务,合理利用 package.json 中的脚本功能,不仅可以让个人的开发流程更加流畅高效,也能为团队合作带来便利。

  • 4.运行服务

执行npm run dev,如果你的眼前突然出现了一堆API路径的信息,恭喜你,你的后端服务已经成功启动了!

image.png

别急着庆祝,我们还没有结束。点击控制台给出的“Endpoints”链接,你会发现一个新的世界——API的详细信息页面展现在你面前。这里列出了所有可用的API路径,以及它们各自的功能说明。是不是感觉瞬间高大上了起来?

image.png

是不是感觉很酷炫呢?但这只是冰山一角,接下来的内容会让你更加惊喜不断。准备好了吗?我们继续前行!

2.2 前端部分的实现

  • 1.创建文件

frontend文件夹内创建一个index.html文件,这是我们的前端界面。

  • 2.引入Bootstrap框架
<link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">

通过这条语句,我们在HTML文档中引入了Twitter Bootstrap框架的CSS样式文件。Bootstrap是一个强大的前端框架,它提供了大量的预定义样式和组件,使得网页布局变得轻松愉快。

  • 3.使用Bootstrap布局类名
<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>
            <tfoot></tfoot>
        </table>
    </div>
</div>

这里我们使用了Bootstrap提供的类名来创建一个居中且美观的表格。container类让内容居中显示,col-md-6 col-md-offset-3则让表格在中等及以上屏幕尺寸下占据一半宽度,并且水平居中。table table-striped类让表格具有条纹效果,看起来更加清爽。

  • 4.使用 fetch() 函数实现前后端的数据交互

fetch()是一个非常强大的工具,它允许我们轻松地发起网络请求,获取或发送数据。下面是一段示例代码:

<script>
        fetch('http://localhost:3001/users')
            // then 方法,它在请求成功时被调用
            .then(res => res.json())
            //then 方法,它会在 JSON 数据解析完成后被调用
            .then(users => {
                 console.log(users);
            })
</script>

indexhtml运行后就会出现这样的结果了,这标志着前端与后端的成功会师,也是你迈向全栈开发的第一步。

image.png

5. 动态生成表格:让你的数据“活”起来!

<script>
        //获取表格的tbody
        const tableBody = document.querySelector('table tbody');
        fetch('http://localhost:3001/users')
            // then 方法,它在请求成功时被调用
            .then(res => res.json())
            //then 方法,它会在 JSON 数据解析完成后被调用
            .then(users => {
                usersData = users;
                //遍历数组
                for (let user of users) {
                    console.log(user);
                    // 创建一个新的 HTML < tr > 元素
                    const tr = document.createElement('tr');
                    // 将新创建的行添加到表格的 tbody 中
                    tableBody.appendChild(tr);

                    // for in json 对象遍历
                    for (let key in user) {
                        //  创建一个新的 HTML < td > 元素
                        const td = document.createElement('td');
                        td.innerText = user[key];
                        tr.appendChild(td);
                        console.log(key, user[key]);
                    }

                }
            })
</script>

这段代码进一步完善了之前的逻辑,不仅获取数据,还动态生成表格行和单元格,这样一来,我们的用户数据就可以优雅地展示在界面上了,感觉像是在做一场魔术表演,让数据瞬间出现在屏幕上!

下面是运行结果的截图: image.png

这样,我们就完全实现了前后端的结合,让数据从后端数据库中“活”了起来,呈现在用户的面前。

  • 6. 理解前后端交互

为了更好地理解前后端交互的过程,下面是一些图片,希望可以帮助你加强对HTTP的理解:

image.png

image.png

通过HTTP协议,前后端之间建立了一个高效、可靠的沟通渠道。每一次请求与响应的交互,都是为了让用户体验更加顺畅、页面加载更快、数据传递更准确,了解HTTP协议不仅有助于我们构建更好的Web应用,还能让我们在遇到问题时,快速定位原因并找到解决方案。

2.3 AI大模型的建立

在frontend中的配置:

  • 1.使用框架内的布局类名
<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>
                <tfoot></tfoot>
            </table>
            <div class="row">
                <form name="aiForm" action="http://www.baidu.com">
                    <div class="from-group">
                        <label for="questionInput">提问</label>
                        <input type="text" id="questionInput" class="form-control" name="question" placeholder="请输入问题"
                            required>
                    </div>
                    <button type="submit" class="btn btn-default" name="btn">查询</button>
                    <p id="message"></p>
                </form>
            </div>
        </div>

这里我们使用了Bootstrap提供的类名来创建一个居中且美观的表格,并且加入了一个表单让用户输入问题。

  • 2. 编写表单提交事件

为了使我们的应用能够与AI模型进行交互并完成问答功能,我们需要在前端JavaScript代码中编写表单提交事件。以下是完整的代码示例:

<script>
        const tableBody = document.querySelector('table tbody');
        let usersData;
        fetch('http://localhost:3001/users')
            .then(res => res.json())
            .then(users => {
                usersData = users;
                for (let user of users) {
                    console.log(user);
                    const tr = document.createElement('tr');
                    tableBody.appendChild(tr);
                    for (let key in user) {
 
                        const td = document.createElement('td');
                        td.innerText = user[key];
                        tr.appendChild(td);
                        console.log(key, user[key]);
                    }
                }
            })

        //  表单提交事件
        const oForm = document.forms['aiForm'];
        oForm.addEventListener('submit', (e) => {
            console.log(e);
            e.preventDefault();
            // const question = oFrom.question.value;
            const question = oForm.question.value.trim();
            if (!question) {
                //alert 弹窗
                alert('请输入问题');
                return;
            }
            fetch(`http://localhost:1314/api?question=${question}&data=${JSON.stringify(usersData)}`)
                //  解析响应数据为 JSON 格式   二进制 => json 
                .then(data => data.json())
                .then(data => {
                    console.log(data)
                    document.getElementById('message').innerText = data.result;
                })

        })
    </script>

这段JavaScript代码负责从后端获取用户数据并动态填充表格,同时处理表单提交事件,将用户的提问发送给AI模型进行回答。当用户点击“查询”按钮时,我们会阻止默认行为,检查输入是否为空,然后发送请求到后端API,最后将得到的回答显示在页面上。

在LLM的 main.js 中的配置:

  • 1.基本配置

确保你已经完成了OpenAI和.env文件的配置,如果你还不清楚如何配置,可以参考这篇文章: # OpenAI新篇章:一起探索多模态应用的无限可能!

  • 2.llm中的代码

接下来,我们来看看如何在main.js中配置LLM,让它能够接收前端的请求并调用OpenAI的API来生成回答。

// node 内置的http 模块
const http = require('http');
const OpenAi = require('openai');
const url = require('url');  // node 内置 查询url的模块
const dotenv = require('dotenv');
dotenv.config();

// 实例化
const client = new OpenAi({
    apiKey: process.env.OPENAI_API_KEY,
    baseUrl: process.env.OPENAI_API_BASE_URL
});

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
}
//req 表示请求对象,res 表示响应对象
const server = http.createServer(async (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'); // 允许的请求头

    const parsedUrl = url.parse(req.url, true);
    const queryObj = parsedUrl.query;

    console.log(parsedUrl.query);
    const prompt = `
    ${queryObj.data}
    请根据上面的json数据,回答${queryObj.question}这个问题
    `;

    const result = await getCompletion(prompt);
    let info = {
        result
    }
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/json');
    res.end(JSON.stringify(info))
})

//监听端口 1314
server.listen(1314)

main.js中,首先引入了必要的模块,包括http用于创建HTTP服务器,OpenAi用于调用OpenAI的API,url用于解析URL,dotenv用于加载环境变量。然后,使用环境变量中的API密钥和基础URL实例化了OpenAI客户端。接着,定义了getCompletion函数,用于构建用户提问的消息并调用OpenAI的API获取回复。创建HTTP服务器时,设置了跨域请求头,解析了请求URL并提取查询参数,构建了提示信息,调用了getCompletion函数获取OpenAI的回复,构建了响应对象并设置了响应状态码和内容类型,最后发送了响应。服务器监听端口1314。

如果你觉得这段代码比较复杂,相关内容可以用AI自己学习一下,例如HTTP请求和响应、Node.js基础、OpenAI API的使用和跨域请求的概念

注意:在使用时一定要使用node main.js保证llm中的main.js处于启动的状态

  • 3.最后就可以实现问答

image.png

可以通过http查看结果是否成功: image.png

也可以在集成终端中看到你提出的问题和页面中存在的数据: image.png

通过这次实践,我发现AI技术真的很强大,而且结合全栈开发可以让我们的应用变得更加智能和有趣。希望大家也能动手尝试一下,相信你们会有更多惊喜发现!

15.jpg

结语

这就是我的第一个全栈AI应用开发经历啦!从后端的数据提取到前端的展示,再到AI驱动的问答系统,整个过程既充满挑战又非常有趣,希望这篇文章能帮助到大家!