Browse Source

feat:实现对markdown文本渲染

master^2
dashan 2 years ago
parent
commit
658b1a48d7
  1. 22
      README.md
  2. 10
      package-lock.json
  3. 2
      package.json
  4. 2
      quasar.conf.js
  5. 7
      src/api/chatbot/chatbot.js
  6. 49
      src/components/EssentialLink.vue
  7. 141
      src/layouts/MainLayout.vue
  8. 61
      src/pages/Index.vue
  9. 2
      src/utils/request.js

22
README.md

@ -2,27 +2,27 @@ @@ -2,27 +2,27 @@
chatbot web
## Install the dependencies
## 效果展示
### PC端效果展示
![](https://raw.githubusercontent.com/DaiShuaishuai/pic/main/picgo/pc1.jpg)
![](https://raw.githubusercontent.com/DaiShuaishuai/pic/main/picgo/pc2.jpg)
### 移动端效果展示
![](https://raw.githubusercontent.com/DaiShuaishuai/pic/main/picgo/yd1.jpg)
![](https://raw.githubusercontent.com/DaiShuaishuai/pic/main/picgo/yd2.jpg)
## 下载依赖
```bash
yarn
# or
npm install
```
### Start the app in development mode (hot-code reloading, error reporting, etc.)
### 启动项目
```bash
quasar dev
```
### Lint the files
```bash
yarn lint
# or
npm run lint
```
### Build the app for production
### 打包
```bash
quasar build
```

10
package-lock.json generated

@ -6186,6 +6186,11 @@ @@ -6186,6 +6186,11 @@
"integrity": "sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==",
"dev": true
},
"github-markdown-css": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/github-markdown-css/-/github-markdown-css-5.2.0.tgz",
"integrity": "sha512-hq5RaCInSUZ48bImOZpkppW2/MT44StRgsbsZ8YA4vJFwLKB/Vo3k7R2t+pUGqO+ThG0QDMi96TewV/B3vyItg=="
},
"glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
@ -7825,6 +7830,11 @@ @@ -7825,6 +7830,11 @@
"object-visit": "^1.0.0"
}
},
"marked": {
"version": "4.2.12",
"resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
"integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw=="
},
"matcher": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",

2
package.json

@ -12,6 +12,8 @@ @@ -12,6 +12,8 @@
"dependencies": {
"@quasar/extras": "^1.0.0",
"core-js": "^3.6.5",
"github-markdown-css": "^5.2.0",
"marked": "^4.2.12",
"moment": "^2.29.4",
"quasar": "^1.0.0"
},

2
quasar.conf.js

