Merge branch 'test' of http://47.103.154.90:83/r/WI/Web.V1.0 into test
| | |
| | | 'Content-Type': 'application/x-www-form-urlencoded', |
| | | }, |
| | | }); |
| | | |
| | | |
| | | export const question_stream_reply = (params) => |
| | | request({ |
| | | url: `/chat/question_stream_reply`, |
| | | method: 'post', |
| | | params: params, |
| | | headers: { |
| | | 'Content-Type': 'application/x-www-form-urlencoded', |
| | | }, |
| | | }); |
| | |
| | | |
| | | <!-- #region ====================== è¿ç¨è¾åº ======================--> |
| | | <el-steps v-show="item.stepIsShow" class="mt-3" direction="vertical" :active="activeStep"> |
| | | |
| | | <el-step |
| | | v-for="(subItem, index) in item.stepList" |
| | | :title="subItem.title" |
| | |
| | | <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 |
| | | <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]"> |
| | | |
| | | |
| | | <component |
| | | :key="`${item.historyId}-${index + 1}-${multiChatIndex + 1}`" |
| | | v-for="(multiChatItem, multiChatIndex) in subItem.subStep" |
| | | :order="`${index + 1}-${multiChatIndex + 1}`" |
| | | :item="multiChatItem" |
| | | :is="multiChatTypeMapCom[multiChatItem.type]" |
| | | :disabled="!(index + 1 === item.stepList.length && isTalking && msgIndex === computedMessageList.length - 1)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | </el-step> |
| | | </el-steps> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="absolute right-28 bottom-40 " v-if="!isBottom"> |
| | | <div class="flex items-center justify-center size-[38px] cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white" @click="scrollToBottom"> |
| | | <div class="absolute right-28 bottom-40" v-if="!isBottom"> |
| | | <div |
| | | class="flex items-center justify-center size-[38px] cursor-pointer hover:text-[#0284ff] border rounded-full hover:bg-[#f6f7f9] shadow bg-white" |
| | | @click="scrollToBottom" |
| | | > |
| | | <i class="ywifont ywicon-xiangxiajiantou !text-[20px]" /> |
| | | </div> |
| | | </div> |
| | |
| | | isSharePage, |
| | | roomConfig, |
| | | } from '/@/stores/chatRoom'; |
| | | |
| | | import { multiChatTypeMapCom } from '/@/components/chat/chatComponents/multiChat'; |
| | | import emitter from '/@/utils/mitt'; |
| | | import { ErrorCode } from '/@/utils/request'; |
| | | import { toMyFixed } from '/@/utils/util'; |
| | | const chatWidth = '75%'; |
| | | const voicePageIsShow = ref(false); |
| | | let isTalking = ref(false); |
| | | |
| | | let messageContent = ref<ChatContent>({ |
| | | type: AnswerType.Text, |
| | | values: '', |
| | |
| | | computedMessageList.value.at(-1).conclusion = chunkRes.value; |
| | | chunkRes.value = 'åæç»æ'; |
| | | } |
| | | |
| | | if (chunkRes.mode === 'question') { |
| | | const stepList = computedMessageList.value.at(-1).stepList; |
| | | const lastStepItem = stepList.at(-1); |
| | | if (!lastStepItem.subStep) { |
| | | lastStepItem.subStep = []; |
| | | } |
| | | lastStepItem.subStep.push({ |
| | | type: chunkRes.value.type, |
| | | data: chunkRes.value, |
| | | }); |
| | | scrollToBottom(); |
| | | return; |
| | | } |
| | | const stepList = computedMessageList.value.at(-1).stepList; |
| | | const currentTimeStamp = new Date().getTime(); |
| | | const ms = toMyFixed(currentTimeStamp - lastTimestamp, 2) + ' ms'; |
| | |
| | | stepList.at(-1).ms = ms; |
| | | } |
| | | lastTimestamp = currentTimeStamp; |
| | | |
| | | const stepItem = convertProcessItem(chunkRes); |
| | | |
| | | stepList.push(stepItem); |
| | | scrollToBottom(); |
| | | |
| | | if (chunkRes.mode !== 'result') { |
| | | scrollToBottom(); |
| | | } |
| | | }, |
| | | { |
| | | cancelToken: currentSource.token, |
| | |
| | | }); |
| | | |
| | | questionRes = await resultP; |
| | | isTalking.value = false; |
| | | // isTalking.value = false; |
| | | |
| | | const content = parseContent(res, true); |
| | | return content; |
| | |
| | | font-size: 16px !important; |
| | | } |
| | | :deep(.el-step__description) { |
| | | height: 20px; |
| | | min-height: 20px; |
| | | } |
| | | |
| | | :deep(.el-step:last-of-type .el-step__description) { |
| | | display: none; |
| | | // display: none; |
| | | } |
| | | </style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="flex flex-col gap-1"> |
| | | <span class="text-gray-600 font-normal">{{ `${order} ${item?.data?.title}` }}</span> |
| | | |
| | | <div v-if="item?.data?.options?.length > 0" class="flex-items-center gap-5"> |
| | | <span |
| | | @click="select(subItem)" |
| | | v-for="subItem in item?.data?.options" |
| | | class="flex w-fit items-center cursor-pointer border-solid border px-3 border-gray-300 hover:text-blue-400 rounded-lg" |
| | | :class="{ 'cursor-not-allowed': disabled, }" |
| | | >{{ subItem }}</span |
| | | > |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup lang="ts"> |
| | | import { ref, watch } from 'vue'; |
| | | import { question_stream_reply } from '/@/api/ai/chat'; |
| | | const props = defineProps(['order', 'item', 'disabled']); |
| | | // :class="[...(subItem === activeOption ? ['bg-blue-400', 'text-white'] : []), disabled ? 'cursor-not-allowed' : '']" |
| | | // 'bg-blue-400': subItem === activeOption, 'text-white': subItem === activeOption.value |
| | | const activeOption = ref(); |
| | | const select = async (option) => { |
| | | if (props.disabled) return; |
| | | const res = await question_stream_reply({ |
| | | select: option, |
| | | reply_id: props.item?.data?.reply_id, |
| | | }); |
| | | if (res.json_ok) { |
| | | activeOption.value = option; |
| | | } |
| | | }; |
| | | |
| | | |
| | | </script> |
| | | <style scoped lang="scss"></style> |
¶Ô±ÈÐÂÎļþ |
| | |
| | | import { MultiChatType } from '../../model/types'; |
| | | import Select from './Select.vue'; |
| | | |
| | | export const multiChatTypeMapCom = { |
| | | [MultiChatType.Select]: Select, |
| | | }; |
| | |
| | | import moment from 'moment'; |
| | | import { Ref, ShallowRef, computed, nextTick, onBeforeUnmount, ref, unref } from 'vue'; |
| | | import { LOAD_CHAT_LIMIT } from '../constants'; |
| | | import { AnswerType, ChatContent, ChatMessage, RoleEnum, StepEnum, StepItem } from '../model/types'; |
| | | import { AnswerType, ChatContent, ChatMessage, MultiChatType, RoleEnum, StepEnum, StepItem } from '../model/types'; |
| | | import { GetHistoryAnswer, QueryHistoryDetail, getShareChatJsonByPost } from '/@/api/ai/chat'; |
| | | import router from '/@/router'; |
| | | import { isSharePage } from '/@/stores/chatRoom'; |
| | |
| | | return { |
| | | status: StepEnum.Success, |
| | | title: processItem.value, |
| | | }; |
| | | } as StepItem; |
| | | }; |
| | | export const convertProcessToStep = (process: any[]) => { |
| | | const stepList = (process ?? []).map<StepItem>((item) => { |
| | | return convertProcessItem(item); |
| | | }); |
| | | const stepList = (process ?? []).reduce((preVal, curVal) => { |
| | | if (curVal.mode === 'question') { |
| | | const last = preVal.at(-1); |
| | | if (!last.subStep) { |
| | | last.subStep = []; |
| | | } |
| | | const sub = { |
| | | data: curVal.value, |
| | | type: MultiChatType.Select, |
| | | }; |
| | | last.subStep.push(sub); |
| | | } else { |
| | | const cur = convertProcessItem(curVal); |
| | | preVal.push(cur); |
| | | } |
| | | return preVal; |
| | | }, []); |
| | | return stepList; |
| | | }; |
| | | |
| | | /** |
| | | * æ»å¨å è½½æ°æ® |
| | | * @returns |
| | |
| | | role: RoleEnum; |
| | | content?: ChatContent; |
| | | state?: null | '1' | '0'; |
| | | sectionAId?:string, |
| | | createTime?:string, |
| | | stepList?:StepItem[], |
| | | stepIsShow?:boolean, |
| | | isStopMsg?:boolean, |
| | | sectionAId?: string; |
| | | createTime?: string; |
| | | stepList?: StepItem[]; |
| | | stepIsShow?: boolean; |
| | | isStopMsg?: boolean; |
| | | /** @description æ¯å¦è¢«éæ©å享 */ |
| | | isChecked:boolean, |
| | | conclusion?:any[] |
| | | isChecked: boolean; |
| | | conclusion?: any[]; |
| | | } |
| | | |
| | | export const roleImageMap = { |
| | | [RoleEnum.user]: userPic, |
| | | [RoleEnum.assistant]: assistantPic, |
| | | }; |
| | | |
| | | |
| | | |
| | | export const enum StepEnum { |
| | | Loading, |
| | |
| | | [StepEnum.Success]: 'process', |
| | | [StepEnum.Error]: 'process', |
| | | }; |
| | | export const enum MultiChatType { |
| | | Select = 'select', |
| | | } |
| | | type SubStep = { |
| | | data:any; |
| | | type: MultiChatType.Select; |
| | | }; |
| | | |
| | | export type StepItem = { |
| | | title: string; |
| | | status: StepEnum; |
| | | // æ¶èæ¶é´ |
| | | ms?:string | number; |
| | | }; |
| | | ms?: string | number; |
| | | subStep?: SubStep[]; |
| | | }; |
| | |
| | | host: '0.0.0.0', |
| | | port: env.VITE_PORT as unknown as number, |
| | | open: JSON.parse(env.VITE_OPEN), |
| | | hmr: false, |
| | | hmr: true, |
| | | }, |
| | | build: { |
| | | // outDir: 'dist/' + mode.mode, |