个人开发实现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是以太网通讯
...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
深入浅出Diffusion模型:从原理到实践的全方位教程
I. 引言:生成式AI的黎明 – Diffusion模型是什么? 近年来,生成式人工智能(Generative AI)领域取得了爆炸性的进展,模型能够根据简单的文本提示创作出逼真的图像、连贯的文本,乃至更多令人惊叹的…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...