Commit b856ece6 authored by chenghong_tao's avatar chenghong_tao

优化部分代码

parent 3213252c
......@@ -17,10 +17,11 @@ npm run dev
## iframe/script 模式
### 注意事项
1. 使用embed模式时,需要手动修改`iframePlugin/embed.js`中的域名或IP地址。
```javascript
// 大概21行
img.src = 'https://tk-test.infi-inside.com:2443/deepseek.png'; // https://tk-test.infi-inside.com:2443修改成自己的ip或域名
// 大概77行
iframe.src = 'https://tk-test.infi-inside.com:2443/index.html'; // https://tk-test.infi-inside.com:2443修改成自己的ip或域名
```
\ No newline at end of file
1. 使用embed模式时,引入embed.js文件时需要带URL参数
```html
<script src="/embed.min.js?url=当前前端所在的IP或域名地址"></script>
```
如:在本地运行前端时,引入embed.js文件时,参数则为url=http://127.0.0.1:3000
```html
<script src="/embed.min.js?url=http://127.0.0.1:3000"></script>
```
(function() {
// 获取URL
const urlParams = new URLSearchParams(window.location.search);
const baseUrl = urlParams.get('url') || 'https://tk-test.infi-inside.com:2443';
// 创建悬浮按钮
const button = document.createElement('button');
button.id = 'dify-chatbot-bubble-button';
button.id = 'chatbot-bubble-button';
button.style.position = 'fixed';
button.style.bottom = '20px';
button.style.right = '20px';
......@@ -18,7 +22,7 @@
// Create an img element
const img = document.createElement('img');
img.src = 'https://tk-test.infi-inside.com:2443/deepseek.png'; // Replace with the path to your image
img.src = baseUrl + '/deepseek.png'; // Replace with the path to your image
img.style.width = '60px';
// img.style.height = '100%';
img.style.objectFit = 'cover';
......@@ -30,7 +34,7 @@
// 创建iframe容器
const iframeContainer = document.createElement('div');
iframeContainer.id = 'dify-chatbot-bubble-window';
iframeContainer.id = 'chatbot-bubble-window';
iframeContainer.style.position = 'fixed';
iframeContainer.style.bottom = '80px';
iframeContainer.style.right = '20px';
......@@ -74,7 +78,9 @@
// 创建iframe
const iframe = document.createElement('iframe');
iframe.src = 'https://tk-test.infi-inside.com:2443/index.html'; // 替换为你的聊天窗口页面地址
// 获取URL
iframe.src = baseUrl; // 替换为你的聊天窗口页面地址
iframe.style.width = '100%';
iframe.style.height = '100%';
iframe.style.border = 'none';
......
......@@ -9,7 +9,7 @@
<template v-for="(item, index) in chatMessageList" :key="'chatMessage - ' + index">
<div class="chat-message-item">
<aiBubble
:query="item.content"
:query="item.query"
v-if="item.type === 'ai' || item.type === 'ai-history'"
:messageType="item.type"
:content="item.content"
......@@ -59,11 +59,13 @@ const userQuery = (query, isLoading=false) => {
}
chatMessageList.value.push({
type: 'user',
query: '',
content: query,
})
chatMessageList.value.push({
type: 'ai',
content: query,
query,
content: null,
})
if (isLoading) {
inputMessageRef.value.changeLoading(true)
......@@ -123,10 +125,12 @@ watch(() => props.historyMsgList, (newValue) => {
newValue.forEach((item) => {
chatMessageList.value.push({
type: 'user',
content: item?.query,
query: '',
content: item.query
})
chatMessageList.value.push({
type: 'ai-history',
query: item.query,
content: item?.answer,
})
console.log('zhisx');
......
......@@ -5,13 +5,28 @@
</template>
<template #content>
<div class="custom-bubble-content" v-adjust-width>
<workflowItem
<!-- 工作流 -->
<!-- <workflowItem
v-if="workflowContent.length > 0"
:workflowContent="workflowContent"
ref="workflowItemRef"
@workflow-is-error="workflowIsError"
/>
/> -->
<!-- 使用 MarkdownRenderer 组件渲染 messageContent -->
<div class="icon" v-if="workflowStatus && workflowStatus != 'success'">
<div v-if="workflowStatus == 'loading'">
<el-icon style="font-size: 18px" class="is-loaidng">
<Loading />
</el-icon>
<span class="is-loaidng">AI正在思考,请您稍等...</span>
</div>
<div v-if="workflowStatus == 'error'">
<el-icon style="font-size: 18px" class="is-error">
<WarningFilled />
</el-icon>
<span class="is-error">AI处理失败,请您重试或重新完善问题描述</span>
</div>
</div>
<MarkdownRenderer :content="messageContent" />
</div>
......@@ -52,7 +67,7 @@
</template>
<script setup>
import { computed, ref, watch } from "vue";
import { Refresh, Search, Star, DocumentCopy } from "@element-plus/icons-vue";
import { Refresh, Search, Star, DocumentCopy, Loading, SuccessFilled, WarningFilled } from "@element-plus/icons-vue";
import workflowItem from "./workflowItem.vue";
import MarkdownRenderer from '../markdown/markdownRender.vue';
import { Bubble, useXStream } from "vue-element-plus-x";
......@@ -93,6 +108,8 @@ watch(
{ immediate: true }
);
const isReStartWorkflow = ref(false)
const workflowStatus = ref(null)
// 默认支持 SSE 协议
async function startSSE(query) {
try {
......@@ -118,7 +135,7 @@ async function startSSE(query) {
// 机器人的 content 计算属性
const workflowContent = computed(() => {
if (props.messageType === 'ai-history') {
if (props.messageType === 'ai-history' && !isReStartWorkflow.value) {
return [];
}
// 以下是处理非历史消息记录
......@@ -131,18 +148,25 @@ const workflowContent = computed(() => {
const parsedChunk = JSON.parse(chunk);
workflowList.push(parsedChunk);
if (parsedChunk.event === "workflow_started") {
workflowStatus.value = 'loading';
taskStore.setTaskId(parsedChunk.task_id);
taskStore.setConversationId(parsedChunk.conversation_id);
taskStore.setMessageId(parsedChunk.message_id);
taskStore.setWorkflowRunId(parsedChunk.workflow_run_id);
}
if (parsedChunk.event === "error") {
ElMessage.error(parsedChunk.message)
workflowStatus.value = 'error';
emit('workflow-is-error', true)
break;
}
if (parsedChunk.event === "message_end") {
workflowStatus.value = 'success';
emits("messageFinished", true);
}
} catch (error) {
// 这个 结束标识 是后端给的,所以这里这样判断
// 实际项目中,以项目需要为准
if (chunk === " [DONE]") {
if (chunk === "[DONE]") {
// 处理数据结束的情况
// console.log('数据接收完毕')
} else {
......@@ -155,15 +179,19 @@ const workflowContent = computed(() => {
return workflowList;
});
const workflowItemRef = ref(null);
// const workflowItemRef = ref(null);
const reStartSSE = () => {
workflowItemRef.value.clearWorkflow();
isReStartWorkflow.value = true;
// if(workflowItemRef.value) {
// workflowItemRef.value.clearWorkflow();
// }
startSSE(props.query);
console.log('reStartSSE', props.query, props.messageType, props.content)
};
// AI回答问题
const messageContent = computed(() => {
if (props.messageType === 'ai-history') {
if (props.messageType === 'ai-history' && !isReStartWorkflow.value) {
return props.content;
}
let messageContent = "";
......@@ -187,11 +215,9 @@ const copyContent = () => {
ElMessage.success("复制成功");
};
const workflowIsError = (isError) => {
emits("workflow-is-error", isError);
};
// const workflowIsError = (isError) => {
// emits("workflow-is-error", isError);
// };
</script>
<style lang="less" scoped>
.message-content {
......@@ -207,4 +233,43 @@ const workflowIsError = (isError) => {
transform: rotate(180deg); /* 旋转 180 度 */
transition: transform 0.3s ease; /* 添加过渡效果,让旋转更平滑 */
}
.icon {
display: flex;
align-items: center;
width: 100%;
line-height: 28px;
background-color: var(--el-color-white);
padding: 5px 0px;
i {
width: 28px;
vertical-align: middle;
}
span {
flex: 1;
vertical-align: middle;
}
.is-success {
color: var(--el-color-success);
}
.is-error {
color: var(--el-color-danger);
}
.is-loaidng {
color: var(--el-color-primary);
animation: spin 1s linear infinite;
}
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment