个人开发实现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是以太网通讯
...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...

AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...

基于开源AI智能名片链动2 + 1模式S2B2C商城小程序的沉浸式体验营销研究
摘要:在消费市场竞争日益激烈的当下,传统体验营销方式存在诸多局限。本文聚焦开源AI智能名片链动2 1模式S2B2C商城小程序,探讨其在沉浸式体验营销中的应用。通过对比传统品鉴、工厂参观等初级体验方式,分析沉浸式体验的优势与价值…...

对象回调初步研究
_OBJECT_TYPE结构分析 在介绍什么是对象回调前,首先要熟悉下结构 以我们上篇线程回调介绍过的导出的PsProcessType 结构为例,用_OBJECT_TYPE这个结构来解析它,0x80处就是今天要介绍的回调链表,但是先不着急,先把目光…...
文件上传漏洞防御全攻略
要全面防范文件上传漏洞,需构建多层防御体系,结合技术验证、存储隔离与权限控制: 🔒 一、基础防护层 前端校验(仅辅助) 通过JavaScript限制文件后缀名(白名单)和大小,提…...