Merge branch 'main' of http://18.167.251.121:10003/aidlab/FiDA_Front
This commit is contained in:
@@ -64,7 +64,8 @@
|
||||
region: '',
|
||||
style: ''
|
||||
},
|
||||
imageUrlList: []
|
||||
imageUrlList: [],
|
||||
quotaUrl: []
|
||||
})
|
||||
|
||||
const sketchList = ref([])
|
||||
@@ -110,7 +111,8 @@
|
||||
text: initialData.text,
|
||||
images: initialData.images,
|
||||
useReport: initialData.useReport,
|
||||
tempImages: initialData.tempImages
|
||||
tempImages: initialData.tempImages,
|
||||
quoteList: initialData.quoteList
|
||||
})
|
||||
// 更新 configParams
|
||||
|
||||
@@ -125,6 +127,7 @@
|
||||
images: Array<{ url: string; name: string }>
|
||||
tempImages: any[]
|
||||
useReport: boolean
|
||||
quoteList: Array<string>
|
||||
},
|
||||
skipUserMessage = false
|
||||
) => {
|
||||
@@ -136,14 +139,14 @@
|
||||
}
|
||||
|
||||
params.imageUrlList = message.images || []
|
||||
|
||||
params.quotaUrl = message.quoteList || []
|
||||
// 如果不是重新生成模式,则添加用户消息到列表
|
||||
if (!skipUserMessage) {
|
||||
messageList.value.push({
|
||||
id: messageList.value.length + 1,
|
||||
text: message.text,
|
||||
isUser: true,
|
||||
imageUrls: message.tempImages
|
||||
imageUrls: message.tempImages.concat(message.quoteList)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -221,12 +224,22 @@
|
||||
const decoder = new TextDecoder()
|
||||
let previousEventName = '' // 记录上一个事件名称
|
||||
let hasReportStarted = false // 标记 report 是否已经开始
|
||||
|
||||
let hasSketchEvent = false
|
||||
let hasReportEvent = false
|
||||
|
||||
try {
|
||||
let flag = true
|
||||
while (flag) {
|
||||
const { done, value } = await reader.read()
|
||||
if (done) {
|
||||
// console.log('传输结束 end---', contentBody)
|
||||
if (hasSketchEvent) {
|
||||
aiMessage.text += `<slot slot-name="sketch"></slot>`
|
||||
}
|
||||
if (hasReportEvent) {
|
||||
aiMessage.text += `<slot slot-name="card" title="Report" content="Report"></slot>`
|
||||
}
|
||||
|
||||
aiMessage.streaming = false
|
||||
aiMessage.loading = false
|
||||
isGenerating.value = false
|
||||
@@ -251,7 +264,8 @@
|
||||
|
||||
if (!hasReportStarted && eventName === 'report') {
|
||||
isGeneratingReport.value = true
|
||||
contentBody += `<slot slot-name="card" title="123" content="123">123</slot>`
|
||||
hasReportEvent = true
|
||||
// contentBody += `<slot slot-name="card" title="Report" content="Report"></slot>`
|
||||
hasReportStarted = true
|
||||
}
|
||||
|
||||
@@ -319,20 +333,21 @@
|
||||
// console.log('jsonData', jsonData)
|
||||
if (jsonData.webAddress) {
|
||||
aiMessage.webAddress = JSON.parse(jsonData.webAddress)
|
||||
contentBody += `<slot slot-name="url">123</slot>`
|
||||
contentBody += `<slot slot-name="url"></slot>`
|
||||
}
|
||||
if (jsonData.title) {
|
||||
emits('setTitle', jsonData.title)
|
||||
}
|
||||
|
||||
if (hasSketch) {
|
||||
hasSketchEvent = true
|
||||
sketchList.value.push({
|
||||
[Object.keys(jsonData)[0]]: jsonData[Object.keys(jsonData)[0]]
|
||||
})
|
||||
// 通知 Preview 有新 sketch 正在加载,传入 sketch 索引
|
||||
MyEvent.emit('loading-sketch', sketchList.value.length - 1)
|
||||
MyEvent.emit('OpenSketch')
|
||||
contentBody += `<slot slot-name="sketch"></slot>`
|
||||
// contentBody += `<slot slot-name="sketch"></slot>`
|
||||
}
|
||||
if (eventName === 'report') {
|
||||
reportsContent.value += jsonData.report
|
||||
@@ -355,6 +370,7 @@
|
||||
}
|
||||
}
|
||||
if (jsonData.type === 'end') {
|
||||
console.log('end------hasSketch', hasSketch)
|
||||
aiMessage.streaming = false
|
||||
aiMessage.loading = false
|
||||
isGenerating.value = false
|
||||
@@ -364,7 +380,10 @@
|
||||
} catch (e) {
|
||||
// 检查是否为纯文本 [DONE]
|
||||
if (jsonText.trim() === '[DONE]') {
|
||||
console.log('done-----------hasSketch', hasSketch)
|
||||
|
||||
console.log('结束-----------------------')
|
||||
aiMessage.text = contentBody
|
||||
aiMessage.streaming = false
|
||||
aiMessage.loading = false
|
||||
isGenerating.value = false
|
||||
@@ -463,11 +482,16 @@
|
||||
// assistant 角色,拼接直到下一个 user
|
||||
let combinedContent = item.content || ''
|
||||
let combinedThinkingText = item.reasoning || ''
|
||||
let combinedImageUrl = item.image_url || null
|
||||
// 继续往后找连续的 assistant 消息
|
||||
let j = i + 1
|
||||
while (j < dialogue.length && dialogue[j].role === 'assistant') {
|
||||
combinedContent += dialogue[j].content || ''
|
||||
combinedThinkingText += dialogue[j].reasoning || ''
|
||||
// 如果有 image_url 则保留
|
||||
if (dialogue[j].image_url) {
|
||||
combinedImageUrl = dialogue[j].image_url
|
||||
}
|
||||
j++
|
||||
}
|
||||
|
||||
@@ -476,6 +500,7 @@
|
||||
content: combinedContent,
|
||||
thinkingText: combinedThinkingText,
|
||||
text: combinedContent,
|
||||
image_url: combinedImageUrl,
|
||||
isUser: false,
|
||||
id: result.length + 1,
|
||||
sessionId: sessionId
|
||||
@@ -512,7 +537,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 收集 report 内容并保存到 localStorage
|
||||
// 2. 收集 report 内容并保存到 sessionStorage
|
||||
let reportStr = ''
|
||||
session.dialogue?.forEach((item) => {
|
||||
if (item.report) {
|
||||
@@ -554,36 +579,27 @@
|
||||
params.configParams.style = project.style
|
||||
params.configParams.temperature = project.temperature
|
||||
}
|
||||
// 如果没有数据,直接返回
|
||||
if (!data) {
|
||||
messageList.value = []
|
||||
return
|
||||
}
|
||||
const { ancestors, current } = data
|
||||
|
||||
// 处理单个会话(ancestor 或 current)
|
||||
|
||||
const imgList = []
|
||||
const ancestorsList = []
|
||||
const idCounterRef = { value: 1 }
|
||||
|
||||
// 处理所有 ancestors
|
||||
ancestors?.forEach((item) => {
|
||||
processSession(item, imgList, ancestorsList, idCounterRef)
|
||||
})
|
||||
|
||||
// 处理 current
|
||||
processSession(current, imgList, ancestorsList, idCounterRef)
|
||||
|
||||
// 延迟设置新数据,确保 UI 有时间响应清空操作
|
||||
nextTick(() => {
|
||||
// 找到每个 sessionId 对应的最后一项,插入sketch卡片
|
||||
const sessionLastIndexMap = new Map<string, number>()
|
||||
ancestorsList.forEach((item, index) => {
|
||||
sessionLastIndexMap.set(item.sessionId, index)
|
||||
})
|
||||
sessionLastIndexMap.forEach((lastIndex) => {
|
||||
ancestorsList[lastIndex].text += '<slot slot-name="sketch"></slot>'
|
||||
ancestorsList.forEach((item) => {
|
||||
if (item.image_url && item.role !== 'user') {
|
||||
item.text += `<slot slot-name="sketch"></slot>`
|
||||
}
|
||||
})
|
||||
|
||||
messageList.value = [...ancestorsList]
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
}>()
|
||||
|
||||
// watch(
|
||||
// () => props.content,
|
||||
// () => props,
|
||||
// (newVal) => {
|
||||
// console.log('newVal-----', newVal)
|
||||
// },
|
||||
@@ -139,8 +139,12 @@
|
||||
const emit = defineEmits(['regenerate'])
|
||||
|
||||
const imageList = computed(() => {
|
||||
const { imageUrls } = props.content
|
||||
const { imageUrls, role } = props.content
|
||||
const list = []
|
||||
if (role === 'user') {
|
||||
const quotaList = props.content.image_url ?? []
|
||||
list.push(...quotaList)
|
||||
}
|
||||
if (!imageUrls || imageUrls.length === 0) return list
|
||||
imageUrls.forEach((item) => {
|
||||
if (typeof item === 'string') {
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
watch(
|
||||
() => props.messageList,
|
||||
(val) => {
|
||||
console.log('messageList',val)
|
||||
scrollToBottom()
|
||||
},
|
||||
{ deep: true }
|
||||
|
||||
@@ -13,12 +13,15 @@
|
||||
<Menu />
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item class="sketch-item flex align-center">
|
||||
<el-dropdown-item
|
||||
class="sketch-item flex align-center"
|
||||
@click="handleClickQuote(item)"
|
||||
>
|
||||
<img
|
||||
src="@/assets/images/restore-sketch.png"
|
||||
class="dropdown-icon restore"
|
||||
/>
|
||||
<span class="dropdown-txt">Quote</span>
|
||||
<span class="dropdown-txt">{{ $t('agent.quote') }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item
|
||||
class="sketch-item flex align-center"
|
||||
@@ -28,7 +31,7 @@
|
||||
src="@/assets/images/delete.png"
|
||||
class="dropdown-icon delete"
|
||||
/>
|
||||
<span class="dropdown-txt del">Delete</span>
|
||||
<span class="dropdown-txt del">{{ $t('agent.delete') }}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
@@ -37,7 +40,7 @@
|
||||
class="edit-btn flex align-center space-between"
|
||||
@click="handleClickEdit(item)"
|
||||
>
|
||||
<div>Edit</div>
|
||||
<div>{{ $t('agent.edit') }}</div>
|
||||
<img src="@/assets/images/arrow-top-right.png" />
|
||||
</div>
|
||||
<!-- 已加载完成的 sketch 显示实际图片 -->
|
||||
@@ -218,6 +221,12 @@
|
||||
myEvent.emit('openFlowCanvas', { url, imgId, nodeId })
|
||||
}
|
||||
|
||||
const handleClickQuote = (item) => {
|
||||
// console.log(item)
|
||||
const url = Object.values(item)[0]
|
||||
MyEvent.emit('quote', url)
|
||||
}
|
||||
|
||||
const handleClickDelete = (item: string | Object) => {
|
||||
deleteSketchFlowCanvas({
|
||||
id: Object.keys(item)[0],
|
||||
|
||||
@@ -1,35 +1,26 @@
|
||||
<template>
|
||||
<div class="report-card" :class="{ 'is-url': isUrl, 'is-sketch': isSketch }">
|
||||
<div class="report-card-header">
|
||||
<span v-if="!isUrl && !isSketch">{{ report.title }}</span>
|
||||
<span v-if="!isUrl && !isSketch">{{ title || '' }}</span>
|
||||
<div v-else class="web-sources flex align-center">
|
||||
<span>{{ report.title }}</span>
|
||||
<span>{{ title || '' }}</span>
|
||||
<img src="@/assets/images/link.png" class="link-icon" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="report-card-content">
|
||||
<span v-if="!isUrl && !isSketch">{{ report.content || 'markdown.md' }}</span>
|
||||
<span v-else>{{ report.content }}</span>
|
||||
<span v-if="!isUrl && !isSketch">{{ content || 'markdown.md' }}</span>
|
||||
<span v-else>{{ content || '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// const props = defineProps<{
|
||||
// title: string
|
||||
// isUrl?: boolean
|
||||
// }>()
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
title?: string
|
||||
content?: string
|
||||
isUrl?: boolean
|
||||
isSketch?: boolean
|
||||
report: {
|
||||
title: ''
|
||||
content: ''
|
||||
}
|
||||
}>(),
|
||||
{
|
||||
isUrl: false,
|
||||
@@ -50,17 +41,24 @@
|
||||
background-size: 100% 100%;
|
||||
padding: 2.9rem;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
&.is-url {
|
||||
background: url('@/assets/images/link-card.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
&.is-sketch {
|
||||
background: url('@/assets/images/sketch-card.png') no-repeat;
|
||||
padding: 2rem 3rem;
|
||||
max-width: 52.5rem;
|
||||
height: 8rem;
|
||||
box-sizing: border-box;
|
||||
background-size: 100% 100%;
|
||||
min-height: initial;
|
||||
.report-card-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
// &:first-of-type{
|
||||
// margin-top: 0;
|
||||
// }
|
||||
|
||||
&-header {
|
||||
font-family: 'Medium';
|
||||
font-size: 1.6rem;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<ReportCard is-sketch :report="{title: 'Sketches Results', content: 'JPG file'}"/>
|
||||
<ReportCard is-sketch title="Sketches Results" content="JPG file" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ReportCard from './ReportCard.vue'
|
||||
import ReportCard from './ReportCard.vue'
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
</style>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ReportCard is-url :report="{title: 'WebSources', content: 'Destination URL'}"/>
|
||||
<ReportCard is-url title="WebSources" content="Destination URL"/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -125,7 +125,6 @@ const {} = toRefs(data)
|
||||
<el-drawer
|
||||
v-model="versionTreeData.drawer"
|
||||
:close-on-press-escape="false"
|
||||
:close-on-click-modal="false"
|
||||
:size="treeState ? '73.5rem' : '73.5rem'"
|
||||
body-class="versionTreeBody"
|
||||
:with-header="false"
|
||||
|
||||
@@ -237,7 +237,7 @@ defineExpose({push})
|
||||
margin-bottom: 0;
|
||||
}
|
||||
> .icon{
|
||||
margin-right: .4rem;
|
||||
margin-right: .8rem;
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
> span{
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
)
|
||||
}
|
||||
|
||||
const handleGetProjectInfoAndHistory = () => {
|
||||
const handleGetProjectInfoAndHistory = () => {
|
||||
handleOpenSketch()
|
||||
getProjectInfo({ id: route.params.id }).then((res) => {
|
||||
if (res) agentRef.value.setChatInfo(res)
|
||||
@@ -131,7 +131,7 @@ const handleGetProjectInfoAndHistory = () => {
|
||||
onMounted(() => {
|
||||
MyEvent.add('openReport', handleOpenReport)
|
||||
MyEvent.add('openUrls', handleOpenUrls)
|
||||
MyEvent.add('OpenSketch', handleOpenSketch)
|
||||
MyEvent.add('openSketch', handleOpenSketch)
|
||||
projectStore.clearProject()
|
||||
if (proJectId.value) {
|
||||
handleGetProjectInfoAndHistory()
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
<div class="assist-input-wrapper flex flex-col" :class="{ agent: isAgentMode }">
|
||||
<div class="animate-container flex-1 flex flex-col">
|
||||
<div class="scroll-content flex-col">
|
||||
<div v-if="uploadedImages.length > 0" class="image-preview-list flex wrap">
|
||||
<div
|
||||
v-if="uploadedImages.length > 0 || quoteList.length > 0"
|
||||
class="image-preview-list flex wrap"
|
||||
>
|
||||
<div
|
||||
v-for="(image, index) in uploadedImages"
|
||||
v-for="(image, index) in [...uploadedImages, ...quoteList]"
|
||||
:key="index"
|
||||
class="image-preview-item"
|
||||
>
|
||||
<img
|
||||
:src="image.url"
|
||||
:alt="image.name"
|
||||
:src="image.url || image"
|
||||
class="preview-image"
|
||||
@click="previewImage(image.url)"
|
||||
/>
|
||||
@@ -35,7 +37,7 @@
|
||||
</div>
|
||||
<div class="operate flex align-center space-between">
|
||||
<div class="left flex align-center">
|
||||
<div class="agent-operate flex flex-center">
|
||||
<div class="agent-operate flex flex-center" v-if="isAgentMode">
|
||||
<el-popover
|
||||
placement="top"
|
||||
trigger="click"
|
||||
@@ -211,7 +213,8 @@
|
||||
|
||||
<div
|
||||
v-if="!isAgentMode"
|
||||
class="report-btn flex space-between align-center"
|
||||
class="report-btn flex space-between align-center outer"
|
||||
:class="{ 'is-cn': isCn }"
|
||||
@click="toogltReportTag"
|
||||
>
|
||||
<SvgIcon class="light-icon" color="#FFDB56" name="light" size="16" />
|
||||
@@ -222,7 +225,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch, nextTick, onMounted } from 'vue'
|
||||
import { computed, ref, watch, nextTick, onMounted, onUnmounted } from 'vue'
|
||||
import { areaList } from '@/utils/area'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useRouter } from 'vue-router'
|
||||
@@ -254,11 +257,16 @@
|
||||
|
||||
const emits = defineEmits(['send', 'pause'])
|
||||
|
||||
const { t } = useI18n()
|
||||
const { t, locale } = useI18n()
|
||||
|
||||
const isCn = computed(() => {
|
||||
return locale.value === 'CHINESE_SIMPLIFIED'
|
||||
})
|
||||
|
||||
// 图片上传相关
|
||||
const fileInputRef = ref<HTMLInputElement | null>(null)
|
||||
const uploadedImages = ref<Array<{ url: string; name: string }>>([])
|
||||
const quoteList = ref<Array<string>>([])
|
||||
|
||||
// 触发文件上传
|
||||
const triggerFileUpload = () => {
|
||||
@@ -684,7 +692,8 @@
|
||||
const payload = {
|
||||
text: inputValue.value.trim(),
|
||||
images: imageUrlList,
|
||||
tempImages: uploadedImages.value
|
||||
tempImages: uploadedImages.value,
|
||||
quoteList: quoteList.value
|
||||
}
|
||||
if (reportTags.value.length > 0) {
|
||||
payload.useReport = true
|
||||
@@ -692,6 +701,7 @@
|
||||
emits('send', payload)
|
||||
// 发送后清空图片列表
|
||||
uploadedImages.value = []
|
||||
quoteList.value = []
|
||||
// 发送后清空输入框
|
||||
if (editorRef.value) {
|
||||
editorRef.value.innerHTML = ''
|
||||
@@ -707,6 +717,7 @@
|
||||
|
||||
// 初始化编辑器高度
|
||||
onMounted(() => {
|
||||
MyEvent.add('quote', handleQuote)
|
||||
nextTick(() => {
|
||||
autoResizeEditor()
|
||||
})
|
||||
@@ -803,6 +814,12 @@
|
||||
previewUrl.value = url
|
||||
}
|
||||
|
||||
const handleQuote = (url: string) => {
|
||||
quoteList.value.push(url)
|
||||
}
|
||||
onUnmounted(() => {
|
||||
MyEvent.remove('quote', handleQuote)
|
||||
})
|
||||
// 暴露方法给父组件
|
||||
defineExpose({
|
||||
addReportTag
|
||||
@@ -821,6 +838,10 @@
|
||||
background-color: #fff;
|
||||
border: 1.1px solid #f6f4ef1a;
|
||||
cursor: pointer;
|
||||
&.outer.is-cn {
|
||||
justify-content: center;
|
||||
column-gap: 3rem;
|
||||
}
|
||||
|
||||
.c-svg {
|
||||
width: 1.5rem;
|
||||
@@ -1378,7 +1399,7 @@
|
||||
.agent-modal {
|
||||
// width: 14.6rem;
|
||||
// height: 8.5rem;
|
||||
|
||||
|
||||
row-gap: 1.2rem;
|
||||
font-family: 'Medium';
|
||||
font-weight: 500;
|
||||
|
||||
Reference in New Issue
Block a user