个人开发实现AI套壳网站快速搭建(Vue+elementUI+SpringBoot)
目录
一、效果展示
二、项目概述
三、手把手快速搭建实现本项目
3.1 前端实现
3.2 后端方向
五、后续开发计划
一、效果展示
默认展示
一般对话展示:
代码对话展示:
二、项目概述
本项目是一个基于Web的智能对话服务平台,通过后端与第三方AI公司的API接口对接,为前端用户提供了一个简洁、直观的聊天界面。该项目的核心价值在于其便捷性与普适性,让用户能够轻松接入高质量的AI对话服务,无论是寻求信息咨询、娱乐互动,还是情感陪伴,都能获得即时响应与个性化体验。
技术模块:
1.前端:采用Vue框架+elementUi框架+HTML本地存储信息
2.后端:采用SpringBoot框架进行数据响应
三、手把手快速搭建实现本项目
3.1 前端实现
前置准备工作:创建一个新的Vue模板,并导入axios
npm install 'axios'
导入elementUI
npm i element-ui -S
Vue中main.js 进行配置
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';Vue.config.productionTip = falseVue.use(ElementUI);new Vue({router,render: h => h(App)
}).$mount('#app')
本项目为了简单化,将项目整体仅设置为了一个Vue主视图(App.vue)
template:
<template><div id="Chat"><el-container><el-aside width="200px"><!-- 添加导航 --><el-row class="tac" ><el-col :span="12" style="width: 100%;"><h1>个人工具网站</h1><el-menu default-active="2" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"><el-submenu index="1"><template slot="title"><i class="el-icon-location"></i><span>人工智能助手</span></template><el-menu-item-group><el-menu-item index="1-1">通义千问</el-menu-item><el-menu-item index="1-2">文言一心</el-menu-item><el-menu-item index="1-2">GPT</el-menu-item></el-menu-item-group> </el-submenu><el-menu-item index="2"><i class="el-icon-menu"></i><span slot="title">知识星球</span></el-menu-item><el-menu-item index="3" ><i class="el-icon-document"></i><span slot="title">工具集合</span></el-menu-item><el-menu-item index="4"><i class="el-icon-setting"></i><span slot="title">素材集合</span></el-menu-item></el-menu></el-col></el-row></el-aside><el-container><el-header><h3>通义千问-API套壳网站</h3></el-header><el-main><div id="ChatLayOut"><!-- 对话内容列举 --><div v-for="(msg, index) in messages" :key="index" id="ChatBubble"><img :src="getImageUrl(msg.sender)" id="chatImage"><!-- <p id="ChatContent">{{ msg.sender }}: {{ msg.content }}</p> --><div class="chat-content-wrap"><!-- 使用预处理后的消息内容 --><div v-html="preprocessMessageContent(msg.sender+':'+msg.content) "></div></div></div></div></el-main><el-footer><!-- 使用flex布局使元素水平排列 --><div style="display: flex; align-items: center;"><!-- 将输入框放入表单中 --><form @submit.prevent="onFormSubmit" style="margin-left: 30%; width: 500px; margin-right: 10px;"><el-input id="DialogTextCSS" v-model="message" :placeholder="DialogText" :disabled="flag"style="flex-grow: 1; "></el-input></form><!-- 提交按钮 --><el-button type="primary" @click="sendMessage" style="width:90px ;">提交</el-button><!-- 清空按钮 --><el-button type="danger" @click="deleteMessage">清空本地聊天记录</el-button></div><div>COPYRIGHT: CSDN-ALPHAMILK</div><div>version : 测试版</div></el-footer></el-container></el-container></div>
</template>
JavaScript:
<script>
import axios from 'axios';export default {data() {return {message: '',messages: [],Identify: '',senderType: '', // 新增一个变量来标识发送者类型flag:false,DialogText:'请您输入内容',}},mounted() {// 页面加载时从localStorage读取消息const savedMessages = JSON.parse(localStorage.getItem('messages'));if(savedMessages===null){this.messages.push({sender: "AI", content: "欢迎使用通义千问API的套壳网站,请您通过输入内容到下方的文本框并提交即可开启聊天"});}if (savedMessages) {this.messages = savedMessages;}},methods: {scrollToBottom() {this.$nextTick(() => {// 尝试手动触发一次重绘,看是否有助于解决滚动问题const chatLayout = this.$el.querySelector('#ChatLayOut');if (chatLayout) {// 强制浏览器重绘void chatLayout.offsetHeight; setTimeout(() => {console.log('scrollHeight:', chatLayout.scrollHeight);window.scrollTop = chatLayout.scrollHeight;console.log('scrollTop after setting:', chatLayout.scrollTop);}, 100); // 增加延时时间以确保元素尺寸和内容更新完成}});
},sendMessage() {if (this.message.trim() !== '') {// 设置身份为用户this.senderType = '用户';this.messages.push({sender: this.senderType, content: this.message});localStorage.setItem('messages', JSON.stringify(this.messages)); // 保存消息到localStorage//禁用对话框this.flag = true;this.DialogText = '请您耐心等待AI的回答';// //进行滚动操作,滚动到最新消息// this.scrollToBottom(); // 调用接口获取AI生成的内容axios.get('http://localhost:8080/Test/Chat',{params:{message : this.message}}).then((response) => {// 设置身份为AIthis.senderType = 'AI';this.messages.push({sender: this.senderType, content: response.data});localStorage.setItem('messages', JSON.stringify(this.messages));//解除对话框this.flag = false;this.DialogText = '请您输入内容';});this.message = ''; // 清空输入框}else{alert("输入不能为空噢!");}},deleteMessage(){localStorage.removeItem("messages");this.messages = [];this.messages.push({sender: "AI", content: "欢迎使用通义千问API的套壳网站,请您通过输入内容到下方的文本框并提交即可开启聊天"});},getImageUrl(sender) {if (sender === 'AI') {return 'https://img.alicdn.com/imgextra/i3/O1CN01sffRIx1nb3dXCKdFC_!!6000000005107-2-tps-1024-1024.png';} else {return 'https://bpic.51yuansu.com/pic3/cover/00/94/68/58dcd742dd10d_610.jpg?x-oss-process=image/resize,h_360,m_lfit/sharpen,100';}},onFormSubmit() {this.sendMessage();},preprocessMessageContent(content) {const codeBlockRegex = /```(.*?)```/gs;const sortTextRegex = /\*\*(.*?)\*\*/gs;let tempContent = content.replace(sortTextRegex, `<p class="sort-text">$1</p>`);let processedContent = tempContent.replace(codeBlockRegex, `<pre class="code-block"><code>$1</code></pre>`);let segments = processedContent.split(/```.*?```/gs); // 分割代码块segments = segments.filter(segment => segment.trim());let finalContent = segments.map((segment) => {return `<p class="content-common">${segment}</p>`;}).join('');return finalContent;
}},handleOpen(key, keyPath) {console.log(key, keyPath);},handleClose(key, keyPath) {console.log(key, keyPath);}}</script>
css:
<style>.el-header, .el-footer {background-color: #B3C0D1;color: #333;text-align: center;line-height: 60px;}.el-aside {background-color: #D3DCE6;color: #333;text-align: center;line-height: 200px;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04)}.el-main {background-color: #E9EEF3;color: #333;text-align: center;line-height: 160px;height: 1000px;}body > .el-container {margin-bottom: 40px;}.el-container:nth-child(5) .el-aside,.el-container:nth-child(6) .el-aside {line-height: 260px;}.el-container:nth-child(7) .el-aside {line-height: 320px;}#ChatBubble{position: relative;padding: 10px;border-radius: 10px;margin-bottom: 30px;max-width: 70%;background-color: white;line-height: normal;}
/* 用户和AI的不同样式 */
#ChatBubble.user {background-color: #E0F2F7; /* 用户气泡颜色 */float: left;clear: both;margin-right: 30px;
}#ChatBubble.AI {background-color: #ECEFF1; /* AI气泡颜色 */float: right;clear: both;margin-left: 30px;
}/* 指向箭头,这里仅示例用户气泡右边的箭头 */
#ChatBubble.user::after {content: "";position: absolute;top: 50%;right: -15px;transform: translateY(-50%);border-style: solid;border-width: 10px 15px 10px 0;border-color: transparent #E0F2F7;
}/* 可能需要清除浮动,避免布局问题 */
#dialog-display::after {content: "";display: block;clear: both;
}#chatImage{float: left;margin-top: 17px;margin-right: 10px;height: 30px;width: 30px;background-color:#faeeee;
}#Topic{background-color: #f6f6fe;border-radius: 10px;height: 60px;}#chat{height: 56px;width: 100%;background-color: pink;}
.el-footer{background-color: #f7f8fc;
}
.el-main{background-color: #f7f8fc;
}
#ChatContent { line-height: 1.5; /* 或者根据需要调整 */padding: 0; /* 取消内边距 */ } #ChatLayOut{margin-left: 20%;
}.el-header{background-color: #333;
}
h3{color: #E9EEF3;
}.el-aside{background: white;box-shadow: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04);/* 实现右边border-radi */border-top-right-radius: 30px;
}
/* 明亮风格的代码块,文字及行号全部左对齐 */
.code-block {background-color: #f8f8f8; /* 明亮背景 */color: #333; /* 深色文字 */font-family: 'Courier New', monospace; /* 适合代码的字体 */white-space: pre-wrap; /* 保留空格和换行 */border-radius: 5px; /* 边角圆润 */overflow-x: auto; /* 横向滚动条,如果需要 */line-height: 1.5;padding: 10px;position: relative; /* 为行号预留位置 */
}/* 显示所有行的行号,确保向左对齐 */
.code-block::before {content: counter(line);counter-increment: line;position: absolute; /* 行号绝对定位 */left: 0; /* 行号紧贴左侧 */margin-left: 15px; /* 与代码内容的距离,可根据需要调整 */text-align: left; /* 行号左对齐 */width: 30px; /* 行号宽度 */color: #666; /* 行号颜色,可调整 */display: block; /* 每行前面均显示 */line-height: inherit; /* 继承代码块的行高 */
}/* 确保代码内容也左对齐 */
.code-block code {display: block; /* 确保代码块内代码作为独立块显示 */padding-left: 45px; /* 为代码内容预留行号和额外的间距 */text-align: left; /* 确保代码文本左对齐 */
}.content-common {/* 为普通文本内容定义样式 */margin-bottom: 10px; /* 示例:增加段落间距 */line-height: 1.5; /* 示例:调整行高 */
}.el-col-12 {width: 100%;
}.sort-text {font-weight: bold; /* 设置为粗体 */text-align: left; /* 文本左对齐 */line-height: normal; /* 行高设置为正常,确保与未加样式时的文本行高一致 */
}</style>
最后配置端口为8081(在vue.config.js文件下):
const { defineConfig } = require('@vue/cli-service')
module.exports = {devServer: {port: 8081, // 将端口设置为你想要的端口号},
};
运行:在控制台启动程序
npm run serve
打开浏览器:前端的配置改为(localhost:8081)
3.2 后端方向
创建一个SpringBoot项目
在项目pom.xml文件导入以下依赖:
<!-- https://mvnrepository.com/artifact/com.alibaba/dashscope-sdk-java --><dependency><groupId>com.alibaba</groupId><artifactId>dashscope-sdk-java</artifactId><version>2.8.2</version></dependency><!--okhttp3 依赖--><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>4.9.3</version></dependency>
由于后端功能十分简单,仅需要一个Utils和一个Controller即可
Utils:(注意:这里要填自己申请的APIKey(十分简单,一毛钱就能开通))
@Component
public class AICHAT {public static String callWithMessage(String message)throws NoApiKeyException, ApiException, InputRequiredException {Generation gen = new Generation();Constants.apiKey="xxxxxx";//TODO:这里填写自己申请的APIKEYMessageManager msgManager = new MessageManager(10);Message systemMsg =Message.builder().role(Role.SYSTEM.getValue()).content("You are a helpful assistant.").build();Message userMsg = Message.builder().role(Role.USER.getValue()).content(message).build();//这里填写对话内容msgManager.add(systemMsg);msgManager.add(userMsg);QwenParam param =QwenParam.builder().model(Generation.Models.QWEN_TURBO).messages(msgManager.get()).resultFormat(QwenParam.ResultFormat.MESSAGE).topP(0.8).enableSearch(true).build();GenerationResult result = gen.call(param);String Message = extractContentFromResult(result);System.out.println(Message);return Message;}// 仅获取JSON结果中message字段的信息public static String extractContentFromResult(GenerationResult result) {if (result != null && result.getOutput() != null && !result.getOutput().getChoices().isEmpty()) {Message message = result.getOutput().getChoices().get(0).getMessage();return message.getContent();}return null; // 或者返回一个默认值}}
ChatController:
@RestController
@RequestMapping("/Test")
@CrossOrigin
public class ChatController {@AutowiredAICHAT aichat;@GetMapping("/Chat")public String GetParameter(String message) {try {if (message != null) {String AiResponse = null;try {AiResponse = aichat.callWithMessage(message);} catch (ApiException | NoApiKeyException | InputRequiredException e) {System.out.println(e.getMessage());}return AiResponse;}} catch (Exception e) {return "出错了>_<"+e.getMessage();}return null;}}
启动(Application):
前后端联调测试:
五、后续开发计划
后续改进计划:
后续将会修改许多的bug,并加入许多新的功能,一步步将其打造成一个能够实现商业化的,满足普通人可以使用的通用网站。关注后即可获取最新的动态
1.加入多个可用个人免费的API,让切换AI模型能够方便快捷
2.加入用户管理,满足以后实现商业化的一步
3.加入动画效果,让聊天更生动
4.加入语音输入功能,与语音输出功能。实现外语教师功能
5.将项目通过nginx部署到服务器上
.......
相关文章:

个人开发实现AI套壳网站快速搭建(Vue+elementUI+SpringBoot)
目录 一、效果展示 二、项目概述 三、手把手快速搭建实现本项目 3.1 前端实现 3.2 后端方向 五、后续开发计划 一、效果展示 默认展示 一般对话展示: 代码对话展示: 二、项目概述 本项目是一个基于Web的智能对话服务平台,通过后端与第…...

Cesium与Three相机同步(3)
Cesium与Three融合的案例demo <!DOCTYPE html> <html lang"en" class"dark"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content&q…...
PMP考试报名项目经历怎么填写?指引请收好
PMP,这一全球公认的项目管理金牌认证,不仅是对项目管理能力的认可,更是职业生涯中的一大助力。然而,在报名PMP时,很多小伙伴都面临一个共同的难题:如何书写项目经验?今天,就让我们一…...
Git的基本使用方法
Git的基本使用方法 大家好,我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编,也是冬天不穿秋裤,天冷也要风度的程序猿!今天我们将深入探讨Git的基本使用方法,Git作为目前最流行的版本控制系统之一&…...
深入剖析 @Autowired 和 @Resource 在 Spring 中的区别
在 Spring 框架中,Autowired 和 Resource 是两个常用的注解,用于实现依赖注入。尽管它们都能达到将依赖对象注入到目标 bean 的目的,但在细节上存在一些显著的差异。本文将深入探讨这两个注解的区别,并结合 Spring 源码进行分析&a…...

Golang-slice理解
slice golang-slice语雀笔记整理 slicego为何设计slice?引用传递实现扩容机制 go为何设计slice? 切片对标其他语言的动态数组,底层通过数组实现,可以说是对数组的抽象,底层的内存是连续分配的所以效率高,可…...

【Linux系统】文件描述符fd
1.回顾一下文件 我们之前对文件的理解是在语言层上,而语言层去理解文件是不可能的!!! 下面是一份c语言文件操作代码!!! #include<stdio.h> int main() {FILE* fd fopen("lo…...
【嵌入式——FreeRTOS】启动任务调度器
【嵌入式——FreeRTOS】启动任务调度器 开启任务调度器vTaskStartScheduler()xPortStartScheduler()prvStartFirstTask()启动第一个任务 开启任务调度器 用于启动任务调度器,任务调度器启动后,FreeRTOS便会开始进行任务调度。 //启动任务,开…...
EFCore_客户端评估与服务端评估
定义 客户端评估: 先将表的所有数据读取至内存,再在内存中对数据进行筛选,数据的筛选工作在客户端服务端评估: 先将代码翻译为SQL语句,再执行SQL语句对数据进行筛选,数据的筛选工作在服务端(默认方式) 如何…...

Java面试题--JVM大厂篇之深入了解G1 GC:高并发、响应时间敏感应用的最佳选择
引言: 在现代Java应用的性能优化中,垃圾回收器(GC)的选择至关重要。对于高并发、响应时间敏感的应用而言,G1 GC(Garbage-First Garbage Collector)无疑是一个强大的工具。本文将深入探讨G1 GC适…...

SAP配置发布WebService接口并调用(超级详细)
文章目录 前言一、案例介绍/笔者需求二、WebService是什么? a.传输协议 b.数据协议 c.WSDL d.UDDI 三、WebService 和 WebApi 的区别以及优缺点 a.主要区别 b.优缺点 四、SAP如何发布一个webser…...
中英双语介绍美国首都:华盛顿哥伦比亚特区(Washington, D.C.)
中文版 华盛顿哥伦比亚特区(Washington, D.C.),简称华盛顿或D.C.,是美国的首都和联邦直辖区。以下是对华盛顿哥伦比亚特区各方面的详细介绍: 人口 截至2020年,美国人口普查数据显示,华盛顿哥…...
java:aocache的单实例缓存(一)
上一篇博客《java:aocache:基于aspectJ实现的方法缓存工具》介绍了aocache的基本使用, 介绍AoCacheable注解时说过,AoCacheable可以定义在构造方法上,定义在构造方法,该构建方法就成了单实例模式。 也就是说,只要构建…...

pcap包常见拆分方法
文章目录 Wireshark 拆分流量包SplitCap使用简介魔数报错示例结果 在进行流量分析时,经常需要分析pcap流量包。但是体积过大的流量包不容易直接分析,经常需要按照一定的规则把它拆分成小的数据包。 这里统一选择cic数据集里的Thursday-WorkingHours.pcap…...

C++中的类型转换操作符:static_cast reinterpret_cast const_cast dynamic_cast
目录 C语言中的类型转换 C中的类型转换 C中的类型转换操作符 static_cast reinterpret_cast const_cast volatile关键字 赋值兼容 dynamic_cast C语言中的类型转换 基本概念:赋值运算符左右两侧类型不同,或形参与实参类型不匹配…...
MySQL-SQL优化Explain命令以及参数详解
前言 在MySQL优化的众多手段中,EXPLAIN命令扮演着至关重要的角色。它是数据库管理员和开发者手中的利器,用于分析SQL查询的执行计划。通过执行EXPLAIN,MySQL会提供一份详细的查询执行计划报告,这份报告揭示了查询将如何执行&…...

别只会重启了!进来告诉你AP无法上线怎么办
号主:老杨丨11年资深网络工程师,更多网工提升干货,请关注公众号:网络工程师俱乐部 你们好,我的网工朋友。 作为网工,咱们都知道无线网络的重要性,尤其是对于企业网络来说,无线接入点…...

数据恢复篇:如何在 Android 手机上恢复未保存/删除的 Word 文档
在 Android 手机上访问 Word 文档通常很简单,但是当这些重要文件被删除或未保存时会发生什么?这种情况虽然令人痛苦,但并非毫无希望。到 2024 年,有几种强大的方法来处理此类数据丢失。本指南重点介绍如何在Android手机上恢复已删…...

Python | Leetcode Python题解之第208题实现Trie(前缀树)
题目: 题解: class Trie:def __init__(self):self.children [None] * 26self.isEnd Falsedef searchPrefix(self, prefix: str) -> "Trie":node selffor ch in prefix:ch ord(ch) - ord("a")if not node.children[ch]:retur…...

Ethernet是以太网通讯
...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...