赞
踩
目录
默认展示
一般对话展示:
代码对话展示:
本项目是一个基于Web的智能对话服务平台,通过后端与第三方AI公司的API接口对接,为前端用户提供了一个简洁、直观的聊天界面。该项目的核心价值在于其便捷性与普适性,让用户能够轻松接入高质量的AI对话服务,无论是寻求信息咨询、娱乐互动,还是情感陪伴,都能获得即时响应与个性化体验。
技术模块:
1.前端:采用Vue框架+elementUi框架+HTML本地存储信息
2.后端:采用SpringBoot框架进行数据响应
前置准备工作:创建一个新的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 = false
-
- Vue.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) => {
- // 设置身份为AI
- this.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)
创建一个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:这里填写自己申请的APIKEY
- MessageManager 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 {
- @Autowired
- AICHAT 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部署到服务器上
.......
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。