| | |
| | | <div class="inline-flex flex-col" :class="{ 'w-full': item.role === RoleEnum.assistant }"> |
| | | <div class="w-full"> |
| | | <div class="rounded-[6px] p-4 leading-relaxed bg-white"> |
| | | <!-- #region ====================== 意图分析 ======================--> |
| | | <div class="flex flex-col" v-if="item?.stepList?.length > 0"> |
| | | <!-- #region ====================== 意图分析 ======================--> |
| | | <div class="flex items-center"> |
| | | <span class="mr-2">意图分析:</span> |
| | | <div |
| | | @click="toggleStepList(item)" |
| | | class="cursor-pointer border border-gray-300 border-solid w-fit px-2 flex items-center space-x-2 rounded-lg hover:bg-gray-100 active:bg-gray-200" |
| | | > |
| | | <span> |
| | | {{ toggleStepLabel(item) }} |
| | | </span> |
| | | <span class="ywifont" :class="{ 'ywicon-unfold': !item.stepIsShow, 'ywicon-fold': item.stepIsShow }"></span> |
| | | </div> |
| | | </div> |
| | | <!-- #endregion --> |
| | | |
| | | <!-- #region ====================== 过程输出 ======================--> |
| | | <el-steps v-show="item.stepIsShow" class="mt-3" direction="vertical" :active="activeStep"> |
| | | <el-step |
| | | :key="`template-${index}`" |
| | | v-for="(subItem, index) in item.stepList" |
| | | :title="subItem.title" |
| | | :status="stepEnumMap[subItem.status]" |
| | | > |
| | | <template |
| | | #icon |
| | | v-if="index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1" |
| | | > |
| | | <span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span> |
| | | </template> |
| | | <template #title> |
| | | <span class=""> |
| | | {{ subItem.title }} |
| | | |
| | | <span v-if="subItem.ms" class="text-green-600">{{ `(${subItem.ms})` }}</span></span |
| | | > |
| | | </template> |
| | | |
| | | <template #description v-if="subItem?.subStep?.length > 0"> |
| | | <div class="my-1 flex flex-col gap-1 text-[14px]"> |
| | | <div |
| | | :key="`${item.historyId}-${index + 1}-${multiChatIndex + 1}`" |
| | | v-for="(multiChatItem, multiChatIndex) in subItem.subStep" |
| | | > |
| | | <component |
| | | v-if="multiChatItem.type === MultiChatType.Select" |
| | | :order="`${index + 1}-${multiChatIndex + 1}`" |
| | | :item="multiChatItem" |
| | | :is="multiChatTypeMapCom[multiChatItem.type]" |
| | | :disabled=" |
| | | !(index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1) |
| | | " |
| | | /> |
| | | <component |
| | | v-else-if="multiChatItem.type === MultiChatType.Result" |
| | | :is="answerTypeMapCom['summary']" |
| | | :data="multiChatItem.data.content.values" |
| | | :originData="multiChatItem.data" |
| | | /> |
| | | <div v-else-if="multiChatItem.type === MultiChatType.Summary" class="ml-4 mt-5 pb-10"> |
| | | <div class="text-gray-600 mb-5">你可以继续问我:</div> |
| | | <div class="space-y-2 inline-flex flex-col"> |
| | | <div |
| | | v-for="item in multiChatItem.data.content.askMoreList" |
| | | :key="item.history_id" |
| | | class="bg-white p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg" |
| | | @click="askMoreClick(item)" |
| | | > |
| | | {{ item.question }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-step> |
| | | </el-steps> |
| | | <!-- #endregion --> |
| | | </div> |
| | | <!-- #endregion --> |
| | | |
| | | <!-- #region ====================== 消息内容 ======================--> |
| | | <template v-if="item.content?.values"> |
| | | <!-- <template v-if="item.content?.values"> --> |
| | | <!-- #region ====================== 报错信息 ======================--> |
| | | <div v-if="item.content.errCode === ErrorCode.Message" class="flex-column w-full"> |
| | | <div v-if="item.content?.errCode === ErrorCode.Message" class="flex-column w-full"> |
| | | <p class="text-red-500"> |
| | | {{ item.content.errMsg }} |
| | | </p> |
| | |
| | | <!-- #region ====================== 回答组件 ======================--> |
| | | <template v-else> |
| | | <template v-if="item.content.type === AnswerType.Report"> |
| | | <component |
| | | v-for="(subItem, index) in item.content.values" |
| | | :key="index" |
| | | :reportIndex="index" |
| | | :conclusion="subItem.conclusion" |
| | | :is="answerTypeMapCom[subItem.content.type]" |
| | | :data="subItem.content.values" |
| | | :originData="subItem" |
| | | :historyId="item.historyId" |
| | | :isTalking="isTalking && msgIndex === computedMessageList.length - 1" |
| | | /> |
| | | <div v-for="(num, index) in item?.stepGroup?.length" :key="index"> |
| | | <!-- #region ====================== 意图分析 ======================--> |
| | | <div class="flex flex-col" v-if="item?.stepGroup?.[index]?.value?.length > 0"> |
| | | <!-- #region ====================== 意图分析 ======================--> |
| | | <div class="flex items-center"> |
| | | <span class="mr-2">意图分析:</span> |
| | | <div |
| | | @click="toggleStepList(item?.stepGroup?.[index])" |
| | | class="cursor-pointer border border-gray-300 border-solid w-fit px-2 flex items-center space-x-2 rounded-lg hover:bg-gray-100 active:bg-gray-200" |
| | | > |
| | | <span> |
| | | {{ toggleStepLabel(item?.stepGroup?.[index]) }} |
| | | </span> |
| | | <span |
| | | class="ywifont" |
| | | :class="{ |
| | | 'ywicon-unfold': !item?.stepGroup?.[index].isShow, |
| | | 'ywicon-fold': item?.stepGroup?.[index].isShow, |
| | | }" |
| | | ></span> |
| | | </div> |
| | | </div> |
| | | <!-- #endregion --> |
| | | |
| | | <!-- #region ====================== 过程输出 ======================--> |
| | | <el-steps |
| | | v-show="item?.stepGroup?.[index].isShow" |
| | | class="mt-3" |
| | | direction="vertical" |
| | | :active="activeStep" |
| | | > |
| | | <el-step |
| | | :key="`template-${stepIndex}`" |
| | | v-for="(subItem, stepIndex) in item?.stepGroup?.[index].value" |
| | | :title="subItem.title" |
| | | :status="stepEnumMap[subItem.status]" |
| | | > |
| | | <template |
| | | #icon |
| | | v-if=" |
| | | stepIndex + 1 === item?.stepGroup?.[index].value.length && |
| | | isTalking && |
| | | msgIndex === computedMessageList.length - 1 |
| | | " |
| | | > |
| | | <span class="ywifont ywicon-loading1 animate-spin !text-[24px]"></span> |
| | | </template> |
| | | <template #title> |
| | | <span class=""> |
| | | {{ subItem.title }} |
| | | |
| | | <span v-if="subItem.ms" class="text-green-600">{{ `(${subItem.ms})` }}</span></span |
| | | > |
| | | </template> |
| | | |
| | | <template #description v-if="subItem?.subStep?.length > 0"> |
| | | <div class="my-1 flex flex-col gap-1 text-[14px]"> |
| | | <div |
| | | :key="`${item.historyId}-${stepIndex + 1}-${multiChatIndex + 1}`" |
| | | v-for="(multiChatItem, multiChatIndex) in subItem.subStep" |
| | | > |
| | | <component |
| | | v-if="multiChatItem.type === MultiChatType.Select" |
| | | :order="`${stepIndex + 1}-${multiChatIndex + 1}`" |
| | | :item="multiChatItem" |
| | | :is="multiChatTypeMapCom[multiChatItem.type]" |
| | | :disabled=" |
| | | !( |
| | | stepIndex + 1 === item?.stepGroup?.[index].value.length && |
| | | isTalking && |
| | | msgIndex === computedMessageList.length - 1 |
| | | ) |
| | | " |
| | | /> |
| | | <component |
| | | v-else-if="multiChatItem.type === MultiChatType.Result" |
| | | :is="answerTypeMapCom['summary']" |
| | | :data="multiChatItem.data.content.values" |
| | | :originData="multiChatItem.data" |
| | | /> |
| | | <div v-else-if="multiChatItem.type === MultiChatType.Summary" class="ml-4 mt-5 pb-10"> |
| | | <div class="text-gray-600 mb-5">你可以继续问我:</div> |
| | | <div class="space-y-2 inline-flex flex-col"> |
| | | <div |
| | | v-for="item in multiChatItem.data.content.askMoreList" |
| | | :key="item.history_id" |
| | | class="bg-white p-3 hover:bg-[#c5e0ff] hover:text-[#1c86ff] cursor-pointer rounded-lg" |
| | | @click="askMoreClick(item)" |
| | | > |
| | | {{ item.question }} |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-step> |
| | | </el-steps> |
| | | <!-- #endregion --> |
| | | </div> |
| | | <!-- #endregion --> |
| | | |
| | | <component |
| | | v-if="item.content?.values?.[index]" |
| | | :reportIndex="index" |
| | | :conclusion="item.content.values[index].conclusion" |
| | | :is="answerTypeMapCom[item.content.values[index].content.type]" |
| | | :data="item.content.values[index].content.values" |
| | | :originData="item.content.values[index]" |
| | | :historyId="item.historyId" |
| | | :isTalking="isTalking && msgIndex === computedMessageList.length - 1" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <component |
| | | v-else |
| | |
| | | </div> |
| | | </template> |
| | | <!-- #endregion --> |
| | | </template> |
| | | <!-- </template> --> |
| | | |
| | | <!-- #endregion --> |
| | | <!-- #region ====================== 附加内容 ======================--> |
| | |
| | | break; |
| | | |
| | | case AnswerType.Summary: |
| | | |
| | | content = { |
| | | type: AnswerType.Summary, |
| | | values: res.summary?.map((item) => { |
| | |
| | | activeStep.value = -1; |
| | | }; |
| | | |
| | | const toggleStepLabel = (item: ChatMessage) => (item.stepIsShow ? '收起' : '展开'); |
| | | const toggleStepList = (item: ChatMessage) => { |
| | | item.stepIsShow = !item.stepIsShow; |
| | | const toggleStepLabel = (item: any) => (item.isShow ? '收起' : '展开'); |
| | | const toggleStepList = (item: any) => { |
| | | item.isShow = !item.isShow; |
| | | }; |
| | | |
| | | //#endregion |
| | |
| | | }; |
| | | questionRes = resReport; |
| | | resolve(resReport); |
| | | // 开始增加新的 stepGroup |
| | | computedMessageList.value.at(-1).stepGroup.push({ |
| | | value: [], |
| | | isShow: true, |
| | | }); |
| | | } else { |
| | | const lastMsg = computedMessageList.value.at(-1); |
| | | const lastMsg = computedMessageList.value.at(-1); |
| | | |
| | | // 已经解析过一次 reports |
| | | lastMsg.content.values.push({ |
| | |
| | | } |
| | | |
| | | if (chunkRes.mode === 'question') { |
| | | const stepList = computedMessageList.value.at(-1).stepList; |
| | | const lastGroup = computedMessageList.value.at(-1).stepGroup.at(-1); |
| | | const stepList = lastGroup?.value ?? []; |
| | | const lastStepItem = stepList.at(-1); |
| | | if (!lastStepItem.subStep) { |
| | | lastStepItem.subStep = []; |
| | |
| | | scrollToBottom(); |
| | | return; |
| | | } |
| | | const stepList = computedMessageList.value.at(-1).stepList; |
| | | |
| | | const lastGroup = computedMessageList.value.at(-1).stepGroup.at(-1); |
| | | const stepList = lastGroup?.value ?? []; |
| | | const currentTimeStamp = new Date().getTime(); |
| | | const ms = toMyFixed(currentTimeStamp - lastTimestamp, 2) + ' ms'; |
| | | if (chunkRes.mode === 'finish') { |
| | |
| | | |
| | | if (stepList?.length >= 1) { |
| | | stepList.at(-1).ms = ms; |
| | | }else{ |
| | | const stepGroup = computedMessageList.value.at(-1).stepGroup |
| | | if(stepGroup.length > 1){ |
| | | const lastStepList = stepGroup.at(-2).value; |
| | | lastStepList.at(-1).ms = ms; |
| | | } |
| | | } |
| | | lastTimestamp = currentTimeStamp; |
| | | const stepItem = convertProcessItem(chunkRes); |
| | | |
| | | stepList.push(stepItem); |
| | | |
| | | // 强制触发更新 |
| | | |
| | | scrollToBottom(); |
| | | }, |
| | | { |
| | |
| | | }) |
| | | .finally(() => { |
| | | isTalking.value = false; |
| | | computedMessageList.value.at(-1).stepIsShow = false; |
| | | // 收起所有 stepGroup |
| | | computedMessageList.value.at(-1).stepGroup.forEach((item) => { |
| | | item.isShow = false; |
| | | }); |
| | | |
| | | resetStep(); |
| | | }); |
| | |
| | | const userItem: ChatMessage = { role: RoleEnum.user, content, isChecked: false } as any; |
| | | const assistantItem: ChatMessage = { |
| | | role: RoleEnum.assistant, |
| | | content: null, |
| | | content: { |
| | | type: AnswerType.Report, |
| | | }, |
| | | state: AnswerState.Null, |
| | | stepList: [], |
| | | stepIsShow: true, |
| | | stepGroup: [ |
| | | { |
| | | value: [], |
| | | isShow: true, |
| | | }, |
| | | ], |
| | | isStopMsg: false, |
| | | isChecked: false, |
| | | } as any; |