ai助理
parent
a747231358
commit
687fa6cffb
|
|
@ -11,6 +11,14 @@ body {
|
|||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.van-button--primary{
|
||||
background-color: #3662FE !important;
|
||||
}
|
||||
.van-floating-bubble{
|
||||
background: transparent !important;
|
||||
width: 140px !important;
|
||||
height: 140px !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg t="1692247991456" class="icon" viewBox="0 0 1024 1024" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" p-id="7389" xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="200" height="200">
|
||||
<path
|
||||
d="M513 19.7c-272.9 0-495 222.1-495 495 0 86 22.4 170.6 64.7 244.9 8.6 15.1-4.4 43.8-18.3 74.2-17.9 39.5-25.1 59.9-17.7 68.5 2.2 2.9 7.3 4.4 15.5 4.4 14.5 0 35.7-4.7 56.3-9.2 21.6-4.8 42.1-9.3 56.9-9.3 8.7 0 14.5 1.5 18.3 4.8 89.1 75.2 202.5 116.7 319.3 116.7 272.9 0 495-222 495-495 0-272.9-222-495-495-495z m0 922.7c-100.9 0-198.9-35.8-275.8-100.8-16.1-13.6-37-20.6-61.8-20.6-10.8 0-22.1 1.3-33.7 3.2 11.9-32.1 17.8-65.8-0.5-97.9-36.6-64.1-55.9-137.3-55.9-211.6C85.3 278.9 277.2 87 513 87c235.9 0 427.8 191.9 427.8 427.7 0 235.8-191.9 427.7-427.8 427.7z"
|
||||
fill="currentColor" p-id="7390"></path>
|
||||
<path
|
||||
d="M445.2 323.5c18.5 0 33.6 15.1 33.6 33.6v315.2c0 18.5-15.1 33.6-33.6 33.6s-33.6-15.1-33.6-33.6V357.1c-0.1-18.5 15.1-33.6 33.6-33.6zM580.9 373.6c18.5 0 33.6 15.1 33.6 33.6v215c0 18.5-15.1 33.6-33.6 33.6s-33.6-15.1-33.6-33.6v-215c0-18.5 15.2-33.6 33.6-33.6zM716.7 449.3c18.5 0 33.6 15.1 33.6 33.6v63.5c0 18.5-15.1 33.6-33.6 33.6s-33.6-15.1-33.6-33.6v-63.5c0-18.4 15.1-33.6 33.6-33.6zM309.4 449.3c18.5 0 33.6 15.1 33.6 33.6v63.5c0 18.5-15.1 33.6-33.6 33.6s-33.6-15.1-33.6-33.6v-63.5c-0.1-18.4 15.1-33.6 33.6-33.6z"
|
||||
fill="currentColor" p-id="7391"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -0,0 +1,79 @@
|
|||
<template>
|
||||
<div>
|
||||
<van-floating-bubble
|
||||
v-model:offset="offsetc"
|
||||
axis="xy"
|
||||
icon="chat"
|
||||
magnetic="x"
|
||||
:gap="0"
|
||||
@click="onClick"
|
||||
@offset-change="onOffsetChange"
|
||||
>
|
||||
<div ref="floatref" class="w-full h-full flex items-center justify-center">
|
||||
<div class="ai-float-btn">
|
||||
<SvgIcon class="text-white" name="生活助手"></SvgIcon>
|
||||
</div>
|
||||
</div>
|
||||
</van-floating-bubble>
|
||||
|
||||
<van-popup teleport="body" v-model:show="show">
|
||||
<div class="relative">
|
||||
<div class="absolute right-20px top-30px">
|
||||
<SvgIcon @click="show=false" class="text-white" name="close"></SvgIcon>
|
||||
</div>
|
||||
<AiAssistant :content="content"></AiAssistant>
|
||||
</div>
|
||||
</van-popup>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRect } from '@vant/use'
|
||||
import AiAssistant from './ai-assistant.vue'
|
||||
const floatref = ref(null)
|
||||
const props = defineProps({
|
||||
offset: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
content: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
})
|
||||
const offsetc = ref({ x: 0, y: 0 })
|
||||
const show = ref(false)
|
||||
const onOffsetChange = (offset) => {
|
||||
console.log(offset)
|
||||
}
|
||||
const setOffset = () => {
|
||||
const { offset } = props
|
||||
const { width,height } = useRect(floatref.value)
|
||||
offsetc.value = {
|
||||
x: offset?.x ?? window.innerWidth - width,
|
||||
y: offset?.y ?? height,
|
||||
}
|
||||
}
|
||||
const onClick = () => {
|
||||
show.value = true
|
||||
}
|
||||
onMounted(() => {
|
||||
setOffset()
|
||||
})
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.ai-float {
|
||||
background: #3662fe;
|
||||
box-shadow: 0px 12px 26px 0px rgba(32, 69, 201, 0.86);
|
||||
}
|
||||
.ai-float-btn {
|
||||
width: 94px;
|
||||
height: 94px;
|
||||
background: #3662fe;
|
||||
box-shadow: 0px 12px 26px 0px rgba(32, 69, 201, 0.86);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,28 +1,16 @@
|
|||
<template>
|
||||
<div class="fixed w-86 h-full z-999" :style="styleObj">
|
||||
<!-- <vue-draggable-resizable
|
||||
:x="0"
|
||||
:y="0"
|
||||
:z="999"
|
||||
:resizable="true"
|
||||
w="auto"
|
||||
h="auto"
|
||||
> -->
|
||||
<div class="w-86 bg-[#161718] p-3" ref="floatWindow">
|
||||
<div class="w-full z-999" :style="styleObj">
|
||||
<div class="w-full bg-[#161718] p-28px" ref="floatWindow">
|
||||
<div class="flex text-white items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<Avatar />
|
||||
<span class="font-bold text-lg ml-4">海兔AI智慧助理</span>
|
||||
<span class="font-bold text-27px ml-26px">海兔AI智慧助理</span>
|
||||
</div>
|
||||
<SvgIcon
|
||||
class="text-white text-xl cursor-pointer"
|
||||
name="close"
|
||||
></SvgIcon>
|
||||
</div>
|
||||
<div class="border-2px border-[#A6A8AF] p-4 mt-4">
|
||||
<div class="grid grid-cols-3 gap-x-2.5 options">
|
||||
<div class="border-1px border-[#A6A8AF] p-32px mt-30px">
|
||||
<div class="grid grid-cols-3 gap-x-21px options">
|
||||
<div
|
||||
class="border-2px border-[#414548] h-6.5 text-center text-sm leading-6.5 text-white cursor-pointer"
|
||||
class="border-1px border-[#414548] h-52px text-center text-27px leading-52px text-white cursor-pointer"
|
||||
:class="{ active: optionIndex === index }"
|
||||
@click="changeOption(index)"
|
||||
v-for="(item, index) in options"
|
||||
|
|
@ -31,30 +19,32 @@
|
|||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-full h-2px bg-[#3662FE] my-2.5"></div>
|
||||
<div class="w-full h-4px bg-[#3662FE] my-20px"></div>
|
||||
<div class="flex justify-end">
|
||||
<SvgIcon
|
||||
v-if="loading"
|
||||
@click="handleStop"
|
||||
class="text-white text-xl ml-2 cursor-pointer"
|
||||
class="text-white text-44px ml-20px cursor-pointer"
|
||||
name="pause"
|
||||
></SvgIcon>
|
||||
<SvgIcon class="text-white text-xl ml-2" name="right-arrow"></SvgIcon>
|
||||
<SvgIcon
|
||||
class="text-white text-44px ml-20px"
|
||||
name="right-arrow"
|
||||
></SvgIcon>
|
||||
</div>
|
||||
<div class="mt-5 h-97 -mx-4">
|
||||
<ScrollContainer ref="scrollRefAi">
|
||||
<div class="px-4">
|
||||
<div class="text-base text-white opacity-40 leading-6">
|
||||
<div class="mt-10px h-600px">
|
||||
<ScrollContainer class="!h-full" ref="scrollRefAi">
|
||||
<div class="px-0">
|
||||
<div class="text-27px text-white opacity-40 leading-34px">
|
||||
<div class="text-center" v-if="contentLoading">
|
||||
<a-spin size="small" />
|
||||
<van-loading type="spinner" size="24"/>
|
||||
</div>
|
||||
<div v-else>
|
||||
{{ contenText }}
|
||||
</div>
|
||||
<!-- 大自然是人类赖以生存发展的基本条件,尊重自然、顺应自然、保护自然是全面建设社会主义现代化国家的内在要求大自然是人类赖以生存发展的基本条件,尊重自然、顺应自然、保护自然是全面建设社会主义现代化国家是全面建设社会主义现代化国家的内在要求 -->
|
||||
</div>
|
||||
<Message
|
||||
class="my-4"
|
||||
class="my-20px"
|
||||
v-for="(item, index) in dataSources"
|
||||
:key="index"
|
||||
:text="item.text"
|
||||
|
|
@ -64,31 +54,30 @@
|
|||
</div>
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<a-input
|
||||
<div class="flex border-1px border-[#414548] h-88px mt-20px">
|
||||
<van-field
|
||||
@pressEnter="sendMessage"
|
||||
v-model:value="prompt"
|
||||
v-model="prompt"
|
||||
size="small"
|
||||
class="flex-1 text-sm rounded-r-none rounded-4px bg-[#414548] bg-opacity-40 text-white placeholder-[#FFFFFF40] border-[#414548]"
|
||||
:border="false"
|
||||
class="cu-field-ai"
|
||||
placeholder="向我提问有关文本的任何问题"
|
||||
></a-input>
|
||||
<a-button
|
||||
></van-field>
|
||||
<van-button
|
||||
@click="sendMessage"
|
||||
type="primary"
|
||||
class="rounded-r-4px rounded-l-none px-6 h-full !w-19"
|
||||
class="!rounded-r-4px !rounded-l-none px-6 h-full !w-155px"
|
||||
>
|
||||
<template #icon>
|
||||
<SvgIcon class="text-white text-xl" name="send"></SvgIcon>
|
||||
<SvgIcon class="text-white text-34px" name="send"></SvgIcon>
|
||||
</template>
|
||||
</a-button>
|
||||
</van-button>
|
||||
</div>
|
||||
<div class="opacity-40 text-sm text-center mt-4">
|
||||
<div class="opacity-40 text-27px text-center mt-40px">
|
||||
文案仅供参考,使用前请核实,风险自负
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- </vue-draggable-resizable> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -100,8 +89,6 @@ import { ref, computed, nextTick } from 'vue'
|
|||
import http from '@/io/request'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useAiChat } from '@/stores/aichat'
|
||||
import VueDraggableResizable from 'vue-draggable-resizable/src/components/vue-draggable-resizable.vue'
|
||||
import 'vue-draggable-resizable/dist/VueDraggableResizable.css'
|
||||
const props = defineProps({
|
||||
top: {
|
||||
type: String,
|
||||
|
|
@ -183,7 +170,7 @@ const changeOption = (index) => {
|
|||
autoMessage()
|
||||
}
|
||||
const currentOption = computed(() => {
|
||||
if(optionIndex.value === null) return null
|
||||
if (optionIndex.value === null) return null
|
||||
return options[optionIndex.value] ?? null
|
||||
})
|
||||
|
||||
|
|
@ -193,11 +180,13 @@ const dataSources = computed(() => {
|
|||
|
||||
const prompt = ref('')
|
||||
|
||||
const autoMessage = async ()=>{
|
||||
|
||||
const message = replacePlaceholder(currentOption.value.value, truncateRichText(props.content, 4000))
|
||||
const autoMessage = async () => {
|
||||
const message = replacePlaceholder(
|
||||
currentOption.value.value,
|
||||
truncateRichText(props.content, 4000)
|
||||
)
|
||||
|
||||
if(loading.value) return
|
||||
if (loading.value) return
|
||||
contentLoading.value = true
|
||||
loading.value = true
|
||||
try {
|
||||
|
|
@ -233,26 +222,24 @@ const autoMessage = async ()=>{
|
|||
}
|
||||
const errorMessage = error?.errmsg ?? '好像出错了,请稍后再试。'
|
||||
contenText.value = errorMessage
|
||||
}finally{
|
||||
} finally {
|
||||
contentLoading.value = false
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function truncateRichText(richText, maxLength) {
|
||||
// 去除标签
|
||||
const plainText = richText.replace(/<[^>]+>/g, '');
|
||||
const plainText = richText.replace(/<[^>]+>/g, '')
|
||||
|
||||
// 截取最多 maxLength 个字符
|
||||
const truncatedText = plainText.substring(0, maxLength);
|
||||
const truncatedText = plainText.substring(0, maxLength)
|
||||
|
||||
return truncatedText;
|
||||
return truncatedText
|
||||
}
|
||||
|
||||
function replacePlaceholder(originalText, replacement) {
|
||||
return originalText.replace('{0}', replacement);
|
||||
return originalText.replace('{0}', replacement)
|
||||
}
|
||||
|
||||
const sendMessage = async () => {
|
||||
|
|
@ -290,8 +277,6 @@ const sendMessage = async () => {
|
|||
const { responseText } = xhr
|
||||
if (xhr.status == 200) {
|
||||
const arr = parseEventMessages(responseText)
|
||||
const { conversation_id, message_id } = arr[0]
|
||||
|
||||
const msg = arr.reduce((acc, item) => {
|
||||
return acc + item.text
|
||||
}, '')
|
||||
|
|
@ -370,15 +355,26 @@ function scrollToBottomIfAtBottom() {
|
|||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.ant-input-group) {
|
||||
.ant-input-group-addon {
|
||||
height: 100%;
|
||||
// display: inline-block;
|
||||
&:last-child {
|
||||
padding: 0;
|
||||
<style lang="scss">
|
||||
.cu-field-ai {
|
||||
height: 100% !important;
|
||||
background-color: #1e1f21;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
height: 52px;
|
||||
font-size: 27px;
|
||||
line-height: 52px;
|
||||
padding: 0 10px;
|
||||
input {
|
||||
color: white !important;
|
||||
&::placeholder {
|
||||
color: #ffffff41 !important;
|
||||
}
|
||||
}
|
||||
.van-field__body {
|
||||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
.options {
|
||||
.active {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,10 @@
|
|||
:data="item"
|
||||
></CardItem>
|
||||
</div>
|
||||
<AiAssistant />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
|
|
@ -34,6 +37,7 @@ import bg01 from '@/assets/images/insights_01.jpg'
|
|||
import bg02 from '@/assets/images/insights_02.jpg'
|
||||
import bg03 from '@/assets/images/insights_03.jpg'
|
||||
import bg04 from '@/assets/images/insights_04.jpg'
|
||||
import AiAssistant from '@/views/chat/components/ai-assistant-float.vue'
|
||||
const list = [
|
||||
{
|
||||
icon: '法律法规',
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ import 'swiper/css/navigation'
|
|||
|
||||
const modules = [Mousewheel, Navigation, EffectCoverflow]
|
||||
|
||||
const pagetSize = 100
|
||||
const pagetSize = 20
|
||||
const weekNewsPage = ref(1)
|
||||
const weekNewsList = ref([])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue