gerson
2024-12-15 69489bc703827ae718cf194faf484ea94a3bfbd9
Merge branch 'test' of http://47.103.154.90:83/r/WI/Web.V1.0 into test
已修改5个文件
已添加2个文件
169 ■■■■ 文件已修改
src/api/ai/chat.ts 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/Chat.vue 60 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/multiChat/Select.vue 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/chatComponents/multiChat/index.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/hooks/useScrollLoad.ts 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/chat/model/types.ts 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/ai/chat.ts
@@ -502,3 +502,14 @@
            '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',
        },
    });
src/components/chat/Chat.vue
@@ -61,6 +61,7 @@
                                                <!-- #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"
@@ -73,10 +74,26 @@
                                                            <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>
@@ -279,8 +296,11 @@
                    </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>
@@ -346,12 +366,15 @@
    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: '',
@@ -547,6 +570,20 @@
                    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';
@@ -560,10 +597,13 @@
                    stepList.at(-1).ms = ms;
                }
                lastTimestamp = currentTimeStamp;
                const stepItem = convertProcessItem(chunkRes);
                stepList.push(stepItem);
                scrollToBottom();
                if (chunkRes.mode !== 'result') {
                    scrollToBottom();
                }
            },
            {
                cancelToken: currentSource.token,
@@ -581,7 +621,7 @@
    });
    questionRes = await resultP;
    isTalking.value = false;
    // isTalking.value = false;
    const content = parseContent(res, true);
    return content;
@@ -945,10 +985,10 @@
    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>
src/components/chat/chatComponents/multiChat/Select.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
<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>
src/components/chat/chatComponents/multiChat/index.ts
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
import { MultiChatType } from '../../model/types';
import Select from './Select.vue';
export const multiChatTypeMapCom = {
    [MultiChatType.Select]: Select,
};
src/components/chat/hooks/useScrollLoad.ts
@@ -1,7 +1,7 @@
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';
@@ -22,14 +22,29 @@
    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
src/components/chat/model/types.ts
@@ -54,22 +54,20 @@
    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,
@@ -81,10 +79,18 @@
    [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[];
};
vite.config.ts
@@ -58,7 +58,7 @@
            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,