@ -81,7 +81,7 @@ module.exports = function (/* ctx */) { @@ -81,7 +81,7 @@ module.exports = function (/* ctx */) {
proxy: {
// 接口地址代理
'/': {
target: 'http://localhost:8090', // 接口的域名
target: 'http://localhost:8092', // 接口的域名
secure: false, // 如果是https接口,需要配置这个参数
changeOrigin: true // 如果接口跨域,需要进行这个参数配置
}

7
src/api/chatbot/chatbot.js

@ -1,7 +1,8 @@ @@ -1,7 +1,8 @@
import service from "../../utils/request";
export const sendQuestion= (param)=>{
export const sendQuestion= (params)=>{
return service({//获取新闻列表
url:'/bot?question='+param,
method:'get'
url:'/bot',
method:'get',
params
})
}

49
src/components/EssentialLink.vue

@ -1,49 +0,0 @@ @@ -1,49 +0,0 @@
<template>
<q-item
clickable
tag="a"
target="_blank"
:href="link"
>
<q-item-section
v-if="icon"
avatar
>
<q-icon :name="icon" />
</q-item-section>
<q-item-section>
<q-item-label>{{ title }}</q-item-label>
<q-item-label caption>
{{ caption }}
</q-item-label>
</q-item-section>
</q-item>
</template>
<script>
export default {
name: 'EssentialLink',
props: {
title: {
type: String,
required: true
},
caption: {
type: String,
default: ''
},
link: {
type: String,
default: '#'
},
icon: {
type: String,
default: ''
}
}
}
</script>

141
src/layouts/MainLayout.vue

@ -15,14 +15,37 @@ @@ -15,14 +15,37 @@
<q-toolbar
class="bg-grey-3 text-black no-shadow row justify-center q-pt-md q-pb-sm"
>
<q-select
bg-color="white"
rounded
outlined
v-model="select_model"
:options="options"
option-value="value"
emit-value
map-options
><q-tooltip>机器人型号</q-tooltip>
<template v-slot:option="{ itemProps, itemEvents, opt }">
<q-item
v-bind="itemProps"
v-on="itemEvents"
>
<q-item-section>
<q-item-label >{{opt.label}}
<q-tooltip >{{opt.value}}</q-tooltip>
</q-item-label>
</q-item-section>
</q-item>
</template>
</q-select
>
<q-input
class="WAL__field col-grow q-mr-sm"
style="max-width: 1000px"
bg-color="white"
bottom-slots
v-model="search_text"
label="请输入你的问题"
counter
rounded
outlined
@keyup.enter.native="sendMsg"
@ -36,9 +59,13 @@ @@ -36,9 +59,13 @@
icon="send"
@click="sendMsg"
>
<q-tooltip anchor="top middle" self="bottom middle" :offset="[10, 10]">
发送问题给机器人
</q-tooltip>
<q-tooltip
anchor="top middle"
self="bottom middle"
:offset="[10, 10]"
>
发送问题给机器人
</q-tooltip>
</q-btn>
<q-btn
:disable="disable"
@ -48,9 +75,13 @@ @@ -48,9 +75,13 @@
icon="close"
@click="clearMsgs"
>
<q-tooltip anchor="top middle" self="bottom middle" :offset="[10, 10]">
清空聊天记录
</q-tooltip>
<q-tooltip
anchor="top middle"
self="bottom middle"
:offset="[10, 10]"
>
清空聊天记录
</q-tooltip>
</q-btn>
</template>
</q-input>
@ -62,70 +93,100 @@ @@ -62,70 +93,100 @@
<script>
import { sendQuestion } from "../api/chatbot/chatbot";
import moment from "moment";
import {dta} from "../utils/date_utils";
const bot_message_records="bot_message_records"
import { dta } from "../utils/date_utils";
const bot_message_records = "bot_message_records";
export default {
name: "MainLayout",
data() {
return {
select_model: "TEXT_DEVINCI_003",
options: [
{
value: "TEXT_DEVINCI_003",
label: "聪明"
},
{
value: "TEXT_CURIE_001",
label: "还行"
},
{
value: "TEXT_BABBAGE_001",
label: "有点呆"
},
{
value: "TEXT_ADA_001",
label: "憨批"
}
],
search_text: "",
disable: false,
messages: [
{
name: "bot",
text: ["请告诉我你的问题"],
text: "请告诉我你的问题",
sent: false,
datetime: moment().format(dta)
},
],
}
]
};
},
created(){
let records = localStorage.getItem(bot_message_records)
if(records&&records!="[]"){
this.messages=JSON.parse(records)
localStorage.removeItem(bot_message_records)
created() {
//localStorage
let records = localStorage.getItem(bot_message_records);
if (records && records != "[]") {
this.messages = JSON.parse(records);
localStorage.removeItem(bot_message_records);
}
window.addEventListener("pagehide",()=>{
localStorage.setItem(bot_message_records,JSON.stringify(this.messages))
})
//pagehide localStorage
window.addEventListener("pagehide", () => {
localStorage.setItem(bot_message_records, JSON.stringify(this.messages));
});
},
methods: {
//
//
async sendMsg() {
if (!this.search_text||this.disable) {
if (!this.search_text || this.disable) {
return;
}
this.disable = true;
//msg
let text = this.search_text
this.search_text = ""
this.addMessage("me", true, text,moment().format(dta));
await sendQuestion(text).then((res) => {
//
this.addMessage("bot", false, res.data,moment().format(dta));
//
}).catch(()=>{
this.addMessage("bot", false, "出错了!!!",moment().format(dta));
})
let text = this.search_text;
this.search_text = "";
this.addMessage("me", true, text, moment().format(dta));
await sendQuestion({question:text,model:this.select_model})
.then((res) => {
if(res.code==1){
this.addMessage("bot", false, res.data, moment().format(dta));
}else{
this.$q.notify({
color:"red",
message:"请求服务器错误",
position:"top",
timeout: 3000
})
this.addMessage("bot", false,"出错了!!!", moment().format(dta));
}
})
.catch(() => {
this.addMessage("bot", false, "出错了!!!", moment().format(dta));
});
this.disable = false;
},
addMessage(name, sent, text,datetime) {
addMessage(name, sent, text, datetime) {
this.messages.push({
name: name,
text: [text],
text: text,
sent: sent,
datetime
});
},
clearMsgs(){
this.messages=[];
localStorage.removeItem(bot_message_records)
clearMsgs() {
this.messages = [];
localStorage.removeItem(bot_message_records);
}
},
}
};
</script>
<style lang="css">

61
src/pages/Index.vue

@ -12,15 +12,30 @@ @@ -12,15 +12,30 @@
:key="index"
>
<q-chat-message
style="white-space: pre-wrap"
:text="message.text"
:name="message.name"
:sent="message.sent"
:stamp="fromNow(message.datetime)"
/>
:bg-color="message.sent ? 'green-7' : 'white'"
>
<div
v-if="message.sent"
:style="{ 'max-width': width * 0.8 + 'px' }"
>
{{ message.text }}
</div>
<div
v-else
class="markdown-body"
:style="{ 'max-width': width * 0.8 + 'px' }"
v-html="markdownToHtml(message.text)"
></div>
</q-chat-message>
</div>
<div class="col-xs-11 col-sm-10 col-md-9 col-lg-8 col-xl-7" v-show="disable">
<q-chat-message name="bot">
<div
class="col-xs-11 col-sm-10 col-md-9 col-lg-8 col-xl-7"
v-show="disable"
>
<q-chat-message name="bot" bg-color="white">
<q-spinner-dots size="2rem" />
</q-chat-message>
<q-tooltip
@ -38,22 +53,54 @@ @@ -38,22 +53,54 @@
<script>
import { dta, fromNow } from "../utils/date_utils";
import { marked } from "marked"; //markdown
import "github-markdown-css";
export default {
props: ["messages", "disable"],
watch: {
messages: function (val) {
//
this.$refs.scrollArea.setScrollPosition("vertical", 9999999, 300);
},
width(val) {
// resize使
if (!this.timer) {
// screenWidthdatascreenWidth
this.width = val;
this.timer = true;
const that = this;
setTimeout(function () {
that.timer = false;
}, 10);
}
}
},
data() {
return {};
return { width: document.body.clientWidth };
},
mounted() {
this.$refs.scrollArea.setScrollPosition("vertical", 9999999, 300);
//
window.onresize = () =>
(() => {
window.screenWidth = document.body.clientWidth;
this.width = window.screenWidth;
})();
},
methods: {
markdownToHtml(text) {
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true, //true Git Hubmarkdown.
tables: true, //true gfm true
breaks: false, //false gfm true
pedantic: false, //false markdown.pl
sanitize: false, //
smartLists: true,
smartypants: false //使
});
return marked(text);
},
fromNow(date) {
return fromNow(date, dta);
}

2
src/utils/request.js

@ -27,7 +27,7 @@ service.interceptors.request.use( @@ -27,7 +27,7 @@ service.interceptors.request.use(
// response拦截器
service.interceptors.response.use(
(response) => {
return response
return response.data
},
(error) => {
if (error && error.response) {

Loading…
Cancel
Save